diff options
author | Andrew G. Morgan <morgan@kernel.org> | 2020-10-27 14:56:34 -0700 |
---|---|---|
committer | Andrew G. Morgan <morgan@kernel.org> | 2020-10-27 14:56:34 -0700 |
commit | 68240b124cc62744a7a412a7afc85b5c56a48e14 (patch) | |
tree | 68345d042be442ad6d3cef46838015753dbea72a | |
parent | 1d03d736252237edd364142bd034715d743ace0b (diff) | |
download | libcap2-68240b124cc62744a7a412a7afc85b5c56a48e14.tar.gz |
If needed search PATH for capsh (==) self-execution.
This addresses the following bug:
https://bugzilla.kernel.org/show_bug.cgi?id=209873
Namely, the following didn't previously work:
PATH=/sbin capsh == --print
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r-- | doc/capsh.1 | 14 | ||||
-rw-r--r-- | progs/capsh.c | 51 | ||||
-rwxr-xr-x | progs/quicktest.sh | 7 |
3 files changed, 67 insertions, 5 deletions
diff --git a/doc/capsh.1 b/doc/capsh.1 index b02793b..ab20c44 100644 --- a/doc/capsh.1 +++ b/doc/capsh.1 @@ -1,4 +1,4 @@ -.TH CAPSH 1 "2020-01-07" "libcap 2" "User Commands" +.TH CAPSH 1 "2020-10-27" "libcap 2" "User Commands" .SH NAME capsh \- capability shell wrapper .SH SYNOPSIS @@ -33,7 +33,15 @@ Execute .B capsh again with the remaining arguments. Useful for testing .BR exec () -behavior. +behavior. Note, PATH is searched when the running +.B capsh +was found via the shell's PATH searching. If the +.B exec +occurs after a +.BI \-\-chroot= /some/path +argument the PATH located binary may not be resolve to the same binary +as that running initially. This behavior is an intented feature as it +can complete the chroot transition. .TP .BI \-\-caps= cap-set Set the prevailing process capabilities to those specified by @@ -179,7 +187,7 @@ The argument is expressed as a numeric bitmask, in any of the formats permitted by .BR strtoul (3). .TP -.BI \-\-chroot= path +.BI \-\-chroot= /some/path Execute the .BR chroot (2) system call with the new root-directory (/) equal to diff --git a/progs/capsh.c b/progs/capsh.c index 7bed98e..4f0b603 100644 --- a/progs/capsh.c +++ b/progs/capsh.c @@ -324,6 +324,49 @@ static void arg_change_amb(const char *arg_names, cap_flag_value_t set) free(names); } +/* + * find_self locates and returns the full pathname of the named binary + * that is running. Importantly, it looks in the context of the + * prevailing CHROOT. Further, it does not fail over to invoking a + * shell if the target binary looks like something other than a + * executable. If an executable is not found, the function terminates + * the program with an error. + */ +static char *find_self(const char *arg0) +{ + int i; + char *parts, *dir, *scratch; + const char *path; + + for (i = strlen(arg0)-1; i >= 0 && arg0[i] != '/'; i--); + if (i >= 0) { + return strdup(arg0); + } + + path = getenv("PATH"); + if (path == NULL) { + fprintf(stderr, "no PATH environment variable found for re-execing\n"); + exit(1); + } + + parts = strdup(path); + scratch = malloc(1+strlen(path)); + if (parts == NULL || scratch == NULL) { + fprintf(stderr, "insufficient memory for path building\n"); + exit(1); + } + + for (i=0; (dir = strtok(parts, ":")); parts = NULL) { + sprintf(scratch, "%s/%s", dir, arg0); + if (access(scratch, X_OK) == 0) { + return scratch; + } + } + + fprintf(stderr, "unable to find executable '%s' in PATH\n", arg0); + exit(1); +} + int main(int argc, char *argv[], char *envp[]) { pid_t child; @@ -782,10 +825,14 @@ int main(int argc, char *argv[], char *envp[]) } else if (!strcmp("--print", argv[i])) { arg_print(); } else if ((!strcmp("--", argv[i])) || (!strcmp("==", argv[i]))) { - argv[i] = strdup(argv[i][0] == '-' ? shell : argv[0]); + if (argv[i][0] == '=') { + argv[i] = find_self(argv[0]); + } else { + argv[i] = strdup(shell); + } argv[argc] = NULL; execve(argv[i], argv+i, envp); - fprintf(stderr, "execve '%s' failed!\n", shell); + fprintf(stderr, "execve '%s' failed!\n", argv[i]); exit(1); } else if (!strncmp("--shell=", argv[i], 8)) { shell = argv[i]+8; diff --git a/progs/quicktest.sh b/progs/quicktest.sh index 5873317..1c21bb4 100755 --- a/progs/quicktest.sh +++ b/progs/quicktest.sh @@ -44,6 +44,13 @@ pass_capsh () { pass_capsh --print +# Validate that PATH expansion works +PATH=$(/bin/pwd)/junk:$(/bin/pwd) capsh == == == --modes +if [ $? -ne 0 ]; then + echo "Failed to execute capsh consecutively for capability manipulation" + exit 1 +fi + # Make a local non-setuid-0 version of capsh and call it privileged cp ./tcapsh-static ./privileged && /bin/chmod -s ./privileged if [ $? -ne 0 ]; then |