From 2db9681bdfdafc3c8b62a8cb230b626ce0f4d9db2a88d8c53b8e7991317fc232 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Mon, 4 Jan 2021 19:31:04 +0000 Subject: [PATCH] - add 0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch 0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch 0003-Minor-fixes-for-cap-package-documentation.patch 0004-checkpoint.patch 0005-Clean-up-the-exit-status-to-match-other-binaries.patch 0006-People-keep-emailing-me-about-the-license-for-libcap.patch 0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch OBS-URL: https://build.opensuse.org/package/show/Base:System/libcap?expand=0&rev=49 --- ...ge-and-diagnostic-message-for-setcap.patch | 138 ++++++++++ ...d-the-Go-build-tag-allthreadssyscall.patch | 103 ++++++++ ...-fixes-for-cap-package-documentation.patch | 54 ++++ 0004-checkpoint.patch | 106 ++++++++ ...-exit-status-to-match-other-binaries.patch | 52 ++++ ...ling-me-about-the-license-for-libcap.patch | 235 ++++++++++++++++++ ...ibcap-mode-with-the-sticky-NO_NEW_PR.patch | 188 ++++++++++++++ libcap.changes | 11 + libcap.spec | 8 + 9 files changed, 895 insertions(+) create mode 100644 0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch create mode 100644 0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch create mode 100644 0003-Minor-fixes-for-cap-package-documentation.patch create mode 100644 0004-checkpoint.patch create mode 100644 0005-Clean-up-the-exit-status-to-match-other-binaries.patch create mode 100644 0006-People-keep-emailing-me-about-the-license-for-libcap.patch create mode 100644 0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch diff --git a/0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch b/0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch new file mode 100644 index 0000000..f60e795 --- /dev/null +++ b/0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch @@ -0,0 +1,138 @@ +From 87514ed4dcf2c1778cd9e405c48a0635551c78af Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Sun, 20 Dec 2020 16:27:13 -0800 +Subject: [PATCH 1/7] Improve the usage and diagnostic message for setcap + +Also, explicitly support -h rather than fail over to display the usage +info. + +Signed-off-by: Andrew G. Morgan +--- + progs/setcap.c | 44 ++++++++++++++++++++++++++++++-------------- + 1 file changed, 30 insertions(+), 14 deletions(-) + +diff --git a/progs/setcap.c b/progs/setcap.c +index 442685d..f675cdd 100644 +--- a/progs/setcap.c ++++ b/progs/setcap.c +@@ -11,15 +11,23 @@ + #include + #include + +-static void usage(void) ++static void usage(int status) + { + fprintf(stderr, +- "usage: setcap [-q] [-v] [-n ] (-r|-|) " ++ "usage: setcap [-h] [-q] [-v] [-n ] (-r|-|) " + "[ ... (-r|-|) ]\n" + "\n" + " Note must be a regular (non-symlink) file.\n" ++ " -r remove capability from file\n" ++ " - read capability text from stdin\n" ++ " cap_from_text(3) formatted file capability\n" ++ "\n" ++ " -h this message and exit status 0\n" ++ " -q quietly\n" ++ " -v validate supplied capability matches file\n" ++ " -n write a user namespace limited capability\n" + ); +- exit(1); ++ exit(status); + } + + #define MAXCAP 2048 +@@ -65,8 +73,8 @@ int main(int argc, char **argv) + cap_value_t capflag; + uid_t rootid = 0, f_rootid; + +- if (argc < 3) { +- usage(); ++ if (argc < 2) { ++ usage(1); + } + + mycaps = cap_get_proc(); +@@ -83,6 +91,9 @@ int main(int argc, char **argv) + quiet = 1; + continue; + } ++ if (!strcmp(*argv, "-h")) { ++ usage(0); ++ } + if (!strcmp(*argv, "-v")) { + verify = 1; + continue; +@@ -107,7 +118,7 @@ int main(int argc, char **argv) + if (!strcmp(*argv,"-")) { + retval = read_caps(quiet, *argv, buffer); + if (retval) +- usage(); ++ usage(1); + text = buffer; + } else { + text = *argv; +@@ -116,7 +127,7 @@ int main(int argc, char **argv) + cap_d = cap_from_text(text); + if (cap_d == NULL) { + perror("fatal error"); +- usage(); ++ usage(1); + } + if (cap_set_nsowner(cap_d, rootid)) { + perror("unable to set nsowner"); +@@ -134,7 +145,7 @@ int main(int argc, char **argv) + } + + if (--argc <= 0) +- usage(); ++ usage(1); + /* + * Set the filesystem capability for this file. + */ +@@ -194,6 +205,7 @@ int main(int argc, char **argv) + if (retval != 0) { + int explained = 0; + int oerrno = errno; ++ int somebits = 0; + #ifdef linux + cap_value_t cap; + cap_flag_value_t per_state; +@@ -201,24 +213,28 @@ int main(int argc, char **argv) + for (cap = 0; + cap_get_flag(cap_d, cap, CAP_PERMITTED, &per_state) != -1; + cap++) { +- cap_flag_value_t inh_state, eff_state; ++ cap_flag_value_t inh_state, eff_state, combined; + + cap_get_flag(cap_d, cap, CAP_INHERITABLE, &inh_state); + cap_get_flag(cap_d, cap, CAP_EFFECTIVE, &eff_state); +- if ((inh_state | per_state) != eff_state) { +- fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n" +- " exactly match the union of selected permitted and inheritable bits.\n"); ++ combined = (inh_state | per_state); ++ somebits |= !!eff_state; ++ if (combined != eff_state) { + explained = 1; + break; + } + } ++ if (somebits && explained) { ++ fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n" ++ " exactly match the union of selected permitted and inheritable bits.\n"); ++ } + #endif /* def linux */ +- ++ + fprintf(stderr, + "Failed to set capabilities on file `%s' (%s)\n", + argv[0], strerror(oerrno)); + if (!explained) { +- usage(); ++ usage(1); + } + } + } +-- +2.29.2 + diff --git a/0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch b/0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch new file mode 100644 index 0000000..cb6f97b --- /dev/null +++ b/0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch @@ -0,0 +1,103 @@ +From 3633ca228671e2ddd9e115e74e09eea50ca8ad09 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Tue, 22 Dec 2020 20:03:54 -0800 +Subject: [PATCH 2/7] No longer need the Go build tag allthreadssyscall. + +Go 1.16 release branch contains the syscall.AllThreadsSyscall now, +so use the Go release tag to identify a build environment that supports +this feature. + +Signed-off-by: Andrew G. Morgan +--- + Make.Rules | 4 ---- + cap/cap.go | 13 +++++-------- + go/Makefile | 8 ++++---- + psx/psx.go | 2 +- + 4 files changed, 10 insertions(+), 17 deletions(-) + +diff --git a/Make.Rules b/Make.Rules +index 3107c94..1b3d780 100644 +--- a/Make.Rules ++++ b/Make.Rules +@@ -113,10 +113,6 @@ CGO_CFLAGS := -I$(topdir)/libcap/include + CGO_LDFLAGS := -L$(topdir)/libcap + CGO_LDFLAGS_ALLOW := -Wl,-?-wrap[=,][^-.@][^,]* + CGO_REQUIRED=$(shell $(topdir)/go/cgo-required.sh) +-ifeq ($(CGO_REQUIRED),0) +-# Hopefully this will not be needed at some point. +-GOBUILDTAG=-tags allthreadssyscall +-endif + endif + endif + +diff --git a/cap/cap.go b/cap/cap.go +index 76f74df..107a345 100644 +--- a/cap/cap.go ++++ b/cap/cap.go +@@ -42,14 +42,11 @@ + // uniformly over the whole Go (and CGo linked) process runtime. + // + // Note, if the Go runtime syscall interface contains the Linux +-// variant syscall.AllThreadsSyscall() API (it is not in go1.15 +-// for example, but see https://github.com/golang/go/issues/1435 for +-// current status) then this present package can use that to invoke +-// Capability setting system calls in pure Go binaries. In such an +-// enhanced Go runtime, to force this behavior, use the CGO_ENABLED=0 +-// environment variable and, for now, a build tag: +-// +-// CGO_ENABLED=0 go build -tags allthreadssyscall ... ++// variant syscall.AllThreadsSyscall() API (it debuted in go1.16 see ++// https://github.com/golang/go/issues/1435 for actual status) then ++// the "psx" package will use that to invoke Capability setting system ++// calls in pure Go binaries. In such an enhanced Go runtime, to force ++// this behavior, use the CGO_ENABLED=0 environment variable. + // + // + // Copyright (c) 2019,20 Andrew G. Morgan +diff --git a/go/Makefile b/go/Makefile +index 05ec7bf..b8745f1 100644 +--- a/go/Makefile ++++ b/go/Makefile +@@ -54,7 +54,7 @@ compare-cap: compare-cap.go $(CAPGOPACKAGE) + GO111MODULE=off CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(GOPATH) $(GO) build $< + + web: ../goapps/web/web.go $(CAPGOPACKAGE) +- GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $(GOBUILDTAG) $< ++ GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $< + ifeq ($(RAISE_GO_FILECAP),yes) + make -C ../progs setcap + sudo ../progs/setcap cap_setpcap,cap_net_bind_service=p web +@@ -62,16 +62,16 @@ ifeq ($(RAISE_GO_FILECAP),yes) + endif + + setid: ../goapps/setid/setid.go $(CAPGOPACKAGE) $(PSXGOPACKAGE) +- GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $(GOBUILDTAG) $< ++ GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $< + + gowns: ../goapps/gowns/gowns.go $(CAPGOPACKAGE) +- GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $(GOBUILDTAG) $< ++ GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $< + + ok: ok.go + GO111MODULE=off CGO_ENABLED=0 GOPATH=$(GOPATH) $(GO) build $< + + try-launching: try-launching.go $(CAPGOPACKAGE) ok +- GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build $(GOBUILDTAG) $< ++ GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build $< + ifeq ($(CGO_REQUIRED),0) + GO111MODULE=off CGO_ENABLED="1" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@-cgo $< + endif +diff --git a/psx/psx.go b/psx/psx.go +index 77858ad..b1b530a 100644 +--- a/psx/psx.go ++++ b/psx/psx.go +@@ -1,5 +1,5 @@ + // +build linux,!cgo +-// +build go1.16 allthreadssyscall ++// +build go1.16 + + package psx // import "kernel.org/pub/linux/libs/security/libcap/psx" + +-- +2.29.2 + diff --git a/0003-Minor-fixes-for-cap-package-documentation.patch b/0003-Minor-fixes-for-cap-package-documentation.patch new file mode 100644 index 0000000..87148b2 --- /dev/null +++ b/0003-Minor-fixes-for-cap-package-documentation.patch @@ -0,0 +1,54 @@ +From 676ced165d907d58af903fba0a434ff69087bba6 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Wed, 23 Dec 2020 08:25:52 -0800 +Subject: [PATCH 3/7] Minor fixes for "cap" package documentation. + +Signed-off-by: Andrew G. Morgan +--- + cap/launch.go | 8 ++++---- + cap/text.go | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/cap/launch.go b/cap/launch.go +index 2f37a2a..4ae449c 100644 +--- a/cap/launch.go ++++ b/cap/launch.go +@@ -106,18 +106,18 @@ var ErrLaunchFailed = errors.New("launch failed") + var ErrNoLaunch = errors.New("launch not supported") + + // ErrAmbiguousChroot indicates that the Launcher is being used in +-// addition to callback supplied Chroot. The former should be used ++// addition to a callback supplied Chroot. The former should be used + // exclusively for this. + var ErrAmbiguousChroot = errors.New("use Launcher for chroot") + + // ErrAmbiguousIDs indicates that the Launcher is being used in +-// addition to callback supplied Credentials. The former should be ++// addition to a callback supplied Credentials. The former should be + // used exclusively for this. + var ErrAmbiguousIDs = errors.New("use Launcher for uids and gids") + + // ErrAmbiguousAmbient indicates that the Launcher is being used in +-// addition callback supplied ambient set and the former should be +-// used exclusively in a Launch call. ++// addition to a callback supplied ambient set and the former should ++// be used exclusively in a Launch call. + var ErrAmbiguousAmbient = errors.New("use Launcher for ambient caps") + + // lName is the name we temporarily give to the launcher thread. Note, +diff --git a/cap/text.go b/cap/text.go +index 11dae90..cf11a2d 100644 +--- a/cap/text.go ++++ b/cap/text.go +@@ -187,7 +187,7 @@ var ErrBadText = errors.New("bad text") + // + // "=p all+ei" "all=pie" "=pi all+e" "=eip" + // +-// "cap_chown=p cap_setuid=i" "cap_chown=ip-p" "cap_chown=i" ++// "cap_setuid=p cap_chown=i" "cap_chown=ip-p" "cap_chown=i" + // + // "cap_chown=-p" "all=" "cap_setuid=pie-pie" "=" + // +-- +2.29.2 + diff --git a/0004-checkpoint.patch b/0004-checkpoint.patch new file mode 100644 index 0000000..780cb8f --- /dev/null +++ b/0004-checkpoint.patch @@ -0,0 +1,106 @@ +From 0799b36a415c081c35a6e8e0f2a6b739d574fbd5 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Tue, 15 Dec 2020 22:09:39 -0800 +Subject: [PATCH 4/7] checkpoint + +--- + progs/capsh.c | 8 +++++--- + progs/getcap.c | 10 ++++++---- + progs/getpcaps.c | 7 ++++--- + 3 files changed, 15 insertions(+), 10 deletions(-) + +diff --git a/progs/capsh.c b/progs/capsh.c +index 899f79c..5ea340b 100644 +--- a/progs/capsh.c ++++ b/progs/capsh.c +@@ -912,7 +912,7 @@ int main(int argc, char *argv[], char *envp[]) + } else { + usage: + printf("usage: %s [args ...]\n" +- " --help this message (or try 'man capsh')\n" ++ " --help, -h this message (or try 'man capsh')\n" + " --print display capability relevant state\n" + " --decode=xxx decode a hex string to a list of caps\n" + " --supports=xxx exit 1 if capability xxx unsupported\n" +@@ -948,8 +948,10 @@ int main(int argc, char *argv[], char *envp[]) + " -- remaining arguments are for " SHELL "\n" + " (without -- [%s] will simply exit(0))\n", + argv[0], argv[0]); +- +- exit(strcmp("--help", argv[i]) != 0); ++ if (strcmp("--help", argv[1]) && strcmp("-h", argv[1])) { ++ exit(1); ++ } ++ exit(0); + } + } + +diff --git a/progs/getcap.c b/progs/getcap.c +index 225207f..b4a9a60 100644 +--- a/progs/getcap.c ++++ b/progs/getcap.c +@@ -23,14 +23,14 @@ static int verbose = 0; + static int recursive = 0; + static int namespace = 0; + +-static void usage(void) ++static void usage(int ok) + { + fprintf(stderr, + "usage: getcap [-v] [-r] [-h] [-n] [ ...]\n" + "\n" + "\tdisplays the capabilities on the queried file(s).\n" + ); +- exit(1); ++ exit(!ok); + } + + static int do_getcap(const char *fname, const struct stat *stbuf, +@@ -93,13 +93,15 @@ int main(int argc, char **argv) + case 'n': + namespace = 1; + break; ++ case 'h': ++ usage(1); + default: +- usage(); ++ usage(0); + } + } + + if (!argv[optind]) +- usage(); ++ usage(0); + + for (i=optind; argv[i] != NULL; i++) { + struct stat stbuf; +diff --git a/progs/getpcaps.c b/progs/getpcaps.c +index 497abcd..5cd81af 100644 +--- a/progs/getpcaps.c ++++ b/progs/getpcaps.c +@@ -18,10 +18,10 @@ static void usage(int exiter) + " This program displays the capabilities on the queried process(es).\n" + " The capabilities are displayed in the cap_from_text(3) format.\n\n" + " Optional arguments:\n" +-" --help or --usage display this message.\n" ++" --help, -h or --usage display this message.\n" + " --verbose use a more verbose output format.\n" + " --ugly or --legacy use the archaic legacy output format.\n\n" +-"[Copyright (c) 1997-8,2007,2019 Andrew G. Morgan ]\n" ++"[Copyright (c) 1997-8,2007,2019 Andrew G. Morgan ]\n" + ); + exit(exiter); + } +@@ -40,7 +40,8 @@ int main(int argc, char **argv) + int pid; + cap_t cap_d; + +- if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "--usage")) { ++ if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "--usage") || ++ !strcmp(argv[0], "-h")) { + usage(0); + } else if (!strcmp(argv[0], "--verbose")) { + verbose = 1; +-- +2.29.2 + diff --git a/0005-Clean-up-the-exit-status-to-match-other-binaries.patch b/0005-Clean-up-the-exit-status-to-match-other-binaries.patch new file mode 100644 index 0000000..4685787 --- /dev/null +++ b/0005-Clean-up-the-exit-status-to-match-other-binaries.patch @@ -0,0 +1,52 @@ +From bdb10e77579c0a7d8a2d952a2cd938f50b02c9d0 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Sat, 26 Dec 2020 16:59:21 -0800 +Subject: [PATCH 5/7] Clean up the exit status to match other binaries. + +Signed-off-by: Andrew G. Morgan +--- + progs/getcap.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/progs/getcap.c b/progs/getcap.c +index b4a9a60..e578bbd 100644 +--- a/progs/getcap.c ++++ b/progs/getcap.c +@@ -23,14 +23,14 @@ static int verbose = 0; + static int recursive = 0; + static int namespace = 0; + +-static void usage(int ok) ++static void usage(int code) + { + fprintf(stderr, + "usage: getcap [-v] [-r] [-h] [-n] [ ...]\n" + "\n" + "\tdisplays the capabilities on the queried file(s).\n" + ); +- exit(!ok); ++ exit(code); + } + + static int do_getcap(const char *fname, const struct stat *stbuf, +@@ -94,14 +94,14 @@ int main(int argc, char **argv) + namespace = 1; + break; + case 'h': +- usage(1); +- default: + usage(0); ++ default: ++ usage(1); + } + } + + if (!argv[optind]) +- usage(0); ++ usage(1); + + for (i=optind; argv[i] != NULL; i++) { + struct stat stbuf; +-- +2.29.2 + diff --git a/0006-People-keep-emailing-me-about-the-license-for-libcap.patch b/0006-People-keep-emailing-me-about-the-license-for-libcap.patch new file mode 100644 index 0000000..4b38e4a --- /dev/null +++ b/0006-People-keep-emailing-me-about-the-license-for-libcap.patch @@ -0,0 +1,235 @@ +From 0f0c1fe489ec0ca69891a7999f5bda1c91e02f92 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Sat, 26 Dec 2020 17:35:40 -0800 +Subject: [PATCH 6/7] People keep emailing me about the license for libcap. + +There seems to have been a misconception that the tools and library +are GPL only. This has never been the case. The system was developed +from the start with a you-choose license: GPL(2 at the time) OR +BSD 3-clause. When GPL3 was released, it was decided that the +distribution would not follow that. As such, everything is: + + BSD 3-clause or GPL2 (you choose). + +Signed-off-by: Andrew G. Morgan +--- + progs/capsh.c | 58 ++++++++++++++++++++++++++---------------------- + progs/getcap.c | 15 ++++++++----- + progs/getpcaps.c | 23 +++++++++++-------- + progs/setcap.c | 10 ++++++++- + 4 files changed, 65 insertions(+), 41 deletions(-) + +diff --git a/progs/capsh.c b/progs/capsh.c +index 5ea340b..dfe420f 100644 +--- a/progs/capsh.c ++++ b/progs/capsh.c +@@ -1,9 +1,10 @@ + /* + * Copyright (c) 2008-11,16,19,2020 Andrew G. Morgan + * +- * This is a simple 'bash' (-DSHELL) wrapper program that can be used +- * to raise and lower both the bset and pI capabilities before +- * invoking /bin/bash. ++ * This is a multifunction shell wrapper tool that can be used to ++ * launch capable files in various ways with a variety of settings. It ++ * also supports some testing modes, which are used extensively as ++ * part of the libcap build system. + * + * The --print option can be used as a quick test whether various + * capability manipulations work as expected (or not). +@@ -909,41 +910,46 @@ int main(int argc, char *argv[], char *envp[]) + exit(1); + } + cap_free(iab); ++ } else if (!strcmp("--license", argv[i])) { ++ printf( ++ "%s has a you choose license: BSD 3-clause or GPL2\n" ++ "Copyright (c) 2008-11,16,19,2020 Andrew G. Morgan" ++ " \n", argv[0]); ++ exit(0); + } else { + usage: + printf("usage: %s [args ...]\n" +- " --help, -h this message (or try 'man capsh')\n" +- " --print display capability relevant state\n" +- " --decode=xxx decode a hex string to a list of caps\n" +- " --supports=xxx exit 1 if capability xxx unsupported\n" +- " --has-p=xxx exit 1 if capability xxx not permitted\n" +- " --has-i=xxx exit 1 if capability xxx not inheritable\n" +- " --drop=xxx remove xxx,.. capabilities from bset\n" +- " --dropped=xxx exit 1 unless bounding cap xxx dropped\n" +- " --has-ambient exit 1 unless ambient vector supported\n" + " --has-a=xxx exit 1 if capability xxx not ambient\n" ++ " --has-ambient exit 1 unless ambient vector supported\n" + " --addamb=xxx add xxx,... capabilities to ambient set\n" +- " --delamb=xxx remove xxx,... capabilities from ambient\n" +- " --noamb reset (drop) all ambient capabilities\n" ++ " --cap-uid= use libcap cap_setuid() to change uid\n" + " --caps=xxx set caps as per cap_from_text()\n" +- " --inh=xxx set xxx,.. inheritable set\n" +- " --secbits= write a new value for securebits\n" ++ " --chroot=path chroot(2) to this path\n" ++ " --decode=xxx decode a hex string to a list of caps\n" ++ " --delamb=xxx remove xxx,... capabilities from ambient\n" ++ " --forkfor= fork and make child sleep for sec\n" ++ " --gid= set gid to (hint: id )\n" ++ " --groups=g,... set the supplemental groups\n" ++ " --has-p=xxx exit 1 if capability xxx not permitted\n" ++ " --has-i=xxx exit 1 if capability xxx not inheritable\n" ++ " --help, -h this message (or try 'man capsh')\n" + " --iab=... use cap_iab_from_text() to set iab\n" +- " --keep= set keep-capability bit to \n" +- " --uid= set uid to (hint: id )\n" +- " --cap-uid= libcap cap_setuid() to change uid\n" ++ " --inh=xxx set xxx,.. inheritable set\n" ++ " --inmode= exit 1 if current mode is not \n" + " --is-uid= exit 1 if uid != \n" +- " --gid= set gid to (hint: id )\n" + " --is-gid= exit 1 if gid != \n" +- " --groups=g,... set the supplemental groups\n" +- " --user= set uid,gid and groups to that of user\n" +- " --chroot=path chroot(2) to this path\n" ++ " --keep= set keep-capability bit to \n" ++ " --killit= send signal(n) to child\n" ++ " --license display license info\n" + " --modes list libcap named capability modes\n" + " --mode= set capability mode to \n" +- " --inmode= exit 1 if current mode is not \n" +- " --killit= send signal(n) to child\n" +- " --forkfor= fork and make child sleep for sec\n" ++ " --noamb reset (drop) all ambient capabilities\n" ++ " --print display capability relevant state\n" ++ " --secbits= write a new value for securebits\n" + " --shell=/xx/yy use /xx/yy instead of " SHELL " for --\n" ++ " --supports=xxx exit 1 if capability xxx unsupported\n" ++ " --uid= set uid to (hint: id )\n" ++ " --user= set uid,gid and groups to that of user\n" + " == re-exec(capsh) with args as for --\n" + " -- remaining arguments are for " SHELL "\n" + " (without -- [%s] will simply exit(0))\n", +diff --git a/progs/getcap.c b/progs/getcap.c +index e578bbd..208bd6a 100644 +--- a/progs/getcap.c ++++ b/progs/getcap.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997,2007 Andrew G. Morgan ++ * Copyright (c) 1997,2007 Andrew G. Morgan + * + * This displays the capabilities of a given file. + */ +@@ -26,9 +26,9 @@ static int namespace = 0; + static void usage(int code) + { + fprintf(stderr, +- "usage: getcap [-v] [-r] [-h] [-n] [ ...]\n" +- "\n" +- "\tdisplays the capabilities on the queried file(s).\n" ++ "usage: getcap [-h] [-l] [-n] [-r] [-v] [ ...]\n" ++ "\n" ++ "\tdisplays the capabilities on the queried file(s).\n" + ); + exit(code); + } +@@ -82,7 +82,7 @@ int main(int argc, char **argv) + { + int i, c; + +- while ((c = getopt(argc, argv, "rvhn")) > 0) { ++ while ((c = getopt(argc, argv, "rvhnl")) > 0) { + switch(c) { + case 'r': + recursive = 1; +@@ -95,6 +95,11 @@ int main(int argc, char **argv) + break; + case 'h': + usage(0); ++ case 'l': ++ printf("%s has a you choose license: BSD 3-clause or GPL2\n" ++ "Copyright (c) 1997,2007 Andrew G. Morgan" ++ " \n", argv[0]); ++ exit(0); + default: + usage(1); + } +diff --git a/progs/getpcaps.c b/progs/getpcaps.c +index 5cd81af..5bc511e 100644 +--- a/progs/getpcaps.c ++++ b/progs/getpcaps.c +@@ -11,19 +11,19 @@ + #include + #include + +-static void usage(int exiter) ++static void usage(int code) + { + fprintf(stderr, + "usage: getcaps [ ...]\n\n" + " This program displays the capabilities on the queried process(es).\n" +-" The capabilities are displayed in the cap_from_text(3) format.\n\n" +-" Optional arguments:\n" +-" --help, -h or --usage display this message.\n" +-" --verbose use a more verbose output format.\n" +-" --ugly or --legacy use the archaic legacy output format.\n\n" +-"[Copyright (c) 1997-8,2007,2019 Andrew G. Morgan ]\n" +- ); +- exit(exiter); ++ " The capabilities are displayed in the cap_from_text(3) format.\n" ++ "\n" ++ " Optional arguments:\n" ++ " --help, -h or --usage display this message.\n" ++ " --verbose use a more verbose output format.\n" ++ " --ugly or --legacy use the archaic legacy output format.\n" ++ " --license display license info\n"); ++ exit(code); + } + + int main(int argc, char **argv) +@@ -43,6 +43,11 @@ int main(int argc, char **argv) + if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "--usage") || + !strcmp(argv[0], "-h")) { + usage(0); ++ } else if (!strcmp(argv[0], "--license")) { ++ printf("%s has a you choose license: BSD 3-clause or GPL2\n" ++"[Copyright (c) 1997-8,2007,2019 Andrew G. Morgan ]\n", ++ argv[0]); ++ exit(0); + } else if (!strcmp(argv[0], "--verbose")) { + verbose = 1; + continue; +diff --git a/progs/setcap.c b/progs/setcap.c +index f675cdd..930429a 100644 +--- a/progs/setcap.c ++++ b/progs/setcap.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997,2007-8 Andrew G. Morgan ++ * Copyright (c) 1997,2007-8,2020 Andrew G. Morgan + * + * This sets/verifies the capabilities of a given file. + */ +@@ -26,6 +26,7 @@ static void usage(int status) + " -q quietly\n" + " -v validate supplied capability matches file\n" + " -n write a user namespace limited capability\n" ++ " --license display the license info\n" + ); + exit(status); + } +@@ -91,6 +92,13 @@ int main(int argc, char **argv) + quiet = 1; + continue; + } ++ if (!strcmp("--license", *argv)) { ++ printf( ++ "%s has a you choose license: BSD 3-clause or GPL2\n" ++ "Copyright (c) 1997,2007-8,2020 Andrew G. Morgan" ++ " \n", argv[0]); ++ exit(0); ++ } + if (!strcmp(*argv, "-h")) { + usage(0); + } +-- +2.29.2 + diff --git a/0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch b/0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch new file mode 100644 index 0000000..2c82a21 --- /dev/null +++ b/0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch @@ -0,0 +1,188 @@ +From f552b8f7403bf535832e703641e8fcee6adf6630 Mon Sep 17 00:00:00 2001 +From: "Andrew G. Morgan" +Date: Sat, 26 Dec 2020 21:42:15 -0800 +Subject: [PATCH 7/7] Augment NOPRIV libcap mode with the sticky NO_NEW_PRIVS + prctl bit. + +Since I last visited securebits no privs mode, a new prctl bit +has been added (it isn't a securebit, but a parallel implementation +of something similar). So, layer that bit on top of NOPRIV mode. + +Signed-off-by: Andrew G. Morgan +--- + cap/convenience.go | 4 ++++ + go/try-launching.go | 10 ++++++++++ + libcap/cap_proc.c | 14 +++++++++++++- + progs/capsh.c | 17 +++++++++++++++-- + tests/libcap_launch_test.c | 3 ++- + 5 files changed, 44 insertions(+), 4 deletions(-) + +diff --git a/cap/convenience.go b/cap/convenience.go +index f094e52..9580903 100644 +--- a/cap/convenience.go ++++ b/cap/convenience.go +@@ -36,6 +36,7 @@ const ( + prSetKeepCaps = 8 + prGetSecureBits = 27 + prSetSecureBits = 28 ++ prSetNoNewPrivs = 38 + ) + + // GetSecbits returns the current setting of the process' Secbits. +@@ -163,6 +164,9 @@ func (sc *syscaller) setMode(m Mode) error { + } + w.ClearFlag(Permitted) + ++ // For good measure. ++ sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0) ++ + return nil + } + +diff --git a/go/try-launching.go b/go/try-launching.go +index 272fd0a..9f20e6b 100644 +--- a/go/try-launching.go ++++ b/go/try-launching.go +@@ -28,6 +28,7 @@ func tryLaunching() { + iab string + uid int + gid int ++ mode cap.Mode + groups []int + }{ + {args: []string{root + "/go/ok"}}, +@@ -44,6 +45,11 @@ func tryLaunching() { + chroot: root + "/go", + fail: syscall.Getuid() != 0, + }, ++ { ++ args: []string{root + "/progs/tcapsh-static", "--inmode=NOPRIV", "--has-no-new-privs"}, ++ mode: cap.ModeNoPriv, ++ fail: syscall.Getuid() != 0, ++ }, + } + + ps := make([]int, len(vs)) +@@ -61,6 +67,9 @@ func tryLaunching() { + if v.gid != 0 { + e.SetGroups(v.gid, v.groups) + } ++ if v.mode != 0 { ++ e.SetMode(v.mode) ++ } + if v.iab != "" { + if iab, err := cap.IABFromText(v.iab); err != nil { + log.Fatalf("failed to parse iab=%q: %v", v.iab, err) +@@ -68,6 +77,7 @@ func tryLaunching() { + e.SetIAB(iab) + } + } ++ log.Printf("[%d] trying: %q\n", i, v.args) + if ps[i], err = e.Launch(nil); err != nil { + if v.fail { + continue +diff --git a/libcap/cap_proc.c b/libcap/cap_proc.c +index 3929f66..1329f94 100644 +--- a/libcap/cap_proc.c ++++ b/libcap/cap_proc.c +@@ -390,13 +390,21 @@ static int _cap_set_secbits(struct syscaller_s *sc, unsigned bits) + } + + /* +- * Set the security mode of the current process. ++ * Set the secbits of the current process. + */ + int cap_set_secbits(unsigned bits) + { + return _cap_set_secbits(&multithread, bits); + } + ++/* ++ * Attempt to raise the no new privs prctl value. ++ */ ++static void _cap_set_no_new_privs(struct syscaller_s *sc) ++{ ++ (void) _libcap_wprctl6(sc, PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0); ++} ++ + /* + * Some predefined constants + */ +@@ -448,7 +456,11 @@ static int _cap_set_mode(struct syscaller_s *sc, cap_mode_t flavor) + (void) _cap_drop_bound(sc, c); + } + (void) cap_clear_flag(working, CAP_PERMITTED); ++ ++ /* for good measure */ ++ _cap_set_no_new_privs(sc); + break; ++ + default: + errno = EINVAL; + ret = -1; +diff --git a/progs/capsh.c b/progs/capsh.c +index dfe420f..a39ceeb 100644 +--- a/progs/capsh.c ++++ b/progs/capsh.c +@@ -108,8 +108,9 @@ static void arg_print(void) + set = cap_get_secbits(); + if (set >= 0) { + const char *b = binary(set); /* verilog convention for binary string */ +- printf("Securebits: 0%lo/0x%lx/%u'b%s\n", set, set, +- (unsigned) strlen(b), b); ++ printf("Securebits: 0%lo/0x%lx/%u'b%s (no-new-privs=%d)\n", set, set, ++ (unsigned) strlen(b), b, ++ prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0, 0)); + printf(" secure-noroot: %s (%s)\n", + (set & SECBIT_NOROOT) ? "yes":"no", + (set & SECBIT_NOROOT_LOCKED) ? "locked":"unlocked"); +@@ -910,6 +911,16 @@ int main(int argc, char *argv[], char *envp[]) + exit(1); + } + cap_free(iab); ++ } else if (!strcmp("--no-new-privs", argv[i])) { ++ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0) != 0) { ++ perror("unable to set no-new-privs"); ++ exit(1); ++ } ++ } else if (!strcmp("--has-no-new-privs", argv[i])) { ++ if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0, 0) != 1) { ++ fprintf(stderr, "no-new-privs not set\n"); ++ exit(1); ++ } + } else if (!strcmp("--license", argv[i])) { + printf( + "%s has a you choose license: BSD 3-clause or GPL2\n" +@@ -932,6 +943,7 @@ int main(int argc, char *argv[], char *envp[]) + " --groups=g,... set the supplemental groups\n" + " --has-p=xxx exit 1 if capability xxx not permitted\n" + " --has-i=xxx exit 1 if capability xxx not inheritable\n" ++ " --has-no-new-privs exit 1 if privs not limited\n" + " --help, -h this message (or try 'man capsh')\n" + " --iab=... use cap_iab_from_text() to set iab\n" + " --inh=xxx set xxx,.. inheritable set\n" +@@ -943,6 +955,7 @@ int main(int argc, char *argv[], char *envp[]) + " --license display license info\n" + " --modes list libcap named capability modes\n" + " --mode= set capability mode to \n" ++ " --no-new-privs set sticky process privilege limiter\n" + " --noamb reset (drop) all ambient capabilities\n" + " --print display capability relevant state\n" + " --secbits= write a new value for securebits\n" +diff --git a/tests/libcap_launch_test.c b/tests/libcap_launch_test.c +index c9ef205..bba38c6 100644 +--- a/tests/libcap_launch_test.c ++++ b/tests/libcap_launch_test.c +@@ -70,7 +70,8 @@ int main(int argc, char **argv) { + .iab = "!^cap_chown" + }, + { +- .args = { "../progs/tcapsh-static", "--inmode=NOPRIV" }, ++ .args = { "../progs/tcapsh-static", "--inmode=NOPRIV", ++ "--has-no-new-privs" }, + .result = 0, + .mode = CAP_MODE_NOPRIV + }, +-- +2.29.2 + diff --git a/libcap.changes b/libcap.changes index be3d1c4..a826191 100644 --- a/libcap.changes +++ b/libcap.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Mon Jan 4 19:30:44 UTC 2021 - Dirk Müller + +- add 0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch + 0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch + 0003-Minor-fixes-for-cap-package-documentation.patch + 0004-checkpoint.patch + 0005-Clean-up-the-exit-status-to-match-other-binaries.patch + 0006-People-keep-emailing-me-about-the-license-for-libcap.patch + 0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch + ------------------------------------------------------------------- Mon Jan 4 08:46:44 UTC 2021 - Dirk Müller diff --git a/libcap.spec b/libcap.spec index b4a98a1..4c341fc 100644 --- a/libcap.spec +++ b/libcap.spec @@ -25,6 +25,13 @@ Group: Development/Libraries/C and C++ URL: https://sites.google.com/site/fullycapable/ Source: https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-%{version}.tar.xz Source2: baselibs.conf +Patch0: 0001-Improve-the-usage-and-diagnostic-message-for-setcap.patch +Patch1: 0002-No-longer-need-the-Go-build-tag-allthreadssyscall.patch +Patch2: 0003-Minor-fixes-for-cap-package-documentation.patch +Patch3: 0004-checkpoint.patch +Patch4: 0005-Clean-up-the-exit-status-to-match-other-binaries.patch +Patch5: 0006-People-keep-emailing-me-about-the-license-for-libcap.patch +Patch6: 0007-Augment-NOPRIV-libcap-mode-with-the-sticky-NO_NEW_PR.patch BuildRequires: fdupes BuildRequires: glibc-devel-static BuildRequires: pkgconfig @@ -89,6 +96,7 @@ libcap. %prep %setup -q +%autopatch -p1 %build %global _lto_cflags %{_lto_cflags} -ffat-lto-objects