From e8c9f02c2cbf937d2547b903b0c803d8a829fe21 Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Sat, 6 Mar 2021 18:21:36 -0800 Subject: Implement libcap:cap_func_launcher() This is a handy function launcher for running a function in a forked copy of the process. This fork will be terminated should the callback return. Signed-off-by: Andrew G. Morgan --- libcap/cap_alloc.c | 16 ++++++++++++++++ libcap/cap_proc.c | 35 +++++++++++++++++++++++++---------- libcap/include/sys/capability.h | 1 + 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/libcap/cap_alloc.c b/libcap/cap_alloc.c index 6dab4e6..88ba6da 100644 --- a/libcap/cap_alloc.c +++ b/libcap/cap_alloc.c @@ -146,6 +146,22 @@ cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv, return attr; } +/* + * cap_func_launcher allocates some memory for a launcher and + * initializes it. The purpose of this launcher, unlike one created + * with cap_new_launcher(), is to execute some function code from a + * forked copy of the program. The forked process will exit when the + * callback function, func, returns. + */ +cap_launch_t cap_func_launcher(int (callback_fn)(void *detail)) +{ + __u32 *data = calloc(1, sizeof(__u32) + sizeof(struct cap_launch_s)); + *(data++) = CAP_LAUNCH_MAGIC; + struct cap_launch_s *attr = (struct cap_launch_s *) data; + attr->custom_setup_fn = callback_fn; + return attr; +} + /* * Scrub and then liberate an internal capability set. */ diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c index 1329f94..4af51c4 100644 --- a/libcap/cap_proc.c +++ b/libcap/cap_proc.c @@ -848,8 +848,9 @@ static int _cap_chroot(struct syscaller_s *sc, const char *root) /* * _cap_launch is invoked in the forked child, it cannot return but is - * required to exit. If the execve fails, it will write the errno value - * over the filedescriptor, fd, and exit with status 0. + * required to exit, if the execve fails. It will write the errno + * value for any failure over the filedescriptor, fd, and exit with + * status 1. */ __attribute__ ((noreturn)) static void _cap_launch(int fd, cap_launch_t attr, void *detail) { @@ -858,6 +859,10 @@ static void _cap_launch(int fd, cap_launch_t attr, void *detail) { if (attr->custom_setup_fn && attr->custom_setup_fn(detail)) { goto defer; } + if (attr->arg0 == NULL) { + /* handle the successful cap_func_launcher completion */ + exit(0); + } if (attr->change_uids && _cap_setuid(sc, attr->uid)) { goto defer; @@ -903,20 +908,30 @@ defer: } /* - * cap_launch performs a wrapped fork+exec that works in both an - * unthreaded environment and also where libcap is linked with - * psx+pthreads. The function supports dropping privilege in the - * forked thread, but retaining privilege in the parent thread(s). + * cap_launch performs a wrapped fork+(callback and/or exec) that + * works in both an unthreaded environment and also where libcap is + * linked with psx+pthreads. The function supports dropping privilege + * in the forked thread, but retaining privilege in the parent + * thread(s). + * + * When applying the IAB vector inside the fork, since the ambient set + * is fragile with respect to changes in I or P, the function + * carefully orders setting of these inheritable characteristics, to + * make sure they stick. * - * Since the ambient set is fragile with respect to changes in I or P, - * the function carefully orders setting of these inheritable - * characteristics, to make sure they stick, or return an error - * of -1 setting errno because the launch failed. + * This function will return an error of -1 setting errno if the + * launch failed. */ pid_t cap_launch(cap_launch_t attr, void *data) { int my_errno; int ps[2]; + /* The launch must have a purpose */ + if (attr->custom_setup_fn == NULL && (attr->arg0 == NULL || attr->argv == NULL)) { + errno = EINVAL; + return -1; + } + if (pipe2(ps, O_CLOEXEC) != 0) { return -1; } diff --git a/libcap/include/sys/capability.h b/libcap/include/sys/capability.h index ac13c12..6d31019 100644 --- a/libcap/include/sys/capability.h +++ b/libcap/include/sys/capability.h @@ -185,6 +185,7 @@ typedef struct cap_launch_s *cap_launch_t; extern cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv, const char * const *envp); +extern cap_launch_t cap_func_launcher(int (callback_fn)(void *detail)); extern void cap_launcher_callback(cap_launch_t attr, int (callback_fn)(void *detail)); extern void cap_launcher_setuid(cap_launch_t attr, uid_t uid); -- cgit v1.2.1