From 9eeb09cd942532c1ace95295f854178c318d89fe Mon Sep 17 00:00:00 2001 From: yixiangzhike Date: Sat, 22 Jan 2022 20:18:56 +0800 Subject: [PATCH] Fix capsh failure with argument '==' --- ...fficient-memory-for-scratch-pathname.patch | 29 ++++ ...search-PATH-for-capsh-self-execution.patch | 148 ++++++++++++++++++ libcap.spec | 8 +- 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 backport-Guarantee-sufficient-memory-for-scratch-pathname.patch create mode 100644 backport-If-needed-search-PATH-for-capsh-self-execution.patch diff --git a/backport-Guarantee-sufficient-memory-for-scratch-pathname.patch b/backport-Guarantee-sufficient-memory-for-scratch-pathname.patch new file mode 100644 index 0000000..ad22a28 --- /dev/null +++ b/backport-Guarantee-sufficient-memory-for-scratch-pathname.patch @@ -0,0 +1,29 @@ +From 9d8eaab7f74cf1d925910901e5181173ab11d14d Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Wed, 28 Oct 2020 06:59:36 -0700 +Subject: Guarantee sufficient memory for scratch pathname + +Fix a malloc bug with single entry/short PATHs in capsh code for "==" +support. + +Signed-off-by: Andrew G. Morgan +--- + progs/capsh.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/progs/capsh.c b/progs/capsh.c +index 95c02fd..6bc54bf 100644 +--- a/progs/capsh.c ++++ b/progs/capsh.c +@@ -366,7 +366,7 @@ static char *find_self(const char *arg0) + } + + parts = strdup(path); +- scratch = malloc(1+strlen(path)); ++ scratch = malloc(2+strlen(path)+strlen(arg0)); + if (parts == NULL || scratch == NULL) { + fprintf(stderr, "insufficient memory for path building\n"); + exit(1); +-- +cgit 1.2.3-1.el7 + diff --git a/backport-If-needed-search-PATH-for-capsh-self-execution.patch b/backport-If-needed-search-PATH-for-capsh-self-execution.patch new file mode 100644 index 0000000..3470b7e --- /dev/null +++ b/backport-If-needed-search-PATH-for-capsh-self-execution.patch @@ -0,0 +1,148 @@ +From 68240b124cc62744a7a412a7afc85b5c56a48e14 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Tue, 27 Oct 2020 14:56:34 -0700 +Subject: 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 +--- + doc/capsh.1 | 14 ++++++++++--- + progs/capsh.c | 51 ++++++++++++++++++++++++++++++++++++++++++++-- + progs/quicktest.sh | 7 +++++++ + 3 files changed, 67 insertions(+), 5 deletions(-) + +diff --git a/doc/capsh.1 b/doc/capsh.1 +index 1e28b59..aee44d5 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 +@@ -32,7 +32,15 @@ Execute + .B capsh + again with 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 +@@ -165,7 +173,7 @@ header file. The program will list these bits via the + .B --print + command. + .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 68b657d..95c02fd 100644 +--- a/progs/capsh.c ++++ b/progs/capsh.c +@@ -340,6 +340,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; +@@ -799,10 +842,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] == '-' ? "/bin/bash" : argv[0]); ++ if (argv[i][0] == '=') { ++ argv[i] = find_self(argv[0]); ++ } else { ++ argv[i] = strdup("/bin/bash"); ++ } + argv[argc] = NULL; + execve(argv[i], argv+i, envp); +- fprintf(stderr, "execve /bin/bash failed!\n"); ++ fprintf(stderr, "execve '%s' failed!\n", argv[i]); + exit(1); + } else if (!strncmp("--has-p=", argv[i], 8)) { + cap_value_t cap; +diff --git a/progs/quicktest.sh b/progs/quicktest.sh +index 96f9929..8ecaccf 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 ./capsh ./privileged && /bin/chmod -s ./privileged + if [ $? -ne 0 ]; then +-- +2.27.0 + diff --git a/libcap.spec b/libcap.spec index 787737f..b4e0a8b 100644 --- a/libcap.spec +++ b/libcap.spec @@ -1,6 +1,6 @@ Name: libcap Version: 2.32 -Release: 3 +Release: 4 Summary: A library for getting and setting POSIX.1e draft 15 capabilities License: GPLv2 URL: https://sites.google.com/site/fullycapable @@ -10,6 +10,8 @@ Patch0: libcap-buildflags.patch Patch1: Avoid-segfaulting-when-the-kernel-is-ahead-of-libcap.patch Patch2: backport-capsh-better-error-handling-for-integer-parsing.patch Patch3: backport-setcap-clean-up-error-handling-of-the-ns-rootid-argument.patch +Patch4: backport-If-needed-search-PATH-for-capsh-self-execution.patch +Patch5: backport-Guarantee-sufficient-memory-for-scratch-pathname.patch BuildRequires: libattr-devel pam-devel perl-interpreter gcc @@ -70,6 +72,10 @@ chmod +x %{buildroot}/%{_libdir}/*.so.* %{_mandir}/man8/*.gz %changelog +* Sat Jan 22 2022 yixiangzhike - 2.32-4 +- If needed search PATH for capsh (==) self-execution +- Guarantee sufficient memory for scratch pathname + * Mon Nov 8 2021 yixiangzhike - 2.32-3 - capsh better error handling for integer parsing - setcap clean up error handling of the ns rootid argument -- Gitee