The branch main has been updated by oshogbo:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=dcdad299479e2d224448cd8a09a33afc1328aa13

commit dcdad299479e2d224448cd8a09a33afc1328aa13
Author:     Mariusz Zaborski <osho...@freebsd.org>
AuthorDate: 2021-01-10 11:44:06 +0000
Commit:     Mariusz Zaborski <osho...@freebsd.org>
CommitDate: 2021-01-10 11:44:06 +0000

    fileargs: add support for realpath
---
 lib/libcasper/services/cap_fileargs/Makefile       |   1 +
 lib/libcasper/services/cap_fileargs/cap_fileargs.3 |  13 +-
 lib/libcasper/services/cap_fileargs/cap_fileargs.c |  62 ++++++++-
 lib/libcasper/services/cap_fileargs/cap_fileargs.h |   6 +
 .../services/cap_fileargs/tests/fileargs_test.c    | 145 +++++++++++++++++++++
 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 <osho...@freebsd.org>
+ * Copyright (c) 2018-2021 Mariusz Zaborski <osho...@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)
 {
@@ -631,6 +666,28 @@ fileargs_command_lstat(const nvlist_t *limits, nvlist_t 
*nvlin,
        return (0);
 }
 
+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
@@ -141,6 +141,57 @@ test_file_lstat(fileargs_t *fa, const char *file)
        return (0);
 }
 
+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)
 {
@@ -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());
 }
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to