diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2021-03-06 18:21:36 -0800 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-03-06 18:21:36 -0800 |
commit | e8c9f02c2cbf937d2547b903b0c803d8a829fe21 (patch) | |
tree | 9473ae3f5374f8d4b937fc8f2f5f72fb7a7b0c3d | |
parent | 5fab07ff916030dfbffc836249c0de2711537605 (diff) | |
download | libcap2-e8c9f02c2cbf937d2547b903b0c803d8a829fe21.tar.gz |
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 <morgan@kernel.org>
-rw-r--r-- | libcap/cap_alloc.c | 16 | ||||
-rw-r--r-- | libcap/cap_proc.c | 35 | ||||
-rw-r--r-- | 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 @@ -147,6 +147,22 @@ cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv, } /* + * 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); |