Index: head/lib/libcasper/services/cap_fileargs/cap_fileargs.h =================================================================== --- head/lib/libcasper/services/cap_fileargs/cap_fileargs.h +++ head/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,8 @@ 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 @@ 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: head/lib/libcasper/services/cap_fileargs/cap_fileargs.3 =================================================================== --- head/lib/libcasper/services/cap_fileargs/cap_fileargs.3 +++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.3 @@ -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 @@ 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 @@ .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 @@ 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: head/lib/libcasper/services/cap_fileargs/cap_fileargs.c =================================================================== --- head/lib/libcasper/services/cap_fileargs/cap_fileargs.c +++ head/lib/libcasper/services/cap_fileargs/cap_fileargs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,37 @@ }; 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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_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 @@ } 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_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 @@ } limits = fileargs_create_limit(argc, (const char * const *)argv, flags, - mode, rightsp); + mode, rightsp, operations); if (limits == NULL) return (NULL); @@ -234,7 +271,7 @@ cap_channel_t *chann; fileargs_t *fa; int serrno, ret; - int flags; + int flags, operations; assert(cas != NULL); @@ -252,6 +289,7 @@ } 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 @@ 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 @@ 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 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 @@ void *cookie; nvlist_t *new; const char *fname; + struct stat sb; if ((capflags & O_CREAT) != 0) { allcached = true; @@ -409,14 +496,25 @@ 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 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ 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); }