aboutsummaryrefslogtreecommitdiff
path: root/lib/libcasper
diff options
context:
space:
mode:
authorMariusz Zaborski <oshogbo@FreeBSD.org>2021-01-10 11:44:06 +0000
committerMariusz Zaborski <oshogbo@FreeBSD.org>2021-01-10 11:44:06 +0000
commitdcdad299479e2d224448cd8a09a33afc1328aa13 (patch)
tree91a6579b818c571c75920028e1978c119dee47d7 /lib/libcasper
parent81b3a0a34145ee6c855f50c8035728f76d63c3f0 (diff)
downloadsrc-dcdad299479e2d224448cd8a09a33afc1328aa13.tar.gz
src-dcdad299479e2d224448cd8a09a33afc1328aa13.zip
fileargs: add support for realpath
Diffstat (limited to 'lib/libcasper')
-rw-r--r--lib/libcasper/services/cap_fileargs/Makefile1
-rw-r--r--lib/libcasper/services/cap_fileargs/cap_fileargs.313
-rw-r--r--lib/libcasper/services/cap_fileargs/cap_fileargs.c62
-rw-r--r--lib/libcasper/services/cap_fileargs/cap_fileargs.h6
-rw-r--r--lib/libcasper/services/cap_fileargs/tests/fileargs_test.c145
5 files changed, 224 insertions, 3 deletions
diff --git a/lib/libcasper/services/cap_fileargs/Makefile b/lib/libcasper/services/cap_fileargs/Makefile
index 04787c01db35..22230f82d9f4 100644
--- a/lib/libcasper/services/cap_fileargs/Makefile
+++ b/lib/libcasper/services/cap_fileargs/Makefile
@@ -35,5 +35,6 @@ MLINKS+=cap_fileargs.3 fileargs_init.3
MLINKS+=cap_fileargs.3 fileargs_initnv.3
MLINKS+=cap_fileargs.3 fileargs_lstat.3
MLINKS+=cap_fileargs.3 fileargs_open.3
+MLINKS+=cap_fileargs.3 fileargs_realpath.3
.include <bsd.lib.mk>
diff --git a/lib/libcasper/services/cap_fileargs/cap_fileargs.3 b/lib/libcasper/services/cap_fileargs/cap_fileargs.3
index b59d30b2d595..acf51e4ed62b 100644
--- a/lib/libcasper/services/cap_fileargs/cap_fileargs.3
+++ b/lib/libcasper/services/cap_fileargs/cap_fileargs.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 5, 2020
+.Dd January 10, 2021
.Dt CAP_FILEARGS 3
.Os
.Sh NAME
@@ -59,6 +59,8 @@
.Fn fileargs_open "fileargs_t *fa" "const char *name"
.Ft "FILE *"
.Fn fileargs_fopen "fileargs_t *fa" "const char *name" "const char *mode"
+.Ft "char *"
+.Fn fileargs_realpath "fileargs_t *fa" "const char *pathname" "char *reserved_path"
.Sh DESCRIPTION
The library is used to simplify Capsicumizing a tools that are using file system.
Idea behind the library is that we are passing a remaining
@@ -115,6 +117,9 @@ and
.It FA_LSTAT
Allow
.Fn fileargs_lstat .
+.It FA_REALPATH
+Allow
+.Fn fileargs_realpath .
.El
.Pp
The function
@@ -161,6 +166,11 @@ and
expect that all arguments are fetched from the
.Va fileargs_t
structure.
+.Pp
+The function
+.Fn fileargs_realpath
+is equivalent to
+.Xr realpath 3 .
.Sh LIMITS
This section describe which values and types should be used to pass arguments to the
.Fa system.fileargs
@@ -261,6 +271,7 @@ fileargs_free(fa);
.Xr err 3 ,
.Xr fopen 3 ,
.Xr getopt 3 ,
+.Xr realpath 3 ,
.Xr capsicum 4 ,
.Xr nv 9
.Sh HISTORY
diff --git a/lib/libcasper/services/cap_fileargs/cap_fileargs.c b/lib/libcasper/services/cap_fileargs/cap_fileargs.c
index a777647b1720..ecab23004fcf 100644
--- a/lib/libcasper/services/cap_fileargs/cap_fileargs.c
+++ b/lib/libcasper/services/cap_fileargs/cap_fileargs.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
- * Copyright (c) 2018 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * Copyright (c) 2018-2021 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -412,6 +412,41 @@ fileargs_lstat(fileargs_t *fa, const char *name, struct stat *sb)
return (0);
}
+char *
+fileargs_realpath(fileargs_t *fa, const char *pathname, char *reserved_path)
+{
+ nvlist_t *nvl;
+ char *ret;
+
+ assert(fa != NULL);
+ assert(fa->fa_magic == FILEARGS_MAGIC);
+
+ if (pathname == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (fa->fa_chann == NULL) {
+ errno = ENOTCAPABLE;
+ return (NULL);
+ }
+
+ nvl = fileargs_fetch(fa, pathname, "realpath");
+ if (nvl == NULL)
+ return (NULL);
+
+ if (reserved_path != NULL) {
+ ret = reserved_path;
+ strcpy(reserved_path,
+ nvlist_get_string(nvl, "realpath"));
+ } else {
+ ret = nvlist_take_string(nvl, "realpath");
+ }
+ nvlist_destroy(nvl);
+
+ return (ret);
+}
+
void
fileargs_free(fileargs_t *fa)
{
@@ -632,6 +667,28 @@ fileargs_command_lstat(const nvlist_t *limits, nvlist_t *nvlin,
}
static int
+fileargs_command_realpath(const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ const char *pathname;
+ char *resolvedpath;
+
+ if (limits == NULL)
+ return (ENOTCAPABLE);
+
+ if (!fileargs_allowed(limits, nvlin, FA_REALPATH))
+ return (ENOTCAPABLE);
+
+ pathname = nvlist_get_string(nvlin, "name");
+ resolvedpath = realpath(pathname, NULL);
+ if (resolvedpath == NULL)
+ return (errno);
+
+ nvlist_move_string(nvlout, "realpath", resolvedpath);
+ return (0);
+}
+
+static int
fileargs_command_open(const nvlist_t *limits, nvlist_t *nvlin,
nvlist_t *nvlout)
{
@@ -668,9 +725,10 @@ 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));
+ if (strcmp(cmd, "realpath") == 0)
+ return (fileargs_command_realpath(limits, nvlin, nvlout));
return (EINVAL);
}
diff --git a/lib/libcasper/services/cap_fileargs/cap_fileargs.h b/lib/libcasper/services/cap_fileargs/cap_fileargs.h
index 03ff5c29d6c0..6e8523cb9423 100644
--- a/lib/libcasper/services/cap_fileargs/cap_fileargs.h
+++ b/lib/libcasper/services/cap_fileargs/cap_fileargs.h
@@ -39,6 +39,7 @@
#define FA_OPEN 1
#define FA_LSTAT 2
+#define FA_REALPATH 4
#ifdef WITH_CASPER
struct fileargs;
@@ -55,6 +56,8 @@ 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);
+char *fileargs_realpath(fileargs_t *fa, const char *pathname,
+ char *reserved_path);
void fileargs_free(fileargs_t *fa);
FILE *fileargs_fopen(fileargs_t *fa, const char *name, const char *mode);
@@ -117,6 +120,9 @@ fileargs_cinitnv(cap_channel_t *cas __unused, nvlist_t *limits)
lstat(name, sb)
#define fileargs_open(fa, name) \
open(name, fa->fa_flags, fa->fa_mode)
+#define fileargs_realpath(fa, pathname, reserved_path) \
+ realpath(pathname, reserved_path)
+
static inline
FILE *fileargs_fopen(fileargs_t *fa, const char *name, const char *mode)
{
diff --git a/lib/libcasper/services/cap_fileargs/tests/fileargs_test.c b/lib/libcasper/services/cap_fileargs/tests/fileargs_test.c
index ad889bb2986f..9a7f9dfcb9aa 100644
--- a/lib/libcasper/services/cap_fileargs/tests/fileargs_test.c
+++ b/lib/libcasper/services/cap_fileargs/tests/fileargs_test.c
@@ -142,6 +142,57 @@ test_file_lstat(fileargs_t *fa, const char *file)
}
static int
+test_file_realpath_static(fileargs_t *fa, const char *file)
+{
+ char fapath[PATH_MAX], origpath[PATH_MAX];
+
+ if (fileargs_realpath(fa, file, fapath) == NULL)
+ return (errno);
+
+ ATF_REQUIRE(realpath(file, origpath) != NULL);
+
+ if (strcmp(fapath, origpath) != 0)
+ return (EINVAL);
+
+ return (0);
+}
+
+static int
+test_file_realpath_alloc(fileargs_t *fa, const char *file)
+{
+ char *fapath, *origpath;
+ int serrno;
+
+ fapath = fileargs_realpath(fa, file, NULL);
+ if (fapath == NULL)
+ return (errno);
+
+ origpath = realpath(file, NULL);
+ ATF_REQUIRE(origpath != NULL);
+
+ serrno = 0;
+ if (strcmp(fapath, origpath) != 0)
+ serrno = EINVAL;
+
+ free(fapath);
+ free(origpath);
+
+ return (serrno);
+}
+
+static int
+test_file_realpath(fileargs_t *fa, const char *file)
+{
+ int serrno;
+
+ serrno = test_file_realpath_static(fa, file);
+ if (serrno != 0)
+ return serrno;
+
+ return (test_file_realpath_alloc(fa, file));
+}
+
+static int
test_file_mode(int fd, int mode)
{
int flags;
@@ -254,6 +305,8 @@ ATF_TC_BODY(fileargs__open_read, tc)
ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
ATF_REQUIRE(test_file_cap(fd, &norights) == false);
ATF_REQUIRE(test_file_write(fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(close(fd) == 0);
@@ -297,6 +350,8 @@ ATF_TC_BODY(fileargs__open_write, tc)
ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
ATF_REQUIRE(test_file_cap(fd, &norights) == false);
ATF_REQUIRE(test_file_read(fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(close(fd) == 0);
@@ -337,6 +392,8 @@ ATF_TC_BODY(fileargs__open_create, tc)
ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
ATF_REQUIRE(test_file_cap(fd, &norights) == false);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(close(fd) == 0);
@@ -417,6 +474,8 @@ ATF_TC_BODY(fileargs__fopen_read, tc)
ENOTCAPABLE);
ATF_REQUIRE(test_file_cap(fd, &norights) == false);
ATF_REQUIRE(test_file_fwrite(pfile) == EBADF);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(fclose(pfile) == 0);
@@ -463,6 +522,8 @@ ATF_TC_BODY(fileargs__fopen_write, tc)
ENOTCAPABLE);
ATF_REQUIRE(test_file_cap(fd, &norights) == false);
ATF_REQUIRE(test_file_fread(pfile) == EBADF);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(fclose(pfile) == 0);
@@ -504,6 +565,8 @@ ATF_TC_BODY(fileargs__fopen_create, tc)
ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
ATF_REQUIRE(test_file_fopen(fa, TEST_FILE, "w+", NULL) ==
ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(fclose(pfile) == 0);
@@ -535,6 +598,8 @@ ATF_TC_BODY(fileargs__lstat, tc)
ATF_REQUIRE(test_file_open(fa, files[i], &fd) == ENOTCAPABLE);
ATF_REQUIRE(test_file_lstat(fa, TEST_FILE) == ENOTCAPABLE);
ATF_REQUIRE(test_file_open(fa, TEST_FILE, &fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
}
}
ATF_TC_CLEANUP(fileargs__lstat, tc)
@@ -542,6 +607,36 @@ ATF_TC_CLEANUP(fileargs__lstat, tc)
clear_files();
}
+ATF_TC_WITH_CLEANUP(fileargs__realpath);
+ATF_TC_HEAD(fileargs__realpath, tc) {}
+ATF_TC_BODY(fileargs__realpath, tc)
+{
+ fileargs_t *fa;
+ size_t i;
+ int fd;
+
+ prepare_files(MAX_FILES, true);
+
+ fa = fileargs_init(MAX_FILES, files, 0, 0, NULL, FA_REALPATH);
+ ATF_REQUIRE(fa != NULL);
+
+ for (i = 0; i < MAX_FILES; i++) {
+ /* ALLOWED */
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(test_file_open(fa, files[i], &fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_lstat(fa, TEST_FILE) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_open(fa, TEST_FILE, &fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
+ }
+}
+ATF_TC_CLEANUP(fileargs__realpath, tc)
+{
+ clear_files();
+}
+
ATF_TC_WITH_CLEANUP(fileargs__open_lstat);
ATF_TC_HEAD(fileargs__open_lstat, tc) {}
ATF_TC_BODY(fileargs__open_lstat, tc)
@@ -576,6 +671,8 @@ ATF_TC_BODY(fileargs__open_lstat, tc)
ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
ATF_REQUIRE(test_file_cap(fd, &norights) == false);
ATF_REQUIRE(test_file_write(fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_realpath(fa, TEST_FILE) == ENOTCAPABLE);
/* CLOSE */
ATF_REQUIRE(close(fd) == 0);
@@ -586,6 +683,51 @@ ATF_TC_CLEANUP(fileargs__open_lstat, tc)
clear_files();
}
+ATF_TC_WITH_CLEANUP(fileargs__open_realpath);
+ATF_TC_HEAD(fileargs__open_realpath, tc) {}
+ATF_TC_BODY(fileargs__open_realpath, tc)
+{
+ cap_rights_t rights, norights;
+ fileargs_t *fa;
+ size_t i;
+ int fd;
+
+ prepare_files(MAX_FILES, true);
+
+ cap_rights_init(&rights, CAP_READ | CAP_FCNTL);
+ cap_rights_init(&norights, CAP_WRITE);
+ fa = fileargs_init(MAX_FILES, files, O_RDONLY, 0, &rights,
+ FA_OPEN | FA_REALPATH);
+ ATF_REQUIRE(fa != NULL);
+
+ for (i = 0; i < MAX_FILES; i++) {
+ /* ALLOWED */
+ /* We open file twice to check if we can. */
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == 0);
+ ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
+ ATF_REQUIRE(close(fd) == 0);
+
+ ATF_REQUIRE(test_file_open(fa, files[i], &fd) == 0);
+ ATF_REQUIRE(test_file_realpath(fa, files[i]) == 0);
+ ATF_REQUIRE(test_file_mode(fd, O_RDONLY) == 0);
+ ATF_REQUIRE(test_file_cap(fd, &rights) == true);
+ ATF_REQUIRE(test_file_read(fd) == 0);
+
+ /* DISALLOWED */
+ ATF_REQUIRE(test_file_open(fa, TEST_FILE, NULL) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_cap(fd, &norights) == false);
+ ATF_REQUIRE(test_file_write(fd) == ENOTCAPABLE);
+ ATF_REQUIRE(test_file_lstat(fa, files[i]) == ENOTCAPABLE);
+
+ /* CLOSE */
+ ATF_REQUIRE(close(fd) == 0);
+ }
+}
+ATF_TC_CLEANUP(fileargs__open_realpath, tc)
+{
+ clear_files();
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -600,7 +742,10 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, fileargs__lstat);
+ ATF_TP_ADD_TC(tp, fileargs__realpath);
+
ATF_TP_ADD_TC(tp, fileargs__open_lstat);
+ ATF_TP_ADD_TC(tp, fileargs__open_realpath);
return (atf_no_error());
}