svn commit: r346315 - head/lib/libcasper/services/cap_fileargs

Ed Maste emaste at FreeBSD.org
Wed Apr 17 16:02:59 UTC 2019


Author: emaste
Date: Wed Apr 17 16:02:57 2019
New Revision: 346315
URL: https://svnweb.freebsd.org/changeset/base/346315

Log:
  cap_fileargs: add fileargs_lstat service
  
  Add fileargs_lstat function to cap_fileargs casper service to be able to
  lstat files while in capability mode.  It can only lstat files given in
  fileargs_init.
  
  Submitted by:	Bora Özarslan <borako.ozarslan at gmail.com>
  Reviewed by:	oshogbo, cem (partial)
  MFC after:	3 weeks
  Relnotes:	Yes
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D19548

Modified:
  head/lib/libcasper/services/cap_fileargs/cap_fileargs.3
  head/lib/libcasper/services/cap_fileargs/cap_fileargs.c
  head/lib/libcasper/services/cap_fileargs/cap_fileargs.h

Modified: head/lib/libcasper/services/cap_fileargs/cap_fileargs.3
==============================================================================
--- head/lib/libcasper/services/cap_fileargs/cap_fileargs.3	Wed Apr 17 16:00:33 2019	(r346314)
+++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.3	Wed Apr 17 16:02:57 2019	(r346315)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 12, 2018
+.Dd April 17, 2019
 .Dt CAP_FILEARGS 3
 .Os
 .Sh NAME
@@ -33,6 +33,7 @@
 .Nm fileargs_init ,
 .Nm fileargs_initnv ,
 .Nm fileargs_free ,
+.Nm fileargs_lstat ,
 .Nm fileargs_open ,
 .Nm fileargs_fopen
 .Nd "library for handling files in capability mode"
@@ -43,9 +44,9 @@
 .In libcasper.h
 .In casper/cap_fileargs.h
 .Ft "fileargs_t *"
-.Fn fileargs_init "int argc" "char *argv[]" "int flags" "mode_t mode" "cap_rights_t *rightsp"
+.Fn fileargs_init "int argc" "char *argv[]" "int flags" "mode_t mode" "cap_rights_t *rightsp" "int operations"
 .Ft "fileargs_t *"
-.Fn fileargs_cinit "cap_channel_t *cas" "int argc" "char *argv[]" "int flags" "mode_t mode" "cap_rights_t *rightsp"
+.Fn fileargs_cinit "cap_channel_t *cas" "int argc" "char *argv[]" "int flags" "mode_t mode" "cap_rights_t *rightsp" "int operations"
 .Ft "fileargs_t *"
 .Fn fileargs_cinitnv "cap_channel_t *cas" "nvlist_t *limits"
 .Ft "fileargs_t *"
@@ -53,6 +54,8 @@
 .Ft "void"
 .Fn fileargs_free "fileargs_t *fa"
 .Ft "int"
+.Fn fileargs_lstat "fileargs_t *fa" "const char *path" "struct stat *sb"
+.Ft "int"
 .Fn fileargs_open "fileargs_t *fa" "const char *name"
 .Ft "FILE *"
 .Fn fileargs_fopen "fileargs_t *fa" "const char *name" "const char *mode"
@@ -97,6 +100,22 @@ The
 argument contains a list of the capability rights which file should be limited to.
 For more details of the capability rights see
 .Xr cap_rights_init 3 .
+The
+.Fa operations
+argument limits the operations that are available using
+.Nm system.fileargs .
+.Fa operations
+is a combination of:
+.Bl -ohang -offset indent
+.It FA_OPEN
+Allow
+.Fn fileargs_open
+and
+.Fn fileargs_fopen .
+.It FA_LSTAT
+Allow
+.Fn fileargs_lstat .
+.El
 .Pp
 The function
 .Fn fileargs_cinit
@@ -126,6 +145,11 @@ The function handle
 .Dv NULL
 argument.
 .Pp
+The function
+.Fn fileargs_lstat
+is equivalent to
+.Xr lstat 2 .
+.Pp
 The functions
 .Fn fileargs_open
 and
