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.ozars...@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)                                  
        \
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to