diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2021-08-14 10:02:23 -0700 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2021-08-14 10:02:23 -0700 |
commit | fd32fac5e3f13fe1b0b2a1cc22d8dfb5e608f2d7 (patch) | |
tree | 613933322df4881b9a67265c75203c739d602526 | |
parent | d5daba542ae15cf47752ab5430ded4cd0d0a7ce3 (diff) | |
download | libcap-fd32fac5e3f13fe1b0b2a1cc22d8dfb5e608f2d7.tar.gz |
Fix cap_launch failures - error propogation.
All credit for this fix goes to Samanta Navarro. The launch error
propagation code was evidently broken previously.
Samanta also provided a proof of concept test case and we've
included that in the tests/libcap_launch_test.c.
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r-- | libcap/cap_proc.c | 18 | ||||
-rw-r--r-- | tests/libcap_launch_test.c | 29 |
2 files changed, 28 insertions, 19 deletions
diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c index c0f66a9..8116734 100644 --- a/libcap/cap_proc.c +++ b/libcap/cap_proc.c @@ -948,9 +948,11 @@ defer: pid_t cap_launch(cap_launch_t attr, void *detail) { int my_errno; int ps[2]; + pid_t child; /* The launch must have a purpose */ - if (attr->custom_setup_fn == NULL && (attr->arg0 == NULL || attr->argv == NULL)) { + if (attr->custom_setup_fn == NULL && + (attr->arg0 == NULL || attr->argv == NULL)) { errno = EINVAL; return -1; } @@ -959,19 +961,19 @@ pid_t cap_launch(cap_launch_t attr, void *detail) { return -1; } - int child = fork(); + child = fork(); my_errno = errno; - close(ps[1]); - if (child < 0) { - goto defer; - } if (!child) { close(ps[0]); prctl(PR_SET_NAME, "cap-launcher", 0, 0, 0); _cap_launch(ps[1], attr, detail); /* no return from this function */ - exit(1); + _exit(1); + } + close(ps[1]); + if (child < 0) { + goto defer; } /* @@ -996,5 +998,5 @@ pid_t cap_launch(cap_launch_t attr, void *detail) { defer: close(ps[0]); errno = my_errno; - return (pid_t) child; + return child; } diff --git a/tests/libcap_launch_test.c b/tests/libcap_launch_test.c index 5286979..f45b2b7 100644 --- a/tests/libcap_launch_test.c +++ b/tests/libcap_launch_test.c @@ -24,6 +24,7 @@ struct test_case_s { const char **envp; const char *iab; cap_mode_t mode; + int launch_abort; int result; int (*callback_fn)(void *detail); }; @@ -64,6 +65,10 @@ int main(int argc, char **argv) { .result = 256 }, { + .args = { "/", "won't", "work" }, + .launch_abort = 1, + }, + { .args = { "../progs/tcapsh-static", "--is-uid=123" }, .uid = 123, .result = 0, @@ -72,7 +77,7 @@ int main(int argc, char **argv) { .args = { "../progs/tcapsh-static", "--is-uid=123" }, .callback_fn = &clean_out, .uid = 123, - .result = 256 + .launch_abort = 1, }, { .args = { "../progs/tcapsh-static", "--is-gid=123" }, @@ -118,7 +123,7 @@ int main(int argc, char **argv) { for (i=0; vs[i].pass_on != NO_MORE; i++) { const struct test_case_s *v = &vs[i]; printf("[%d] test should %s\n", i, - v->result ? "generate error" : "work"); + v->result || v->launch_abort ? "generate error" : "work"); cap_launch_t attr; if (v->args[0] != NULL) { attr = cap_new_launcher(v->args[0], v->args, v->envp); @@ -160,28 +165,30 @@ int main(int argc, char **argv) { pid_t child = cap_launch(attr, NULL); if (child <= 0) { - fprintf(stderr, "[%d] failed to launch", i); - perror(":"); - success = 0; + fprintf(stderr, "[%d] failed to launch: ", i); + perror(""); + if (!v->launch_abort) { + success = 0; + } continue; } if (cap_free(attr)) { - fprintf(stderr, "[%d] failed to free launcher", i); - perror(":"); + fprintf(stderr, "[%d] failed to free launcher: ", i); + perror(""); success = 0; } int result; int ret = waitpid(child, &result, 0); if (ret != child) { - fprintf(stderr, "[%d] failed to wait", i); - perror(":"); + fprintf(stderr, "[%d] failed to wait: ", i); + perror(""); success = 0; continue; } if (result != v->result) { - fprintf(stderr, "[%d] bad result: got=%d want=%d", i, result, + fprintf(stderr, "[%d] bad result: got=%d want=%d: ", i, result, v->result); - perror(":"); + perror(""); success = 0; continue; } |