@@ -165,6 +189,15 @@ must contain the
 The
 .Va mode
 argument tells which what mode file should be created.
+.It operations (NV_TYPE_NUMBER)
+The
+.Va operations
+limits the usable operations for
+.Fa system.fileargs .
+The possible values are explained as
+.Va operations
+argument with
+.Fn fileargs_init .
 .El
 .Pp
 The
@@ -201,7 +234,7 @@ argv += optind;
 
 /* Create capability to the system.fileargs service. */
 fa = fileargs_init(argc, argv, O_RDONLY, 0,
-    cap_rights_init(&rights, CAP_READ));
+    cap_rights_init(&rights, CAP_READ), FA_OPEN);
 if (fa == NULL)
 	err(1, "unable to open system.fileargs service");
 
@@ -222,6 +255,7 @@ fileargs_free(fa);
 .Ed
 .Sh SEE ALSO
 .Xr cap_enter 2 ,
+.Xr lstat 2 ,
 .Xr open 2 ,
 .Xr cap_rights_init 3 ,
 .Xr err 3 ,

Modified: head/lib/libcasper/services/cap_fileargs/cap_fileargs.c
==============================================================================
--- head/lib/libcasper/services/cap_fileargs/cap_fileargs.c	Wed Apr 17 16:00:33 2019	(r346314)
+++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.c	Wed Apr 17 16:02:57 2019	(r346315)
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/cnv.h>
 #include <sys/dnv.h>
 #include <sys/nv.h>
+#include <sys/stat.h>
 
 #include <assert.h>
 #include <errno.h>
@@ -59,8 +60,37 @@ struct fileargs {
 };
 
 static int
-fileargs_get_cache(fileargs_t *fa, const char *name)
+fileargs_get_lstat_cache(fileargs_t *fa, const char *name, struct stat *sb)
 {
+	const nvlist_t *nvl;
+	size_t size;
+	const void *buf;
+
+	assert(fa != NULL);
+	assert(fa->fa_magic == FILEARGS_MAGIC);
+	assert(name != NULL);
+
+	if (fa->fa_cache == NULL)
+		return (-1);
+
+	nvl = dnvlist_get_nvlist(fa->fa_cache, name, NULL);
+	if (nvl == NULL)
+		return (-1);
+
+	if (!nvlist_exists_binary(nvl, "stat")) {
+		return (-1);
+	}
+
+	buf = nvlist_get_binary(nvl, "stat", &size);
+	assert(size == sizeof(*sb));
+	memcpy(sb, buf, size);
+
+	return (0);
+}
+
+static int
+fileargs_get_fd_cache(fileargs_t *fa, const char *name)
+{
 	int fd;
 	const nvlist_t *nvl;
 	nvlist_t *tnvl;
@@ -80,6 +110,12 @@ fileargs_get_cache(fileargs_t *fa, const char *name)
 		return (-1);
 
 	tnvl = nvlist_take_nvlist(fa->fa_cache, name);
+
+	if (!nvlist_exists_descriptor(tnvl, "fd")) {
+		nvlist_destroy(tnvl);
+		return (-1);
+	}
+
 	fd = nvlist_take_descriptor(tnvl, "fd");
 	nvlist_destroy(tnvl);
 
@@ -102,7 +138,7 @@ fileargs_set_cache(fileargs_t *fa, nvlist_t *nvl)
 }
 
 static nvlist_t*
