From b56400f81ddd42e0e57372c957e668e6d5a72834 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Fri, 27 Aug 2021 10:20:21 -0700 Subject: Implement libcap:cap_proc_root() function. This is needed to locally configure libcap to find the pid data if the proc filesystem is not mounted at "/proc" (rare). Currently libcap only uses this info to implement cap_iab_get_pid(). This brings libcap back to parity with the Go "cap" package. Signed-off-by: Andrew G. Morgan --- libcap/cap_alloc.c | 9 ++++++--- libcap/cap_test.c | 26 ++++++++++++++++++++++++++ libcap/cap_text.c | 27 ++++++++++++++++++++++++++- libcap/include/sys/capability.h | 16 ++++++++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/libcap/cap_alloc.c b/libcap/cap_alloc.c index df1a275..5733e2f 100644 --- a/libcap/cap_alloc.c +++ b/libcap/cap_alloc.c @@ -8,19 +8,22 @@ #include "libcap.h" /* - * This gets set via the pre-main() executed constructor function below it. + * These get set via the pre-main() executed constructor function below it. */ static cap_value_t _cap_max_bits; -__attribute__((constructor (300))) static void _initialize_libcap(void) { +__attribute__((constructor (300))) static void _initialize_libcap(void) +{ if (_cap_max_bits) { return; } cap_set_syscall(NULL, NULL); _binary_search(_cap_max_bits, cap_get_bound, 0, __CAP_MAXBITS, __CAP_BITS); + cap_proc_root("/proc"); } -cap_value_t cap_max_bits(void) { +cap_value_t cap_max_bits(void) +{ return _cap_max_bits; } diff --git a/libcap/cap_test.c b/libcap/cap_test.c index 41192b7..9fa7300 100644 --- a/libcap/cap_test.c +++ b/libcap/cap_test.c @@ -118,6 +118,7 @@ static int test_alloc(void) cap_t c; cap_iab_t iab; cap_launch_t launcher; + char *old_root; c = cap_init(); if (c == NULL) { @@ -153,6 +154,31 @@ static int test_alloc(void) goto drop_launcher; } + old_root = cap_proc_root("blah"); + if (old_root == NULL || strcmp(old_root, "/proc") != 0) { + printf("bad initial proc_root [%s]\n", old_root); + retval = -1; + } + if (cap_free(old_root)) { + perror("unable to free old proc root"); + retval = -1; + } + if (retval) { + goto drop_launcher; + } + old_root = cap_proc_root("/proc"); + if (strcmp(old_root, "blah") != 0) { + printf("bad proc_root value [%s]\n", old_root); + retval = -1; + } + if (cap_free(old_root)) { + perror("unable to free replacement proc root"); + retval = -1; + } + if (retval) { + goto drop_launcher; + } + drop_launcher: if (cap_free(launcher)) { perror("failed to free launcher"); diff --git a/libcap/cap_text.c b/libcap/cap_text.c index a0857bc..013eb1e 100644 --- a/libcap/cap_text.c +++ b/libcap/cap_text.c @@ -667,6 +667,31 @@ static __u32 _parse_vec_string(__u32 *vals, const char *c, int invert) return ~0; } +/* + * libcap believes this is the root of the mounted "/proc" + * filesystem + */ +static char *_cap_proc_dir; + +/* + * cap_proc_root reads and (optionally: when root != NULL) changes + * libcap's notion of where the "/proc" filesystem is mounted. It + * defaults to the value "/proc". Note, this is a global value and not + * considered thread safe to write - so the client should take + * suitable care when changing it. Further, libcap will allocate + * memory for storing the replacement root, and it is this memory that + * is returned. So, when changing the value, the caller should + * cap_free(the-return-value) when done with it. + */ +char *cap_proc_root(const char *root) +{ + char *old = _cap_proc_dir; + if (root != NULL) { + _cap_proc_dir = _libcap_strdup(root); + } + return old; +} + #define PROC_LINE_MAX (8 + 8*_LIBCAP_CAPABILITY_U32S + 100) /* * cap_iab_get_pid fills an IAB tuple from the content of @@ -680,7 +705,7 @@ cap_iab_t cap_iab_get_pid(pid_t pid) FILE *file; char line[PROC_LINE_MAX]; - if (asprintf(&path, "/proc/%d/status", pid) <= 0) { + if (asprintf(&path, "%s/%d/status", _cap_proc_dir, pid) <= 0) { return NULL; } file = fopen(path, "r"); diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h index f98da5a..59f9377 100644 --- a/libcap/include/sys/capability.h +++ b/libcap/include/sys/capability.h @@ -53,6 +53,22 @@ typedef int cap_value_t; */ extern cap_value_t cap_max_bits(void); +/* + * cap_proc_root reads and (optionally: when root != NULL) changes + * libcap's notion of where the "/proc" filesystem is mounted. It + * defaults to the value "/proc". + * + * Note, this is a global value and not considered thread safe to + * write - so the client should take suitable care when changing + * it. + * + * Further, libcap will allocate a memory copy for storing the + * replacement root, and it is this kind of memory that is returned. + * So, when changing the value, the caller should + * cap_free(the-return-value) when done with it. + */ +extern char *cap_proc_root(const char *root); + /* * Set identifiers */ -- cgit v1.2.1