summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2021-03-06 18:21:36 -0800
committerAndrew G. Morgan <morgan@kernel.org>2021-03-06 18:21:36 -0800
commite8c9f02c2cbf937d2547b903b0c803d8a829fe21 (patch)
tree9473ae3f5374f8d4b937fc8f2f5f72fb7a7b0c3d
parent5fab07ff916030dfbffc836249c0de2711537605 (diff)
downloadlibcap2-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.c16
-rw-r--r--libcap/cap_proc.c35
-rw-r--r--libcap/include/sys/capability.h1
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);