-fileargs_fetch(fileargs_t *fa, const char *name)
+fileargs_fetch(fileargs_t *fa, const char *name, const char *cmd)
 {
 	nvlist_t *nvl;
 	int serrno;
@@ -111,7 +147,7 @@ fileargs_fetch(fileargs_t *fa, const char *name)
 	assert(name != NULL);
 
 	nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
-	nvlist_add_string(nvl, "cmd", "open");
+	nvlist_add_string(nvl, "cmd", cmd);
 	nvlist_add_string(nvl, "name", name);
 
 	nvl = cap_xfer_nvlist(fa->fa_chann, nvl);
@@ -130,7 +166,7 @@ fileargs_fetch(fileargs_t *fa, const char *name)
 
 static nvlist_t *
 fileargs_create_limit(int argc, const char * const *argv, int flags,
-    mode_t mode, cap_rights_t *rightsp)
+    mode_t mode, cap_rights_t *rightsp, int operations)
 {
 	nvlist_t *limits;
 	int i;
@@ -140,6 +176,7 @@ fileargs_create_limit(int argc, const char * const *ar
 		return (NULL);
 
 	nvlist_add_number(limits, "flags", flags);
+	nvlist_add_number(limits, "operations", operations);
 	if (rightsp != NULL) {
 		nvlist_add_binary(limits, "cap_rights", rightsp,
 		    sizeof(*rightsp));
@@ -172,7 +209,7 @@ fileargs_create(cap_channel_t *chan, int fdflags)
 
 fileargs_t *
 fileargs_init(int argc, char *argv[], int flags, mode_t mode,
-    cap_rights_t *rightsp)
+    cap_rights_t *rightsp, int operations)
 {
 	nvlist_t *limits;
 
@@ -181,7 +218,7 @@ fileargs_init(int argc, char *argv[], int flags, mode_
 	}
 
 	limits = fileargs_create_limit(argc, (const char * const *)argv, flags,
-	   mode, rightsp);
+	   mode, rightsp, operations);
 	if (limits == NULL)
 		return (NULL);
 
@@ -190,7 +227,7 @@ fileargs_init(int argc, char *argv[], int flags, mode_
 
 fileargs_t *
 fileargs_cinit(cap_channel_t *cas, int argc, char *argv[], int flags,
-     mode_t mode, cap_rights_t *rightsp)
+     mode_t mode, cap_rights_t *rightsp, int operations)
 {
 	nvlist_t *limits;
 
@@ -199,7 +236,7 @@ fileargs_cinit(cap_channel_t *cas, int argc, char *arg
 	}
 
 	limits = fileargs_create_limit(argc, (const char * const *)argv, flags,
-	   mode, rightsp);
+	   mode, rightsp, operations);
 	if (limits == NULL)
 		return (NULL);
 
@@ -234,7 +271,7 @@ fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits)
 	cap_channel_t *chann;
 	fileargs_t *fa;
 	int serrno, ret;
-	int flags;
+	int flags, operations;
 
 	assert(cas != NULL);
 
@@ -252,6 +289,7 @@ fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits)
 	}
 
 	flags = nvlist_get_number(limits, "flags");
+	operations = nvlist_get_number(limits, "operations");
 
 	/* Limits are consumed no need to free them. */
 	ret = cap_limit_set(chann, limits);
@@ -291,11 +329,11 @@ fileargs_open(fileargs_t *fa, const char *name)
 		return (-1);
 	}
 
-	fd = fileargs_get_cache(fa, name);
+	fd = fileargs_get_fd_cache(fa, name);
 	if (fd != -1)
 		return (fd);
 
-	nvl = fileargs_fetch(fa, name);
+	nvl = fileargs_fetch(fa, name, "open");
 	if (nvl == NULL)
 		return (-1);
 
@@ -322,6 +360,53 @@ fileargs_fopen(fileargs_t *fa, const char *name, const
 	return (fdopen(fd, mode));
 }
 
