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@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
This commit is contained in:
parent
fc07a84f80
commit
7b558caee3
@ -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 ,
|
||||
|
@ -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,7 +60,36 @@ 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;
|
||||
@ -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 *argv, int flags,
|
||||
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_t 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_t 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 *argv[], int flags,
|
||||
}
|
||||
|
||||
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 char *mode)
|
||||
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 *limits,
|
||||
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 *limits,
|
||||
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 *limits,
|
||||
}
|
||||
|
||||
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_t *newlimits)
|
||||
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 +562,37 @@ fileargs_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
|
||||
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, 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 *nvlin,
|
||||
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");
|
||||
@ -498,6 +631,9 @@ fileargs_command(const char *cmd, const nvlist_t *limits,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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, int flags, mode_t mode,
|
||||
|
||||
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 *limits)
|
||||
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) \
|
||||
|
Loading…
Reference in New Issue
Block a user