aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2021-08-14 10:02:23 -0700
committerAndrew G. Morgan <morgan@kernel.org>2021-08-14 10:02:23 -0700
commitfd32fac5e3f13fe1b0b2a1cc22d8dfb5e608f2d7 (patch)
tree613933322df4881b9a67265c75203c739d602526
parentd5daba542ae15cf47752ab5430ded4cd0d0a7ce3 (diff)
downloadlibcap-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.c18
-rw-r--r--tests/libcap_launch_test.c29
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;
}