+int
+fileargs_lstat(fileargs_t *fa, const char *name, struct stat *sb)
+{
+	nvlist_t *nvl;
+	const void *buf;
+	size_t size;
+	char *cmd;
+
+	assert(fa != NULL);
+	assert(fa->fa_magic == FILEARGS_MAGIC);
+
+	if (name == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (sb == NULL) {
+		errno = EFAULT;
+		return (-1);
+	}
+
+	if (fa->fa_chann == NULL) {
+		errno = ENOTCAPABLE;
+		return (-1);
+	}
+
+	if (fileargs_get_lstat_cache(fa, name, sb) != -1)
+		return (0);
+
+	nvl = fileargs_fetch(fa, name, "lstat");
+	if (nvl == NULL)
+		return (-1);
+
+	buf = nvlist_get_binary(nvl, "stat", &size);
+	assert(size == sizeof(*sb));
+	memcpy(sb, buf, size);
+
+	cmd = nvlist_take_string(nvl, "cmd");
+	if (strcmp(cmd, "cache") == 0)
+		fileargs_set_cache(fa, nvl);
+	else
+		nvlist_destroy(nvl);
+	free(cmd);
+
+	return (0);
+}
+
 void
 fileargs_free(fileargs_t *fa)
 {
@@ -348,6 +433,7 @@ static void *cacheposition;
 static bool allcached;
 static const cap_rights_t *caprightsp;
 static int capflags;
+static int allowed_operations;
 static mode_t capmode;
 
 static int
@@ -382,6 +468,7 @@ fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *l
 	void *cookie;
 	nvlist_t *new;
 	const char *fname;
+	struct stat sb;
 
 	if ((capflags & O_CREAT) != 0) {
 		allcached = true;
@@ -409,14 +496,25 @@ fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *l
 			continue;
 		}
 
-		fd = open_file(fname);
-		if (fd < 0) {
-			i--;
-			continue;
+		new = nvlist_create(NV_FLAG_NO_UNIQUE);
+		if ((allowed_operations & FA_OPEN) != 0) {
+			fd = open_file(fname);
+			if (fd < 0) {
+				i--;
+				nvlist_destroy(new);
+				continue;
+			}
+			nvlist_move_descriptor(new, "fd", fd);
 		}
+		if ((allowed_operations & FA_LSTAT) != 0) {
+			if (lstat(fname, &sb) < 0) {
+				i--;
+				nvlist_destroy(new);
+				continue;
+			}
+			nvlist_add_binary(new, "stat", &sb, sizeof(sb));
+		}
 
-		new = nvlist_create(NV_FLAG_NO_UNIQUE);
-		nvlist_move_descriptor(new, "fd", fd);
 		nvlist_add_nvlist(nvlout, fname, new);
 	}
 	cacheposition = cookie;
@@ -424,10 +522,13 @@ fileargs_add_cache(nvlist_t *nvlout, const nvlist_t *l
 }
 
 static bool
-fileargs_allowed(const nvlist_t *limits, const nvlist_t *request)
+fileargs_allowed(const nvlist_t *limits, const nvlist_t *request, int operation)
 {
 	const char *name;
 
+	if ((allowed_operations & operation) == 0)
+		return (false);
+
 	name = dnvlist_get_string(request, "name", NULL);
 	if (name == NULL)
 		return (false);
@@ -450,6 +551,7 @@ fileargs_limit(const nvlist_t *oldlimits, const nvlist
 		return (ENOTCAPABLE);
 
 	capflags = (int)dnvlist_get_number(newlimits, "flags", 0);
+	allowed_operations = (int)dnvlist_get_number(newlimits, "operations", 0);
 	if ((capflags & O_CREAT) != 0)
 		capmode = (mode_t)nvlist_get_number(newlimits, "mode");
 	else
@@ -461,6 +563,37 @@ fileargs_limit(const nvlist_t *oldlimits, const nvlist
 }
 
 static int
+fileargs_command_lstat(const nvlist_t *limits, nvlist_t *nvlin,
+    nvlist_t *nvlout)
+{
+	int stat;
+	const char *name;
+	struct stat sb;
+
+	if (limits == NULL)
+		return (ENOTCAPABLE);
+
+	if (!fileargs_allowed(limits, nvlin, FA_LSTAT))
+		return (ENOTCAPABLE);
+
+	name = nvlist_get_string(nvlin, "name");
+
+	stat = lstat(name, &sb);
+	if (stat < 0)
+		return (errno);
+
+	if (!allcached && (lastname == NULL ||
+	    strcmp(name, lastname) == 0)) {
+		nvlist_add_string(nvlout, "cmd", "cache");
+		fileargs_add_cache(nvlout, limits, name);
+	} else {
+		nvlist_add_string(nvlout, "cmd", "lstat");
+	}
+	nvlist_add_binary(nvlout, "stat", &sb, sizeof(sb));
+	return (0);
+}
+
+static int
 fileargs_command_open(const nvlist_t *limits, nvlist_t *nvlin,
     nvlist_t *nvlout)
 {
@@ -470,7 +603,7 @@ fileargs_command_open(const nvlist_t *limits, nvlist_t
 	if (limits == NULL)
 		return (ENOTCAPABLE);
 
-	if (!fileargs_allowed(limits, nvlin))
+	if (!fileargs_allowed(limits, nvlin, FA_OPEN))
 		return (ENOTCAPABLE);
 
 	name = nvlist_get_string(nvlin, "name");
@@ -497,6 +630,9 @@ fileargs_command(const char *cmd, const nvlist_t *limi
 
 	if (strcmp(cmd, "open") == 0)
 		return (fileargs_command_open(limits, nvlin, nvlout));
+
+	if (strcmp(cmd, "lstat") == 0)
+		return (fileargs_command_lstat(limits, nvlin, nvlout));
 
 	return (EINVAL);
 }

Modified: head/lib/libcasper/services/cap_fileargs/cap_fileargs.h
==============================================================================
--- head/lib/libcasper/services/cap_fileargs/cap_fileargs.h	Wed Apr 17 16:00:33 2019	(r346314)
+++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.h	Wed Apr 17 16:02:57 2019	(r346315)
@@ -36,16 +36,21 @@
 
 #include <stdbool.h>
 
+#define	FA_OPEN		1
+#define	FA_LSTAT	2
+
 #ifdef WITH_CASPER
 struct fileargs;
 typedef struct fileargs fileargs_t;
+struct stat;
 
 fileargs_t *fileargs_init(int argc, char *argv[], int flags, mode_t mode,
-    cap_rights_t *rightsp);
+    cap_rights_t *rightsp, int operations);
 fileargs_t *fileargs_cinit(cap_channel_t *cas, int argc, char *argv[],
-    int flags, mode_t mode, cap_rights_t *rightsp);
+    int flags, mode_t mode, cap_rights_t *rightsp, int operations);
 fileargs_t *fileargs_initnv(nvlist_t *limits);
 fileargs_t *fileargs_cinitnv(cap_channel_t *cas, nvlist_t *limits);
+int fileargs_lstat(fileargs_t *fa, const char *name, struct stat *sb);
 int fileargs_open(fileargs_t *fa, const char *name);
 void fileargs_free(fileargs_t *fa);
 FILE *fileargs_fopen(fileargs_t *fa, const char *name, const char *mode);
@@ -57,7 +62,7 @@ typedef struct fileargs {
 
 static inline fileargs_t *
 fileargs_init(int argc __unused, char *argv[] __unused, int flags, mode_t mode,
-    cap_rights_t *rightsp __unused) {
+    cap_rights_t *rightsp __unused, int operations __unused) {
 	fileargs_t *fa;
 
 	fa = malloc(sizeof(*fa));
@@ -71,10 +76,10 @@ fileargs_init(int argc __unused, char *argv[] __unused
 
 static inline fileargs_t *
 fileargs_cinit(cap_channel_t *cas __unused, int argc, char *argv[], int flags,
-    mode_t mode, cap_rights_t *rightsp)
+    mode_t mode, cap_rights_t *rightsp, int operations)
 {
 
-	return (fileargs_init(argc, argv, flags, mode, rightsp));
+	return (fileargs_init(argc, argv, flags, mode, rightsp, operations));
 }
 
 static inline fileargs_t *
@@ -85,7 +90,8 @@ fileargs_initnv(nvlist_t *limits)
 	fa = fileargs_init(0, NULL,
 	    nvlist_get_number(limits, "flags"),
 	    dnvlist_get_number(limits, "mode", 0),
-	    NULL);
+	    NULL,
+	    nvlist_get_number(limits, "operations"));
 	nvlist_destroy(limits);
 
 	return (fa);
@@ -98,6 +104,8 @@ fileargs_cinitnv(cap_channel_t *cas __unused, nvlist_t
 	return (fileargs_initnv(limits));
 }
 
+#define fileargs_lstat(fa, name, sb)						\
+	lstat(name, sb)
 #define	fileargs_open(fa, name)							\
 	open(name, fa->fa_flags, fa->fa_mode)
 #define	fileargs_fopen(fa, name, mode)						\


More information about the svn-src-all mailing list