Index: lib/libcasper/services/cap_fileargs/cap_fileargs.h =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.h +++ lib/libcasper/services/cap_fileargs/cap_fileargs.h @@ -36,16 +36,21 @@ #include +#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 @@ 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 @@ 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,7 @@ fa = fileargs_init(0, NULL, nvlist_get_number(limits, "flags"), dnvlist_get_number(limits, "mode", 0), - NULL); + NULL, 0); nvlist_destroy(limits); return (fa); @@ -98,6 +103,8 @@ 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) \ Index: lib/libcasper/services/cap_fileargs/cap_fileargs.3 =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.3 +++ lib/libcasper/services/cap_fileargs/cap_fileargs.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 12, 2018 +.Dd March 12, 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 @@ 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 @@ -120,12 +139,17 @@ The .Fa fileargs_free close connection to the -.Nm system.filerags +.Nm system.fileargs service and free are structures. 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 @@ -139,11 +163,11 @@ structure. .Sh LIMITS This section describe which values and types should be used to pass arguments to the -.Fa system.filerags +.Fa system.fileargs through the -.Fn fileargs_ininv +.Fn fileargs_initnv and -.Fn fileargs_cinit +.Fn fileargs_cinitnv functions. The .Xr nvlist 9 @@ -165,6 +189,15 @@ 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 @@ /* 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 @@ .Ed .Sh SEE ALSO .Xr cap_enter 2 , +.Xr lstat 2 , .Xr open 2 , .Xr cap_rights_init 3 , .Xr err 3 , Index: lib/libcasper/services/cap_fileargs/cap_fileargs.c =================================================================== --- lib/libcasper/services/cap_fileargs/cap_fileargs.c +++ lib/libcasper/services/cap_fileargs/cap_fileargs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -56,10 +57,40 @@ nvlist_t *fa_cache; cap_channel_t *fa_chann; int fa_fdflags; + int fa_operations; }; 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; @@ -80,6 +111,12 @@ 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 +139,7 @@ } 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 +148,7 @@ 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 +167,7 @@ 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 +177,7 @@ 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)); @@ -155,7 +193,7 @@ } static fileargs_t * -fileargs_create(cap_channel_t *chan, int fdflags) +fileargs_create(cap_channel_t *chan, int fdflags, int operations) { fileargs_t *fa; @@ -165,6 +203,7 @@ fa->fa_chann = chan; fa->fa_fdflags = fdflags; fa->fa_magic = FILEARGS_MAGIC; + fa->fa_operations = operations; } return (fa); @@ -172,16 +211,16 @@ 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; if (argc <= 0 || argv == NULL) { - return (fileargs_create(NULL, 0)); + return (fileargs_create(NULL, 0, 0)); } limits = fileargs_create_limit(argc, (const char * const *)argv, flags, - mode, rightsp); + mode, rightsp, operations); if (limits == NULL) return (NULL); @@ -190,16 +229,16 @@ 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; if (argc <= 0 || argv == NULL) { - return (fileargs_create(NULL, 0)); + return (fileargs_create(NULL, 0, 0)); } limits = fileargs_create_limit(argc, (const char * const *)argv, flags, - mode, rightsp); + mode, rightsp, operations); if (limits == NULL) return (NULL); @@ -213,7 +252,7 @@ fileargs_t *fa; if (limits == NULL) { - return (fileargs_create(NULL, 0)); + return (fileargs_create(NULL, 0, 0)); } cas = cap_init(); @@ -234,12 +273,12 @@ cap_channel_t *chann; fileargs_t *fa; int serrno, ret; - int flags; + int flags, operations; assert(cas != NULL); if (limits == NULL) { - return (fileargs_create(NULL, 0)); + return (fileargs_create(NULL, 0, 0)); } chann = NULL; @@ -252,13 +291,14 @@ } 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); if (ret < 0) goto out; - fa = fileargs_create(chann, flags); + fa = fileargs_create(chann, flags, operations); if (fa == NULL) goto out; @@ -286,16 +326,16 @@ return (-1); } - if (fa->fa_chann == NULL) { + if (fa->fa_chann == NULL || (fa->fa_operations & FA_OPEN) == 0) { errno = ENOTCAPABLE; 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 +362,53 @@ 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 || (fa->fa_operations & FA_LSTAT) == 0) { + 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 +435,7 @@ static bool allcached; static const cap_rights_t *caprightsp; static int capflags; +static int allowed_operations; static mode_t capmode; static int @@ -382,6 +470,7 @@ void *cookie; nvlist_t *new; const char *fname; + struct stat sb; if ((capflags & O_CREAT) != 0) { allcached = true; @@ -409,14 +498,25 @@ continue; } - fd = open_file(fname); - if (fd < 0) { - i--; - continue; + new = nvlist_create(NV_FLAG_NO_UNIQUE); + if (allowed_operations & FA_OPEN) { + fd = open_file(fname); + if (fd < 0) { + i--; + nvlist_destroy(new); + continue; + } + nvlist_move_descriptor(new, "fd", fd); + } + if (allowed_operations & FA_LSTAT) { + 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; @@ -450,6 +550,7 @@ 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 @@ -460,6 +561,37 @@ return (0); } +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)) + 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) @@ -498,6 +630,9 @@ 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); }