Projects
openEuler:22.03:LTS:Next
libcap
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 3
View file
_service:tar_scm_kernel_repo:libcap.spec
Changed
@@ -1,15 +1,12 @@ Name: libcap -Version: 2.32 -Release: 3 +Version: 2.61 +Release: 1 Summary: A library for getting and setting POSIX.1e draft 15 capabilities License: GPLv2 URL: https://sites.google.com/site/fullycapable Source0: https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/%{name}-%{version}.tar.gz 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 BuildRequires: libattr-devel pam-devel perl-interpreter gcc @@ -40,6 +37,9 @@ mv -f doc/*.3 %{buildroot}/%{_mandir}/man3/ chmod +x %{buildroot}/%{_libdir}/*.so.* +%check +%make_build COPTS="%{optflags}" test + %pre %preun @@ -70,6 +70,9 @@ %{_mandir}/man8/*.gz %changelog +* Thu Nov 25 2021 yixiangzhike <yixiangzhike007@163.com> - 2.61-1 +- update to 2.61 + * Mon Nov 8 2021 yixiangzhike <yixiangzhike007@163.com> - 2.32-3 - capsh better error handling for integer parsing - setcap clean up error handling of the ns rootid argument
View file
_service:tar_scm_kernel_repo:Avoid-segfaulting-when-the-kernel-is-ahead-of-libcap.patch
Deleted
@@ -1,58 +0,0 @@ -From 2f72ffb7c9f28fbd143010dd68730b73ad1596f4 Mon Sep 17 00:00:00 2001 -From: "Andrew G. Morgan" <morgan@kernel.org> -Date: Sat, 2 May 2020 17:10:25 -0700 -Subject: [PATCH] Avoid segfaulting when the kernel is ahead of libcap. - -Fixes bug report from Heiner Kallweit: - - https://bugzilla.kernel.org/show_bug.cgi?id=207549 - -This bug was triggered when the kernel being run knows about -more capabilities than the running build of libcap does. The -issue is that in two places libcap assumed that _cap_names[] -was long enough to name cap_max_bits() worth of capabilities. - -Signed-off-by: Andrew G. Morgan <morgan@kernel.org> ---- - libcap/cap_text.c | 14 +++++++++----- - 1 file changed, 9 insertions(+), 5 deletions(-) - -diff --git a/libcap/cap_text.c b/libcap/cap_text.c -index 00fbbc6..8ea4b05 100644 ---- a/libcap/cap_text.c -+++ b/libcap/cap_text.c -@@ -57,8 +57,9 @@ static char const *namcmp(char const *str, char const *nam) - } - - /* -- * forceall forces all of the named capabilities to be assigned the -- * masked value, and zeroed otherwise. -+ * forceall forces all of the kernel named capabilities to be assigned -+ * the masked value, and zeroed otherwise. Note, if the kernel is ahead -+ * of libcap, the upper bits will be referred to by number. - */ - static void forceall(__u32 *flat, __u32 value, unsigned blks) - { -@@ -112,13 +113,16 @@ static int lookupname(char const **strp) - } - #else /* ie., ndef GPERF_DOWNCASE */ - char const *s; -- unsigned n; -- -- for (n = cap_max_bits(); n--; ) -+ unsigned n = cap_max_bits(); -+ if (n > __CAP_BITS) { -+ n = __CAP_BITS; -+ } -+ while (n--) { - if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) { - *strp = s; - return n; - } -+ } - #endif /* def GPERF_DOWNCASE */ - - return -1; /* No definition available */ --- -2.27.GIT -
View file
_service:tar_scm_kernel_repo:backport-capsh-better-error-handling-for-integer-parsing.patch
Deleted
@@ -1,141 +0,0 @@ -From 9c4997d6592e5daf046a6968ac83cf615c51fbe1 Mon Sep 17 00:00:00 2001 -From: "Andrew G. Morgan" <morgan@kernel.org> -Date: Sat, 6 Nov 2021 08:45:06 -0700 -Subject: [PATCH] capsh: better error handling for integer parsing. - -Bug reported by meitingli: - - https://bugzilla.kernel.org/show_bug.cgi?id=214911 - -Signed-off-by: Andrew G. Morgan <morgan@kernel.org> ---- - progs/capsh.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- - 1 file changed, 40 insertions(+), 9 deletions(-) - -diff --git a/progs/capsh.c b/progs/capsh.c -index 2295359..4f568c3 100644 ---- a/progs/capsh.c -+++ b/progs/capsh.c -@@ -40,6 +40,35 @@ - - #define MAX_GROUPS 100 /* max number of supplementary groups for user */ - -+/* parse a non-negative integer with some error handling */ -+static unsigned long nonneg_uint(const char *text, const char *prefix, int *ok) -+{ -+ char *remains; -+ unsigned long value; -+ ssize_t len = strlen(text); -+ -+ if (len == 0 || *text == '-') { -+ goto fail; -+ } -+ value = strtoul(text, &remains, 0); -+ if (*remains) { -+ goto fail; -+ } -+ if (ok != NULL) { -+ *ok = 1; -+ } -+ return value; -+ -+fail: -+ if (ok == NULL) { -+ fprintf(stderr, "%s: want non-negative integer, got \"%s\"\n", -+ prefix, text); -+ exit(1); -+ } -+ *ok = 0; -+ return 0; -+} -+ - static char *binary(unsigned long value) - { - static char string[8*sizeof(unsigned long) + 1]; -@@ -667,7 +696,7 @@ int main(int argc, char *argv[], char *envp[]) - unsigned value; - int set; - -- value = strtoul(argv[i]+7, NULL, 0); -+ value = nonneg_uint(argv[i]+7, "invalid --keep value", NULL); - set = prctl(PR_SET_KEEPCAPS, value); - if (set < 0) { - fprintf(stderr, "prctl(PR_SET_KEEPCAPS, %u) failed: %s\n", -@@ -724,7 +753,7 @@ int main(int argc, char *argv[], char *envp[]) - } else if (!strncmp("--secbits=", argv[i], 10)) { - unsigned value; - int status; -- value = strtoul(argv[i]+10, NULL, 0); -+ value = nonneg_uint(argv[i]+10, "invalid --secbits value", NULL); - status = cap_set_secbits(value); - if (status < 0) { - fprintf(stderr, "failed to set securebits to 0%o/0x%x\n", -@@ -737,8 +766,9 @@ int main(int argc, char *argv[], char *envp[]) - fprintf(stderr, "already forked\n"); - exit(1); - } -- value = strtoul(argv[i]+10, NULL, 0); -+ value = nonneg_uint(argv[i]+10, "invalid --forkfor value", NULL); - if (value == 0) { -+ fprintf(stderr, "require non-zero --forkfor value\n"); - goto usage; - } - child = fork(); -@@ -753,7 +783,8 @@ int main(int argc, char *argv[], char *envp[]) - pid_t result; - unsigned value; - -- value = strtoul(argv[i]+9, NULL, 0); -+ value = nonneg_uint(argv[i]+9, "invalid --killit signo value", -+ NULL); - if (!child) { - fprintf(stderr, "no forked process to kill\n"); - exit(1); -@@ -779,7 +810,7 @@ int main(int argc, char *argv[], char *envp[]) - unsigned value; - int status; - -- value = strtoul(argv[i]+6, NULL, 0); -+ value = nonneg_uint(argv[i]+6, "invalid --uid value", NULL); - status = setuid(value); - if (status < 0) { - fprintf(stderr, "Failed to set uid=%u: %s\n", -@@ -790,7 +821,7 @@ int main(int argc, char *argv[], char *envp[]) - unsigned value; - int status; - -- value = strtoul(argv[i]+10, NULL, 0); -+ value = nonneg_uint(argv[i]+10, "invalid --cap-uid value", NULL); - status = cap_setuid(value); - if (status < 0) { - fprintf(stderr, "Failed to cap_setuid(%u): %s\n", -@@ -801,7 +832,7 @@ int main(int argc, char *argv[], char *envp[]) - unsigned value; - int status; - -- value = strtoul(argv[i]+6, NULL, 0); -+ value = nonneg_uint(argv[i]+6, "invalid --gid value", NULL); - status = setgid(value); - if (status < 0) { - fprintf(stderr, "Failed to set gid=%u: %s\n", -@@ -1009,7 +1040,7 @@ int main(int argc, char *argv[], char *envp[]) - } else if (!strncmp("--is-uid=", argv[i], 9)) { - unsigned value; - uid_t uid; -- value = strtoul(argv[i]+9, NULL, 0); -+ value = nonneg_uint(argv[i]+9, "invalid --is-uid value", NULL); - uid = getuid(); - if (uid != value) { - fprintf(stderr, "uid: got=%d, want=%d\n", uid, value); -@@ -1018,7 +1049,7 @@ int main(int argc, char *argv[], char *envp[]) - } else if (!strncmp("--is-gid=", argv[i], 9)) { - unsigned value; - gid_t gid; -- value = strtoul(argv[i]+9, NULL, 0); -+ value = nonneg_uint(argv[i]+9, "invalid --is-gid value", NULL); - gid = getgid(); - if (gid != value) { - fprintf(stderr, "gid: got=%d, want=%d\n", gid, value); --- -1.8.3.1 -
View file
_service:tar_scm_kernel_repo:backport-setcap-clean-up-error-handling-of-the-ns-rootid-argument.patch
Deleted
@@ -1,70 +0,0 @@ -From 8e1e967bc8d99a3233d51f67f6b88620cdff78dc Mon Sep 17 00:00:00 2001 -From: "Andrew G. Morgan" <morgan@kernel.org> -Date: Sat, 6 Nov 2021 08:02:20 -0700 -Subject: [PATCH] setcap: clean up error handling of the ns rootid argument. - -Bug reported by Artem S. Tashkinov: - -https://bugzilla.kernel.org/show_bug.cgi?id=214909 - -Signed-off-by: Andrew G. Morgan <morgan@kernel.org> ---- - progs/setcap.c | 35 ++++++++++++++++++++++++++++++----- - 1 file changed, 30 insertions(+), 5 deletions(-) - -diff --git a/progs/setcap.c b/progs/setcap.c -index 442685d..fe985cd 100644 ---- a/progs/setcap.c -+++ b/progs/setcap.c -@@ -22,6 +22,35 @@ static void usage(void) - exit(1); - } - -+/* parse a positive integer with some error handling */ -+static unsigned long pos_uint(const char *text, const char *prefix, int *ok) -+{ -+ char *remains; -+ unsigned long value; -+ ssize_t len = strlen(text); -+ -+ if (len == 0 || *text == '-') { -+ goto fail; -+ } -+ value = strtoul(text, &remains, 0); -+ if (*remains || value == 0) { -+ goto fail; -+ } -+ if (ok != NULL) { -+ *ok = 1; -+ } -+ return value; -+ -+fail: -+ if (ok == NULL) { -+ fprintf(stderr, "%s: want positive integer, got \"%s\"\n", -+ prefix, text); -+ exit(1); -+ } -+ *ok = 0; -+ return 0; -+} -+ - #define MAXCAP 2048 - - static int read_caps(int quiet, const char *filename, char *buffer) -@@ -93,11 +122,7 @@ int main(int argc, char **argv) - exit(1); - } - --argc; -- rootid = (uid_t) atoi(*++argv); -- if (rootid+1 < 2) { -- fprintf(stderr, "invalid rootid!=0 of '%s'", *argv); -- exit(1); -- } -+ rootid = (uid_t) pos_uint(*++argv, "bad ns rootid", NULL); - continue; - } - --- -1.8.3.1 -
View file
_service:tar_scm_kernel_repo:libcap-buildflags.patch
Changed
@@ -1,34 +1,29 @@ From 11bdd43001c41d96769e437498bc57e8665ada2f Mon Sep 17 00:00:00 2001 From: zhangchenfeng <zhangchenfeng1@huawei.com> Date: Fri, 17 Apr 2020 10:21:28 +0800 -Subject: [PATCH] bcap-2.32-buildflags +Subject: [PATCH] libcap-2.61-buildflags --- Make.Rules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Make.Rules b/Make.Rules -index f02c770..b5d682b 100644 +index 70d5829..2160012 100644 --- a/Make.Rules +++ b/Make.Rules -@@ -50,7 +50,7 @@ KERNEL_HEADERS := $(topdir)/libcap/include/uapi - IPATH += -fPIC -I$(KERNEL_HEADERS) -I$(topdir)/libcap/include - - CC := gcc --CFLAGS := -O2 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -+CFLAGS := $(RPM_OPT_FLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 - BUILD_CC := $(CC) - BUILD_CFLAGS := $(CFLAGS) $(IPATH) - AR := ar -@@ -61,7 +61,7 @@ WARNINGS=-Wall -Wwrite-strings \ - -Wstrict-prototypes -Wmissing-prototypes \ - -Wnested-externs -Winline -Wshadow - LD=$(CC) -Wl,-x -shared --LDFLAGS := #-g -+LDFLAGS := $(RPM_LD_FLAGS) #-g - LIBCAPLIB := -L$(topdir)/libcap -lcap - LIBPSXLIB := -L$(topdir)/libcap -lpsx -lpthread +@@ -81,10 +81,10 @@ WARNINGS=-Wall -Wwrite-strings -Wpointer-arith -Wcast-qual -Wcast-align \ + -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs \ + -Winline -Wshadow -Wunreachable-code + COPTS ?= -O2 +-CFLAGS ?= $(COPTS) $(DEBUG) ++CFLAGS ?= $(RPM_OPT_FLAGS) $(DEBUG) + CFLAGS += $(WARNINGS) + CPPFLAGS += -Dlinux $(DEFINES) $(LIBCAP_INCLUDES) +-LDFLAGS ?= # -g ++LDFLAGS ?= $(RPM_OPT_FLAGS) + BUILD_CC ?= $(CC) + BUILD_LD ?= $(BUILD_CC) -Wl,-x -shared -- 1.8.3.1
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/.gitignore
Deleted
@@ -1,3 +0,0 @@ -names.go -syscalls.go -syscalls_cgo.go
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang
Deleted
-(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang/.gitignore
Deleted
@@ -1,4 +0,0 @@ -posix -posix-cgo -posix-cgo.go -posix.go
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang/Makefile
Deleted
@@ -1,13 +0,0 @@ -all: posix.go posix-cgo.go - CGO_ENABLED=0 go build posix.go - go build posix-cgo.go - -posix.go: ptest.go posix.stub_go Makefile - sed -e '/\/\/ main_here/ r posix.stub_go' ptest.go > $@ - -posix-cgo.go: ptest.go posix-cgo.stub_go Makefile - sed -e '/\/\/ main_here/ r posix-cgo.stub_go' ptest.go > $@ - -clean: - rm -f posix.go posix - rm -f posix-cgo.go posix-cgo
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang/README
Deleted
@@ -1,23 +0,0 @@ -This directory contains some test code for system calls that need -POSIX semantics to work under Go. There are 9 system calls wrapped in -a nptl:setxid mechanism in glibc, and the following development patch -adds support for these 9 to native Go. - -https://go-review.googlesource.com/c/go/+/210639/ - -The Go support works with or without CGO_ENABLED. - -With a patched Go runtime library: - - make - sudo ./posix - sudo ./posix-cgo - -should validate that all is working as intended. - -The above Go patch also exposes the mechanism that achieves this in -the Go runtime, to ensure that the native Go "libcap/cap" package can -work with and without CGO_ENABLED. - -Andrew G. Morgan <morgan@kernel.org> -2019-12-10
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang/posix-cgo.stub_go
Deleted
@@ -1,52 +0,0 @@ - -// #include <stdio.h> -// #include <stdlib.h> -// #include <pthread.h> -// #include <unistd.h> -// #include <sys/types.h> -// -// pthread_t *t = NULL; -// pthread_mutex_t mu; -// int nts = 0; -// int all_done = 0; -// -// static void *aFn(void *vargp) { -// int done = 0; -// while (!done) { -// usleep(100); -// pthread_mutex_lock(&mu); -// done = all_done; -// pthread_mutex_unlock(&mu); -// } -// printf("tid=%d done\n", pthread_self()); -// return NULL; -// } -// -// void trial(int argc) { -// nts = argc; -// t = calloc(nts, sizeof(pthread_t)); -// pthread_mutex_init(&mu, NULL); -// for (int i = 0; i < nts; i++) { -// printf("launch C-pthread [%d]\n", i); -// pthread_create(&t[i], NULL, aFn, NULL); -// } -// } -// -// void cleanup(void) { -// pthread_mutex_lock(&mu); -// all_done = 1; -// pthread_mutex_unlock(&mu); -// for (int i = 0; i < nts; i++) { -// printf("join C-pthread [%d]\n", i); -// pthread_join(t[i], NULL); -// } -// pthread_mutex_destroy(&mu); -// } -import "C" - -func main() { - const cts = 3 - C.trial(cts) - defer C.cleanup() - ptest() -}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang/posix.stub_go
Deleted
@@ -1,5 +0,0 @@ - -func main() { - log.Print("Running pure Go test") - ptest() -}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/golang/ptest.go
Deleted
@@ -1,140 +0,0 @@ -// Program posix is a test case to confirm that Go is capable of -// exhibiting posix semantics for system calls. -// -// This code is a template for two programs: posix.go and posix-cgo.go -// which are built by the Makefile to using sed. -package main - -import ( - "fmt" - "io/ioutil" - "log" - "os" - "strings" - "syscall" -) - -// main_here - -func dumpStatus(testCase string, err error, filter, expect string) bool { - fmt.Printf("%s [%v]:\n", testCase, err) - var failed bool - pid := syscall.Getpid() - fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid)) - if err != nil { - log.Fatal(err) - } - for _, f := range fs { - tf := fmt.Sprintf("/proc/%s/status", f.Name()) - d, err := ioutil.ReadFile(tf) - if err != nil { - fmt.Println(tf, err) - failed = true - continue - } - lines := strings.Split(string(d), "\n") - for _, line := range lines { - if strings.HasPrefix(line, filter) { - fails := line != expect - failure := "" - if fails { - failed = fails - failure = " (bad)" - } - fmt.Printf("%s %s%s\n", tf, line, failure) - break - } - } - } - return failed -} - -func ptest() { - var err error - var bad bool - - // egid setting - bad = bad || dumpStatus("initial state", nil, "Gid:", "Gid:\t0\t0\t0\t0") - err = syscall.Setegid(1001) - bad = bad || dumpStatus("setegid(1001) state", err, "Gid:", "Gid:\t0\t1001\t0\t1001") - err = syscall.Setegid(1002) - bad = bad || dumpStatus("setegid(1002) state", err, "Gid:", "Gid:\t0\t1002\t0\t1002") - err = syscall.Setegid(0) - bad = bad || dumpStatus("setegid(0) state", err, "Gid:", "Gid:\t0\t0\t0\t0") - - // euid setting (no way back from this one) - bad = bad || dumpStatus("initial euid", nil, "Uid:", "Uid:\t0\t0\t0\t0") - err = syscall.Seteuid(1) - bad = bad || dumpStatus("seteuid(1)", err, "Uid:", "Uid:\t0\t1\t0\t1") - err = syscall.Seteuid(0) - bad = bad || dumpStatus("seteuid(0)", err, "Uid:", "Uid:\t0\t0\t0\t0") - - // gid setting - bad = bad || dumpStatus("initial state", nil, "Gid:", "Gid:\t0\t0\t0\t0") - err = syscall.Setgid(1001) - bad = bad || dumpStatus("setgid(1001) state", err, "Gid:", "Gid:\t1001\t1001\t1001\t1001") - err = syscall.Setgid(1002) - bad = bad || dumpStatus("setgid(1002) state", err, "Gid:", "Gid:\t1002\t1002\t1002\t1002") - err = syscall.Setgid(0) - bad = bad || dumpStatus("setgid(0) state", err, "Gid:", "Gid:\t0\t0\t0\t0") - - // groups setting - bad = bad || dumpStatus("initial groups", nil, "Groups:", "Groups:\t0 ") - err = syscall.Setgroups([]int{0, 1, 2, 3}) - bad = bad || dumpStatus("setgroups(0,1,2,3)", err, "Groups:", "Groups:\t0 1 2 3 ") - err = syscall.Setgroups([]int{3, 2, 1}) - bad = bad || dumpStatus("setgroups(2,3,1)", err, "Groups:", "Groups:\t1 2 3 ") - err = syscall.Setgroups(nil) - bad = bad || dumpStatus("setgroups(nil)", err, "Groups:", "Groups:\t ") - err = syscall.Setgroups([]int{0}) - bad = bad || dumpStatus("setgroups(0)", err, "Groups:", "Groups:\t0 ") - - // regid setting - bad = bad || dumpStatus("initial state", nil, "Gid:", "Gid:\t0\t0\t0\t0") - err = syscall.Setregid(1001, 0) - bad = bad || dumpStatus("setregid(1001) state", err, "Gid:", "Gid:\t1001\t0\t0\t0") - err = syscall.Setregid(0, 1002) - bad = bad || dumpStatus("setregid(1002) state", err, "Gid:", "Gid:\t0\t1002\t1002\t1002") - err = syscall.Setregid(0, 0) - bad = bad || dumpStatus("setregid(0) state", err, "Gid:", "Gid:\t0\t0\t0\t0") - - // reuid setting - bad = bad || dumpStatus("initial state", nil, "Uid:", "Uid:\t0\t0\t0\t0") - err = syscall.Setreuid(1, 0) - bad = bad || dumpStatus("setreuid(1,0) state", err, "Uid:", "Uid:\t1\t0\t0\t0") - err = syscall.Setreuid(0, 2) - bad = bad || dumpStatus("setreuid(0,2) state", err, "Uid:", "Uid:\t0\t2\t2\t2") - err = syscall.Setreuid(0, 0) - bad = bad || dumpStatus("setreuid(0) state", err, "Uid:", "Uid:\t0\t0\t0\t0") - - // resgid setting - bad = bad || dumpStatus("initial state", nil, "Gid:", "Gid:\t0\t0\t0\t0") - err = syscall.Setresgid(1, 0, 2) - bad = bad || dumpStatus("setresgid(1,0,2) state", err, "Gid:", "Gid:\t1\t0\t2\t0") - err = syscall.Setresgid(0, 2, 1) - bad = bad || dumpStatus("setresgid(0,2,1) state", err, "Gid:", "Gid:\t0\t2\t1\t2") - err = syscall.Setresgid(0, 0, 0) - bad = bad || dumpStatus("setresgid(0) state", err, "Gid:", "Gid:\t0\t0\t0\t0") - - // resuid setting - bad = bad || dumpStatus("initial state", nil, "Uid:", "Uid:\t0\t0\t0\t0") - err = syscall.Setresuid(1, 0, 2) - bad = bad || dumpStatus("setresuid(1,0,2) state", err, "Uid:", "Uid:\t1\t0\t2\t0") - err = syscall.Setresuid(0, 2, 1) - bad = bad || dumpStatus("setresuid(0,2,1) state", err, "Uid:", "Uid:\t0\t2\t1\t2") - err = syscall.Setresuid(0, 0, 0) - bad = bad || dumpStatus("setresuid(0) state", err, "Uid:", "Uid:\t0\t0\t0\t0") - - // uid setting (no way back from this one) - bad = bad || dumpStatus("initial uid", nil, "Uid:", "Uid:\t0\t0\t0\t0") - err = syscall.Setuid(1) - bad = bad || dumpStatus("setuid(1)", err, "Uid:", "Uid:\t1\t1\t1\t1") - err = syscall.Setuid(0) - bad = bad || dumpStatus("setuid(0)", err, "Uid:", "Uid:\t1\t1\t1\t1") - - if bad { - log.Print("TEST FAILED") - os.Exit(1) - } - log.Print("TEST PASSED") -}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/psx_register.3
Deleted
@@ -1 +0,0 @@ -.so man3/libpsx.3
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/syscalls.sh
Deleted
@@ -1,67 +0,0 @@ -#!/bin/bash - -dir="$1" -if [[ -z "$dir" ]]; then - echo need an argument directory - exit 1 -fi - -# We use one or the other syscalls.go file based on whether or not the -# Go runtime include syscall.PerOSThreadSyscall or not. -if [ -z "$(go doc syscall 2>/dev/null|grep PerOSThreadSyscall)" ]; then - rm -f "${dir}/syscalls_cgo.go" - cat > "${dir}/syscalls.go" <<EOF -// +build linux - -package cap - -import ( - "libcap/psx" - "syscall" -) - -// callKernel variables overridable for testing purposes. -// (Go build tree has no syscall.PerOSThreadSyscall support.) -var callWKernel = psx.Syscall3 -var callWKernel6 = psx.Syscall6 -var callRKernel = syscall.RawSyscall -var callRKernel6 = syscall.RawSyscall6 -EOF - - exit 0 -fi - -# pure Go support. -cat > "${dir}/syscalls.go" <<EOF -// +build linux,!cgo - -package cap - -import "syscall" - -// callKernel variables overridable for testing purposes. -// (Go build tree contains syscall.PerOSThreadSyscall support.) -var callWKernel = syscall.PerOSThreadSyscall -var callWKernel6 = syscall.PerOSThreadSyscall6 -var callRKernel = syscall.RawSyscall -var callRKernel6 = syscall.RawSyscall6 -EOF - -cat > "${dir}/syscalls_cgo.go" <<EOF -// +build linux,cgo - -package cap - -import ( - "libcap/psx" - "syscall" -) - -// callKernel variables overridable for testing purposes. -// We use this version when we are cgo compiling because -// we need to manage the native C pthreads too. -var callWKernel = psx.Syscall3 -var callWKernel6 = psx.Syscall6 -var callRKernel = syscall.RawSyscall -var callRKernel6 = syscall.RawSyscall6 -EOF
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/web.go
Deleted
@@ -1,136 +0,0 @@ -// Progam web provides an example of a webserver using capabilities to -// bind to a privileged port, and then drop all capabilities before -// handling the first web request. -// -// This program cannot work reliably as a pure Go application without -// the equivalent of the Go runtime patch that adds a POSIX semantics -// wrapper around the system calls that change kernel state. A patch -// for the pure Go compiler/runtime to add this support is available -// here [2019-12-14]: -// -// https://go-review.googlesource.com/c/go/+/210639/ -// -// Until that patch, or something like it, is absorbed into the Go -// runtime the only way to get capabilities to work reliably on the Go -// runtime is to use something like libpsx via cgo to do capability -// setting syscalls in C with POSIX semantics. As of this build of the -// Go "libcap/cap" package, courtesy of the "libcap/psx" package, this -// is how things work. -// -// To set this up, compile and empower this binary as follows -// (packages libcap/{cap,psx} should be installed, as must libpsx.a): -// -// go build web.go -// sudo setcap cap_setpcap,cap_net_bind_service=p web -// ./web --port=80 -// -// Make requests using wget and observe the log of web: -// -// wget -o/dev/null -O/dev/stdout localhost:80 -package main - -import ( - "flag" - "fmt" - "libcap/cap" - "log" - "net" - "net/http" - "runtime" - "syscall" -) - -var ( - port = flag.Int("port", 0, "port to listen on") - skipPriv = flag.Bool("skip", false, "skip raising the effective capability - will fail for low ports") -) - -// ensureNotEUID aborts the program if it is running setuid something, -// or being invoked by root. That is, the preparer isn't setting up -// the program correctly. -func ensureNotEUID() { - euid := syscall.Geteuid() - uid := syscall.Getuid() - egid := syscall.Getegid() - gid := syscall.Getgid() - if uid != euid || gid != egid { - log.Fatalf("go runtime is setuid uids:(%d vs %d), gids(%d vs %d)", uid, euid, gid, egid) - } - if uid == 0 { - log.Fatalf("go runtime is running as root - cheating") - } -} - -// listen creates a listener by raising effective privilege only to -// bind to address and then lowering that effective privilege. -func listen(network, address string) (net.Listener, error) { - if *skipPriv { - return net.Listen(network, address) - } - - orig := cap.GetProc() - defer orig.SetProc() // restore original caps on exit. - - c, err := orig.Dup() - if err != nil { - return nil, fmt.Errorf("failed to dup caps: %v", err) - } - - if on, _ := c.GetFlag(cap.Permitted, cap.NET_BIND_SERVICE); !on { - return nil, fmt.Errorf("insufficient privilege to bind to low ports - want %q, have %q", cap.NET_BIND_SERVICE, c) - } - - if err := c.SetFlag(cap.Effective, true, cap.NET_BIND_SERVICE); err != nil { - return nil, fmt.Errorf("unable to set capability: %v", err) - } - - if err := c.SetProc(); err != nil { - return nil, fmt.Errorf("unable to raise capabilities %q: %v", c, err) - } - return net.Listen(network, address) -} - -// Handler is used to abstract the ServeHTTP function. -type Handler struct{} - -// ServeHTTP says hello from a single Go hardware thread and reveals -// its capabilities. -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - runtime.LockOSThread() - // Get some numbers consistent to the current execution, so - // the returned web page demonstrates that the code execution - // is bouncing around on different kernel thread ids. - p := syscall.Getpid() - t := syscall.Gettid() - c := cap.GetProc() - runtime.UnlockOSThread() - - log.Printf("Saying hello from proc: %d->%d, caps=%q", p, t, c) - fmt.Fprintf(w, "Hello from proc: %d->%d, caps=%q\n", p, t, c) -} - -func main() { - flag.Parse() - - if *port == 0 { - log.Fatal("please supply --port value") - } - - ensureNotEUID() - - ls, err := listen("tcp", fmt.Sprintf(":%d", *port)) - if err != nil { - log.Fatalf("aborting: %v", err) - } - defer ls.Close() - - if !*skipPriv { - if err := cap.ModeNoPriv.Set(); err != nil { - panic(fmt.Errorf("unable to drop all privilege: %v", err)) - } - } - - if err := http.Serve(ls, &Handler{}); err != nil { - log.Fatalf("server failed: %v", err) - } -}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/include/sys/psx_syscall.h
Deleted
@@ -1,128 +0,0 @@ -/* - * Copyright (c) 2019 Andrew G. Morgan <morgan@kernel.org> - * - * This header, and the -lpsx library, provide a number of things to - * support POSIX semantics for syscalls associated with the pthread - * library. Linking this code is tricky and is done as follows: - * - * ld ... -lpsx -lpthread --wrap=pthread_create - * or, gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create - * - * glibc provides a subset of this functionality natively through the - * nptl:setxid mechanism and could implement psx_syscall() directly - * using that style of functionality but, as of 2019-11-30, the setxid - * mechanism is limited to 9 specific set*() syscalls that do not - * support the syscall6 API (needed for prctl functions and the ambient - * capabilities set for example). - * - * This psx library API also includes explicit registration of threads - * if implicit wrapping the pthread_create() function is problematic - * for your application via the psx_pthread_create() function. To use - * the library in that way, you should include this line in the file - * containing your main() function: - * - * ----------- - * #include <sys/psx_syscall.h> - * - * int main(...) { - * - * .... - * - * } - * PSX_NO_LINKER_WRAPPING - * ----------- - * - * This will ensure that your binary can link. - */ - -#ifndef _SYS_PSX_SYSCALL_H -#define _SYS_PSX_SYSCALL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <pthread.h> - -/* - * This function is actually provided by the linker trick: - * - * gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create - */ -int __real_pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg); - -#define PSX_NO_LINKER_WRAPPING int \ - __real_pthread_create(pthread_t *thread, const pthread_attr_t *attr, \ - void *(*start_routine) (void *), void *arg) { \ - return -1; \ - } - -/* - * psx_syscall performs the specified syscall on all psx registered - * threads. The mecanism by which this occurs is much less efficient - * than a standard system call on Linux, so it should only be used - * when POSIX semantics are required to change process relevant - * security state. - * - * Glibc has native support for POSIX semantics on setgroups() and the - * 8 set*[gu]id() functions. So, there is no need to use psx_syscall() - * for these calls. This call exists for all the other system calls - * that need to maintain parity on all pthreads of a program. - * - * Some macrology is used to allow the caller to provide only as many - * arguments as needed, thus psx_syscall() cannot be used as a - * function pointer. For those situations, we define psx_syscall3() - * and psx_syscall6(). - */ -#define psx_syscall(syscall_nr, ...) \ - __psx_syscall(syscall_nr, __VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) -long int __psx_syscall(long int syscall_nr, ...); -long int psx_syscall3(long int syscall_nr, - long int arg1, long int arg2, long int arg3); -long int psx_syscall6(long int syscall_nr, - long int arg1, long int arg2, long int arg3, - long int arg4, long int arg5, long int arg6); - -/* - * psx_register registers a pthread with the psx abstraction of system - * calls. - */ -void psx_register(pthread_t thread); - -/* - * psx_pthread_create() wraps the -lpthread pthread_create() function - * call and registers the generated thread with the psx_syscall - * infrastructure. - * - * Note, to transparently redirect all the pthread_create() calls in - * your binary to psx_pthread_create(), link with: - * - * gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create - * - * [That is, libpsx contains an internal definition for the - * __wrap_pthread_create function to invoke psx_pthread_create - * functionality instead.] - */ -int psx_pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void *(*start_routine) (void *), void *arg); - -/* - * This function should be used by systems to obtain pointers to the - * two syscall functions provided by the PSX library. A linkage trick - * is to define this function as weak in a library that can optionally - * use libpsx and then, should the caller link -lpsx, that library can - * implicitly use these POSIX semantics syscalls. See libcap for an - * example of this useage. - */ -void psx_load_syscalls(long int (**syscall_fn)(long int, - long int, long int, long int), - long int (**syscall6_fn)(long int, - long int, long int, long int, - long int, long int, long int)); - -#ifdef __cplusplus -} -#endif - -#endif /* _SYS_PSX_SYSCALL_H */
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/psx.c
Deleted
@@ -1,427 +0,0 @@ -/* - * Copyright (c) 2019 Andrew G Morgan <morgan@kernel.org> - * - * This file contains a collection of routines that perform thread - * synchronization to ensure that a whole process is running as a - * single privilege object - independent of the number of pthreads. - * - * The whole file would be unnecessary if glibc exported an explicit - * psx_syscall()-like function that leveraged the nptl:setxid - * mechanism to synchronize thread state over the whole process. - */ -#define _POSIX_C_SOURCE 199309L -#define _GNU_SOURCE - -#include <errno.h> -#include <pthread.h> -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/psx_syscall.h> -#include <sys/syscall.h> - -/* - * psx_load_syscalls() is weakly defined so we can have it overriden - * by libpsx if it is linked. Specifically, when libcap calls - * psx_load_sycalls it will override their defaut values. As can be - * seen here this present function is a no-op. However, if libpsx is - * linked, the one present in that library (not being weak) will - * replace this one. - */ -void psx_load_syscalls(long int (**syscall_fn)(long int, - long int, long int, long int), - long int (**syscall6_fn)(long int, - long int, long int, long int, - long int, long int, long int)) -{ - *syscall_fn = psx_syscall3; - *syscall6_fn = psx_syscall6; -} - -/* - * type to keep track of registered threads. - */ -typedef struct registered_thread_s { - struct registered_thread_s *next, *prev; - pthread_t thread; -} registered_thread_t; - -static pthread_once_t psx_tracker_initialized = PTHREAD_ONCE_INIT; - -typedef int psx_tracker_state_t; - -#define _PSX_IDLE ((psx_tracker_state_t) 0) -#define _PSX_SETUP ((psx_tracker_state_t) 1) -#define _PSX_SYSCALL ((psx_tracker_state_t) 2) -#define _PSX_CREATE ((psx_tracker_state_t) 3) - -/* - * This global structure holds the global coordination state for - * libcap's psx_posix_syscall() support. - */ -static struct psx_tracker_s { - pthread_mutex_t state_mu; - pthread_cond_t cond; - psx_tracker_state_t state; - - int initialized; - int psx_sig; - - struct { - long syscall_nr; - long arg1, arg2, arg3, arg4, arg5, arg6; - int six; - int active; - int todo; - } cmd; - - struct sigaction sig_action; - registered_thread_t *root; -} psx_tracker; - -/* - * psx_posix_syscall_actor performs the system call on the targeted - * thread and decreases the outstanding syscall counter. - */ -static void psx_posix_syscall_actor(int signum, siginfo_t *info, void *ignore) { - /* bail early if this isn't something we recognize */ - if (signum != psx_tracker.psx_sig || !psx_tracker.cmd.active || - info == NULL || info->si_code != SI_TKILL || info->si_pid != getpid()) { - return; - } - - if (!psx_tracker.cmd.six) { - (void) syscall(psx_tracker.cmd.syscall_nr, - psx_tracker.cmd.arg1, - psx_tracker.cmd.arg2, - psx_tracker.cmd.arg3); - } else { - (void) syscall(psx_tracker.cmd.syscall_nr, - psx_tracker.cmd.arg1, - psx_tracker.cmd.arg2, - psx_tracker.cmd.arg3, - psx_tracker.cmd.arg4, - psx_tracker.cmd.arg5, - psx_tracker.cmd.arg6); - } - - pthread_mutex_lock(&psx_tracker.state_mu); - --psx_tracker.cmd.todo; - pthread_cond_broadcast(&psx_tracker.cond); - pthread_mutex_unlock(&psx_tracker.state_mu); -} - -long int psx_syscall3(long int syscall_nr, - long int arg1, long int arg2, long int arg3) { - return psx_syscall(syscall_nr, arg1, arg2, arg3); -} - -long int psx_syscall6(long int syscall_nr, - long int arg1, long int arg2, long int arg3, - long int arg4, long int arg5, long int arg6) { - return psx_syscall(syscall_nr, arg1, arg2, arg3, arg4, arg5, arg6); -} - -/* - * psx_signal_start initializes the signal handler as a constructor - * using a linker trick. This runs before Go has a chance to mess with - * all the signal handlers. The constructor index is the priority we - * can use without generating a linker complaint. - */ -static void psx_signal_start(void) { - /* - * glibc nptl picks from the SIGRTMIN end, so we pick from the - * SIGRTMAX end - */ - psx_tracker.psx_sig = SIGRTMAX; - psx_tracker.sig_action.sa_sigaction = psx_posix_syscall_actor; - sigemptyset(&psx_tracker.sig_action.sa_mask); - psx_tracker.sig_action.sa_flags = SA_SIGINFO | SA_RESTART;; - sigaction(psx_tracker.psx_sig, &psx_tracker.sig_action, NULL); -} - -/* - * psx_syscall_start initializes the subsystem. - */ -static void psx_syscall_start(void) { - psx_tracker.initialized = 1; - psx_signal_start(); -} - -static void psx_do_registration(pthread_t thread) { - int first_time = !psx_tracker.initialized; - (void) pthread_once(&psx_tracker_initialized, psx_syscall_start); - - if (first_time) { - /* First invocation, use recursion to register main() thread. */ - psx_do_registration(pthread_self()); - } - - registered_thread_t *node = calloc(1, sizeof(registered_thread_t)); - node->next = psx_tracker.root; - if (node->next) { - node->next->prev = node; - } - node->thread = thread; - psx_tracker.root = node; -} - -/* - * psx_register registers the a thread as pariticipating in the single - * (POSIX) pool of privilege used by the library. - * - * In normal, expected, use you should never need to call this because - * the linker magic wrapping will arrange for this function to be - * called implicitly every time a pthread is created with - * pthread_create() or psx_pthread_create(). If, however, you are - * unable to use the linker trick to wrap pthread_create(), you should - * include this line in one and only one place in your code. Just - * after the end of the main() function would be a good place, for - * example: - * - * int main(int argc, char **argv) { - - * ... - * } - * - * PSX_NO_LINKER_WRAPPING - * - * This is required for libpsx to link. It also requires the coder to - * explicitly use psx_register() for all threads not started with - * psx_pthread_create(). - * - * Note, there is no need to ever register the main() process thread. - */ -void psx_register(pthread_t thread) { - pthread_mutex_lock(&psx_tracker.state_mu); - psx_do_registration(thread);
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/CHANGELOG -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/CHANGELOG
Changed
@@ -1,17 +1,15 @@ -For release notes and other info pointers: +For release notes and other info pointers for submitting patches etc.: - http://sites.google.com/site/fullycapable/ + http://sites.google.com/site/fullycapable/ -See GIT repository for detailed source history +See GIT repository for detailed source history: - https://git.kernel.org/cgit/linux/kernel/git/morgan/libcap.git/ + https://git.kernel.org/pub/scm/libs/libcap/libcap.git/ Or simply download the source: - git clone git://git.kernel.org/pub/scm/linux/kernel/git/morgan/libcap.git + git clone git://git.kernel.org/pub/scm/libs/libcap/libcap.git The license for this library is here: - https://git.kernel.org/cgit/linux/kernel/git/morgan/libcap.git/tree/License - -please submit patches compatible with this to morgan at kernel.org. + https://git.kernel.org/pub/scm/libs/libcap/libcap.git/tree/License
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/License -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/License
Changed
@@ -1,8 +1,16 @@ Unless otherwise *explicitly* stated, the following text describes the licensed conditions under which the contents of this libcap release -may be used and distributed: +may be used and distributed. + +The licensed conditions are one or the other of these two Licenses: + + - BSD 3-clause + - GPL v2.0 ------------------------------------------------------------------------- +BSD 3-clause: +------------- + Redistribution and use in source and binary forms of libcap, with or without modification, are permitted provided that the following conditions are met: @@ -20,13 +28,6 @@ products derived from this software without their specific prior written permission. -ALTERNATIVELY, this product may be distributed under the terms of the -GNU General Public License (v2.0 - see below), in which case the -provisions of the GNU GPL are required INSTEAD OF the above -restrictions. (This clause is necessary due to a potential conflict -between the GNU GPL and the restrictions contained in a BSD-style -copyright.) - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. @@ -38,7 +39,15 @@ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ------------------------------------------------------------------------- +GPL v2.0: +--------- + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License (v2.0 - see below), in which case the +provisions of the GNU GPL are required INSTEAD OF the above +restrictions. ------------------------- Full text of gpl-2.0.txt:
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/Make.Rules -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/Make.Rules
Changed
@@ -1,8 +1,13 @@ +# Common version number defines for libcap +LIBTITLE=libcap +VERSION=2 +MINOR=61 + # ## Optional prefixes: # -# common 'packaging' directoty +# common 'packaging' directory FAKEROOT=$(DESTDIR) @@ -16,6 +21,14 @@ lib=$(shell ldd /usr/bin/ld|egrep "ld-linux|ld.so"|cut -d/ -f2) endif +ifndef sbin +sbin=sbin +endif + +ifdef sbindir +sbin=$(sbindir) +endif + ifdef prefix exec_prefix=$(prefix) lib_prefix=$(exec_prefix) @@ -32,60 +45,111 @@ # Target directories MANDIR=$(man_prefix)/man -SBINDIR=$(exec_prefix)/sbin +SBINDIR=$(exec_prefix)/$(sbin) INCDIR=$(inc_prefix)/include LIBDIR=$(lib_prefix)/$(lib) -PKGCONFIGDIR=$(prefix)/$(lib)/pkgconfig +PKGCONFIGDIR=$(LIBDIR)/pkgconfig GOPKGDIR=$(prefix)/share/gocode/src -# common defines for libcap -LIBTITLE=libcap -VERSION=2 -MINOR=32 -# +# From here on out, the Go module packages should always remain +# backwardly compatible. I will only resort to using major version 2 +# etc if Go's syntax dramatically changes in a backwards incompatible +# manner. (Let's hope not. If that happens, I'll also drop deprecated +# API functions.) +GOMAJOR=1 # Compilation specifics KERNEL_HEADERS := $(topdir)/libcap/include/uapi -IPATH += -fPIC -I$(KERNEL_HEADERS) -I$(topdir)/libcap/include - -CC := gcc -CFLAGS := -O2 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -BUILD_CC := $(CC) -BUILD_CFLAGS := $(CFLAGS) $(IPATH) -AR := ar -RANLIB := ranlib -DEBUG = -g #-DDEBUG -WARNINGS=-Wall -Wwrite-strings \ - -Wpointer-arith -Wcast-qual -Wcast-align \ - -Wstrict-prototypes -Wmissing-prototypes \ - -Wnested-externs -Winline -Wshadow -LD=$(CC) -Wl,-x -shared -LDFLAGS := #-g -LIBCAPLIB := -L$(topdir)/libcap -lcap -LIBPSXLIB := -L$(topdir)/libcap -lpsx -lpthread +LIBCAP_INCLUDES = -I$(KERNEL_HEADERS) -I$(topdir)/libcap/include +DEFINES := -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +SYSTEM_HEADERS = /usr/include +SUDO := sudo +CC := $(CROSS_COMPILE)gcc +LD := $(CC) -Wl,-x -shared +AR := $(CROSS_COMPILE)ar +RANLIB := $(CROSS_COMPILE)ranlib +OBJCOPY := $(CROSS_COMPILE)objcopy + +# Reference: +# CPPFLAGS used for building .o files from .c & .h files +# CFLAGS used when building libraries from .o, .c and .h files + +DEBUG = # -g -DDEBUG +WARNINGS=-Wall -Wwrite-strings -Wpointer-arith -Wcast-qual -Wcast-align \ + -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs \ + -Winline -Wshadow -Wunreachable-code +COPTS ?= -O2 +CFLAGS ?= $(COPTS) $(DEBUG) +CFLAGS += $(WARNINGS) +CPPFLAGS += -Dlinux $(DEFINES) $(LIBCAP_INCLUDES) +LDFLAGS ?= # -g + +BUILD_CC ?= $(CC) +BUILD_LD ?= $(BUILD_CC) -Wl,-x -shared +BUILD_COPTS ?= $(COPTS) +BUILD_CFLAGS ?= $(BUILD_COPTS) +BUILD_CPPFLAGS += -Dlinux $(WARNINGS) $(DEBUG) $(DEFINES) $(LIBCAP_INCLUDES) +BUILD_LDFLAGS ?= $(LDFLAGS) BUILD_GPERF := $(shell which gperf >/dev/null 2>/dev/null && echo yes) -SYSTEM_HEADERS = /usr/include +LIBCAPLIB := -L$(topdir)/libcap -lcap +PSXLINKFLAGS := -lpthread -Wl,-wrap,pthread_create +LIBPSXLIB := -L$(topdir)/libcap -lpsx $(PSXLINKFLAGS) + INCS=$(topdir)/libcap/include/sys/capability.h -LDFLAGS += -L$(topdir)/libcap -CFLAGS += -Dlinux $(WARNINGS) $(DEBUG) -PAM_CAP := $(shell if [ -f /usr/include/security/pam_modules.h ]; then echo yes ; else echo no ; fi) INDENT := $(shell if [ -n "$$(which indent 2>/dev/null)" ]; then echo "| indent -kr" ; fi) -DYNAMIC := $(shell if [ ! -d "$(topdir)/.git" ]; then echo yes; fi) -GOLANG := $(shell if [ -n "$(shell go version 2>/dev/null)" ]; then echo yes ; else echo no ; fi) +# SHARED tracks whether or not the SHARED libraries (libcap.so, +# libpsx.so and pam_cap.so) are built. (Some environments don't +# support shared libraries.) +SHARED ?= yes +# DYNAMIC controls how capsh etc are linked - to shared or static libraries +# Force enabled with "make DYNAMIC=yes ...". +DYNAMIC := $(shell if [ ! -d "$(topdir)/.git" ]; then echo $(SHARED); else echo no ; fi) + +PAM_CAP ?= $(shell if [ -f /usr/include/security/pam_modules.h ]; then echo $(SHARED) ; else echo no ; fi) + +# If your system does not support pthreads, override this as "no". +# +# make PTHREADS=no ... +# +# This implies no Go support and no C/C++ libpsx build. Why might you +# need libpsx for non-Go use? Tl;dr for POSIX semantics security: +# +# https://sites.google.com/site/fullycapable/who-ordered-libpsx +# +PTHREADS ?= yes + +ifeq ($(PTHREADS),yes) +GO ?= go +GOLANG ?= $(shell if [ -n "$(shell $(GO) version 2>/dev/null)" ]; then echo yes ; else echo no ; fi) ifeq ($(GOLANG),yes) -GOROOT := $(shell go env GOROOT) -GOCGO := $(shell if [ "$(shell go env CGO_ENABLED)" = 1 ]; then echo yes ; else echo no ; fi) -GOOSARCH := $(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) +GOROOT ?= $(shell $(GO) env GOROOT) +GOCGO ?= $(shell if [ "$(shell $(GO) env CGO_ENABLED)" = 1 ]; then echo yes ; else echo no ; fi) +GOOSARCH ?= $(shell $(GO) env GOHOSTOS)_$(shell $(GO) env GOHOSTARCH) +CGO_REQUIRED := $(shell $(topdir)/go/cgo-required.sh $(GO)) +ifeq ($(CGO_REQUIRED),1) +# Strictly speaking go1.15 doesn't need this, but 1.16 is when the +# real golang support arrives for non-cgo support, so drop the last +# vestige of legacy workarounds then. +CGO_LDFLAGS_ALLOW := CGO_LDFLAGS_ALLOW="-Wl,-?-wrap[=,][^-.@][^,]*" +endif CGO_CFLAGS := -I$(topdir)/libcap/include CGO_LDFLAGS := -L$(topdir)/libcap -CGO_LDFLAGS_ALLOW := -Wl,-wrap,.+ -CGO_REQUIRED=$(shell $(topdir)/go/cgo-required.sh) +GO_BUILD_FLAGS := +endif endif +# If you want capsh to launch with something other than /bin/bash +# build like this: +# +# make CAPSH_SHELL='-DSHELL=\"/bin/sh\"' +# +# or undefine the following: +#CAPSH_SHELL := '-DSHELL="/bin/sh"' + # When installing setcap, you can arrange for the installation process # to set its inheritable bit to be able to place capabilities on files. # It can be used in conjunction with pam_cap (associated with su and @@ -93,11 +157,11 @@ # # make RAISE_SETFCAP=yes install # -# This is now defaulted to no because some distributions have started -# shipping with all users blessed with full inheritable sets which makes -# no sense whatsoever! +# This is now defaulted to no because some distributions started +# shipping with all users blessed with full inheritable sets which +# makes no sense whatsoever! # -# Indeed, it looks alarmingly like these distributions are recreating +# Indeed, it looked alarmingly like these distributions were recreating # the environment for what became known as the sendmail-capabilities # bug from 2000: # @@ -112,7 +176,7 @@ # # In the context of this tree, on such such systems, a yes setting will # guarantee that every user, by default, is able to bless any binary with -# any capability - a ready made local exploit machanism. +# any capability - a ready made local exploit mechanism. RAISE_SETFCAP := no
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/Makefile
Changed
@@ -8,21 +8,25 @@ # flags # -all install clean kdebug: %: %-here +all test sudotest install clean: %: %-here $(MAKE) -C libcap $@ ifneq ($(PAM_CAP),no) $(MAKE) -C pam_cap $@ endif ifeq ($(GOLANG),yes) $(MAKE) -C go $@ + rm -f cap/go.sum endif $(MAKE) -C tests $@ $(MAKE) -C progs $@ $(MAKE) -C doc $@ - $(MAKE) -C kdebug $@ all-here: +test-here: + +sudotest-here: + install-here: clean-here: @@ -30,35 +34,49 @@ distclean: clean $(DISTCLEAN) + @echo "CONFIRM Go package cap has right version dependency on cap/psx:" + for x in $$(find . -name go.mod); do grep -F -v "module" $$x | fgrep "kernel.org/pub/linux/libs/security/libcap" > /dev/null || continue ; grep -F "v$(GOMAJOR).$(VERSION).$(MINOR)" $$x > /dev/null && continue ; echo "$$x is not updated. Try running: ./gomods.sh v$(GOMAJOR).$(VERSION).$(MINOR)" ; exit 1 ; done + @echo "ALL go.mod files updated" + @echo "Now validate that everything is checked in to a clean tree.." + test -z "$$(git status --ignored -s)" + @echo "All good!" release: distclean cd .. && ln -s libcap libcap-$(VERSION).$(MINOR) && tar cvf libcap-$(VERSION).$(MINOR).tar --exclude patches libcap-$(VERSION).$(MINOR)/* && rm libcap-$(VERSION).$(MINOR) -test: all - make -C libcap $@ - make -C tests $@ -ifneq ($(PAM_CAP),no) - $(MAKE) -C pam_cap $@ -endif -ifeq ($(GOLANG),yes) - make -C go $@ -endif - make -C progs $@ +ktest: all + $(MAKE) -C kdebug test -sudotest: all - make -C tests $@ -ifneq ($(PAM_CAP),no) - $(MAKE) -C pam_cap $@ -endif -ifeq ($(GOLANG),yes) - make -C go $@ -endif - make -C progs $@ +distcheck: + ./distcheck.sh + $(MAKE) DYNAMIC=no COPTS="-D_FORTIFY_SOURCE=2 -O1 -g" clean test + $(MAKE) DYNAMIC=yes clean all test sudotest + $(MAKE) DYNAMIC=no COPTS="-O2 -std=c89" clean all test sudotest + $(MAKE) PAM_CAP=no CC=/usr/local/musl/bin/musl-gcc clean all test sudotest + $(MAKE) CC=clang clean all test sudotest + $(MAKE) clean all test sudotest + $(MAKE) distclean + +morgangodoc: + @echo "Now the release is made, you want to remember to run one of:" + @echo + @echo " GOPROXY=https://proxy.golang.org GO111MODULE=on go get kernel.org/pub/linux/libs/security/libcap/cap@v$(GOMAJOR).$(VERSION).$(MINOR)" + @echo + @echo or press the request button on this page: + @echo + @echo " https://pkg.go.dev/kernel.org/pub/linux/libs/security/libcap/cap@v$(GOMAJOR).$(VERSION).$(MINOR)" + @echo + @echo "This will cause a go.dev documentation update." -morganrelease: distclean - @echo "sign the tag twice: older DSA key; and newer RSA kernel.org key" +morganrelease: distcheck + @echo "sign the main library tag twice: older DSA key; and newer RSA (kernel.org) key" git tag -u D41A6DF2 -s libcap-$(VERSION).$(MINOR) -m "This is libcap-$(VERSION).$(MINOR)" git tag -u E2CCF3F4 -s libcap-korg-$(VERSION).$(MINOR) -m "This is libcap-$(VERSION).$(MINOR)" - make release + @echo "The following are for the Go module tracking." + git tag -u D41A6DF2 -s v$(GOMAJOR).$(VERSION).$(MINOR) -m "This is the version tag for the 'libcap' Go base directory associated with libcap-$(VERSION).$(MINOR)." + git tag -u D41A6DF2 -s psx/v$(GOMAJOR).$(VERSION).$(MINOR) -m "This is the (stable) version tag for the 'psx' Go package associated with libcap-$(VERSION).$(MINOR)." + git tag -u D41A6DF2 -s cap/v$(GOMAJOR).$(VERSION).$(MINOR) -m "This is the (stable) version tag for the 'cap' Go package associated with libcap-$(VERSION).$(MINOR)." + $(MAKE) release @echo "sign the tar file using korg key" cd .. && gpg -sba -u E2CCF3F4 libcap-$(VERSION).$(MINOR).tar + $(MAKE) morgangodoc
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/README -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/README
Changed
@@ -5,41 +5,52 @@ This library would not have been possible without the help of - Aleph1, Roland Buresund and Andrew Main, Alexander Kjeldaas. + Aleph1, Roland Buresund and Andrew Main, Alexander Kjeldaas. More information on capabilities in the Linux kernel, links to the -official git repostitory for libcap, release notes and how to report +official git repository for libcap, release notes and how to report bugs can be found at: - http://sites.google.com/site/fullycapable/ + http://sites.google.com/site/fullycapable/ + +The primary upstream git repository is this one: + + https://git.kernel.org/pub/scm/libs/libcap/libcap.git/ # BUILDING AND INSTALLATION - $ make + $ make + + builds the library and the programs that are expected to work + on your system. For example, if you have Linux-PAM installed, + pam_cap is built. A golang installation is required to build + the Go packages. + + $ make test - builds the library and the programs that are expected - to work on your system. For example, if you have - Linux-PAM installed, pam_cap is built. A golang - installation is required to build the Go packages. + runs all of the tests not requiring privilege - $ make test + $ make sudotest - runs all of the tests not requiring privilege + runs all of the tests including those that require privilege. - $ make sudotest + $ sudo make install - runs all of the tests including those that require privilege. + default installs the library libcap.XX.Y in /lib[64]/ + the binaries in /sbin/ + the header files in /usr/include + the {libcap,libpsx}.pc files in /usr/lib[64]/pkgconfig + the Go packages (if built) under /usr/share/gocode/src - $ sudo make install +For some example C programs look in the progs/ directory. +Specifically, capsh, getpcaps, setcap and getcap. There are some C +tests in the tests/ directory. - installs the library libcap.XX.Y in /lib[64]/ - the binaries in /sbin/ - the header files in /usr/include - the {libcap,libpsx}.pc files in /usr/lib[64]/pkgconfig +Go example programs are to be found in the goapps/ directory. There +are also some more complicated integration tests in the go/ directory. -For some example programs look in the progs/ directory. Specifically, -capsh, getpcaps, setcap and getcap. Go example programs are to be -found in the go/ directory. +There are also some oddball experimental things in the contrib/ +directory, but they are mostly curiosities. Cheers
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/License
Added
@@ -0,0 +1,396 @@ +Unless otherwise *explicitly* stated, the following text describes the +licensed conditions under which the contents of this libcap/cap release +may be used and distributed. + +The licensed conditions are one or the other of these two Licenses: + + - BSD 3-clause + - GPL v2.0 + +------------------------------------------------------------------------- +BSD 3-clause: +------------- + +Redistribution and use in source and binary forms of libcap/cap, with +or without modification, are permitted provided that the following +conditions are met: + +1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +------------------------------------------------------------------------- +GPL v2.0: +--------- + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License (v2.0 - see below), in which case the +provisions of the GNU GPL are required INSTEAD OF the above +restrictions. (This clause is necessary due to a potential conflict +between the GNU GPL and the restrictions contained in a BSD-style +copyright.) + +------------------------- +Full text of gpl-2.0.txt: +------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/README
Added
@@ -0,0 +1,10 @@ +Package cap is the libcap API for Linux Capabilities written in +Go. The official release announcement site for libcap is: + + https://sites.google.com/site/fullycapable/ + +Like libcap, the cap package is distributed with a "you choose" +License. Specifically: BSD three clause, or GPL2. See the License +file. + +Andrew G. Morgan <morgan@kernel.org>
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/cap.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/cap.go
Changed
@@ -1,18 +1,83 @@ -// Package cap is the Linux capabilities user space API (libcap) +// Package cap provides all the Linux Capabilities userspace library API // bindings in native Go. // -// For cgo linked binaries, package "libcap/psx" is used to broker the -// POSIX semantics system calls that manipulate process state. +// Capabilities are a feature of the Linux kernel that allow fine +// grain permissions to perform privileged operations. Privileged +// operations are required to do irregular system level operations +// from code. You can read more about how Capabilities are intended to +// work here: // -// If the Go runtime syscall interface contains the -// syscall.PerOSThreadSyscall() API then then this package will use -// that to invoke capability setting system calls for pure Go -// binaries. To force this behavior use the CGO_ENABLED=0 environment -// variable. -// -// If syscall.PerOSThreadSyscall() is not present, the "libcap/cap" -// package will failover to using "libcap/psx". -package cap +// https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/33528.pdf +// +// This package supports native Go bindings for all the features +// described in that paper as well as supporting subsequent changes to +// the kernel for other styles of inheritable Capability. +// +// Some simple things you can do with this package are: +// +// // Read and display the capabilities of the running process +// c := cap.GetProc() +// log.Printf("this process has these caps:", c) +// +// // Drop any privilege a process might have (including for root, +// // but note root 'owns' a lot of system files so a cap-limited +// // root can still do considerable damage to a running system). +// old := cap.GetProc() +// empty := cap.NewSet() +// if err := empty.SetProc(); err != nil { +// log.Fatalf("failed to drop privilege: %q -> %q: %v", old, empty, err) +// } +// now := cap.GetProc() +// if cf, _ := now.Cf(empty); cf != 0 { +// log.Fatalf("failed to fully drop privilege: have=%q, wanted=%q", now, empty) +// } +// +// The "cap" package operates with POSIX semantics for security +// state. That is all OS threads are kept in sync at all times. The +// package "kernel.org/pub/linux/libs/security/libcap/psx" is used to +// implement POSIX semantics system calls that manipulate thread state +// uniformly over the whole Go (and any CGo linked) process runtime. +// +// Note, if the Go runtime syscall interface contains the Linux +// variant syscall.AllThreadsSyscall() API (it debuted in go1.16 see +// https://github.com/golang/go/issues/1435 for its history) then the +// "libcap/psx" package will use that to invoke Capability setting +// system calls in pure Go binaries. With such an enhanced Go runtime, +// to force this behavior, use the CGO_ENABLED=0 environment variable. +// +// POSIX semantics are more secure than trying to manage privilege at +// a thread level when those threads share a common memory image as +// they do under Linux: it is trivial to exploit a vulnerability in +// one thread of a process to cause execution on any another +// thread. So, any imbalance in security state, in such cases will +// readily create an opportunity for a privilege escalation +// vulnerability. +// +// POSIX semantics also work well with Go, which deliberately tries to +// insulate the user from worrying about the number of OS threads that +// are actually running in their program. Indeed, Go can efficiently +// launch and manage tens of thousands of concurrent goroutines +// without bogging the program or wider system down. It does this by +// aggressively migrating idle threads to make progress on unblocked +// goroutines. So, inconsistent security state across OS threads can +// also lead to program misbehavior. +// +// The only exception to this process-wide common security state is +// the cap.Launcher related functionality. This briefly locks an OS +// thread to a goroutine in order to launch another executable - the +// robust implementation of this kind of support is quite subtle, so +// please read its documentation carefully, if you find that you need +// it. +// +// See https://sites.google.com/site/fullycapable/ for recent updates, +// some more complete walk-through examples of ways of using +// 'cap.Set's etc and information on how to file bugs. +// +// Copyright (c) 2019-21 Andrew G. Morgan <morgan@kernel.org> +// +// The cap and psx packages are licensed with a (you choose) BSD +// 3-clause or GPL2. See LICENSE file for details. +package cap // import "kernel.org/pub/linux/libs/security/libcap/cap" import ( "errors" @@ -25,10 +90,12 @@ // Value is the type of a single capability (or permission) bit. type Value uint -// Flag is the type of one of the three Value vectors held in a Set. +// Flag is the type of one of the three Value dimensions held in a +// Set. It is also used in the (*IAB).Fill() method for changing the +// Bounding and Ambient Vectors. type Flag uint -// Effective, Permitted, Inheritable are the three vectors of Values +// Effective, Permitted, Inheritable are the three Flags of Values // held in a Set. const ( Effective Flag = iota @@ -36,12 +103,43 @@ Inheritable ) +// Diff summarizes the result of the (*Set).Cf() function. +type Diff uint + +const ( + effectiveDiff Diff = 1 << Effective + permittedDiff Diff = 1 << Permitted + inheritableDiff Diff = 1 << Inheritable +) + +// String identifies a Flag value by its conventional "e", "p" or "i" +// string abbreviation. +func (f Flag) String() string { + switch f { + case Effective: + return "e" + case Permitted: + return "p" + case Inheritable: + return "i" + default: + return "<Error>" + } +} + // data holds a 32-bit slice of the compressed bitmaps of capability // sets as understood by the kernel. type data [Inheritable + 1]uint32 // Set is an opaque capabilities container for a set of system -// capbilities. +// capbilities. It holds individually addressable capability Value's +// for the three capability Flag's. See GetFlag() and SetFlag() for +// how to adjust them individually, and Clear() and ClearFlag() for +// how to do bulk operations. +// +// For admin tasks associated with managing namespace specific file +// capabilities, Set can also support a namespace-root-UID value which +// defaults to zero. See GetNSOwner() and SetNSOwner(). type Set struct { // mu protects all other members of a Set. mu sync.RWMutex @@ -62,7 +160,7 @@ ) var ( - // starUp protects setting of the following values: magic, + // startUp protects setting of the following values: magic, // words, maxValues. startUp sync.Once @@ -70,7 +168,7 @@ magic uint32 // words holds the number of uint32's associated with each - // capability vector for this session. + // capability Flag for this session. words int // maxValues holds the number of bit values that are named by @@ -84,14 +182,25 @@ pid int32 } +// syscaller is a type for abstracting syscalls. The r* variants are +// for reading state, and can be parallelized, the w* variants need to +// be serialized so all OS threads can share state. +type syscaller struct { + r3 func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + w3 func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) + r6 func(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + w6 func(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) +} + // caprcall provides a pointer etc wrapper for the system calls // associated with getcap. -func caprcall(call uintptr, h *header, d []data) error { +//go:uintptrescapes +func (sc *syscaller) caprcall(call uintptr, h *header, d []data) error { x := uintptr(0) if d != nil { x = uintptr(unsafe.Pointer(&d[0])) } - _, _, err := callRKernel(call, uintptr(unsafe.Pointer(h)), x, 0) + _, _, err := sc.r3(call, uintptr(unsafe.Pointer(h)), x, 0) if err != 0 {
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/cap_test.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/cap_test.go
Changed
@@ -57,8 +57,12 @@ }{ {"", "", ErrBadText}, {"=", "=", nil}, - {"= cap_chown+iep cap_chown-i", "= cap_chown+ep", nil}, - {"= cap_setfcap,cap_chown+iep cap_chown-i", "= cap_setfcap+eip cap_chown+ep", nil}, + {"= cap_chown+iep cap_chown-i", "cap_chown=ep", nil}, + {"= cap_setfcap,cap_chown+iep cap_chown-i", "cap_setfcap=eip cap_chown+ep", nil}, + {"cap_setfcap,cap_chown=iep cap_chown-i", "cap_setfcap=eip cap_chown+ep", nil}, + {"=i =p", "=p", nil}, + {"all+pie", "=eip", nil}, + {"all=p+ie-e", "=ip", nil}, } for i, v := range vs { c, err := FromText(v.from) @@ -102,6 +106,18 @@ return nil } +func confirmExpectedExport(t *testing.T, info string, c *Set, size uint) { + if ex, err := c.Export(); err != nil { + t.Fatalf("[%s] failed to export empty set: %v", info, err) + } else if n := 5 + 3*size; uint(len(ex)) != n { + t.Fatalf("[%s] wrong length: got=%d [%0x] want=%d", info, len(ex), ex, n) + } else if im, err := Import(ex); err != nil { + t.Fatalf("[%s] failed to import empty set: %v", info, err) + } else if got, want := im.String(), c.String(); got != want { + t.Fatalf("[%s] import != export: got=%q want=%q [%02x]", info, got, want, ex) + } +} + func TestImportExport(t *testing.T) { wantQ := "=ep cap_chown-e 63+ip" if q, err := FromText(wantQ); err != nil { @@ -112,15 +128,7 @@ // Sanity check empty import/export. c := NewSet() - if ex, err := c.Export(); err != nil { - t.Fatalf("failed to export empty set: %v", err) - } else if len(ex) != 5 { - t.Fatalf("wrong length: got=%d want=%d", len(ex), 5) - } else if im, err := Import(ex); err != nil { - t.Fatalf("failed to import empty set: %v", err) - } else if got, want := im.String(), c.String(); got != want { - t.Fatalf("import != export: got=%q want=%q", got, want) - } + confirmExpectedExport(t, "empty", c, MinExtFlagSize) // Now keep flipping bits on and off and validate that all // forms of import/export work. for i := uint(0); i < 7000; i += 13 { @@ -139,4 +147,156 @@ t.Fatalf("[%d] miscompare (%q vs. %q): %v", i, got, parsed, err) } } + + oMin := MinExtFlagSize + for j := uint(0); j < 5; j++ { + t.Logf("exporting with min flag size %d", j) + MinExtFlagSize = j + c = NewSet() + for i := uint(0); i < maxValues; i++ { + s := Flag(i % 3) + v := Value(i) + c.SetFlag(s, true, v) + size := 1 + i/8 + if size < MinExtFlagSize { + size = MinExtFlagSize + } + confirmExpectedExport(t, fmt.Sprintf("%d added %d %v %v", j, i, s, v), c, size) + } + } + MinExtFlagSize = oMin +} + +func TestIAB(t *testing.T) { + vs := []struct { + text string + bad bool + }{ + {text: "cup_full", bad: true}, + {text: ""}, + {text: "!%cap_chown"}, + {text: "!cap_chown,^cap_setuid"}, + {text: "cap_chown,cap_setuid"}, + {text: "^cap_chown,cap_setuid"}, + {text: "^cap_chown,!cap_setuid"}, + } + for i, v := range vs { + want := v.text + iab, err := IABFromText(want) + if err != nil { + if v.bad { + continue + } + t.Errorf("[%d] want=%q, got=%q", i, want, iab) + continue + } + if got := iab.String(); got != want { + t.Errorf("[%d] got=%q want=%q", i, got, want) + } + } + + one, err := GetPID(1) + if err != nil { + t.Fatalf("failed to get init's capabilities: %v", err) + } + iab := NewIAB() + if err := iab.Fill(Amb, one, Permitted); err != nil { + t.Fatalf("failed to fill Amb from Permitted: %v", err) + } + for i := 0; i < words; i++ { + if iab.i[i] != iab.a[i] { + t.Errorf("[%d: %q] i=0x%08x != a=0x%08x", i, one, iab.i[i], iab.a[i]) + } + } + one.ClearFlag(Inheritable) + iab.Fill(Inh, one, Inheritable) + for i := 0; i < words; i++ { + if iab.i[i] != iab.a[i] { + t.Errorf("[%d: %q] i=0x%08x != a=0x%08x", i, one, iab.i[i], iab.a[i]) + } + } + + for n := uint(0); n < 1000; n += 13 { + enabled := ((n % 5) & 2) != 0 + vec := Vector(n % 3) + c := Value(n % maxValues) + if err := iab.SetVector(vec, enabled, c); err != nil { + t.Errorf("[%d] failed to set vec=%v enabled=%v %q in %q", n, vec, enabled, c, iab) + continue + } + replay, err := IABFromText(iab.String()) + if err != nil { + t.Errorf("failed to replay: %v", err) + continue + } + for i := 0; i < words; i++ { + if replay.i[i] != iab.i[i] || replay.a[i] != iab.a[i] || replay.nb[i] != iab.nb[i] { + t.Errorf("[%d,%d] got=%q want=%q", n, i, replay, iab) + } + } + } +} + +func TestFuncLaunch(t *testing.T) { + if _, err := FuncLauncher(func(data interface{}) error { + return nil + }).Launch(nil); err != nil { + t.Fatalf("trivial launcher failed: %v", err) + } + + for i := 0; i < 100; i++ { + expect := i & 1 + before, err := Prctl(prGetKeepCaps) + if err != nil { + t.Fatalf("failed to get PR_KEEP_CAPS: %v", err) + } + if before != expect { + t.Fatalf("invalid initial state: got=%d want=%d", before, expect) + } + + if _, err := FuncLauncher(func(data interface{}) error { + was, ok := data.(int) + if !ok { + return fmt.Errorf("data was not an int: %v", data) + } + if _, err := Prctlw(prSetKeepCaps, uintptr(1-was)); err != nil { + return err + } + if v, err := Prctl(prGetKeepCaps); err != nil { + return err + } else if v == was { + return fmt.Errorf("PR_KEEP_CAPS unchanged: got=%d, want=%v", v, 1-was) + } + // All good. + return nil + }).Launch(before); err != nil { + t.Fatalf("trivial launcher failed: %v", err) + } + + // Now validate that the main process is still OK. + if after, err := Prctl(prGetKeepCaps); err != nil { + t.Fatalf("failed to get PR_KEEP_CAPS: %v", err) + } else if before != after { + t.Fatalf("FuncLauncher leaked privileged state: got=%v want=%v", after, before) + } + + // Now force the other way + if _, err := Prctlw(prSetKeepCaps, uintptr(1-expect)); err != nil { + t.Fatalf("[%d] attempt to flip PR_KEEP_CAPS failed: %v", i, err) + } + } +} + +func TestFill(t *testing.T) { + c, err := FromText("cap_setfcap=p") + if err != nil { + t.Fatalf("failed to parse: %v", err) + }
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/convenience.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/convenience.go
Changed
@@ -2,6 +2,7 @@ import ( "errors" + "fmt" "syscall" "unsafe" ) @@ -31,21 +32,36 @@ securedAmbientBits = securedBasicBits | SecbitNoCapAmbientRaise | SecbitNoCapAmbientRaiseLocked ) +// defines from uapi/linux/prctl.h +const ( + prGetKeepCaps = 7 + prSetKeepCaps = 8 + prGetSecureBits = 27 + prSetSecureBits = 28 + prSetNoNewPrivs = 38 +) + // GetSecbits returns the current setting of the process' Secbits. func GetSecbits() Secbits { - v, err := prctlrcall(PR_GET_SECUREBITS, 0, 0) + v, err := multisc.prctlrcall(prGetSecureBits, 0, 0) if err != nil { panic(err) } return Secbits(v) } +func (sc *syscaller) setSecbits(s Secbits) error { + _, err := sc.prctlwcall(prSetSecureBits, uintptr(s), 0) + return err +} + // Set attempts to force the process Secbits to a value. This function // will raise cap.SETPCAP in order to achieve this operation, and will -// completely lower the Effective vector of the process returning. +// completely lower the Effective Flag of the process upon returning. func (s Secbits) Set() error { - _, err := prctlwcall(PR_SET_SECUREBITS, uintptr(s), 0) - return err + state, sc := scwStateSC() + defer scwSetState(launchBlocked, state, -1) + return sc.setSecbits(s) } // Mode summarizes a complicated secure-bits and capability mode in a @@ -53,7 +69,7 @@ type Mode uint // ModeUncertain etc are how libcap summarizes security modes -// involving capabilitys and seure-bits. +// involving capabilities and secure-bits. const ( ModeUncertain Mode = iota ModeNoPriv @@ -61,13 +77,6 @@ ModePure1E ) -// defines from uapi/linux/prctl.h -const ( - PR_SET_KEEPCAPS = 8 - PR_GET_SECUREBITS = 27 - PR_SET_SECUREBITS = 28 -) - // GetMode assesses the current process state and summarizes it as // a Mode. This function always succeeds. Unfamiliar modes are // declared ModeUncertain. @@ -92,12 +101,12 @@ w := GetProc() e := NewSet() - cf, _ := w.Compare(e) + cf, _ := w.Cf(e) - if Differs(cf, Inheritable) { + if cf.Has(Inheritable) { return ModePure1E } - if Differs(cf, Permitted) || Differs(cf, Effective) { + if cf.Has(Permitted) || cf.Has(Effective) { return ModePure1EInit } @@ -114,27 +123,21 @@ return ModeNoPriv } +// ErrBadMode is the error returned when an attempt is made to set an +// unrecognized libcap security mode. var ErrBadMode = errors.New("unsupported mode") -// Set attempts to enter the specified mode. An attempt is made to -// enter the mode, so if you prefer this operation to be a no-op if -// entering the same mode, call only if CurrentMode() disagrees with -// the desired mode. -// -// This function will raise cap.SETPCAP in order to achieve this -// operation, and will completely lower the Effective vector of the -// process before returning. -func (m Mode) Set() error { +func (sc *syscaller) setMode(m Mode) error { w := GetProc() defer func() { w.ClearFlag(Effective) - w.SetProc() + sc.setProc(w) }() if err := w.SetFlag(Effective, true, SETPCAP); err != nil { return err } - if err := w.SetProc(); err != nil { + if err := sc.setProc(w); err != nil { return err } @@ -147,11 +150,11 @@ sb := securedAmbientBits if _, err := GetAmbient(0); err != nil { sb = securedBasicBits - } else if err := ResetAmbient(); err != nil { + } else if err := sc.resetAmbient(); err != nil { return err } - if err := sb.Set(); err != nil { + if err := sc.setSecbits(sb); err != nil { return err } @@ -159,13 +162,32 @@ return nil } - for c := Value(0); DropBound(c) == nil; c++ { + for c := Value(0); sc.dropBound(c) == nil; c++ { } w.ClearFlag(Permitted) + // For good measure. + sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0) + return nil } +// Set attempts to enter the specified mode. An attempt is made to +// enter the mode, so if you prefer this operation to be a no-op if +// entering the same mode, call only if CurrentMode() disagrees with +// the desired mode. +// +// This function will raise cap.SETPCAP in order to achieve this +// operation, and will completely lower the Effective Flag of the +// process' Set before returning. This function may fail for lack of +// permission or because (some of) the Secbits are already locked for +// the current process. +func (m Mode) Set() error { + state, sc := scwStateSC() + defer scwSetState(launchBlocked, state, -1) + return sc.setMode(m) +} + // String returns the libcap conventional string for this mode. func (m Mode) String() string { switch m { @@ -182,16 +204,11 @@ } } -// SetUID is a convenience function for robustly setting the UID and -// all other variants of UID (EUID etc) to the specified value without -// dropping the privilege of the current process. This function will -// raise cap.SETUID in order to achieve this operation, and will -// completely lower the Effective vector of the process before returning. -func SetUID(uid int) error { +func (sc *syscaller) setUID(uid int) error { w := GetProc() defer func() { w.ClearFlag(Effective) - w.SetProc() + sc.setProc(w) }() if err := w.SetFlag(Effective, true, SETUID); err != nil { @@ -200,43 +217,54 @@ // these may or may not work depending on whether or not they // are locked. We try them just in case. - prctlwcall(PR_SET_KEEPCAPS, 1, 0) - defer prctlwcall(PR_SET_KEEPCAPS, 0, 0) + sc.prctlwcall(prSetKeepCaps, 1, 0) + defer sc.prctlwcall(prSetKeepCaps, 0, 0) - if err := w.SetProc(); err != nil { + if err := sc.setProc(w); err != nil { return err
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/file.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/file.go
Changed
@@ -17,32 +17,32 @@ // uapi/linux/capability.h defined. const ( - VFS_CAP_REVISION_MASK = uint32(0xff000000) - VFS_CAP_FLAGS_MASK = ^VFS_CAP_REVISION_MASK - VFS_CAP_FLAGS_EFFECTIVE = uint32(1) - - VFS_CAP_REVISION_1 = uint32(0x01000000) - VFS_CAP_REVISION_2 = uint32(0x02000000) - VFS_CAP_REVISION_3 = uint32(0x03000000) + vfsCapRevisionMask = uint32(0xff000000) + vfsCapFlagsMask = ^vfsCapRevisionMask + vfsCapFlagsEffective = uint32(1) + + vfsCapRevision1 = uint32(0x01000000) + vfsCapRevision2 = uint32(0x02000000) + vfsCapRevision3 = uint32(0x03000000) ) // Data types stored in little-endian order. -type vfs_caps_1 struct { +type vfsCaps1 struct { MagicEtc uint32 Data [1]struct { Permitted, Inheritable uint32 } } -type vfs_caps_2 struct { +type vfsCaps2 struct { MagicEtc uint32 Data [2]struct { Permitted, Inheritable uint32 } } -type vfs_caps_3 struct { +type vfsCaps3 struct { MagicEtc uint32 Data [2]struct { Permitted, Inheritable uint32 @@ -50,13 +50,23 @@ RootID uint32 } -// ErrBadSize indicates the the loaded file capability has +// ErrBadSize indicates the loaded file capability has // an invalid number of bytes in it. -var ( - ErrBadSize = errors.New("filecap bad size") - ErrBadMagic = errors.New("unsupported magic") - ErrBadPath = errors.New("file is not a regular executable") -) +var ErrBadSize = errors.New("filecap bad size") + +// ErrBadMagic indicates that the kernel preferred magic number for +// capability Set values is not supported by this package. This +// generally implies you are using an exceptionally old +// "../libcap/cap" package. An upgrade is needed, or failing that see +// https://sites.google.com/site/fullycapable/ for how to file a bug. +var ErrBadMagic = errors.New("unsupported magic") + +// ErrBadPath indicates a failed attempt to set a file capability on +// an irregular (non-executable) file. +var ErrBadPath = errors.New("file is not a regular executable") + +// ErrOutOfRange indicates an erroneous value for MinExtFlagSize. +var ErrOutOfRange = errors.New("flag length invalid for export") // digestFileCap unpacks a file capability and returns it in a *Set // form. @@ -64,9 +74,9 @@ if err != nil { return nil, err } - var raw1 vfs_caps_1 - var raw2 vfs_caps_2 - var raw3 vfs_caps_3 + var raw1 vfsCaps1 + var raw2 vfsCaps2 + var raw3 vfsCaps3 if sz < binary.Size(raw1) || sz > binary.Size(raw3) { return nil, ErrBadSize } @@ -78,36 +88,36 @@ c := NewSet() b.Seek(0, io.SeekStart) - switch magicEtc & VFS_CAP_REVISION_MASK { - case VFS_CAP_REVISION_1: + switch magicEtc & vfsCapRevisionMask { + case vfsCapRevision1: if err = binary.Read(b, binary.LittleEndian, &raw1); err != nil { return nil, err } data := raw1.Data[0] c.flat[0][Permitted] = data.Permitted c.flat[0][Inheritable] = data.Inheritable - if raw1.MagicEtc&VFS_CAP_FLAGS_MASK == VFS_CAP_FLAGS_EFFECTIVE { + if raw1.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective { c.flat[0][Effective] = data.Inheritable | data.Permitted } - case VFS_CAP_REVISION_2: + case vfsCapRevision2: if err = binary.Read(b, binary.LittleEndian, &raw2); err != nil { return nil, err } for i, data := range raw2.Data { c.flat[i][Permitted] = data.Permitted c.flat[i][Inheritable] = data.Inheritable - if raw2.MagicEtc&VFS_CAP_FLAGS_MASK == VFS_CAP_FLAGS_EFFECTIVE { + if raw2.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective { c.flat[i][Effective] = data.Inheritable | data.Permitted } } - case VFS_CAP_REVISION_3: + case vfsCapRevision3: if err = binary.Read(b, binary.LittleEndian, &raw3); err != nil { return nil, err } for i, data := range raw3.Data { c.flat[i][Permitted] = data.Permitted c.flat[i][Inheritable] = data.Inheritable - if raw3.MagicEtc&VFS_CAP_FLAGS_MASK == VFS_CAP_FLAGS_EFFECTIVE { + if raw3.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective { c.flat[i][Effective] = data.Inheritable | data.Permitted } } @@ -118,11 +128,13 @@ return c, nil } +//go:uintptrescapes + // GetFd returns the file capabilities of an open (*os.File).Fd(). func GetFd(file *os.File) (*Set, error) { - var raw3 vfs_caps_3 + var raw3 vfsCaps3 d := make([]byte, binary.Size(raw3)) - sz, _, oErr := callRKernel6(syscall.SYS_FGETXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0) + sz, _, oErr := multisc.r6(syscall.SYS_FGETXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0) var err error if oErr != 0 { err = oErr @@ -130,15 +142,17 @@ return digestFileCap(d, int(sz), err) } +//go:uintptrescapes + // GetFile returns the file capabilities of a named file. func GetFile(path string) (*Set, error) { p, err := syscall.BytePtrFromString(path) if err != nil { return nil, err } - var raw3 vfs_caps_3 + var raw3 vfsCaps3 d := make([]byte, binary.Size(raw3)) - sz, _, oErr := callRKernel6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0) + sz, _, oErr := multisc.r6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0) if oErr != 0 { err = oErr } @@ -150,27 +164,47 @@ if magic < kv3 { return 0, ErrBadMagic } + c.mu.RLock() + defer c.mu.RUnlock() return c.nsRoot, nil } +// SetNSOwner adds an explicit namespace owner UID to the capability +// Set. This is only honored when generating file capabilities, and is +// generally for use by a setup process when installing binaries that +// use file capabilities to become capable inside a namespace to be +// administered by that UID. If capability aware code within that +// namespace writes file capabilities without explicitly setting such +// a UID, the kernel will fix-up the capabilities to be specific to +// that owner. In this way, the kernel prevents filesystem +// capabilities from leaking out of that restricted namespace. +func (c *Set) SetNSOwner(uid int) { + c.mu.Lock() + defer c.mu.Unlock() + c.nsRoot = uid +} + // packFileCap transforms a system capability into a VFS form. Because // of the way Linux stores capabilities in the file extended // attributes, the process is a little lossy with respect to effective // bits. func (c *Set) packFileCap() ([]byte, error) { + c.mu.RLock() + defer c.mu.RUnlock() + var magic uint32 switch words {
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/flags.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/flags.go
Changed
@@ -2,13 +2,13 @@ import "errors" -// GetFlag determines if the requested bit is enabled in the Flag -// vector of the capability Set. +// GetFlag determines if the requested Value is enabled in the +// specified Flag of the capability Set. func (c *Set) GetFlag(vec Flag, val Value) (bool, error) { - if c == nil || len(c.flat) == 0 { + if err := c.good(); err != nil { // Checked this first, because otherwise we are sure // cInit has been called. - return false, ErrBadSet + return false, err } offset, mask, err := bitOf(vec, val) if err != nil { @@ -25,10 +25,10 @@ // bits be checked for validity and permission by the kernel. If the // function returns an error, the Set will not be modified. func (c *Set) SetFlag(vec Flag, enable bool, val ...Value) error { - if c == nil || len(c.flat) == 0 { + if err := c.good(); err != nil { // Checked this first, because otherwise we are sure // cInit has been called. - return ErrBadSet + return err } c.mu.Lock() defer c.mu.Unlock() @@ -62,8 +62,8 @@ // Clear fully clears a capability set. func (c *Set) Clear() error { - if c == nil || len(c.flat) == 0 { - return ErrBadSet + if err := c.good(); err != nil { + return err } // startUp.Do(cInit) is not called here because c cannot be // initialized except via this package and doing that will @@ -75,13 +75,52 @@ return nil } +// FillFlag copies the from flag values of ref into the to flag of +// c. With this function, you can raise all of the permitted values in +// the c Set from those in ref with c.Fill(cap.Permitted, ref, +// cap.Permitted). +func (c *Set) FillFlag(to Flag, ref *Set, from Flag) error { + if err := c.good(); err != nil { + return err + } + if err := ref.good(); err != nil { + return err + } + if to > Inheritable || from > Inheritable { + return ErrBadValue + } + + // Avoid deadlock by using a copy. + if c != ref { + var err error + ref, err = ref.Dup() + if err != nil { + return err + } + } + + c.mu.Lock() + defer c.mu.Unlock() + for i := range c.flat { + c.flat[i][to] = ref.flat[i][from] + } + return nil +} + +// Fill copies the from flag values into the to flag. With this +// function, you can raise all of the permitted values in the +// effective flag with c.Fill(cap.Effective, cap.Permitted). +func (c *Set) Fill(to, from Flag) error { + return c.FillFlag(to, c, from) +} + // ErrBadValue indicates a bad capability value was specified. var ErrBadValue = errors.New("bad capability value") -// bitOf converts from a Value into the offset and mask for a -// specific Value bit in the compressed (kernel ABI) representation of -// a capability vector. If the requested bit is unsupported, an error -// is returned. +// bitOf converts from a Value into the offset and mask for a specific +// Value bit in the compressed (kernel ABI) representation of a +// capabilities. If the requested bit is unsupported, an error is +// returned. func bitOf(vec Flag, val Value) (uint, uint32, error) { if vec > Inheritable || val > Value(words*32) { return 0, 0, ErrBadValue @@ -108,9 +147,12 @@ } // forceFlag sets 'all' capability values (supported by the kernel) of -// a flag vector to enable. +// a specified Flag to enable. func (c *Set) forceFlag(vec Flag, enable bool) error { - if c == nil || len(c.flat) == 0 || vec > Inheritable { + if err := c.good(); err != nil { + return err + } + if vec > Inheritable { return ErrBadSet } m := uint32(0) @@ -125,36 +167,105 @@ return nil } -// ClearFlag clears a specific vector of Values associated with the -// specified Flag. +// ClearFlag clears all the Values associated with the specified Flag. func (c *Set) ClearFlag(vec Flag) error { return c.forceFlag(vec, false) } -// Compare returns 0 if c and d are identical in content. Otherwise, -// this function returns a non-zero value of 3 independent bits: -// (differE ? 1:0) | (differP ? 2:0) | (differI ? 4:0). -func (c *Set) Compare(d *Set) (uint, error) { - if c == nil || len(c.flat) == 0 || d == nil || len(d.flat) == 0 { - return 0, ErrBadSet +// Cf returns 0 if c and d are identical. A non-zero Diff value +// captures a simple macroscopic summary of how they differ. The +// (Diff).Has() function can be used to determine how the two +// capability sets differ. +func (c *Set) Cf(d *Set) (Diff, error) { + if err := c.good(); err != nil { + return 0, err } - var cf uint + if c == d { + return 0, nil + } + d, err := d.Dup() + if err != nil { + return 0, err + } + + c.mu.RLock() + defer c.mu.RUnlock() + + var cf Diff for i := 0; i < words; i++ { if c.flat[i][Effective]^d.flat[i][Effective] != 0 { - cf |= (1 << Effective) + cf |= effectiveDiff } if c.flat[i][Permitted]^d.flat[i][Permitted] != 0 { - cf |= (1 << Permitted) + cf |= permittedDiff } if c.flat[i][Inheritable]^d.flat[i][Inheritable] != 0 { - cf |= (1 << Inheritable) + cf |= inheritableDiff } } return cf, nil } +// Compare returns 0 if c and d are identical in content. +// +// Deprecated: Replace with (*Set).Cf(). +// +// Example, replace this: +// +// diff, err := a.Compare(b) +// if err != nil { +// return err +// } +// if diff == 0 { +// return nil +// } +// if diff & (1 << Effective) { +// log.Print("a and b difference includes Effective values") +// } +// +// with this: +// +// diff, err := a.Cf(b) +// if err != nil { +// return err +// } +// if diff == 0 { +// return nil +// } +// if diff.Has(Effective) { +// log.Print("a and b difference includes Effective values") +// } +func (c *Set) Compare(d *Set) (uint, error) { + u, err := c.Cf(d)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/go.mod
Added
@@ -0,0 +1,5 @@ +module kernel.org/pub/linux/libs/security/libcap/cap + +go 1.11 + +require kernel.org/pub/linux/libs/security/libcap/psx v1.2.61
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/iab.go
Added
@@ -0,0 +1,483 @@ +package cap + +import ( + "fmt" + "io/ioutil" + "strconv" + "strings" + "sync" +) + +// omask returns the offset and mask for a specific capability. +func omask(c Value) (uint, uint32) { + u := uint(c) + return u >> 5, uint32(1) << (u & 31) +} + +// IAB holds a summary of all of the inheritable capability vectors: +// Inh, Amb and Bound. The Bound vector is the logical inverse (two's +// complement) of the process' Bounding set. That is, raising a Value +// in the Bound (think blocked) vector is equivalent to dropping that +// Value from the process' Bounding set. This convention is used to +// support the empty IAB as being mostly harmless. +type IAB struct { + mu sync.RWMutex + a, i, nb []uint32 +} + +// Vector enumerates which of the inheritable IAB capability vectors +// is being manipulated. +type Vector uint + +// Inh, Amb, Bound enumerate the IAB vector components. (Vector) Inh +// is equivalent to (Flag) Inheritable. They are named differently for +// syntax/type checking reasons. +const ( + Inh Vector = iota + Amb + Bound +) + +// IABDiff holds the non-error result of an (*IAB).Cf() +// function call. It can be interpreted with the function +// (IABDiff).Has(). +type IABDiff uint + +// iBits, iBits and bBits track the (semi-)independent parts of an +// IABDiff. +const ( + iBits IABDiff = 1 << Inh + aBits IABDiff = 1 << Amb + bBits IABDiff = 1 << Bound +) + +// Has determines if an IAB comparison differs in a specific vector. +func (d IABDiff) Has(v Vector) bool { + return d&(1<<v) != 0 +} + +// String identifies a Vector value by its conventional I A or B +// string abbreviation. +func (v Vector) String() string { + switch v { + case Inh: + return "I" + case Amb: + return "A" + case Bound: + return "B" + default: + return "<Error>" + } +} + +// NewIAB returns an empty IAB. +func NewIAB() *IAB { + startUp.Do(multisc.cInit) + return &IAB{ + i: make([]uint32, words), + a: make([]uint32, words), + nb: make([]uint32, words), + } +} + +// good confirms the iab looks to be initialized. +func (iab *IAB) good() error { + if iab == nil || len(iab.i) == 0 || len(iab.i) != words || len(iab.a) != words || len(iab.nb) != words { + return ErrBadValue + } + return nil +} + +// Dup returns a duplicate copy of the IAB. +func (iab *IAB) Dup() (*IAB, error) { + if err := iab.good(); err != nil { + return nil, err + } + v := NewIAB() + iab.mu.RLock() + defer iab.mu.RUnlock() + copy(v.i, iab.i) + copy(v.a, iab.a) + copy(v.nb, iab.nb) + return v, nil +} + +// IABInit allocates a new IAB tuple. +// +// Deprecated: Replace with NewIAB. +// +// Example, replace this: +// +// iab := IABInit() +// +// with this: +// +// iab := NewIAB() +func IABInit() *IAB { + return NewIAB() +} + +// IABGetProc summarizes the Inh, Amb and Bound capability vectors of +// the current process. +func IABGetProc() *IAB { + iab := NewIAB() + current := GetProc() + iab.Fill(Inh, current, Inheritable) + for c := MaxBits(); c > 0; { + c-- + offset, mask := omask(c) + if a, _ := GetAmbient(c); a { + iab.a[offset] |= mask + } + if b, err := GetBound(c); err == nil && !b { + iab.nb[offset] |= mask + } + } + return iab +} + +// IABFromText parses a string representing an IAB, as generated +// by IAB.String(), to generate an IAB. +func IABFromText(text string) (*IAB, error) { + iab := NewIAB() + if len(text) == 0 { + return iab, nil + } + for _, f := range strings.Split(text, ",") { + var i, a, nb bool + var j int + for j = 0; j < len(f); j++ { + switch f[j : j+1] { + case "!": + nb = true + case "^": + i = true + a = true + case "%": + i = true + default: + goto done + } + } + done: + c, err := FromName(f[j:]) + if err != nil { + return nil, err + } + offset, mask := omask(c) + if i || !nb { + iab.i[offset] |= mask + } + if a { + iab.a[offset] |= mask + } + if nb { + iab.nb[offset] |= mask + } + } + return iab, nil +} + +// String serializes an IAB to a string format. +func (iab *IAB) String() string { + if err := iab.good(); err != nil { + return "<invalid>" + } + var vs []string + iab.mu.RLock() + defer iab.mu.RUnlock() + for c := Value(0); c < Value(maxValues); c++ { + offset, mask := omask(c) + i := (iab.i[offset] & mask) != 0 + a := (iab.a[offset] & mask) != 0 + nb := (iab.nb[offset] & mask) != 0 + var cs []string + if nb { + cs = append(cs, "!") + } + if a {
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/launch.go
Added
@@ -0,0 +1,408 @@ +package cap + +import ( + "errors" + "os" + "runtime" + "sync" + "syscall" + "unsafe" +) + +// Launcher holds a configuration for executing an optional callback +// function and/or launching a child process with capability state +// different from the parent. +// +// Note, go1.10 is the earliest version of the Go toolchain that can +// support this abstraction. +type Launcher struct { + mu sync.RWMutex + + // Note, path and args must be set, or callbackFn. They cannot + // both be empty. In such cases .Launch() will error out. + path string + args []string + env []string + + callbackFn func(pa *syscall.ProcAttr, data interface{}) error + + // The following are only honored when path is non empty. + changeUIDs bool + uid int + + changeGIDs bool + gid int + groups []int + + changeMode bool + mode Mode + + iab *IAB + + chroot string +} + +// NewLauncher returns a new launcher for the specified program path +// and args with the specified environment. +func NewLauncher(path string, args []string, env []string) *Launcher { + return &Launcher{ + path: path, + args: args, + env: env, + } +} + +// FuncLauncher returns a new launcher whose purpose is to only +// execute fn in a disposable security context. This is a more bare +// bones variant of the more elaborate program launcher returned by +// cap.NewLauncher(). +// +// Note, this launcher will fully ignore any overrides provided by the +// (*Launcher).SetUID() etc. methods. Should your fn() code want to +// run with a different capability state or other privilege, it should +// use the cap.*() functions to set them directly. The cap package +// will ensure that their effects are limited to the runtime of this +// individual function invocation. Warning: executing non-cap.*() +// syscall functions may corrupt the state of the program runtime and +// lead to unpredictable results. +// +// The properties of fn are similar to those supplied via +// (*Launcher).Callback(fn) method. However, this launcher is bare +// bones because, when launching, all privilege management performed +// by the fn() is fully discarded when the fn() completes +// execution. That is, it does not end by exec()ing some program. +func FuncLauncher(fn func(interface{}) error) *Launcher { + return &Launcher{ + callbackFn: func(ignored *syscall.ProcAttr, data interface{}) error { + return fn(data) + }, + } +} + +// Callback changes the callback function for Launch() to call before +// changing privilege. The only thing that is assumed is that the OS +// thread in use to call this callback function at launch time will be +// the one that ultimately calls fork to complete the launch of a path +// specified executable. Any returned error value of said function +// will terminate the launch process. +// +// A nil fn causes there to be no callback function invoked during a +// Launch() sequence - it will remove any pre-existing callback. +// +// If the non-nil fn requires any effective capabilities in order to +// run, they can be raised prior to calling .Launch() or inside the +// callback function itself. +// +// If the specified callback fn should call any "cap" package +// functions that change privilege state, these calls will only affect +// the launch goroutine itself. While the launch is in progress, other +// (non-launch) goroutines will block if they attempt to change +// privilege state. These routines will unblock once there are no +// in-flight launches. +// +// Note, the first argument provided to the callback function is the +// *syscall.ProcAttr value to be used when a process launch is taking +// place. A non-nil structure pointer can be modified by the callback +// to enhance the launch. For example, the .Files field can be +// overridden to affect how the launched process' stdin/out/err are +// handled. +// +// Further, the 2nd argument to the callback function is provided at +// Launch() invocation and can communicate contextual info to and from +// the callback and the main process. +func (attr *Launcher) Callback(fn func(*syscall.ProcAttr, interface{}) error) { + if attr == nil { + return + } + attr.mu.Lock() + defer attr.mu.Unlock() + attr.callbackFn = fn +} + +// SetUID specifies the UID to be used by the launched command. +func (attr *Launcher) SetUID(uid int) { + if attr == nil { + return + } + attr.mu.Lock() + defer attr.mu.Unlock() + attr.changeUIDs = true + attr.uid = uid +} + +// SetGroups specifies the GID and supplementary groups for the +// launched command. +func (attr *Launcher) SetGroups(gid int, groups []int) { + if attr == nil { + return + } + attr.mu.Lock() + defer attr.mu.Unlock() + attr.changeGIDs = true + attr.gid = gid + attr.groups = groups +} + +// SetMode specifies the libcap Mode to be used by the launched command. +func (attr *Launcher) SetMode(mode Mode) { + if attr == nil { + return + } + attr.mu.Lock() + defer attr.mu.Unlock() + attr.changeMode = true + attr.mode = mode +} + +// SetIAB specifies the IAB capability vectors to be inherited by the +// launched command. A nil value means the prevailing vectors of the +// parent will be inherited. Note, a duplicate of the provided IAB +// tuple is actually stored, so concurrent modification of the iab +// value does not affect the launcher. +func (attr *Launcher) SetIAB(iab *IAB) { + if attr == nil { + return + } + attr.mu.Lock() + defer attr.mu.Unlock() + attr.iab, _ = iab.Dup() +} + +// SetChroot specifies the chroot value to be used by the launched +// command. An empty value means no-change from the prevailing value. +func (attr *Launcher) SetChroot(root string) { + if attr == nil { + return + } + attr.mu.Lock() + defer attr.mu.Unlock() + attr.chroot = root +} + +// lResult is used to get the result from the doomed launcher thread. +type lResult struct { + // tid holds the tid of the locked launching thread which dies + // as the launch completes. + tid int + + // pid is the pid of the launched program (path, args). In + // the case of a FuncLaunch() this value is zero on success. + // pid holds -1 in the case of error. + pid int + + // err is nil on success, but otherwise holds the reason the + // launch failed. + err error +} + +// ErrLaunchFailed is returned if a launch was aborted with no more +// specific error.
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/legacy.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/legacy.go
Changed
@@ -4,4 +4,4 @@ import "syscall" -var sys_setgroups_variant = uintptr(syscall.SYS_SETGROUPS32) +var sysSetGroupsVariant = uintptr(syscall.SYS_SETGROUPS32)
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/modern.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/modern.go
Changed
@@ -5,4 +5,4 @@ import "syscall" -var sys_setgroups_variant = uintptr(syscall.SYS_SETGROUPS) +var sysSetGroupsVariant = uintptr(syscall.SYS_SETGROUPS)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/names.go
Added
@@ -0,0 +1,436 @@ +package cap + +/* ** DO NOT EDIT THIS FILE. IT WAS AUTO-GENERATED BY LIBCAP'S GO BUILDER (mknames.go) ** */ + +// NamedCount holds the number of capability values with official +// names known at the time this libcap/cap version, was released. The +// "../libcap/cap" package is fully able to manipulate higher numbered +// capability values by numerical value. However, if you find +// cap.NamedCount < cap.MaxBits(), it is probably time to upgrade this +// package on your system. +// +// FWIW the userspace tool '/sbin/capsh' also contains a runtime check +// for the condition that libcap is behind the running kernel in this +// way. +const NamedCount = 41 + +// CHOWN etc., are the named capability values of the Linux +// kernel. The canonical source for each name is the +// "uapi/linux/capabilities.h" file. Some values may not be available +// (yet) where the kernel is older. The actual number of capabities +// supported by the running kernel can be obtained using the +// cap.MaxBits() function. +const ( + // CHOWN allows a process to arbitrarily change the user and + // group ownership of a file. + CHOWN Value = iota + + // DAC_OVERRIDE allows a process to override of all Discretionary + // Access Control (DAC) access, including ACL execute + // access. That is read, write or execute files that the + // process would otherwise not have access to. This + // excludes DAC access covered by cap.LINUX_IMMUTABLE. + DAC_OVERRIDE + + // DAC_READ_SEARCH allows a process to override all DAC restrictions + // limiting the read and search of files and + // directories. This excludes DAC access covered by + // cap.LINUX_IMMUTABLE. + DAC_READ_SEARCH + + // FOWNER allows a process to perform operations on files, even + // where file owner ID should otherwise need be equal to + // the UID, except where cap.FSETID is applicable. It + // doesn't override MAC and DAC restrictions. + FOWNER + + // FSETID allows a process to set the S_ISUID and S_ISUID bits of + // the file permissions, even when the process' effective + // UID or GID/supplementary GIDs do not match that of the + // file. + FSETID + + // KILL allows a process to send a kill(2) signal to any other + // process - overriding the limitation that there be a + // [E]UID match between source and target process. + KILL + + // SETGID allows a process to freely manipulate its own GIDs: + // - arbitrarily set the GID, EGID, REGID, RESGID values + // - arbitrarily set the supplementary GIDs + // - allows the forging of GID credentials passed over a + // socket + SETGID + + // SETUID allows a process to freely manipulate its own UIDs: + // - arbitrarily set the UID, EUID, REUID and RESUID + // values + // - allows the forging of UID credentials passed over a + // socket + SETUID + + // SETPCAP allows a process to freely manipulate its inheritable + // capabilities. + // + // Linux supports the POSIX.1e Inheritable set, the POXIX.1e (X + // vector) known in Linux as the Bounding vector, as well as + // the Linux extension Ambient vector. + // + // This capability permits dropping bits from the Bounding + // vector (ie. raising B bits in the libcap IAB + // representation). It also permits the process to raise + // Ambient vector bits that are both raised in the Permitted + // and Inheritable sets of the process. This capability cannot + // be used to raise Permitted bits, Effective bits beyond those + // already present in the process' permitted set, or + // Inheritable bits beyond those present in the Bounding + // vector. + // + // [Historical note: prior to the advent of file capabilities + // (2008), this capability was suppressed by default, as its + // unsuppressed behavior was not auditable: it could + // asynchronously grant its own Permitted capabilities to and + // remove capabilities from other processes arbitrarily. The + // former leads to undefined behavior, and the latter is better + // served by the kill system call.] + SETPCAP + + // LINUX_IMMUTABLE allows a process to modify the S_IMMUTABLE and + // S_APPEND file attributes. + LINUX_IMMUTABLE + + // NET_BIND_SERVICE allows a process to bind to privileged ports: + // - TCP/UDP sockets below 1024 + // - ATM VCIs below 32 + NET_BIND_SERVICE + + // NET_BROADCAST allows a process to broadcast to the network and to + // listen to multicast. + NET_BROADCAST + + // NET_ADMIN allows a process to perform network configuration + // operations: + // - interface configuration + // - administration of IP firewall, masquerading and + // accounting + // - setting debug options on sockets + // - modification of routing tables + // - setting arbitrary process, and process group + // ownership on sockets + // - binding to any address for transparent proxying + // (this is also allowed via cap.NET_RAW) + // - setting TOS (Type of service) + // - setting promiscuous mode + // - clearing driver statistics + // - multicasing + // - read/write of device-specific registers + // - activation of ATM control sockets + NET_ADMIN + + // NET_RAW allows a process to use raw networking: + // - RAW sockets + // - PACKET sockets + // - binding to any address for transparent proxying + // (also permitted via cap.NET_ADMIN) + NET_RAW + + // IPC_LOCK allows a process to lock shared memory segments for IPC + // purposes. Also enables mlock and mlockall system + // calls. + IPC_LOCK + + // IPC_OWNER allows a process to override IPC ownership checks. + IPC_OWNER + + // SYS_MODULE allows a process to initiate the loading and unloading + // of kernel modules. This capability can effectively + // modify kernel without limit. + SYS_MODULE + + // SYS_RAWIO allows a process to perform raw IO: + // - permit ioper/iopl access + // - permit sending USB messages to any device via + // /dev/bus/usb + SYS_RAWIO + + // SYS_CHROOT allows a process to perform a chroot syscall to change + // the effective root of the process' file system: + // redirect to directory "/" to some other location. + SYS_CHROOT + + // SYS_PTRACE allows a process to perform a ptrace() of any other + // process. + SYS_PTRACE + + // SYS_PACCT allows a process to configure process accounting. + SYS_PACCT + + // SYS_ADMIN allows a process to perform a somewhat arbitrary + // grab-bag of privileged operations. Over time, this + // capability should weaken as specific capabilities are + // created for subsets of cap.SYS_ADMINs functionality: + // - configuration of the secure attention key + // - administration of the random device + // - examination and configuration of disk quotas + // - setting the domainname + // - setting the hostname + // - calling bdflush() + // - mount() and umount(), setting up new SMB connection + // - some autofs root ioctls + // - nfsservctl + // - VM86_REQUEST_IRQ + // - to read/write pci config on alpha + // - irix_prctl on mips (setstacksize) + // - flushing all cache on m68k (sys_cacheflush) + // - removing semaphores + // - Used instead of cap.CHOWN to "chown" IPC message + // queues, semaphores and shared memory + // - locking/unlocking of shared memory segment + // - turning swap on/off + // - forged pids on socket credentials passing + // - setting readahead and flushing buffers on block + // devices + // - setting geometry in floppy driver + // - turning DMA on/off in xd driver + // - administration of md devices (mostly the above, but + // some extra ioctls) + // - tuning the ide driver + // - access to the nvram device + // - administration of apm_bios, serial and bttv (TV)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/oslockluster.go
Added
@@ -0,0 +1,33 @@ +// +build !go1.10 + +package cap + +import "syscall" + +// LaunchSupported indicates that is safe to return from a locked OS +// Thread and have that OS Thread be terminated by the runtime. The +// Launch functionality really needs to rely on the fact that an +// excess of runtime.LockOSThread() vs. runtime.UnlockOSThread() calls +// in a returning go routine will cause the underlying locked OSThread +// to terminate. That feature was added to the Go runtime in version +// 1.10. +// +// See these bugs for the discussion and feature assumed by the code +// in this Launch() functionality: +// +// https://github.com/golang/go/issues/20395 +// https://github.com/golang/go/issues/20458 +// +// A value of false for this constant causes the Launch functionality +// to fail with an error: cap.ErrNoLaunch. If this value is false you +// have two choices with respect to the Launch functionality: +// +// 1) don't use cap.(*Launcher).Launch() +// 2) upgrade your Go toolchain to 1.10+ (ie., do this one). +const LaunchSupported = false + +// validatePA confirms that the pa.Sys entry is not incompatible with +// Launch. +func validatePA(pa *syscall.ProcAttr, chroot string) (bool, error) { + return false, ErrNoLaunch +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/oslocks.go
Added
@@ -0,0 +1,51 @@ +// +build go1.10 + +package cap + +import "syscall" + +// LaunchSupported indicates that is safe to return from a locked +// OS Thread and have that OS Thread be terminated by the runtime. The +// Launch functionality really needs to rely on the fact that an +// excess of runtime.LockOSThread() vs. runtime.UnlockOSThread() calls +// in a returning go routine will cause the underlying locked OSThread +// to terminate. That feature was added to the Go runtime in version +// 1.10. +// +// See these bugs for the discussion and feature assumed by the code +// in this Launch() functionality: +// +// https://github.com/golang/go/issues/20395 +// https://github.com/golang/go/issues/20458 +// +// A value of false for this constant causes the Launch functionality +// to fail with an error: cap.ErrNoLaunch. If this value is false you +// have two choices with respect to the Launch functionality: +// +// 1) don't use cap.(*Launcher).Launch() +// 2) upgrade your Go toolchain to 1.10+ (ie., do this one). +const LaunchSupported = true + +// validatePA confirms that the pa.Sys entry is not incompatible with +// Launch and loads up the chroot value. +func validatePA(pa *syscall.ProcAttr, chroot string) (bool, error) { + s := pa.Sys + if s == nil { + if chroot == "" { + return false, nil + } + s = &syscall.SysProcAttr{ + Chroot: chroot, + } + pa.Sys = s + } else if s.Chroot != "" { + return false, ErrAmbiguousChroot + } + if s.Credential != nil { + return false, ErrAmbiguousIDs + } + if len(s.AmbientCaps) != 0 { + return false, ErrAmbiguousAmbient + } + return s != nil && s.Chroot != "", nil +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/syscalls.go
Added
@@ -0,0 +1,121 @@ +package cap + +import ( + "runtime" + "sync" + "syscall" + + "kernel.org/pub/linux/libs/security/libcap/psx" +) + +// multisc provides syscalls overridable for testing purposes that +// support a single kernel security state for all OS threads. +// We use this version when we are cgo compiling because +// we need to manage the native C pthreads too. +var multisc = &syscaller{ + w3: psx.Syscall3, + w6: psx.Syscall6, + r3: syscall.RawSyscall, + r6: syscall.RawSyscall6, +} + +// singlesc provides a single threaded implementation. Users should +// take care to ensure the thread is locked and marked nogc. +var singlesc = &syscaller{ + w3: syscall.RawSyscall, + w6: syscall.RawSyscall6, + r3: syscall.RawSyscall, + r6: syscall.RawSyscall6, +} + +// launchState is used to track which variant of the write syscalls +// should execute. +type launchState int + +// these states are used to understand when a launch is in progress. +const ( + launchIdle launchState = iota + launchActive + launchBlocked +) + +// scwMu is used to fully serialize the write system calls. Note, this +// would generally not be necessary, but in the case of Launch we get +// into a situation where the launching thread is temporarily allowed +// to deviate from the kernel state of the rest of the runtime and +// allowing other threads to perform w* syscalls will potentially +// interfere with the launching process. In pure Go binaries, this +// will lead inevitably to a panic when the AllThreadsSyscall +// discovers inconsistent thread state. +// +// scwMu protects scwTIDs and scwState +var scwMu sync.Mutex + +// scwTIDs holds the thread IDs of the threads that are executing a +// launch it is empty when no launches are occurring. +var scwTIDs = make(map[int]bool) + +// scwState captures whether a launch is in progress or not. +var scwState = launchIdle + +// scwCond is used to announce when scwState changes to other +// goroutines waiting for it to change. +var scwCond = sync.NewCond(&scwMu) + +// scwSetState blocks until a launch state change between states from +// and to occurs. We use this for more context specific syscaller +// use. In the case that the caller is requesting a launchActive -> +// launchIdle transition they are declaring that tid is no longer +// launching. If another thread is also launching the call will +// complete, but the launchState will remain launchActive. +func scwSetState(from, to launchState, tid int) { + scwMu.Lock() + for scwState != from { + if scwState == launchActive && from == launchIdle && to == launchActive { + break // This "transition" is also allowed. + } + scwCond.Wait() + } + if from == launchIdle && to == launchActive { + scwTIDs[tid] = true + } else if from == launchActive && to == launchIdle { + delete(scwTIDs, tid) + if len(scwTIDs) != 0 { + to = from // not actually idle + } + } + scwState = to + scwCond.Broadcast() + scwMu.Unlock() +} + +// scwStateSC blocks until the current syscaller is available for +// writes, and then marks launchBlocked. Use scwSetState to perform +// the reverse transition (blocked->returned state value). +func scwStateSC() (launchState, *syscaller) { + sc := multisc + scwMu.Lock() + for { + if scwState == launchIdle { + break + } + runtime.LockOSThread() + if scwState == launchActive && scwTIDs[syscall.Gettid()] { + sc = singlesc + // note, we don't runtime.UnlockOSThread() + // here because we have no reason to ever + // allow this thread to return to normal use - + // we need it dead before we can return to the + // launchIdle state. + break + } + runtime.UnlockOSThread() + scwCond.Wait() + } + old := scwState + scwState = launchBlocked + scwCond.Broadcast() + scwMu.Unlock() + + return old, sc +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/cap/text.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/cap/text.go
Changed
@@ -21,7 +21,7 @@ // FromName converts a named capability Value to its binary // representation. func FromName(name string) (Value, error) { - startUp.Do(cInit) + startUp.Do(multisc.cInit) v, ok := bits[name] if ok { if v >= Value(words*32) { @@ -48,7 +48,8 @@ var combos = []string{"", "e", "p", "ep", "i", "ei", "ip", "eip"} // histo generates a histogram of flag state combinations. -func (c *Set) histo(m uint, bins []int, patterns []uint, from, limit Value) uint { +// Note: c is locked by or private to the caller. +func (c *Set) histo(bins []int, patterns []uint, from, limit Value) uint { for v := from; v < limit; v++ { b := uint(v & 31) u, bit, err := bitOf(0, v) @@ -60,28 +61,42 @@ x |= uint((c.flat[u][Inheritable]&bit)>>b) * iBin bins[x]++ patterns[uint(v)] = x - if bins[m] <= bins[x] { - m = x + } + // Note, in the loop, we use >= to pick the smallest value for + // m with the highest bin value. That is ties break towards + // m=0. + m := uint(7) + for t := m; t > 0; { + t-- + if bins[t] >= bins[m] { + m = t } } return m } -// String converts a full capability Set into it canonical readable -// string representation (which may contain spaces). +// String converts a full capability Set into a single short readable +// string representation (which may contain spaces). See the +// cap.FromText() function for an explanation of its return values. +// +// Note (*cap.Set).String() may evolve to generate more compact +// strings representing the a given Set over time, but it should +// maintain compatibility with the libcap:cap_to_text() function for +// any given release. Further, it will always be an inverse of +// cap.FromText(). func (c *Set) String() string { - if c == nil || len(c.flat) == 0 { + if err := c.good(); err != nil { return "<invalid>" } bins := make([]int, 8) - patterns := make([]uint, 32*words) + patterns := make([]uint, maxValues) c.mu.RLock() defer c.mu.RUnlock() // Note, in order to have a *Set pointer, startUp.Do(cInit) // must have been called which sets maxValues. - m := c.histo(0, bins, patterns, 0, Value(maxValues)) + m := c.histo(bins, patterns, 0, Value(maxValues)) // Background state is the most popular of the named bits. vs := []string{"=" + combos[m]} @@ -97,19 +112,29 @@ } list = append(list, Value(j).String()) } + x := strings.Join(list, ",") + var y, z string if cf := i & ^m; cf != 0 { - vs = append(vs, strings.Join(list, ",")+"+"+combos[cf]) + op := "+" + if len(vs) == 1 && vs[0] == "=" { + // Special case "= foo+..." == "foo=...". + // Prefer because it + vs = nil + op = "=" + } + y = op + combos[cf] } if cf := m & ^i; cf != 0 { - vs = append(vs, strings.Join(list, ",")+"-"+combos[cf]) + z = "-" + combos[cf] } + vs = append(vs, x+y+z) } // The unnamed bits can only add to the above named ones since // unnamed ones are always defaulted to lowered. uBins := make([]int, 8) uPatterns := make([]uint, 32*words) - c.histo(0, uBins, uPatterns, Value(maxValues), 32*Value(words)) + c.histo(uBins, uPatterns, Value(maxValues), 32*Value(words)) for i := uint(7); i > 0; i-- { if uBins[i] == 0 { continue @@ -132,6 +157,43 @@ // FromText converts the canonical text representation for a Set into // a freshly allocated Set. +// +// The format follows the following pattern: a set of space separated +// sequences. Each sequence applies over the previous sequence to +// build up a Set. The format of a sequence is: +// +// [comma list of cap_values][[ops][flags]]* +// +// Examples: +// +// "all=ep" +// "cap_chown,cap_setuid=ip cap_setuid+e" +// "=p cap_setpcap-p+i" +// +// Here "all" refers to all named capabilities known to the hosting +// kernel, and "all" is assumed if no capabilities are listed before +// an "=". +// +// The ops values, "=", "+" and "-" imply "reset and raise", "raise" +// and "lower" respectively. The "e", "i" and "p" characters +// correspond to the capabilities of the corresponding Flag: "e" +// (Effective); "i" (Inheritable); "p" (Permitted). +// +// This syntax is overspecified and there are many ways of building +// the same final Set state. Any sequence that includes a '=' resets +// the accumulated state of all Flags ignoring earlier sequences. On +// each of the following lines we give three or more examples of ways +// to specify a common Set. The last entry on each line is the one +// generated by (*cap.Set).String() from that Set. +// +// "=p all+ei" "all=pie" "=pi all+e" "=eip" +// +// "cap_setuid=p cap_chown=i" "cap_chown=ip-p" "cap_chown=i" +// +// "cap_chown=-p" "all=" "cap_setuid=pie-pie" "=" +// +// Note: FromText() is tested at release time to completely match the +// import ability of the libcap:cap_from_text() function. func FromText(text string) (*Set, error) { c := NewSet() scanner := bufio.NewScanner(strings.NewReader(text)) @@ -139,7 +201,8 @@ chunks := 0 for scanner.Scan() { chunks++ - // Parsing for xxx[-+=][eip]+ + + // Parsing for xxx([-+=][eip]+)+ t := scanner.Text() i := strings.IndexAny(t, "=+-") if i < 0 { @@ -147,7 +210,11 @@ } var vs []Value sep := t[i] - if vals := t[:i]; vals != "all" && vals != "" { + if vals := t[:i]; vals == "all" { + for v := Value(0); v < Value(maxValues); v++ { + vs = append(vs, v) + } + } else if vals != "" { for _, name := range strings.Split(vals, ",") { v, err := FromName(name) if err != nil { @@ -155,43 +222,101 @@ } vs = append(vs, v) } - } else if sep != '=' && vals == "" { - return nil, ErrBadText // Only "=" supports ""=="all". - } - sets := t[i+1:] - var fE, fP, fI bool - for j := 0; j < len(sets); j++ { - switch sets[j] { - case 'e': - fE = true - case 'p': - fP = true - case 'i': - fI = true - default: + } else if sep != '=' { + if vals == "" { + // Only "=" supports ""=="all". return nil, ErrBadText } + } else if j := i + 1; j+1 < len(t) { + switch t[j] { + case '+': + sep = 'P' + i++ + case '-': + sep = 'M' + i++
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/Makefile
Changed
@@ -1,3 +1,3 @@ .PHONY: all clean all clean: - for x in bug* ; do make -C $$x $@ || exit 1 ; done + for x in bug* ; do $(MAKE) -C $$x $@ || exit 1 ; done
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/bug400591/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/bug400591/Makefile
Changed
@@ -1,8 +1,8 @@ all: bug bug: bug.c ../../libcap Makefile - make -C ../../libcap - cc -g -I../../libcap/include --static -o $@ $< -L../../libcap -lcap + $(MAKE) -C ../../libcap + $(CC) $(CFLAGS) $(CPPFLAGS) -g -I../../libcap/include --static -o $@ $< -L../../libcap -lcap ./bug clean:
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/capso
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/capso/Makefile
Added
@@ -0,0 +1,23 @@ +topdir=$(shell pwd)/../.. +include ../../Make.Rules + +# Always build sources this way: +CFLAGS += -fPIC $(CAPSO_DEBUG) + +all: bind + +bind: bind.c capso.so + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ bind.c capso.so -L../../libcap -lcap + +../../libcap/loader.txt: + $(MAKE) -C ../../libcap loader.txt + +capso.o: capso.c capso.h ../../libcap/execable.h ../../libcap/loader.txt + $(CC) $(CFLAGS) $(CPPFLAGS) -DLIBCAP_VERSION=\"libcap-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat ../../libcap/loader.txt)\" -c capso.c -o $@ + +capso.so: capso.o + $(LD) $(LDFLAGS) -o $@ $< $(LIBCAPLIB) -ldl -Wl,-e,__so_start + sudo setcap cap_net_bind_service=p $@ + +clean: + rm -f bind capso.o capso.so *~
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/capso/README.md
Added
@@ -0,0 +1,20 @@ +# Leveraging file capabilities on shared libraries + +This directory contains an example of a shared library (capso.so) that +can be installed with file capabilities. When the library is linked +against an unprivileged program, it includes internal support for +re-invoking itself as a child subprocess to execute a privileged +operation on bahalf of the parent. + +The idea for doing this was evolved from the way pam_unix.so is able +to leverage a separate program, and libcap's recently added support +for supporting binary execution of all the .so files built by the +package. + +The actual program example 'bind' leverages the +"cap_net_bind_service=p" ./capso.so file to bind to the privileged +port 80. + +A writeup of how to explore this example is provided here: + +https://sites.google.com/site/fullycapable/capable-shared-objects
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/capso/bind.c
Added
@@ -0,0 +1,29 @@ +/* + * Unprivileged program that binds to port 80. It does this by + * leveraging a file capable shared library. + */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "capso.h" + +int main(int argc, char **argv) { + int f = bind80("127.0.0.1"); + if (f < 0) { + perror("unable to bind to port 80"); + exit(1); + } + if (listen(f, 10) == -1) { + perror("unable to listen to port 80"); + exit(1); + } + printf("Webserver code to use filedes = %d goes here.\n" + "(Sleeping for 60s... Try 'netstat -tlnp|grep :80')\n", f); + fflush(stdout); + sleep(60); + close(f); + printf("Done.\n"); +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/capso/capso.c
Added
@@ -0,0 +1,299 @@ +/* + * Worked example for a shared object with a file capability on it + * leveraging itself for preprogrammed functionality. + * + * This example implements a shared library that can bind to + * the privileged port. ":80". + * + * The shared library needs to be installed with + * cap_net_bind_service=p. As a shared library, it provides the + * function bind80(). + */ + +#define _GNU_SOURCE + +#include <dlfcn.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/capability.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "capso.h" + +/* + * where_am_i determines the full path for the shared libary that + * contains this function. It allocates the path in strdup()d memory + * that should be free()d by the caller. If it can't find itself, it + * returns NULL. + */ +static char *where_am_i(void) +{ + Dl_info info; + if (dladdr(where_am_i, &info) == 0) { + return NULL; + } + return strdup(info.dli_fname); +} + +/* + * try_bind80 attempts to reuseably bind to port 80 with the given + * hostname. It returns a bound filedescriptor or -1 on error. + */ +static int try_bind80(const char *hostname) +{ + struct addrinfo *conf, *detail = NULL; + int err, ret = -1, one = 1; + + conf = calloc(1, sizeof(*conf)); + if (conf == NULL) { + return -1; + } + + conf->ai_family = PF_UNSPEC; + conf->ai_socktype = SOCK_STREAM; + conf->ai_protocol = 0; + conf->ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + + err = getaddrinfo(hostname, "80", conf, &detail); + if (err != 0) { + goto done; + } + + ret = socket(detail->ai_family, detail->ai_socktype, detail->ai_protocol); + if (ret == -1) { + goto done; + } + + if (setsockopt(ret, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + close(ret); + ret = -1; + goto done; + } + + if (bind(ret, detail->ai_addr, detail->ai_addrlen)) { + close(ret); + ret = -1; + goto done; + } + + done: + if (detail != NULL) { + freeaddrinfo(detail); + } + free(conf); + + return ret; +} + +/* + * set_fd3 forces file descriptor 3 to be associated with a unix + * socket that can be used to send a file descriptor back to the + * parent program. + */ +static int set_fd3(void *detail) +{ + int *sp = detail; + + close(sp[0]); + if (dup2(sp[1], 3) != 3) { + return -1; + } + close(sp[1]); + + return 0; +} + +/* + * bind80 returns a socket filedescriptor that is bound to port 80 of + * the provided service address. + * + * Example: + * + * int fd = bind80("localhost"); + * + * fd < 0 in the case of error. + */ +int bind80(const char *hostname) +{ + cap_launch_t helper; + pid_t child; + char const *args[3]; + char *path; + int fd, ignored; + int sp[2]; + char junk[1]; + const int rec_buf_len = CMSG_SPACE(sizeof(int)); + char *rec_buf[CMSG_SPACE(sizeof(int))]; + struct iovec *iov; + struct msghdr *msg; + + fd = try_bind80(hostname); + if (fd >= 0) { + return fd; + } + +#ifdef CAPSO_DEBUG + printf("application bind80(%s) attempt failed\n", hostname); + sleep(30); +#endif + + iov = calloc(1, sizeof(struct iovec)); + if (iov == NULL) { + return -1; + } + msg = calloc(1, sizeof(struct msghdr)); + if (msg == NULL) { + free(iov); + return -1; + } + + /* + * Initial attempt didn't work, so try launching the shared + * library as an executable and getting it to yield a bound + * filedescriptor for us via a unix socket pair. + */ + path = where_am_i(); + if (path == NULL) { + perror("unable to find self"); + goto drop_alloc; + } + + args[0] = "bind80-helper"; + args[1] = hostname; + args[2] = NULL; + + helper = cap_new_launcher(path, args, NULL); + if (helper == NULL) { + goto drop_path; + } + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp)) { + goto drop_helper; + } + + cap_launcher_callback(helper, set_fd3); + child = cap_launch(helper, sp); + close(sp[1]); + + if (child <= 0) { + goto drop_sp; + } + + iov[0].iov_base = junk; + iov[0].iov_len = 1; + + msg->msg_name = NULL; + msg->msg_namelen = 0; + msg->msg_iov = iov; + msg->msg_iovlen = 1; + msg->msg_control = rec_buf; + msg->msg_controllen = rec_buf_len; + + if (recvmsg(sp[0], msg, 0) != -1) { + fd = * (int *) CMSG_DATA(CMSG_FIRSTHDR(msg));
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/capso/capso.h
Added
@@ -0,0 +1,16 @@ +#ifndef CAPSO_H +#define CAPSO_H + +/* + * bind80 returns a socket filedescriptor that is bound to port 80 of + * the provided service address. + * + * Example: + * + * int fd = bind80("localhost"); + * + * fd < 0 in the case of error. + */ +extern int bind80(const char *hostname); + +#endif /* ndef CAPSO_H */
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/pcaps4convenience -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/pcaps4convenience
Changed
@@ -63,22 +63,22 @@ # are we sane? WICH=`which which 2>/dev/null` if [ $WICH == "" ]; then - # thats bad + # that's bad echo "Sorry, I haven't found which" exit fi - # we needt his apps + # we need this app SETCAP=`which setcap 2>/dev/null` if [ "$SETCAP" == "" ]; then - echo "Sorry, I'm missing setcap !" + echo "Sorry, I'm missing setcap!" exit fi - # checking setcap for SET_SETFCAP PCap ? + # checking setcap for SET_SETFCAP PCap? # for now we stick to root if [ "$( id -u )" != "0" ]; then - echo "Sorry, you must be root !" + echo "Sorry, you must be root!" exit 1 fi } @@ -113,7 +113,7 @@ p4c_app_revert(){ - # revert a singel app + # revert a single app # $1 is app name APP=`which -a $1 2>/dev/null` if [ "$APP" != "" ]; then @@ -136,7 +136,7 @@ p4c_convert(){ - # we go throug the APPSARRAY and call s2p_app_convert to do the job + # we go through the APPSARRAY and call s2p_app_convert to do the job COUNTER=0 let UPPER=${#APPSARRAY[*]}-1 until [ $COUNTER == $UPPER ]; do @@ -170,9 +170,9 @@ echo "through the PAM module pam_cap.so." echo "A user who has not the needed PCaps in his Inheritance Set CAN NOT execute" echo "these binaries successful." - echo "(well, still per sudo or su -c - but thats not the point here)" + echo "(well, still per sudo or su -c - but that's not the point here)" echo - echo "You need and I will check fot the utilities which and setcap." + echo "You need and I will check for the utilities which and setcap." echo echo "Your Filesystem has to support extended attributes and your kernel must have" echo "support for POSIX File Capabilities (CONFIG_SECURITY_FILE_CAPABILITIES)."
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/pcaps4server -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/pcaps4server
Changed
@@ -8,7 +8,7 @@ # changelog: # 1 - initial release pcaps4convenience # 1 - 2007.02.15 - initial release -# 2 - 2007.11.02 - changed to new setfcaps api; each app is now callable; supressed error of id +# 2 - 2007.11.02 - changed to new setfcaps api; each app is now callable; suppressed error of id # 3 - 2007.12.28 - changed to libcap2 package setcap/getcap # 4 - renamed to pcaps4server # removed suid0 and convenience files,
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/contrib/pcaps4suid0 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/pcaps4suid0
Changed
@@ -77,23 +77,23 @@ # are we sane? WICH=`which which 2>/dev/null` if [ $WICH == "" ]; then - # thats bad + # that's bad echo "Sorry, I haven't found which" exit fi - # we needt his apps + # we need these apps CHMOD=`which chmod 2>/dev/null` SETCAP=`which setcap 2>/dev/null` if [ "$CHMOD" == "" -o "$SETCAP" == "" ]; then - echo "Sorry, I'm missing chmod or setcap !" + echo "Sorry, I'm missing chmod or setcap!" exit fi - # checking setcap for SET_SETFCAP PCap ? + # checking setcap for SET_SETFCAP PCap? # for now we stick to root if [ "$( id -u )" != "0" ]; then - echo "Sorry, you must be root !" + echo "Sorry, you must be root!" exit 1 fi } @@ -129,7 +129,7 @@ p4s_app_revert(){ - # revert a singel app + # revert a single app # $1 is app name APP=`which -a $1 2>/dev/null` if [ "$APP" != "" ]; then @@ -153,7 +153,7 @@ p4s_convert(){ - # we go throug the APPSARRAY and call s2p_app_convert to do the job + # we go through the APPSARRAY and call s2p_app_convert to do the job COUNTER=0 let UPPER=${#APPSARRAY[*]}-1 until [ $COUNTER == $UPPER ]; do @@ -190,7 +190,7 @@ echo "If you are using pam_cap.so, you might want to change the set into the" echo "Inherited and Effective set (check for the SET var)." echo - echo "You need and I will check fot the utilities which, chmod and setcap." + echo "You need and I will check for the utilities which, chmod and setcap." echo echo "Your Filesystem has to support extended attributes and your kernel must have" echo "support for POSIX File Capabilities (CONFIG_SECURITY_FILE_CAPABILITIES)."
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/seccomp
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/seccomp/explore.go
Added
@@ -0,0 +1,277 @@ +// Program explore is evolved from the code discussed in more depth +// here: +// +// https://github.com/golang/go/issues/3405 +// +// The code here demonstrates that while PR_SET_NO_NEW_PRIVS only +// applies to the calling thread, since +// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=103502a35cfce0710909da874f092cb44823ca03 +// the seccomp filter application forces the setting to be mirrored on +// all the threads of a process. +// +// Based on the command line options, we can manipulate the program to +// behave in various ways. Example command lines: +// +// sudo ./explore +// sudo ./explore --kill=false +// sudo ./explore --kill=false --errno=0 +// +// Supported Go toolchains are after go1.10. Those prior to go1.15 +// require this environment variable to be set to build successfully: +// +// export CGO_LDFLAGS_ALLOW="-Wl,-?-wrap[=,][^-.@][^,]*" +// +// Go toolchains go1.16+ can be compiled CGO_ENABLED=0 too, +// demonstrating native nocgo support for seccomp features. +package main + +import ( + "flag" + "fmt" + "log" + "runtime" + "syscall" + "time" + "unsafe" + + "kernel.org/pub/linux/libs/security/libcap/psx" +) + +var ( + withPSX = flag.Bool("psx", false, "use the psx mechanism to invoke prctl syscall") + delays = flag.Bool("delays", false, "use this to pause the program at various places") + kill = flag.Bool("kill", true, "kill the process if setuid attempted") + errno = flag.Int("errno", int(syscall.ENOTSUP), "if kill is false, block syscall and return this errno") +) + +const ( + prSetNoNewPrivs = 38 + + sysSeccomp = 317 // x86_64 syscall number + seccompSetModeFilter = 1 // uses user-supplied filter. + seccompFilterFlagTsync = (1 << 0) // mirror filtering on all threads. + seccompRetErrno = 0x00050000 // returns an errno + seccompRetData = 0x0000ffff // mask for RET data payload (ex. errno) + seccompRetKillProcess = 0x80000000 // kill the whole process immediately + seccompRetTrap = 0x00030000 // disallow and force a SIGSYS + seccompRetAllow = 0x7fff0000 + + bpfLd = 0x00 + bpfJmp = 0x05 + bpfRet = 0x06 + + bpfW = 0x00 + + bpfAbs = 0x20 + bpfJeq = 0x10 + + bpfK = 0x00 + + auditArchX86_64 = 3221225534 // HACK: I don't understand this value + archNr = auditArchX86_64 + + syscallNr = 0 +) + +// SockFilter is a single filter block. +type SockFilter struct { + // Code is the filter code instruction. + Code uint16 + // Jt is the target for a true result from the code execution. + Jt uint8 + // Jf is the target for a false result from the code execution. + Jf uint8 + // K is a generic multiuse field + K uint32 +} + +// SockFProg is a +type SockFProg struct { + // Len is the number of contiguous SockFilter blocks that can + // be found at *Filter. + Len uint16 + // Filter is the address of the first SockFilter block of a + // program sequence. + Filter *SockFilter +} + +// SockFilterSlice is a subprogram filter. +type SockFilterSlice []SockFilter + +func bpfStmt(code uint16, k uint32) SockFilter { + return SockFilter{code, 0, 0, k} +} + +func bpfJump(code uint16, k uint32, jt uint8, jf uint8) SockFilter { + return SockFilter{code, jt, jf, k} +} + +func validateArchitecture() []SockFilter { + return []SockFilter{ + bpfStmt(bpfLd+bpfW+bpfAbs, 4), // HACK: I don't understand this 4. + bpfJump(bpfJmp+bpfJeq+bpfK, archNr, 1, 0), + bpfStmt(bpfRet+bpfK, seccompRetKillProcess), + } +} + +func examineSyscall() []SockFilter { + return []SockFilter{ + bpfStmt(bpfLd+bpfW+bpfAbs, syscallNr), + } +} + +func allowSyscall(syscallNum uint32) []SockFilter { + return []SockFilter{ + bpfJump(bpfJmp+bpfJeq+bpfK, syscallNum, 0, 1), + bpfStmt(bpfRet+bpfK, seccompRetAllow), + } +} + +func disallowSyscall(syscallNum, errno uint32) []SockFilter { + return []SockFilter{ + bpfJump(bpfJmp+bpfJeq+bpfK, syscallNum, 0, 1), + bpfStmt(bpfRet+bpfK, seccompRetErrno|(errno&seccompRetData)), + } +} + +func killProcess() []SockFilter { + return []SockFilter{ + bpfStmt(bpfRet+bpfK, seccompRetKillProcess), + } +} + +func notifyProcessAndDie() []SockFilter { + return []SockFilter{ + bpfStmt(bpfRet+bpfK, seccompRetTrap), + } +} + +func trapOnSyscall(syscallNum uint32) []SockFilter { + return []SockFilter{ + bpfJump(bpfJmp+bpfJeq+bpfK, syscallNum, 0, 1), + bpfStmt(bpfRet+bpfK, seccompRetTrap), + } +} + +func allGood() []SockFilter { + return []SockFilter{ + bpfStmt(bpfRet+bpfK, seccompRetAllow), + } +} + +// prctl executes the prctl - unless the --psx commandline argument is +// used, this is on a single thread. +//go:uintptrescapes +func prctl(option, arg1, arg2, arg3, arg4, arg5 uintptr) error { + var e syscall.Errno + if *withPSX { + _, _, e = psx.Syscall6(syscall.SYS_PRCTL, option, arg1, arg2, arg3, arg4, arg5) + } else { + _, _, e = syscall.RawSyscall6(syscall.SYS_PRCTL, option, arg1, arg2, arg3, arg4, arg5) + } + if e != 0 { + return e + } + if *delays { + fmt.Println("prctl'd - check now") + time.Sleep(1 * time.Minute) + } + return nil +} + +// SeccompSetModeFilter is our wrapper for performing our seccomp system call. +//go:uintptrescapes +func SeccompSetModeFilter(prog *SockFProg) error { + if _, _, e := syscall.RawSyscall(sysSeccomp, seccompSetModeFilter, seccompFilterFlagTsync, uintptr(unsafe.Pointer(prog))); e != 0 { + return e + } + return nil +} + +var empty func() + +func lockProcessThread(pick bool) { + // Make sure we are + pid := uintptr(syscall.Getpid()) + runtime.LockOSThread() + for { + tid, _, _ := syscall.RawSyscall(syscall.SYS_GETTID, 0, 0, 0) + if (tid == pid) == pick {
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/seccomp/go.mod
Added
@@ -0,0 +1,5 @@ +module explore + +go 1.14 + +require kernel.org/pub/linux/libs/security/libcap/psx v1.2.61
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/sucap
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/sucap/Makefile
Added
@@ -0,0 +1,12 @@ +topdir=$(shell pwd)/../.. +include ../../Make.Rules + +all: su + +su: su.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DPAM_APP_NAME=\"sucap\" -o $@ $< -lpam -lpam_misc -lcap + # to permit all ambient capabilities, this needs all permitted. + sudo setcap =p ./su + +clean: + rm -f su su.o *~
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/sucap/README.md
Added
@@ -0,0 +1,41 @@ +This directory contains a port of the SimplePAMApp su to more +aggressively use libcap. + +The Makefile builds a binary called `su` that registers with PAM as +the application `sucap`. We've provided a sample `/etc/pam.d/sucap` +file in this directory named `sucap.pamconfig`. + +The point of developing this is to better test the full libcap +implementation, and to also provide a non-setuid-root worked example +for testing PAM interaction with libcap and pam_cap.so. The +expectations for `pam_unix.so` are that it includes this commit: + +https://github.com/linux-pam/linux-pam/pull/373/commits/bf9b1d8ad909634000a7356af2d865a79d3f86f3 + +The original sources were found here: + +https://kernel.org/pub/linux/libs/pam/pre/applications/SimplePAMApps-0.60.tar.gz + +The SimplePAMApps contain the same License as libcap (they were +originally started by the same authors!). The credited Authors in the +above tarball were: + +- Andrew [G.] Morgan +- Andrey V. Savochkin +- Alexei V. Galatenko + +The code in this present directory is freely adapted from the above +tar ball and is thus a derived work from that. + +**NOTE** As of the time of writing, this adaptation is likely rife + with bugs. + +Finally, Andrew would like to apologize to Andrey for removing all of +the config support he worked to add all those decades ago..! I just +wanted to make a quick tester for a potential workaround for this +pam_cap issue: + +- https://bugzilla.kernel.org/show_bug.cgi?id=212945 + +Andrew G. Morgan <morgan@kernel.org> +2021-06-30
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/sucap/su.c
Added
@@ -0,0 +1,1617 @@ +/* + * Originally based on an implementation of `su' by + * + * Peter Orbaek <poe@daimi.aau.dk> + * + * obtained circa 1997 from ftp://ftp.daimi.aau.dk/pub/linux/poe/ + * + * Rewritten for Linux-PAM by Andrew G. Morgan <morgan@linux.kernel.org> + * Modified by Andrey V. Savochkin <saw@msu.ru> + * Modified for use with libcap by Andrew G. Morgan <morgan@kernel.org> + */ + +/* #define PAM_DEBUG */ + +#include <sys/prctl.h> + +/* non-root user of convenience to block signals */ +#define TEMP_UID 1 + +#ifndef PAM_APP_NAME +#define PAM_APP_NAME "su" +#endif /* ndef PAM_APP_NAME */ + +#define DEFAULT_HOME "/" +#define DEFAULT_SHELL "/bin/bash" +#define SLEEP_TO_KILL_CHILDREN 3 /* seconds to wait after SIGTERM before + SIGKILL */ +#define SU_FAIL_DELAY 2000000 /* usec on authentication failure */ + +#define RHOST_UNKNOWN_NAME "" /* perhaps "[from.where?]" */ +#define DEVICE_FILE_PREFIX "/dev/" +#define WTMP_LOCK_TIMEOUT 3 /* in seconds */ + +#ifndef UT_IDSIZE +#define UT_IDSIZE 4 /* XXX - this is sizeof(struct utmp.ut_id) */ +#endif + +#include <stdlib.h> +#include <signal.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <string.h> +#include <syslog.h> +#include <errno.h> +#include <fcntl.h> +#include <termios.h> +#include <sys/wait.h> +#include <utmp.h> +#include <ctype.h> +#include <stdarg.h> +#include <netdb.h> +#include <unistd.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> +#include <sys/capability.h> + +#include <security/_pam_macros.h> + +/* -------------------------------------------- */ +/* ------ declarations ------------------------ */ +/* -------------------------------------------- */ + +extern char **environ; +static pam_handle_t *pamh = NULL; + +static int wait_for_child_caught=0; +static int need_job_control=0; +static int is_terminal = 0; +static struct termios stored_mode; /* initial terminal mode settings */ +static uid_t terminal_uid = (uid_t) -1; +static uid_t invoked_uid = (uid_t) -1; + +/* -------------------------------------------- */ +/* ------ some local (static) functions ------- */ +/* -------------------------------------------- */ + +/* + * We will attempt to transcribe the following env variables + * independent of whether we keep the whole environment. Others will + * be set elsewhere: either in modules; or after the identity of the + * user is known. + */ + +static const char *posix_env[] = { + "LANG", + "LC_COLLATE", + "LC_CTYPE", + "LC_MONETARY", + "LC_NUMERIC", + "TZ", + NULL +}; + +/* + * make_environment transcribes a selection of environment variables + * from the invoking user. + */ +static int make_environment(int keep_env) +{ + const char *tmpe; + int i; + int retval; + + if (keep_env) { + /* preserve the original environment */ + return pam_misc_paste_env(pamh, (const char * const *)environ); + } + + /* we always transcribe some variables anyway */ + tmpe = getenv("TERM"); + if (tmpe == NULL) { + tmpe = "dumb"; + } + retval = pam_misc_setenv(pamh, "TERM", tmpe, 0); + if (retval == PAM_SUCCESS) { + retval = pam_misc_setenv(pamh, "PATH", "/bin:/usr/bin", 0); + } + if (retval != PAM_SUCCESS) { + tmpe = NULL; + D(("error setting environment variables")); + return retval; + } + + /* also propagate the POSIX specific ones */ + for (i=0; retval == PAM_SUCCESS && posix_env[i]; ++i) { + tmpe = getenv(posix_env[i]); + if (tmpe != NULL) { + retval = pam_misc_setenv(pamh, posix_env[i], tmpe, 0); + } + } + tmpe = NULL; + + return retval; +} + +/* + * checkfds ensures that stdout and stderr filedescriptors are + * defined. If all else fails, it directs them to /dev/null. + */ +static void checkfds(void) +{ + struct stat st; + int fd; + + if (fstat(1, &st) == -1) { + fd = open("/dev/null", O_WRONLY); + if (fd == -1) exit(1); + if (fd != 1) { + if (dup2(fd, 1) == -1) exit(1); + if (close(fd) == -1) exit(1); + } + } + if (fstat(2, &st) == -1) { + fd = open("/dev/null", O_WRONLY); + if (fd == -1) exit(1); + if (fd != 2) { + if (dup2(fd, 2) == -1) exit(1); + if (close(fd) == -1) exit(1); + } + } +} + +/* + * store_terminal_modes captures the current state of the input + * terminal. Calling this at the start of the program, we ensure we + * can restore these default settings when su exits. + */ +static void store_terminal_modes(void) +{ + if (isatty(STDIN_FILENO)) { + is_terminal = 1; + if (tcgetattr(STDIN_FILENO, &stored_mode) != 0) { + fprintf(stderr, PAM_APP_NAME ": couldn't copy terminal mode"); + exit(1); + } + return; + } + fprintf(stderr, PAM_APP_NAME ": must be run from a terminal\n"); + exit(1); +} + +/* + * restore_terminal_modes resets the terminal to the state it was in + * when the program started. + * + * Returns: + * 0 ok + * 1 error + */ +static int restore_terminal_modes(void) +{ + if (is_terminal && tcsetattr(STDIN_FILENO, TCSAFLUSH, &stored_mode) != 0) { + fprintf(stderr, PAM_APP_NAME ": cannot restore terminal mode: %s\n", + strerror(errno));
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/contrib/sucap/sucap.pamconfig
Added
@@ -0,0 +1,6 @@ +#%PAM-1.0 +auth required pam_cap.so config=/etc/security/capability.conf +auth required pam_unix.so +account required pam_unix.so +password required pam_unix.so +session required pam_unix.so
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/distcheck.sh
Added
@@ -0,0 +1,13 @@ +#!/bin/bash + +actual=$(wget -o/dev/null -O/dev/stdout https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/linux/capability.h | grep "#define.CAP_LAST_CAP"|awk '{print $3}') +working=$(grep "#define.CAP_LAST_CAP" libcap/include/uapi/linux/capability.h|awk '{print $3}') + +if [[ ${actual} = ${working} ]]; then + echo "up to date with officially named caps" + exit 0 +fi + +echo "want: ${actual}" +echo "have: ${working}" +exit 1
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/Makefile
Changed
@@ -8,22 +8,37 @@ MAN1S = capsh.1 MAN3S = cap_init.3 cap_free.3 cap_dup.3 \ cap_clear.3 cap_clear_flag.3 cap_get_flag.3 cap_set_flag.3 \ + cap_fill.3 cap_fill_flag.3 \ cap_compare.3 cap_get_proc.3 cap_get_pid.3 cap_set_proc.3 \ cap_get_file.3 cap_get_fd.3 cap_set_file.3 cap_set_fd.3 \ - cap_copy_ext.3 cap_size.3 cap_copy_int.3 \ + cap_copy_ext.3 cap_size.3 cap_copy_int.3 cap_mode.3 \ cap_from_text.3 cap_to_text.3 cap_from_name.3 cap_to_name.3 \ capsetp.3 capgetp.3 libcap.3 \ cap_get_bound.3 cap_drop_bound.3 \ cap_get_mode.3 cap_set_mode.3 cap_mode_name.3 \ cap_get_secbits.3 cap_set_secbits.3 \ cap_setuid.3 cap_setgroups.3 \ - psx_register.3 psx_syscall.3 psx_syscall3.3 psx_syscall6.3 libpsx.3 -MAN8S = getcap.8 setcap.8 getpcaps.8 + cap_launch.3 cap_func_launcher.3 cap_launcher_callback.3 \ + cap_launcher_set_chroot.3 cap_launcher_set_mode.3 \ + cap_launcher_setgroups.3 cap_launcher_setuid.3 \ + cap_launcher_set_iab.3 cap_new_launcher.3 \ + cap_iab.3 cap_iab_init.3 cap_iab_dup.3 cap_iab_compare.3 \ + cap_iab_get_proc.3 cap_iab_get_pid.3 cap_iab_set_proc.3 \ + cap_iab_to_text.3 cap_iab_from_text.3 cap_iab_get_vector.3 \ + cap_iab_set_vector.3 cap_iab_fill.3 \ + psx_syscall.3 psx_syscall3.3 psx_syscall6.3 libpsx.3 +MAN8S = getcap.8 setcap.8 getpcaps.8 captree.8 MANS = $(MAN1S) $(MAN3S) $(MAN8S) all: $(MANS) +test: + @echo no doc tests available + +sudotest: + @echo no doc sudotests available + .PHONY: html html: mkdir -p html
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/cap_clear.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_clear.3
Changed
@@ -1,30 +1,29 @@ -.TH CAP_CLEAR 3 "2008-05-11" "" "Linux Programmer's Manual" +.TH CAP_CLEAR 3 "2021-10-01" "" "Linux Programmer's Manual" .SH NAME -cap_clear, cap_clear_flag, cap_get_flag, cap_set_flag, cap_compare \- capability data object manipulation +cap_clear, cap_clear_flag, cap_get_flag, cap_set_flag, cap_fill_flag, cap_fill, cap_compare \- capability data object manipulation .SH SYNOPSIS .nf -.B #include <sys/capability.h> -.sp -.BI "int cap_clear(cap_t " cap_p ); -.sp -.BI "int cap_clear_flag(cap_t " cap_p ", cap_flag_t " flag ");" -.sp -.BI "int cap_get_flag(cap_t " cap_p ", cap_value_t " cap , -.BI " cap_flag_t " flag ", cap_flag_value_t *" value_p ");" -.sp -.BI "int cap_set_flag(cap_t " cap_p ", cap_flag_t " flag ", int " ncap , -.BI " const cap_value_t *" caps \ -", cap_flag_value_t " value ");" -.sp -.BI "int cap_compare(cap_t " cap_a ", cap_t " cap_b ");" -.sp -Link with \fI-lcap\fP. +#include <sys/capability.h> + +int cap_clear(cap_t cap_p); +int cap_clear_flag(cap_t cap_p, cap_flag_t flag); +int cap_get_flag(cap_t cap_p, cap_value_t cap, + cap_flag_t flag, cap_flag_value_t *value_p); +int cap_set_flag(cap_t cap_p, cap_flag_t flag, int ncap, + const cap_value_t *caps, cap_flag_value_t value); +int cap_fill_flag(cap_t cap_p, cap_flag_t to, + const cap_t ref, cap_flag_t from); +int cap_fill(cap_t cap_p, cap_flag_t to, cap_flag_t from); +int cap_compare(cap_t cap_a, cap_t cap_b); +cap_value_t cap_max_bits(); .fi +.sp +Link with \fI\-lcap\fP. .SH DESCRIPTION These functions work on a capability state held in working storage. A .I cap_t -holds information about the capabilities in each of the three sets, +holds information about the capabilities in each of the three flags, Permitted, Inheritable, and Effective. Each capability in a set may be clear (disabled, 0) or set (enabled, 1). .PP @@ -36,7 +35,7 @@ .TP .I cap_flag_t identifies one of the three flags associated with a capability -(i.e., it identifies one of the three capability sets). +(i.e., it identifies one of the three capability dimensions). Valid values for this type are .BR CAP_EFFECTIVE , .B CAP_INHERITABLE @@ -85,22 +84,39 @@ is used to specify the number of capabilities in the array, .IR caps . .PP +.BR cap_fill_flag () +fills the to flag of one capability set, with the values in the from +flag of a reference capability set. +.PP +.BR cap_fill () +fills the to flag values by copying all of the from flag values. +.PP .BR cap_compare () compares two full capability sets and, in the spirit of .BR memcmp (), returns zero if the two capability sets are identical. A positive -return value, -.BR status , -indicates there is a difference between them. The -returned value carries further information about which of three sets, -.I cap_flag_t -.BR flag , -differ. Specifically, the macro +return +.I value +indicates there is a difference between them. The returned +.I value +carries further information about the +.BI "cap_flag_t " flag +differences. Specifically, the macro .B CAP_DIFFERS -.RI ( status ", " flag ) -evaluates to non-zero if the returned status differs in its +.RI ( value ", " flag ) +evaluates to non-zero if the returned +.I value +differs in its .I flag components. +.PP +.BR cap_max_bits () +returns the number of capability values known to the running +kernel. This may differ from libcap's list known at compilation +time. Unnamed, at compilation time, capabilites can be referred to +numerically and libcap will handle them appropriately. Note, the +running kernel wins and it gets to define what "all" capabilities +means. .SH "RETURN VALUE" .BR cap_clear (), .BR cap_clear_flag (), @@ -110,7 +126,12 @@ .BR cap_compare () return zero on success, and \-1 on failure. Other return values for .BR cap_compare () -are described above. +are described above. The function +.BR cap_max_bits () +returns a numeric value of type +.B cap_value_t +that is one larger than the largest actual value known to the running +kernel. .PP On failure, .I errno
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/cap_copy_ext.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_copy_ext.3
Changed
@@ -1,17 +1,17 @@ -.TH CAP_COPY_EXT 3 "2008-05-11" "" "Linux Programmer's Manual" +.TH CAP_COPY_EXT 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME cap_copy_ext, cap_size, cap_copy_int \- capability state external representation translation .SH SYNOPSIS -.B #include <sys/capability.h> +.nf +#include <sys/capability.h> + +ssize_t cap_size(cap_t cap_p); +ssize_t cap_copy_ext(void *ext_p, cap_t cap_p, ssize_t size); +cap_t cap_copy_int(const void * ext_p); +.fi .sp -.BI "ssize_t cap_size(cap_t " cap_p ); -.sp -.BI "ssize_t cap_copy_ext(void *" ext_p ", cap_t " cap_p ", ssize_t " size ); -.sp -.BI "cap_t cap_copy_int(const void *" ext_p ); -.sp -Link with \fI-lcap\fP. +Link with \fI\-lcap\fP. .SH DESCRIPTION These functions translate between internal and external representations of a capability state. The external representation is @@ -34,7 +34,7 @@ .BR cap_copy_ext () copies a capability state in working storage, identified by .IR cap_p , -from system managed space to user-managed space (pointed to by +from system-managed space to user-managed space (pointed to by .IR ext_p ) and returns the length of the resulting data record. The size parameter represents the maximum size, in bytes, of the resulting data record. The @@ -74,12 +74,12 @@ .SH "RETURN VALUE" .BR cap_size () returns the length required to hold a capability data record on success, -and -1 on failure. +and \-1 on failure. .PP .BR cap_copy_ext () returns the number of bytes placed in the user managed space pointed to by .I ext_p -on success, and -1 on failure. +on success, and \-1 on failure. .PP .BR cap_copy_int () returns a pointer to the newly created capability state in working storage
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_fill.3
Added
@@ -0,0 +1 @@ +.so man3/cap_clear.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_fill_flag.3
Added
@@ -0,0 +1 @@ +.so man3/cap_clear.3
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/cap_from_text.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_from_text.3
Changed
@@ -1,22 +1,21 @@ .\" .\" written by Andrew Main <zefram@dcs.warwick.ac.uk> .\" -.TH CAP_FROM_TEXT 3 "2008-05-10" "" "Linux Programmer's Manual" +.TH CAP_FROM_TEXT 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME cap_from_text, cap_to_text, cap_to_name, cap_from_name \- capability state textual representation translation .SH SYNOPSIS -.B #include <sys/capability.h> -.sp -.BI "cap_t cap_from_text(const char *" buf_p ); -.sp -.BI "char *cap_to_text(cap_t " caps ", ssize_t *" length_p ); -.sp -.BI "int cap_from_name(const char *" name ", cap_value_t *" cap_p ); -.sp -.BI "char *cap_to_name(cap_value_t " cap ); +.nf +#include <sys/capability.h> + +cap_t cap_from_text(const char* buf_p ); +char *cap_to_text(cap_t caps, ssize_t * length_p); +int cap_from_name(const char* name , cap_value_t* cap_p); +char *cap_to_name(cap_value_t cap); +.fi .sp -Link with \fI-lcap\fP. +Link with \fI\-lcap\fP. .SH DESCRIPTION These functions translate a capability state between an internal representation and a textual one. @@ -100,7 +99,7 @@ An action-list consists of a sequence of .I operator flag pairs. Legal operators are: -.RB ` = "', '" + "', and `" - "'." +.RB ` = "', '" + "', and `" \- "'." Legal flags are: .RB ` e "', `" i "', and `" p "'." These flags are case-sensitive and specify the Effective, Inheritable @@ -136,15 +135,22 @@ clauses are equivalent to each other (and indicate a completely empty capability set): "all="; "="; "cap_chown,<every-other-capability>=". .PP -The operators, `+' and `-' both require an explicit preceding +The operators, `+' and `\-' both require an explicit preceding capability list and one or more explicit trailing flags. The `+' operator will raise all of the listed capabilities in the flagged -capability sets. The `-' operator will lower all of the listed +capability sets. The `\-' operator will lower all of the listed capabilities in the flagged capability sets. For example: -"all+p" will raise all of the Permitted capabilities; "cap_fowner+p-i" -will raise the override-file-ownership capability in the Permitted -capability set and lower this Inheritable capability; -"cap_fowner+pe-i" and "cap_fowner=+pe" are equivalent. +"all+p" will raise all of the Permitted capabilities and +"cap_fowner\-i" will lower the override-file-ownership in the Inheritable set. +.PP +The action list can consist of multiple +.I operator flag +pairs; the actions are performed in left-to-right order. +Thus, for example, +"cap_fowner+p\-i" +is equivalent to "cap_fowner+p cap_fowner\-i". +As another example, +"cap_fowner+pe\-i" and "cap_fowner=+pe" are equivalent. .SH "RETURN VALUE" .BR cap_from_text (), .BR cap_to_text () @@ -152,7 +158,7 @@ .BR cap_to_name () return a non-NULL value on success, and NULL on failure. .BR cap_from_name () -returns 0 for success, and -1 on failure (unknown capability). +returns 0 for success, and \-1 on failure (unknown capability). .PP On failure, .I errno @@ -174,17 +180,15 @@ .BR cap_from_text () and .BR cap_to_text (). -The following shell session shows a some example runs: -.in +4n +The following shell session shows some example runs: .nf $ ./a.out "cap_chown=p cap_chown+e" -caps_to_text() returned "= cap_chown+ep" -$ ./a.out "all=pe cap_chown-e cap_kill-pe" -caps_to_text() returned "=ep cap_chown-e cap_kill-ep" +caps_to_text() returned "cap_chown=ep" +$ ./a.out "all=pe cap_chown\-e cap_kill\-pe" +caps_to_text() returned "=ep cap_chown\-e cap_kill\-ep" .fi -.in The source code of the program is as follows: .nf @@ -225,7 +229,6 @@ .SH "SEE ALSO" .BR libcap (3), .BR cap_clear (3), -.BR cap_compare (3), .BR cap_copy_ext (3), .BR cap_get_file (3), .BR cap_get_proc (3),
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_func_launcher.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/cap_get_file.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_get_file.3
Changed
@@ -1,28 +1,23 @@ .\" .\" written by Andrew Main <zefram@dcs.warwick.ac.uk> .\" -.TH CAP_GET_FILE 3 "2008-05-11" "" "Linux Programmer's Manual" +.TH CAP_GET_FILE 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME cap_get_file, cap_set_file, cap_get_fd, cap_set_fd \- capability manipulation on files .SH SYNOPSIS -.B -.sp -.B #include <sys/capability.h> -.sp -.BI "cap_t cap_get_file(const char *" path_p ); -.sp -.BI "int cap_set_file(const char *" path_p ", cap_t " cap_p ); -.sp -.BI "cap_t cap_get_fd(int " fd ); -.sp -.BI "int cap_set_fd(int " fd ", cap_t " caps ); -.sp -.BI "uid_t cap_get_nsowner(cap_t " caps ); -.sp -.BI "int cap_set_nsowner(cap_t " caps ", uid_t " rootid ); +.nf +#include <sys/capability.h> + +cap_t cap_get_file(const char *path_p); +int cap_set_file(const char *path_p, cap_t cap_p); +cap_t cap_get_fd(int fd); +int cap_set_fd(int fd, cap_t caps); +uid_t cap_get_nsowner(cap_t caps); +int cap_set_nsowner(cap_t caps, uid_t rootuid); +.fi .sp -Link with \fI-lcap\fP. +Link with \fI\-lcap\fP. .SH DESCRIPTION .BR cap_get_file () and @@ -59,22 +54,22 @@ .IR cap_p is used to indicate that capabilities for the file should be deleted. For these functions to succeed, the calling process must have the -effective capability, -.BR CAP_SETFCAP , -enabled and either the effective user ID of the process must match the +.BR CAP_SETFCAP +capability in its effective set +and either the effective user ID of the process must match the file owner or the calling process must have the .B CAP_FOWNER -flag in its effective capability set. The effects of writing the +capability in its effective capability set. The effects of writing the capability state to any file type other than a regular file are undefined. .PP -A capability set held in memory can be associated with the rootid in -use in a specific namespace. It is possible to get and set this value +A capability set held in memory can be associated with the root user ID in +use in a specific user namespace. It is possible to get and set this value (in the memory copy) with .BR cap_get_nsowner () and .BR cap_set_nsowner () -respectively. The rootid is ignored by the libcap library in all cases +respectively. The root user ID is ignored by the libcap library in all cases other than when the capability is written to a file. Only if the value is non-zero will the library attempt to include it in the written file capability set. @@ -136,4 +131,5 @@ .BR cap_from_text (3), .BR cap_get_proc (3), .BR cap_init (3), -.BR capabilities (7) +.BR capabilities (7), +.BR user_namespaces (7)
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/cap_get_proc.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_get_proc.3
Changed
@@ -1,51 +1,44 @@ -.TH CAP_GET_PROC 3 "2019-12-21" "" "Linux Programmer's Manual" +.TH CAP_GET_PROC 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME cap_get_proc, cap_set_proc, capgetp, cap_get_bound, cap_drop_bound, \ cap_get_ambient, cap_set_ambient, cap_reset_ambient, \ cap_get_secbits, cap_set_secbits, cap_get_mode, cap_set_mode, \ -cap_mode_name, cap_get_pid, cap_setuid, cap_setgroups \ +cap_mode_name, cap_get_pid, cap_setuid, cap_prctl, cap_prctlw, cap_setgroups \ \- capability manipulation on processes .SH SYNOPSIS -.B #include <sys/capability.h> -.sp -.B "cap_t cap_get_proc(void);" -.sp -.BI "int cap_set_proc(cap_t " cap_p ); -.sp -.BI "int cap_get_bound(cap_value_t " cap ); -.sp -.BI "CAP_IS_SUPPORTED(cap_value_t " cap ); -.sp -.BI "int cap_drop_bound(cap_value_t " cap ); -.sp -.BI "int cap_get_ambient(cap_value_t " cap ); -.sp -.BI "int cap_set_ambient(cap_value_t " cap ", cap_flag_value_t " value ); -.sp -.B int cap_reset_ambient(void); -.sp -.BI CAP_AMBIENT_SUPPORTED(); -.sp -.B "unsigned cap_get_secbits(void);" -.sp -.BI "int cap_set_secbits(unsigned " bits ); -.sp -.B "cap_mode_t cap_get_mode(void);" -.sp -.BU "const char *cap_mode_name(cap_mode_t " mode ); -.sp -.BI "int cap_set_mode(cap_mode_t " mode ); -.sp -.B #include <sys/types.h> -.sp -.BI "cap_t cap_get_pid(pid_t " pid ); -.sp -.BI "int cap_setuid(uid_t " uid ); -.sp -.BI "int cap_setgroups(gid_t " gid ", size_t " ngroups ", const gid_t " \ -groups ); +.nf +#include <sys/capability.h> + +cap_t cap_get_proc(void); +int cap_set_proc(cap_t cap_p); + +int cap_get_bound(cap_value_t cap); +CAP_IS_SUPPORTED(cap_value_t cap); + +int cap_drop_bound(cap_value_t cap); +int cap_get_ambient(cap_value_t cap); +int cap_set_ambient(cap_value_t cap, cap_flag_value_t value); +int cap_reset_ambient(void); +CAP_AMBIENT_SUPPORTED(); + +unsigned cap_get_secbits(void); +int cap_set_secbits(unsigned bits); +cap_mode_t cap_get_mode(void); +const char *cap_mode_name(cap_mode_t mode); +int cap_prctl(long int pr_cmd, long int arg1, long int arg2, + long int arg3, long int arg4, long int arg5); +int cap_prctlw(long int pr_cmd, long int arg1, long int arg2, + long int arg3, long int arg4, long int arg5); +int cap_set_mode(cap_mode_t mode); + +#include <sys/types.h> + +cap_t cap_get_pid(pid_t pid); +int cap_setuid(uid_t uid); +int cap_setgroups(gid_t gid, size_t ngroups, const gid_t groups); +.fi .sp -Link with \fI-lcap\fP. +Link with \fI\-lcap\fP. .SH DESCRIPTION .BR cap_get_proc () allocates a capability state in working storage, sets its state to @@ -78,6 +71,9 @@ .BR cap_init (3), with the process capabilities of the process indicated by .IR pid . +(If +.I pid +is 0, then the calling process's capabilities are returned.) This information can also be obtained from the .I /proc/<pid>/status file. @@ -86,8 +82,8 @@ with a .I cap as an argument returns the current value of this bounding set -capability flag in effect for the current process. This operation is -unpriveged. Note, a macro function +capability flag in effect for the calling process. This operation is +unprivileged. Note, a macro function .BR "CAP_IS_SUPPORTED(cap_value_t " cap ) is provided that evaluates to true (1) if the system supports the specified capability, @@ -119,11 +115,11 @@ .BR CAP_SETPCAP . Further, to raise a specific ambient capability the .IR inheritable " and " permitted -sets of the current process must contain the specified capability, and +sets of the calling process must contain the specified capability, and raised ambient bits will only be retained as long as this remains true. .PP .BR cap_reset_ambient () -resets all of the ambient capabilities for the current process to +resets all of the ambient capabilities for the calling process to their lowered value. To complete successfully, the prevailing .I effective capability set must have a raised @@ -136,12 +132,12 @@ fixing up the ambient set can also drop ambient bits. .PP .BR cap_get_secbits () -returns the securebits of the current process. These bits affect the -way in which the current process implements things like setuid-root +returns the securebits of the calling process. These bits affect the +way in which the calling process implements things like setuid-root fixup and ambient capabilities. .PP .BR cap_set_secbits () -attempts to modify the securebits of the current process. Note +attempts to modify the securebits of the calling process. Note .B CAP_SETPCAP must be in the effective capability set for this to be effective. Some settings lock the sub-states of the securebits, so attempts to set values @@ -164,11 +160,17 @@ .RB ( cap_mode_t )0 which .BR cap_get_name () -declares as -.IR "UNCERTAIN" . +identifies as +.RI `` UNCERTAIN ''. Supported modes are: .BR CAP_MODE_NOPRIV ", " CAP_MODE_PURE1E_INIT " and " CAP_MODE_PURE1E . .PP +.BR cap_prctl () +can be used to read state via the \fBprctl\fI()\fP system call. +.PP +.BR cap_prctlw () +can be used to write state via the \fBprctl\fI()\fP system call. +.PP .BR cap_set_mode () can be used to set the desired mode. The permitted capability .B CAP_SETPCAP @@ -202,7 +204,7 @@ .PP The function .BR cap_get_bound () -returns -1 if the requested capability is unknown, otherwise the +returns \-1 if the requested capability is unknown, otherwise the return value reflects the current state of that capability in the prevailing bounding set. Note, a macro function, .PP @@ -216,7 +218,7 @@ .I errno is set to .BR EINVAL , -.BR EPERM, +.BR EPERM , or .BR ENOMEM . .SH "CONFORMING TO" @@ -236,19 +238,22 @@ .B libcap is packaged with a separate POSIX semantics system call library: .BR libpsx . -If your program uses POSIX threads, to achieve meaninful POSIX -sematics capability manipulation, you should link your program with: +If your program uses POSIX threads, to achieve meaningful POSIX +semantics capability manipulation, you should link your program with: .sp -.B ld ... -lcap -lpsx -lpthread --wrap=pthread_create +.B ld ... \-lcap \-lpsx \-lpthread \-\-wrap=pthread_create .sp or, .sp -.B gcc ... -lcap -lpsx -lpthread -Wl,-wrap,pthread_create +.B gcc ... \-lcap \-lpsx \-lpthread \-Wl,\-wrap,pthread_create .sp When linked this way, due to linker magic, libcap uses .BR psx_syscall "(3) and " psx_syscall6 (3) -to perform state setting system calls. -.PP +to perform state setting system calls. Notably, this also ensures that +.BI cap_prctlw () +can be used to ensure process control bits are shared over all threads +of a single process.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab.3
Added
@@ -0,0 +1,189 @@ +.TH CAP_IAB 3 "2021-11-17" "" "Linux Programmer's Manual" +.SH NAME +.nf +#include <sys/capability.h> + +cap_iab_t cap_iab_init(void); + +cap_iab_t cap_iab_dup(cap_iab_t iab); + +cap_iab_t cap_iab_get_proc(void); + +cap_iab_t cap_iab_get_pid(pid_t pid); + +int cap_iab_set_proc(cap_iab_t iab); + +char *cap_iab_to_text(cap_iab_t iab); + +cap_iab_t cap_iab_from_text(const char *text); + +cap_flag_value_t cap_iab_get_vector(cap_iab_t iab, cap_iab_vector_t vec, + cap_value_t val); + +int cap_iab_compare(cap_iab_t a, cap_iab_t b); + +int cap_iab_set_vector(cap_iab_t iab, cap_iab_vector_t vec, cap_value_t val, + cap_flag_value_t enable); + +int cap_iab_fill(cap_iab_t iab, cap_iab_vector_t vec, + cap_t set, cap_flag_t flag); + +.fi +.sp +Link with \fI\-lcap\fP. +.SH "DESCRIPTION" +The functions defined in this man page concern the three naively +inheritable process capability vectors: Inh, Amb and Bound. This +\fIIAB\fP 3-tuple of capability vectors, captured in type +\fIcap_iab_t\fP combine to pass capabilities from one process to +another through +.BR execve (2) +system calls. The convolution rules using the IAB tuple are a fail over +set of rules when the executed file has no configured +\fIfile-capabilities\fP. +.PP +There are some constraints enforced by the kernel with respect to the +three components of an IAB tuple and the Permitted process capability +flag. They are: the Inh vector is entirely equal to the process +Inheritable flag at all times; the Amb vector contains no more +capability values than the intersection of the Inh vector and the +Permitted flag for the process; and the Bound (or \fIblocked\fP) +vector is the twos-complement of the process bounding vector. +.PP +In some environments, it is considered desirable to \fInaively\fP +inherit capabilities. That is pass capabilities, independent of the +status of the executed binary, from parent to child through +\fBexec*\fP system calls. The surviving capabilities become the +Permitted flag for the post-exec process. This method of inheritance +differs significantly from the handshake inheritance between a +pre-exec* process and a file-capability bestowed executable of the +traditional (POSIX.1e) capability mechanism. +.PP +The convolution rules for IAB style inheritance are: I'=I; A'=A&I; +P'=A&I&P. Where P etc are the pre-exec values and P' etc are the +post-exec values. +.PP +With an understanding of these convolution rules, we can explain how +.BR libcap (3) +support for the IAB tuple is managed: the IAB API. +.PP +.BR cap_iab_init () +returns an empty IAB value. That is a \fImostly-harmless\fP tuple. It +will not block any Permitted file capabilities through exec, but it +won't bestow any either. The returned \fIcap_iab_t\fP should be freed +with +.BR cap_free (3). +.sp +.BR cap_iab_dup () +returns a copy of the specified IAB value. The returned cap_iab_t +should be freed with +.BR cap_free (3). +.sp +.BR cap_iab_get_proc () +returns a copy of the IAB value for the current process. The returned +cap_iab_t should be freed with +.BR cap_free (3). +.sp +.BR cap_iab_get_pid () +returns a copy of the IAB value for the specified process. The returned +cap_iab_t should be freed with +.BR cap_free (3). +.sp +.BR cap_iab_set_proc () +can be used to set the IAB value carried by the current process. Such +a setting will fail if the process is insufficiently capable. The +process requires CAP_SETPCAP raised in the E flag and a superset of P +and I values over those in the A vectors. +.sp +.BR cap_iab_to_text () +will convert an IAB tuple to a canonical text representation. The +representation is slightly redundant but libcap will try to generate +as short a representation as it is able. +.sp +.BR cap_iab_from_text () +generates an IAB tuple from a text string (likely generated by the +previous function). The returned IAB tuple should be freed with +.BR cap_free (3). +.sp +The text format accepted by +.BR cap_iab_from_text () +is a comma separated list of capability values. Each capability is +prefixed by nothing (or %) (Inh); ! (Bound, but think Blocked); ^ +(Amb). Or, some combination thereof. Since the Amb vector is +constrained to be no greater than the Inh vector, ^ is equivalent to +%^. Further, unless B is non-zero, % can be omitted. The following are +legal text representations: "!%cap_chown" (Bound but Inh), +"!cap_chown,^cap_chown" (Bound, Inh+Amb). "cap_setuid,!cap_chown" +(Inh, Bound). As noted above, this text representation is the syntax +for the \fIpam_cap.so\fP config file. +.sp +.BR cap_iab_get_vector () +can be used to determine the specific capability value of an IAB +vector. +.sp +.BR cap_iab_compare () +can be used to compare two cap_iab_t tuples. When the return value is +non-zero, the macro \fBCAP_IAB_DIFFERS\fR(\fIstatus\fR, \fIvector\fR) +evaluates to non-zero if the returned status differs in its +.I vector +components. +.sp +.BR cap_iab_set_vector () +can be used to set a specific vector value to the enable setting. +.sp +.BR cap_iab_fill () +can be used to wholesale copy a cap_t flag value into the vec vector +of the IAB tuple. Copying into Amb in this way may implicitly raise Inh +values in the IAB tuple. Similarly copying into the Inh vector may +implicitly lower Amb values that are not present in the resulting Inh +vector. +.SH "ERRORS" +The functions returning \fIcap_iab_t\fP values or allocated memory in +the form of a string return NULL on error. + +Integer return values are -1 on error and 0 on success. + +In the case of error consult \fIerrno\fP. +.SH "NOTES" +.PP +Unlike the traditional \fIcap_t\fP capability set, the +IAB tuple, taken together, is incompatible with filesystem capabilities +created via tools like +.BR setcap (8). +That is, the Amb vector of the IAB tuple is rendered moot when an +executable with a file capability is executed. +.PP +Further, there are libcap +.BR cap_mode (3)s +that render the Amb vector and its method of process inheritance +disabled. + +.SH "HISTORY" +The IAB format for inheritable variants of capabilities was first +developed as the configuration syntax for the \fIpam_cap.so\fP +Linux-PAM module in libcap-2.29. It was introduced to extend the +\fIsimple\fP comma separated list of process Inheritable capabilities, +that the module could besow on an authenticated process tree, to +include enforced limits on the Bounding vector and introduce support +for the Amibient vector of capability bits. + +While the Inheritable and Bounding vectors were anticipated by the +POSIX.1e draft that introduced capabilities, the Ambient vector is a +Linux invention, and incompatible with the POSIX.1e file capability +model. As such, it was felt that trying to meld together all of the 5 +capability vectors into one text representation was not going to +work. Instead the \fIpam_cap.so\fP config syntax was generalized into +a whole set of libcap functions for bundling together all three +naively inheritable capabilities: the IAB tuple. The support for this +debuted in libcap-2.33. +.SH "REPORTING BUGS" +Please report bugs via: +.TP +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 +.SH "SEE ALSO" +.BR libcap (3), +.BR cap_launch (3), +.BR cap_init (3), +.BR capabilities (7) +and +.BR errno (3).
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_compare.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_dup.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_fill.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_from_text.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_get_pid.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_get_proc.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_get_vector.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_init.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_set_proc.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_set_vector.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_iab_to_text.3
Added
@@ -0,0 +1 @@ +.so man3/cap_iab.3
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/cap_init.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_init.3
Changed
@@ -1,19 +1,19 @@ .\" .\" written by Andrew Main <zefram@dcs.warwick.ac.uk> .\" -.TH CAP_INIT 3 "2008-05-11" "" "Linux Programmer's Manual" +.TH CAP_INIT 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME cap_init, cap_free, cap_dup \- capability data object storage management .SH SYNOPSIS -.B #include <sys/capability.h> +.nf +#include <sys/capability.h> + +cap_t cap_init(void); +int cap_free(void *obj_d); +cap_t cap_dup(cap_t cap_p); +.fi .sp -.B cap_t cap_init(void); -.sp -.BI "int cap_free(void *" obj_d ); -.sp -.BI "cap_t cap_dup(cap_t " cap_p ); -.sp -Link with \fI-lcap\fP. +Link with \fI\-lcap\fP. .SH DESCRIPTION The capabilities associated with a file or process are never edited directly. Instead, working storage is allocated to contain a @@ -41,7 +41,7 @@ argument may identify either a .I cap_t entity, or a -.I char * +.I "char\ *" entity allocated by the .BR cap_to_text () function.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launch.3
Added
@@ -0,0 +1,186 @@ +.TH CAP_LAUNCH 3 "2021-08-01" "" "Linux Programmer's Manual" +.SH NAME +.nf +#include <sys/capability.h> + +cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv, + const char * const *envp); + +cap_launch_t cap_func_launcher(int (callback_fn)(void *detail)); + +int cap_launcher_callback(cap_launch_t attr, + int (callback_fn)(void *detail)); +int cap_launcher_set_mode(cap_launch_t attr, cap_mode_t flavor); +cap_iab_t cap_launcher_set_iab(cap_launch_t attr, cap_iab_t iab); +int cap_launcher_set_chroot(cap_launch_t attr, const char *chroot); + +#include <sys/types.h> + +pid_t cap_launch(cap_launch_t attr, void *detail); +int cap_launcher_setuid(cap_launch_t attr, uid_t uid); +int cap_launcher_setgroups(cap_launch_t attr, gid_t gid, + int ngroups, const gid_t *groups); +.fi +.sp +Link with \fI\-lcap\fP. +.SH DESCRIPTION +A launcher provides a mechanism for code to execute a callback +function and/or a program executable in an environment with a modified +security context. Essentially it provides a mechanism for a program to +.BR fork (2) +a new context from that of the main program manipulate capability and other privileged state in that +.BR fork (2)d +process before (optionally) +.BR execve (2)ing +a new program. When the application links to \fI\-lpsx\fP this support +is needed to robustly execute the launched code without modifying the +privilge of the whole (POSIX semantics honoring) main application. +.PP +A launcher is defined by one of these two functions: +.BR cap_new_launcher () +or +.BR cap_func_launcher (). +The return value being of opaque type +.B cap_launch_t +a return value of NULL implies an error has occurred. +.PP +Once defined, a +.B cap_launch_t +value can be used with +.BR cap_launch () +to execute that \fIlauncher\fP. In such cases, a non-negative return +value indicates success: zero meaning success without a program being +invoked; non-zero being equal to the process ID +.RB ( pid_t ) +of the newly launched program. +.PP +A +.B cap_launch_t +occupies allocated memory and should be freed with +.BR cap_free (3). +Before being +.BR cap_free (3)d +a +.B cap_value_t +value may be reused for multiple independent launches. The +.I detail +argument to +.BR cap_launch (), +in conjunction with the launcher's callback function, can be used to +customize the invocation of the launch. Care must be taken to leverage +custom shared memory (see +.BR mmap (2)) +or some other IPC to return values to the main program via +.I detail +since the callback and any subsequent program execution will occur +outside the main process of the calling application. An example of +this would be to allocate detail as follows: +.nf + + const *char[] args = { "echo", "hello", NULL }; + cap_launch_t cmd = cap_new_launcher("/usr/bin/echo", args, NULL); + int *detail = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + cap_launcher_callback(cmd, &answer_detail_fn); + *detail = 41; + pid_t pid = cap_launch(cmd, detail); + printf("launcher callback set detail to %d\\n", *detail); + munmap(detail, sizeof(int)); + +.fi +.PP +Unless modified by the callback function, the launched code will +execute with the capability and other security context of the +application. + +If the callback function returns anything other than zero, a +.BR cap_launch () +will be aborted. If detail of the failure is important to the caller, +it should be communicated via the +.I detail +argument. + +The following functions can be used to instruct the launcher to modify +the security state of the invoked program without altering the state +of the calling program. Such modifications must be performed prior to +calling \fBcap_launch\fP() if they are to have the desired +effect. Further, they are only invoked after any installed callback +has completed. For example, one can drop or modify capabilities, +\fIjust\fP for executing a file. +.PP +The following functions instruct the launcher to do some common tasks +of this sort (note some require permitted capability bits to succeed): +.sp +.BR cap_launcher_callback () +can be used to install or replace the currently installed callback +function of the launcher. +.sp +.BR cap_launcher_set_mode () +can be used to ensure that the libcap-mode of the launched program is +the desired one. +.sp +.BR cap_launcher_set_iab () +This function returns the \fBcap_iab_t\fP previously associated with +the launcher. Calling this function with an IAB value of NULL will +configure the launcher to not set an IAB value (the default). See +\fBcap_iab\fP(3) for details on the IAB set. Note, the launcher is +associated directly with the supplied \fIiab\fP value, and does not +make a copy of it. This iab value is locked to the laucher and cannot +be modified while associated with the launcher. Set with NULL to +regain control over the memory associated with that IAB value, +otherwise the IAB value will be \fBcap_free\fI()\fP'd when the +launcher is. +.sp +.BR cap_launcher_set_chroot () +This function causes the launched program executable to be invoked +inside a chroot \fIroot\fP directory. +.sp +.BR cap_launcher_setuid () +This function causes the launched program executable to be invoked +with the specified user identifier (\fIuid_t\fP). +.sp +.BR cap_launcher_setgroups () +This function causes the launched program executable to be invoked +with the specified primary and supplementary group IDs. +.sp +.PP +Note, if any of the launcher enhancements made by the above functions +should fail to take effect (typically for a lack of sufficient +privilege), the launch will fail and return -1. + +.SH "ERRORS" +A return of NULL for a +.B cap_launch_t +should be considered an error. +.PP +.BR cap_launch () +returns -1 in the case of an error. +.PP +In all such cases a return value of 0 implies success. In other cases, +consult +.BR errno (3) +for further details. +.SH "HISTORY" +The \fBcap_launch\fP() family of functions were introduced in libcap +2.33. It primarily addresses a complexity with \fI-lpsx\fP linked +pthreads(7) applications that use capabilities but also honor POSIX +semantics. + +Using \fI\-lcap\fP and \fI\-lpthread\fP together without the POSIX +semantics support from \fI\-lpsx\fP introduces a subtle class of +exposure to privilege escalation. (See +https://sites.google.com/site/fullycapable/who-ordered-libpsx for an +explanation.) +.SH "SEE ALSO" +.BR libpsx (3), +.BR psx_syscall (3), +.BR libcap (3), +.BR cap_mode (3), +.BR cap_iab (3), +.BR capabilities (7), +.BR errno (3), +.BR fork (2), +.BR mmap (2), +.BR chroot (2), +and +.BR munmap (2).
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launcher_callback.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launcher_set_chroot.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launcher_set_iab.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launcher_set_mode.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launcher_setgroups.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_launcher_setuid.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_max_bits.3
Added
@@ -0,0 +1 @@ +.so man3/cap_clear.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_mode.3
Added
@@ -0,0 +1 @@ +.so man3/cap_get_proc.3
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/cap_new_launcher.3
Added
@@ -0,0 +1 @@ +.so man3/cap_launch.3
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/capability.notes -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/capability.notes
Changed
@@ -22,7 +22,7 @@ user can be made the owner of all of the system directories on your system and critical system binaries too. -Why is this a good idea? In a simple case, the CAP_FUSER capabilty is +Why is this a good idea? In a simple case, the CAP_FUSER capability is required for the superuser to delete files owned by a non-root user in a 'sticky-bit' protected non-root owned directory. Thus, the sticky bit can help you protect the /lib/ directory from an compromized
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/capsh.1 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/capsh.1
Changed
@@ -1,4 +1,4 @@ -.TH CAPSH 1 "2020-01-07" "libcap 2" "User Commands" +.TH CAPSH 1 "2021-10-22" "libcap" "User Commands" .SH NAME capsh \- capability shell wrapper .SH SYNOPSIS @@ -10,31 +10,54 @@ of capability testing and environment creation. It also provides some debugging features useful for summarizing capability state. .SH OPTIONS -The tool takes a number of optional arguments, acting on them in the +.B capsh +takes a number of optional arguments, acting on them in the order they are provided. They are as follows: -.TP 22 -.B --help +.TP +.B \-\-help Display the list of commands supported by .BR capsh . .TP -.B --print +.B \-\-print Display prevailing capability and related state. .TP -.BI -- " [args]" +.B \-\-current +Display prevailing capability state, 1e capabilities and IAB vector. +.TP +.BI \-\- " [args]" Execute .B /bin/bash with trailing arguments. Note, you can use -.B -c 'command to execute' +.B \-c 'command to execute' for specific commands. .TP -.B == +.BI \-\+ " [args]" +Uses \fBcap_launch\fP(3) to fork a child to execute the shell. When +the child exits, \fBcapsh\fP exits with the status of the child or 1 +in the case that the child was terminated by a signal. +.TP +.BI == " [args]" Execute .B capsh -again with remaining arguments. Useful for testing +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 intended feature as it +can complete the chroot transition. +.TP +.BI =\+ " [args]" +Uses \fBcap_launch\fP(3) to fork a child to re-execute +\fBcapsh\fP. When this child exits, \fBcapsh\fP exits with the status +of the child or 1 in the case that the child was terminated by a +signal. .TP -.BI --caps= cap-set +.BI \-\-caps= cap-set Set the prevailing process capabilities to those specified by .IR cap-set . Where @@ -42,28 +65,31 @@ is a text-representation of capability state as per .BR cap_from_text (3). .TP -.BI --drop= cap-list +.BI \-\-drop= cap-list Remove the listed capabilities from the prevailing bounding set. The -capabilites are a comma separated list of capabilities as recognized +capabilities are a comma-separated list of capabilities as recognized by the .BR cap_from_name (3) -function. Use of this feature requires that the capsh program is -operating with +function. Use of this feature requires that +.B capsh +is operating with .B CAP_SETPCAP in its effective set. .TP -.BI --inh= cap-list +.BI \-\-inh= cap-list Set the inheritable set of capabilities for the current process to equal those provided in the comma separated list. For this action to succeed, the prevailing process should already have each of these capabilities in the union of the current inheritable and permitted -capability sets, or the capsh program is operating with +capability sets, or +.B capsh +should be operating with .B CAP_SETPCAP in its effective set. .TP -.BI --user= username +.BI \-\-user= username Assume the identity of the named user. That is, look up the user's -.IR uid " and " gid +UID and GID with .BR getpwuid (3) and their group memberships with @@ -73,25 +99,32 @@ and .BR cap_setgroups (3). Following this command, the effective capabilities will be cleared, -but the permitted set will not be so the running program is still +but the permitted set will not be, so the running program is still privileged. .TP -.B --modes -Lists all of the libcap modes supported by -.BR --mode . +.B \-\-mode +Display the prevailing libcap mode as guessed by the +.BR cap_get_mode (3) +function. .TP -.BR --mode= <mode> +.BR \-\-mode= <mode> Force the program into a .BR cap_set_mode (3) security mode. This is a set of securebits and prevailing capability arrangement recommended for its pre-determined security stance. .TP -.BR --inmode= <mode> -Confirm that the prevailing mode is so named, or exit with a status 1. +.B \-\-modes +Lists all of the libcap modes supported by +.BR \-\-mode= <mode>. +.TP +.BR \-\-inmode= <mode> +Confirm that the prevailing mode is that specified in +.IR <mode> , +or exit with a status 1. .TP -.BI --uid= id +.BI \-\-uid= id Force all -.B uid +UID values to equal .I id using the @@ -99,44 +132,46 @@ system call. This argument may require explicit preparation of the effective set. .TP -.BR --cap-uid= <uid> +.BR \-\-cap\-uid= <uid> use the .BR cap_setuid (3) -function to set the uid of the current process. This performs all -prepations for setting the uid without dropping capabilities in the +function to set the UID of the current process. This performs all +preparations for setting the UID without dropping capabilities in the process. Following this command the prevailing effective capabilities will be lowered. .TP -.BI --is-uid= <id> +.BI \-\-is\-uid= <id> Exit with status 1 unless the current -.IR uid " equals " <id> . +UID equals +.IR <id> . .TP -.BI --gid= <id> +.BI \-\-gid= <id> Force all -.B gid +GID values to equal .I id using the .BR setgid (2) system call. .TP -.BI --is-gid= <id> +.BI \-\-is\-gid= <id> Exit with status 1 unless the current -.IR gid " equals " <id> . +GIQ equals +.IR <id> . .TP -.BI --groups= <gid-list> +.BI \-\-groups= <gid-list> Set the supplementary groups to the numerical list provided. The groups are set with the .BR setgroups (2) system call. See -.B --user
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/captree.8
Added
@@ -0,0 +1,70 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH CAPTREE 8 "2021-09-02" +.\" Please adjust this date whenever revising the manpage. +.SH NAME +captree \- display process tree capabilities +.SH SYNOPSIS +.BR captree " [optional args] " +.IR [pid|glob-name ... ] +.SH DESCRIPTION +.B captree +displays the capabilities on the mentioned processes indicated by +.IR pid or glob-name +value(s) given on the command line. If no +.I pid +etc values are supplied, +.IR pid =1 +is implied. A +.I pid +value of 0 displays all the processes known to the kernel. +.PP +The POSIX.1e capabilities are displayed in double quotes in the +.BR cap_from_text (3) +format. The IAB tuple of capabilities is displayed between square +brackets in the text format described in +.BR cap_iab (3). +Note, the IAB tuple text is omitted if it contains empty A and B +components. This is because the regular POSIX.1e text contains +information about the Inheritable flag already. This behavior can be +overridden with the +.B --verbose +command line argument. +.PP +Optional arguments (which must precede the list of pid|glob-name +values): +.TP +.B \-\-help +Displays usage information and exits. +.TP +.BR \-\-verbose +Displays capability sets and IAB tuples even when they are empty, or +redundant. +.TP +.BI \-\-depth =n +Displays the process tree to a depth of +.IR n . +Note, the default value for this parameter is 0, which implies +infinite depth. +.TP +.BI \-\-colo[u]r =false +Colo[u]rs the targeted PIDs, if stdout is a TTY, in red. This option +defaults to true when running via a TTY. The \fB--color\fI=false\fR +argument will suppress this color. Piping the output into some other +program will also suppress the use of colo[u]r. + +.SH REPORTING BUGS +Please report bugs via: +.TP +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 +.SH SEE ALSO +.BR cap_from_text(3), +.BR capabilities (7), +and +.BR cap_iab (3). + +There is a longer article about \fBcaptree\fP, which includes some +examples, here: + + https://sites.google.com/site/fullycapable/captree +.SH AUTHOR +Andrew G. Morgan <morgan@kernel.org>
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/getcap.8 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/getcap.8
Changed
@@ -1,34 +1,41 @@ -.\" written by Andrew Main <zefram@dcs.warwick.ac.uk> -.TH GETCAP 8 "2020-01-07" +.\" originally written by Andrew Main <zefram@dcs.warwick.ac.uk> +.TH GETCAP 8 "2021-08-29" .SH NAME getcap \- examine file capabilities .SH SYNOPSIS -\fBgetcap\fP [-v] [-n] [-r] [-h] \fIfilename\fP [ ... ] +\fBgetcap\fP [\-v] [\-n] [\-r] [\-h] \fIfilename\fP [ ... ] .SH DESCRIPTION .B getcap -displays the name and capabilities of each specified +displays the name and capabilities of each specified file. .SH OPTIONS .TP 4 -.B -h +.B \-h prints quick usage. .TP 4 -.B -n -prints any non-zero namespace rootid value found to be associated with +.B \-n +prints any non-zero user namespace root user ID value +found to be associated with a file's capabilities. .TP 4 -.B -r +.B \-r enables recursive search. .TP 4 -.B -v -enables to display all searched entries, even if it has no file-capabilities. +.B \-v +display all searched entries, even if the have no file-capabilities. .TP 4 .IR filename One file per line. .SH "REPORTING BUGS" Please report bugs via: .TP -https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1047723&product=Tools&resolution=--- +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 .SH "SEE ALSO" +.BR capsh (1), .BR cap_get_file (3), .BR cap_to_text (3), -.BR setcap (8) +.BR capabilities (7), +.BR user_namespaces (7), +.BR captree (8), +.BR getpcaps (8) +and +.BR setcap (8).
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/getpcaps.8 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/getpcaps.8
Changed
@@ -1,34 +1,57 @@ .\" Hey, EMACS: -*- nroff -*- -.TH GETPCAPS 8 "2020-01-04" +.TH GETPCAPS 8 "2020-08-29" .\" Please adjust this date whenever revising the manpage. .SH NAME getpcaps \- display process capabilities .SH SYNOPSIS -.BR getpcaps "[optional args]" +.BR getpcaps " [optional args]" .IR pid ... .SH DESCRIPTION .B getpcaps displays the capabilities on the processes indicated by the .I pid -value(s) given on the commandline. The capabilities are displayed in +value(s) given on the command line. +A +.I pid +of 0 displays the capabilities of the process that is running +.B getpcaps +itself. +.PP +The capabilities are displayed in the .BR cap_from_text (3) format. .PP Optional arguments: -.PP -.BR --help " or " --usage +.TP +.BR \-\-help " or " \-\-usage Displays usage information and exits. -.PP -.BR --ugly " or " --legacy +.TP +.BR \-\-ugly " or " \-\-legacy Displays output in a somewhat ugly legacy format. -.PP -.B --verbose +.TP +.B \-\-verbose Displays usage in a legacy-like format but not quite so ugly in modern default terminal fonts. +.TP +.B \-\-iab +Displays IAB tuple capabilities from the process. The output format +here is the text format described in \fBcap_iab\fR(3). Double +quotes encase the regular process capabilities and square brackets +encase the IAB tuple. This format is also used by \fBcaptree\fR(8). +.SH "REPORTING BUGS" +Please report bugs via: +.TP +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 .SH SEE ALSO -.BR capsh "(8), " setcap "(8) and " getcap (8). -.br +.BR capsh (1), +.BR cap_from_text (3), +.BR cap_iab (3), +.BR capabilities (7), +.BR captree (8), +.BR getcap (8), +and +.BR setcap (8). .SH AUTHOR This manual page was originally written by Robert Bihlmeyer <robbe@debian.org>, for the Debian GNU/Linux system (but may be used
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/libcap.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/libcap.3
Changed
@@ -1,4 +1,4 @@ -.TH LIBCAP 3 "2020-01-07" "" "Linux Programmer's Manual" +.TH LIBCAP 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME cap_clear, cap_clear_flag, cap_compare, cap_copy_ext, cap_copy_int, \ cap_free, cap_from_name, cap_from_text, cap_get_fd, cap_get_file, \ @@ -7,56 +7,39 @@ cap_get_pid, cap_dup \- capability data object manipulation .SH SYNOPSIS .nf -.B #include <sys/capability.h> -.sp -.BI "int cap_clear(cap_t " cap_p ); -.sp -.BI "int cap_clear_flag(cap_t " cap_p ", cap_flag_t " flag ");" -.sp -.BI "int cap_compare(cap_t " cap_a ", cap_t " cap_b ");" -.sp -.BI "ssize_t cap_copy_ext(void *" ext_p ", cap_t " cap_p ", ssize_t " size ); -.sp -.BI "cap_t cap_copy_int(const void *" ext_p ); -.sp -.BI "int cap_free(void *" obj_d ); -.sp -.BI "int cap_from_name(const char *" name ", cap_value_t *" cap_p ); -.sp -.BI "cap_t cap_from_text(const char *" buf_p ); -.sp -.BI "cap_t cap_get_fd(int " fd ); -.sp -.BI "cap_t cap_get_file(const char *" path_p ); -.sp -.BI "int cap_get_flag(cap_t " cap_p ", cap_value_t " cap , -.BI " cap_flag_t " flag ", cap_flag_value_t *" value_p ");" -.sp -.B #include <sys/types.h> -.BI "cap_t cap_get_pid(pid_t " pid ); -.sp -.B "cap_t cap_get_proc(void);" -.sp -.BI "int cap_set_fd(int " fd ", cap_t " caps ); -.sp -.BI "int cap_set_file(const char *" path_p ", cap_t " cap_p ); -.sp -.sp -.BI "int cap_set_flag(cap_t " cap_p ", cap_flag_t " flag ", int " ncap , -.BI " const cap_value_t *" caps ", cap_flag_value_t " value ");" -.BI "int cap_set_proc(cap_t " cap_p ); -.sp -.BI "ssize_t cap_size(cap_t " cap_p ); -.sp -.BI "char *cap_to_name(cap_value_t " cap ); -.sp -.BI "char *cap_to_text(cap_t " caps ", ssize_t *" length_p ); -.sp -.BI "cap_t cap_get_pid(pid_t " pid ); -.sp -.BI "cap_t cap_dup(cap_t " cap_p ); +#include <sys/capability.h> + +int cap_clear(cap_t cap_p); +int cap_clear_flag(cap_t cap_p, cap_flag_t flag); +int cap_compare(cap_t cap_a, cap_t cap_b); +ssize_t cap_copy_ext(void *ext_p, cap_t cap_p, ssize_t size); +cap_t cap_copy_int(const void *ext_p); +int cap_free(void *obj_d); +int cap_from_name(const char *name, cap_value_t *cap_p); +cap_t cap_from_text(const char *buf_p); +cap_t cap_get_fd(int fd); +cap_t cap_get_file(const char *path_p); +int cap_get_flag(cap_t cap_p, cap_value_t cap , + cap_flag_t flag, cap_flag_value_t *value_p); +cap_value_t cap_max_bits(); + +#include <sys/types.h> + +cap_t cap_get_pid(pid_t pid); +cap_t cap_get_proc(void); +int cap_set_fd(int fd, cap_t caps); +int cap_set_file(const char *path_p, cap_t cap_p); +int cap_set_flag(cap_t cap_p, cap_flag_t flag, int ncap , + const cap_value_t *caps, cap_flag_value_t value); +int cap_set_proc(cap_t cap_p); +ssize_t cap_size(cap_t cap_p); +char *cap_to_name(cap_value_t cap); +char *cap_to_text(cap_t caps, ssize_t *length_p); +cap_t cap_get_pid(pid_t pid); +cap_t cap_dup(cap_t cap_p); +.fi .sp -Link with \fI-lcap\fP. +Link with \fI\-lcap\fP. .fi .SH DESCRIPTION These functions work on a capability state held in working storage. @@ -102,9 +85,14 @@ and .BR cap_compare (). .SH "REPORTING BUGS" -Please report bugs via: +The +.B libcap +library is distributed from +https://sites.google.com/site/fullycapable/ where the release notes +may already cover recent issues. Please report newly discovered bugs +via: .TP -https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1047723&product=Tools&resolution=--- +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 .SH "SEE ALSO" .BR cap_clear (3), .BR cap_copy_ext (3), @@ -113,5 +101,7 @@ .BR cap_get_proc (3), .BR cap_init (3), .BR capabilities (7), -.BR getpid (2) +.BR getpid (2), .BR capsh (1) +and +.BR libpsx (3).
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/libpsx.3 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/libpsx.3
Changed
@@ -1,19 +1,19 @@ -.TH LIBPSX 3 "2020-01-07" "" "Linux Programmer's Manual" +.TH LIBPSX 3 "2021-03-06" "" "Linux Programmer's Manual" .SH NAME psx_syscall3, psx_syscall6 \- POSIX semantics for system calls .SH SYNOPSIS .nf -.B #include <sys/psx_syscall.h> -.sp -.BI "long int psx_syscall3(long int" " syscall_nr, " "long int" " arg1, " "long int" " arg2, " "long int" " arg3);" -.sp -.BI "long int psx_syscall6(long int" " syscall_nr, " "long int" " arg1, " "long int" " arg2, " "long int" " arg3, " "long int" " arg4, " "long int" " arg5, " "long int" " arg6);" +#include <sys/psx_syscall.h> + +long int psx_syscall3(long int syscall_nr, long int arg1, long int arg2, long int arg3); +long int psx_syscall6(long int syscall_nr, long int arg1, long int arg2, long int arg3, long int arg4, long int arg5, long int arg6); +.fi .sp Link with one of these: .sp -.I ld ... -lpsx -lpthread --wrap=pthread_create +.I ld ... \-lpsx \-lpthread \-\-wrap=pthread_create .sp -.I gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create +.I gcc ... \-lpsx \-lpthread \-Wl,\-wrap,pthread_create .SH DESCRIPTION The .B libpsx @@ -25,47 +25,49 @@ all of the threads associated with the current process. However, other credential state is not supported by this abstraction. To support these extended kernel managed security attributes, -.BR libpsx (3) +.B libpsx provides a more generic pair of wrapping system call functions: -.BR psx_syscall3 "(3) and " psx_syscall6 (3). +.BR psx_syscall3 "() and " psx_syscall6 (). Like the .B setxid -mechanism, the coordination of thread state is arranged by a realtime -signal SIGRTMAX which is usurped for this process. +mechanism, the coordination of thread state is mediated by a realtime +signal. Whereas the +.B nptl:setxid +mechanism uses signo=33 (which is hidden by glibc below a redefined +SIGRTMIN), +.B libpsx +inserts itself in the SIGSYS handler stack. It goes to great length to +be the first such handler but acts as a pass-through for other SIGSYS +uses. .PP A linker trick of .I wrapping the .BR pthread_create () -call with a psx thread registration function is used to allow +call with a psx thread registration function is used to ensure .B libpsx -to keep track of all pthreads. If that trick is not usable by your application, then the much more cumbersome and fragile -.BR psx_register ( pthread_t " thread)" -function is provided to register threads manually with the library. To -successfully use this approach an explanation of how to code for it is -provided at the top of the -.B <sys/psx_syscall.h> -header file. +can keep track of all pthreads. .PP -An inefficient macrology trick supports the psx_syscall() pseudo -function which takes 1 to 7 arguments, depending on the needs of the -caller. The macrology pads out the call to actually use -.BR psx_syscall3 (3) +An inefficient macrology trick supports the +.BR psx_syscall () +pseudo function which takes 1 to 7 arguments, depending on the needs +of the caller. The macrology pads out the call to actually use +.BR psx_syscall3 () or -.BR psx_syscall6 (3) +.BR psx_syscall6 () with zeros filling the missing arguments. While using this in source code will make it appear clean, the actual code footprint is larger. You are encouraged to use the more explicit -.BR psx_syscall3 (3) +.BR psx_syscall3 () and -.BR psx_syscall6 (3) -functions. +.BR psx_syscall6 () +functions as needed. .SH RETURN VALUE The return value for system call functions is generally the value -returned by the kernel, or -1 in the case of an error. In such cases +returned by the kernel, or \-1 in the case of an error. In such cases .BR errno (3) is set to the detailed error value. The -.BR psx_syscall3 " and " psx_syscall6 +.BR psx_syscall3 "() and " psx_syscall6 () functions attempt a single threaded system call and return immediately in the case of an error. Should this call succeed, then the same system calls are executed from a signal handler on each of the other @@ -73,11 +75,19 @@ .SH CONFORMING TO The needs of .BR libcap (3) -for POSIX semantics of capability manipulation. +for POSIX semantics of capability manipulation. You can read more +about why this is needed here: +.TP +https://sites.google.com/site/fullycapable/who-ordered-libpsx .SH "REPORTING BUGS" -Please report bugs via: +The +.B libpsx +library is distributed from +https://sites.google.com/site/fullycapable/ where the release notes +may already cover recent issues. Please report newly discovered bugs +via: .TP -https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1047723&product=Tools&resolution=--- +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 .SH SEE ALSO .BR libcap (3), .BR pthreads "(7) and"
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/md2html.lua
Added
@@ -0,0 +1,6 @@ +-- This is the links-to-html.lua example from stackoverflow: +-- https://stackoverflow.com/questions/40993488/convert-markdown-links-to-html-with-pandoc +function Link(el) + el.target = string.gsub(el.target, "%.md", ".html") + return el +end
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/mkmd.sh
Added
@@ -0,0 +1,81 @@ +#!/bin/bash +# +# Handy script to rebuild the markdown version of the man pages. +# This uses pandoc if it is installed. +# +# For rendering the md, we can use a different command: +# +# cd md; for x in *.md ; do pandoc -s $x --metadata pagetitle="${x%.md}" -o ${x%.md}.html --lua-filter=../md2html.lua ; done + +if [[ -z "$(which pandoc)" ]]; then + echo "pandoc not found - skipping conversion" + exit 0 +fi + +outdir="$1" +if [[ -z "${outdir}" ]]; then + echo "usage $0 <outdir>" + exit 1 +fi + +mkdir -p "${outdir}" +if [[ $? -ne 0 ]]; then + echo "failed to make output directory: ${outdir}" + exit 1 +fi + +index="${outdir}/index.md" + +function do_page () { + m="$1" + base="${m%.*}" + sect="${m#*.}" + output="${base}-${sect}.md" + + echo "converting ${m}" 1>&2 + + redir="$(grep '^.so man' "${m}")" + if [[ $? -eq 0 ]]; then + r="${redir#*/}" + rbase="${r%.*}" + rsect="${r#*.}" + echo "* [${base}(${sect})](${rbase}-${rsect}.md)" >> "${index}" + return + fi + + pandoc -f man -t markdown < "${m}" | sed 's/\*\*\([^*]\+\)\*\*(\([138]\+\))/[\1(\2)](\1-\2.md)/g' > "${outdir}/${base}-${sect}.md" + echo "* [${base}(${sect})](${base}-${sect}.md)" >> "${index}" +} + +cat > "${index}" <<EOF +# Manpages for libcap and libpsx + +## Individual reference pages +EOF + +# Assumes the m's are listed alphabetically. +for n in 1 3 8 ; do + cat >> "${index}" <<EOF + +### Section ${n} + +EOF + for m in *.${n}; do + do_page "${m}" + done +done + +cat >> "${index}" <<EOF + +## More information + +For further information, see the +[FullyCapable](https://sites.google.com/site/fullycapable/) homepage +for libcap. + +## MD page generation + +These official man pages for libcap and libpsx were converted to +markdown using [pandoc](https://pandoc.org). + +EOF
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/old/_setfilecap.2 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/old/_setfilecap.2
Changed
@@ -93,7 +93,7 @@ .TP .SB ELOOP .I filename -containes a circular reference (via symlinks). +contains a circular reference (via symlinks). .TP .SB EBADF .I fd
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/doc/setcap.8 -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/setcap.8
Changed
@@ -1,11 +1,11 @@ -.TH SETCAP 8 "2020-01-07" +.TH SETCAP 8 "2020-08-29" .SH NAME setcap \- set file capabilities .SH SYNOPSIS -\fBsetcap\fP [-q] [-n <rootid>] [-v] {\fIcapabilities|-|-r} filename\fP [ ... \fIcapabilitiesN\fP \fIfileN\fP ] +\fBsetcap\fP [\-q] [\-n <rootuid>] [\-v] {\fIcapabilities|\-|\-r} filename\fP [ ... \fIcapabilitiesN\fP \fIfileN\fP ] .SH DESCRIPTION In the absence of the -.B -v +.B \-v (verify) option .B setcap sets the capabilities of each specified @@ -13,38 +13,38 @@ to the .I capabilities specified. The optional -.B -n <rootid> +.B \-n <rootuid> argument can be used to set the file capability for use only in a -namespace with this rootid owner. The -.B -v +user namespace with this root user ID owner. The +.B \-v option is used to verify that the specified capabilities are currently -associated with the file. If -v and -n are supplied, the -.B -n <rootid> +associated with the file. If \-v and \-n are supplied, the +.B \-n <rootuid> argument is also verified. .PP The .I capabilities are specified in the form described in -.IR cap_from_text (3). +.BR cap_from_text (3). .PP The special capability string, -.BR '-' , +.BR '\-' , can be used to indicate that capabilities are read from the standard input. In such cases, the capability set is terminated with a blank line. .PP The special capability string, -.BR '-r' , +.BR '\-r' , is used to remove a capability set from a file. Note, setting an empty capability set is .B not the same as removing it. An empty set can be used to guarantee a file is not -executed with privilege inspite of the fact that the prevailing +executed with privilege in spite of the fact that the prevailing ambient+inheritable sets would otherwise bestow capabilities on executed binaries. .PP The -.B -q +.B \-q flag is used to make the program less verbose in its output. .SH "EXIT CODE" The @@ -54,8 +54,14 @@ .SH "REPORTING BUGS" Please report bugs via: .TP -https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1047723&product=Tools&resolution=--- +https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1090757 .SH "SEE ALSO" +.BR capsh (1), .BR cap_from_text (3), -.BR cap_set_file (3), +.BR cap_get_file (3), +.BR capabilities (7), +.BR user_namespaces (7), +.BR captree (8), .BR getcap (8) +and +.BR getpcaps (8).
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/0.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to arbitrarily change the user and +group ownership of a file.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/1.txt
Added
@@ -0,0 +1,5 @@ +Allows a process to override of all Discretionary +Access Control (DAC) access, including ACL execute +access. That is read, write or execute files that the +process would otherwise not have access to. This +excludes DAC access covered by CAP_LINUX_IMMUTABLE.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/10.txt
Added
@@ -0,0 +1,3 @@ +Allows a process to bind to privileged ports: + - TCP/UDP sockets below 1024 + - ATM VCIs below 32
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/11.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to broadcast to the network and to +listen to multicast.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/12.txt
Added
@@ -0,0 +1,17 @@ +Allows a process to perform network configuration +operations: + - interface configuration + - administration of IP firewall, masquerading and + accounting + - setting debug options on sockets + - modification of routing tables + - setting arbitrary process, and process group + ownership on sockets + - binding to any address for transparent proxying + (this is also allowed via CAP_NET_RAW) + - setting TOS (Type of service) + - setting promiscuous mode + - clearing driver statistics + - multicasing + - read/write of device-specific registers + - activation of ATM control sockets
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/13.txt
Added
@@ -0,0 +1,5 @@ +Allows a process to use raw networking: + - RAW sockets + - PACKET sockets + - binding to any address for transparent proxying + (also permitted via CAP_NET_ADMIN)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/14.txt
Added
@@ -0,0 +1,3 @@ +Allows a process to lock shared memory segments for IPC +purposes. Also enables mlock and mlockall system +calls.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/15.txt
Added
@@ -0,0 +1 @@ +Allows a process to override IPC ownership checks.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/16.txt
Added
@@ -0,0 +1,3 @@ +Allows a process to initiate the loading and unloading +of kernel modules. This capability can effectively +modify kernel without limit.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/17.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to perform raw IO: + - permit ioper/iopl access + - permit sending USB messages to any device via + /dev/bus/usb
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/18.txt
Added
@@ -0,0 +1,3 @@ +Allows a process to perform a chroot syscall to change +the effective root of the process' file system: +redirect to directory "/" to some other location.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/19.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to perform a ptrace() of any other +process.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/2.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to override all DAC restrictions +limiting the read and search of files and +directories. This excludes DAC access covered by +CAP_LINUX_IMMUTABLE.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/20.txt
Added
@@ -0,0 +1 @@ +Allows a process to configure process accounting.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/21.txt
Added
@@ -0,0 +1,43 @@ +Allows a process to perform a somewhat arbitrary +grab-bag of privileged operations. Over time, this +capability should weaken as specific capabilities are +created for subsets of CAP_SYS_ADMINs functionality: + - configuration of the secure attention key + - administration of the random device + - examination and configuration of disk quotas + - setting the domainname + - setting the hostname + - calling bdflush() + - mount() and umount(), setting up new SMB connection + - some autofs root ioctls + - nfsservctl + - VM86_REQUEST_IRQ + - to read/write pci config on alpha + - irix_prctl on mips (setstacksize) + - flushing all cache on m68k (sys_cacheflush) + - removing semaphores + - Used instead of CAP_CHOWN to "chown" IPC message + queues, semaphores and shared memory + - locking/unlocking of shared memory segment + - turning swap on/off + - forged pids on socket credentials passing + - setting readahead and flushing buffers on block + devices + - setting geometry in floppy driver + - turning DMA on/off in xd driver + - administration of md devices (mostly the above, but + some extra ioctls) + - tuning the ide driver + - access to the nvram device + - administration of apm_bios, serial and bttv (TV) + device + - manufacturer commands in isdn CAPI support driver + - reading non-standardized portions of PCI + configuration space + - DDI debug ioctl on sbpcd driver + - setting up serial ports + - sending raw qic-117 commands + - enabling/disabling tagged queuing on SCSI + controllers and sending arbitrary SCSI commands + - setting encryption key on loopback filesystem + - setting zone reclaim policy
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/22.txt
Added
@@ -0,0 +1 @@ +Allows a process to initiate a reboot of the system.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/23.txt
Added
@@ -0,0 +1,6 @@ +Allows a process to maipulate the execution priorities +of arbitrary processes: + - those involving different UIDs + - setting their CPU affinity + - alter the FIFO vs. round-robin (realtime) + scheduling for itself and other processes.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/24.txt
Added
@@ -0,0 +1,14 @@ +Allows a process to adjust resource related parameters +of processes and the system: + - set and override resource limits + - override quota limits + - override the reserved space on ext2 filesystem + (this can also be achieved via CAP_FSETID) + - modify the data journaling mode on ext3 filesystem, + which uses journaling resources + - override size restrictions on IPC message queues + - configure more than 64Hz interrupts from the + real-time clock + - override the maximum number of consoles for console + allocation + - override the maximum number of keymaps
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/25.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to perform time manipulation of clocks: + - alter the system clock + - enable irix_stime on MIPS + - set the real-time clock
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/26.txt
Added
@@ -0,0 +1,3 @@ +Allows a process to manipulate tty devices: + - configure tty devices + - perform vhangup() of a tty
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/27.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to perform privileged operations with +the mknod() system call.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/28.txt
Added
@@ -0,0 +1 @@ +Allows a process to take leases on files.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/29.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to write to the audit log via a +unicast netlink socket.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/3.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to perform operations on files, even +where file owner ID should otherwise need be equal to +the UID, except where CAP_FSETID is applicable. It +doesn't override MAC and DAC restrictions.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/30.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to configure audit logging via a +unicast netlink socket.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/31.txt
Added
@@ -0,0 +1,6 @@ +Allows a process to set capabilities on files. +Permits a process to uid_map the uid=0 of the +parent user namespace into that of the child +namespace. Also, permits a process to override +securebits locks through user namespace +creation.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/32.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to override Manditory Access Control +(MAC) access. Not all kernels are configured with a MAC +mechanism, but this is the capability reserved for +overriding them.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/33.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to configure the Mandatory Access +Control (MAC) policy. Not all kernels are configured +with a MAC enabled, but if they are this capability is +reserved for code to perform administration tasks.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/34.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to configure the kernel's syslog +(printk) behavior.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/35.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to trigger something that can wake the +system up.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/36.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to block system suspends - prevent the +system from entering a lower power state.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/37.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to read the audit log via a multicast +netlink socket.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/38.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to enable observability of privileged +operations related to performance. The mechanisms +include perf_events, i915_perf and other kernel +subsystems.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/39.txt
Added
@@ -0,0 +1,33 @@ +Allows a process to manipulate aspects of the kernel +enhanced Berkeley Packet Filter (BPF) system. This is +an execution subsystem of the kernel, that manages BPF +programs. CAP_BPF permits a process to: + - create all types of BPF maps + - advanced verifier features: + - indirect variable access + - bounded loops + - BPF to BPF function calls + - scalar precision tracking + - larger complexity limits + - dead code elimination + - potentially other features + +Other capabilities can be used together with CAP_BFP to +further manipulate the BPF system: + - CAP_PERFMON relaxes the verifier checks as follows: + - BPF programs can use pointer-to-integer + conversions + - speculation attack hardening measures can be + bypassed + - bpf_probe_read to read arbitrary kernel memory is + permitted + - bpf_trace_printk to print the content of kernel + memory + - CAP_SYS_ADMIN permits the following: + - use of bpf_probe_write_user + - iteration over the system-wide loaded programs, + maps, links BTFs and convert their IDs to file + descriptors. + - CAP_PERFMON is required to load tracing programs. + - CAP_NET_ADMIN is required to load networking + programs.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/4.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to set the S_ISUID and S_ISUID bits of +the file permissions, even when the process' effective +UID or GID/supplementary GIDs do not match that of the +file.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/40.txt
Added
@@ -0,0 +1,4 @@ +Allows a process to perform checkpoint +and restore operations. Also permits +explicit PID control via clone3() and +also writing to ns_last_pid.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/5.txt
Added
@@ -0,0 +1,3 @@ +Allows a process to send a kill(2) signal to any other +process - overriding the limitation that there be a +[E]UID match between source and target process.
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/6.txt
Added
@@ -0,0 +1,5 @@ +Allows a process to freely manipulate its own GIDs: + - arbitrarily set the GID, EGID, REGID, RESGID values + - arbitrarily set the supplementary GIDs + - allows the forging of GID credentials passed over a + socket
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/7.txt
Added
@@ -0,0 +1,5 @@ +Allows a process to freely manipulate its own UIDs: + - arbitrarily set the UID, EUID, REUID and RESUID + values + - allows the forging of UID credentials passed over a + socket
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/8.txt
Added
@@ -0,0 +1,24 @@ +Allows a process to freely manipulate its inheritable +capabilities. + +Linux supports the POSIX.1e Inheritable set, the POXIX.1e (X +vector) known in Linux as the Bounding vector, as well as +the Linux extension Ambient vector. + +This capability permits dropping bits from the Bounding +vector (ie. raising B bits in the libcap IAB +representation). It also permits the process to raise +Ambient vector bits that are both raised in the Permitted +and Inheritable sets of the process. This capability cannot +be used to raise Permitted bits, Effective bits beyond those +already present in the process' permitted set, or +Inheritable bits beyond those present in the Bounding +vector. + +[Historical note: prior to the advent of file capabilities +(2008), this capability was suppressed by default, as its +unsuppressed behavior was not auditable: it could +asynchronously grant its own Permitted capabilities to and +remove capabilities from other processes arbitrarily. The +former leads to undefined behavior, and the latter is better +served by the kill system call.]
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/doc/values/9.txt
Added
@@ -0,0 +1,2 @@ +Allows a process to modify the S_IMMUTABLE and +S_APPEND file attributes.
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/.gitignore -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/.gitignore
Changed
@@ -1,5 +1,17 @@ +good-names.go compare-cap +try-launching +try-launching-cgo +psx-signals +psx-signals-cgo +b210613 mknames web -pkg -src +setid +gowns +captree +ok +vendor +go.sum +PSXGOPACKAGE +CAPGOPACKAGE
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/Makefile
Changed
@@ -1,76 +1,146 @@ -# Building the libcap/{cap.psx} Go packages. Note, we use symlinks to -# construct a go friendly src tree. +# Building the libcap/{cap.psx} Go packages, and examples. +# +# Note, we use symlinks to construct a go.mod build friendly tree. The +# packages themselves are intended to be (ultimately) found via proxy +# as "kernel.org/pub/linux/libs/security/libcap/cap" and +# "kernel.org/pub/linux/libs/security/libcap/psx". However, to +# validate their use on these paths, we fake such a structure in the +# build tree with symlinks and a vendor directory. topdir=$(realpath ..) include $(topdir)/Make.Rules -GOPATH=$(realpath .) -PSXGOPACKAGE=pkg/$(GOOSARCH)/libcap/psx.a -CAPGOPACKAGE=pkg/$(GOOSARCH)/libcap/cap.a +IMPORTDIR=kernel.org/pub/linux/libs/security/libcap +PKGDIR=pkg/$(GOOSARCH)/$(IMPORTDIR) DEPS=../libcap/libcap.a ../libcap/libpsx.a +TESTS=compare-cap try-launching psx-signals -all: $(PSXGOPACKAGE) $(CAPGOPACKAGE) web compare-cap +all: PSXGOPACKAGE CAPGOPACKAGE web setid gowns captree $(DEPS): - make -C ../libcap all + $(MAKE) -C ../libcap all -src/libcap/psx: - mkdir -p src/libcap - ln -s $(topdir)/psx src/libcap/ +../progs/tcapsh-static: + $(MAKE) -C ../progs tcapsh-static -src/libcap/cap: - mkdir -p src/libcap - ln -s $(topdir)/cap src/libcap/ +vendor/$(IMPORTDIR) vendor/modules.txt: + mkdir -p "vendor/$(IMPORTDIR)" + echo "# $(IMPORTDIR)/psx v$(GOMAJOR).$(VERSION).$(MINOR)" > vendor/modules.txt + echo "$(IMPORTDIR)/psx" >> vendor/modules.txt + echo "# $(IMPORTDIR)/cap v$(GOMAJOR).$(VERSION).$(MINOR)" >> vendor/modules.txt + echo "$(IMPORTDIR)/cap" >> vendor/modules.txt + +vendor/$(IMPORTDIR)/psx: vendor/modules.txt + ln -sf $(topdir)/psx vendor/$(IMPORTDIR) + touch ../psx + +vendor/$(IMPORTDIR)/cap: vendor/modules.txt + ln -sf $(topdir)/cap vendor/$(IMPORTDIR) + touch ../cap + +$(topdir)/libcap/cap_names.h: + $(MAKE) -C $(topdir)/libcap cap_names.h + +good-names.go: $(topdir)/libcap/cap_names.h vendor/$(IMPORTDIR)/cap mknames.go + CC="$(CC)" $(GO) run -mod=vendor mknames.go --header=$< --textdir=$(topdir)/doc/values | gofmt > $@ || rm -f $@ + diff -u ../cap/names.go $@ -$(topdir)/libcap/cap_names.h: $(DEPS) - make -C $(topdir)/libcap all +PSXGOPACKAGE: vendor/$(IMPORTDIR)/psx ../psx/*.go $(DEPS) + touch $@ -src/libcap/cap/names.go: $(topdir)/libcap/cap_names.h src/libcap/cap mknames.go - go run mknames.go --header=$< | gofmt > $@ || rm -f $@ - -src/libcap/cap/syscalls.go: ./syscalls.sh src/libcap/cap - ./syscalls.sh src/libcap/cap - -$(PSXGOPACKAGE): src/libcap/psx src/libcap/psx/psx.go src/libcap/psx/psx_test.go $(DEPS) - mkdir -p pkg - CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH="$(GOPATH)" go install libcap/psx - -$(CAPGOPACKAGE): src/libcap/cap/syscalls.go src/libcap/cap/names.go src/libcap/cap/cap.go src/libcap/cap/text.go $(PSXGOPACKAGE) - CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(GOPATH) go install libcap/cap +CAPGOPACKAGE: vendor/$(IMPORTDIR)/cap ../cap/*.go good-names.go $(PSXGOPACKAGE) + touch $@ # Compiles something with this package to compare it to libcap. This # tests more when run under sudotest (see ../progs/quicktest.sh for that). -compare-cap: compare-cap.go $(CAPGOPACKAGE) - CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(GOPATH) go build $< +compare-cap: compare-cap.go CAPGOPACKAGE + CC="$(CC)" $(CGO_LDFLAGS_ALLOW) CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build $(GO_BUILD_FLAGS) -mod=vendor $< -web: web.go $(CAPGOPACKAGE) - CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(GOPATH) go build $< +web: ../goapps/web/web.go CAPGOPACKAGE + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) build $(GO_BUILD_FLAGS) -mod=vendor -o $@ $< ifeq ($(RAISE_GO_FILECAP),yes) - make -C ../progs setcap - sudo ../progs/setcap cap_setpcap,cap_net_bind_service=p web - @echo "NOTE: RAISED cap_net_bind_service ON web binary" + $(MAKE) -C ../progs setcap + $(SUDO) ../progs/setcap cap_setpcap,cap_net_bind_service=p web + @echo "NOTE: RAISED cap_setpcap,cap_net_bind_service ON web binary" endif -test: all - CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH="$(GOPATH)" go test libcap/psx - CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(GOPATH) go test libcap/cap - LD_LIBRARY_PATH=../libcap ./compare-cap +setid: ../goapps/setid/setid.go CAPGOPACKAGE PSXGOPACKAGE + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) build $(GO_BUILD_FLAGS) -mod=vendor -o $@ $< + +gowns: ../goapps/gowns/gowns.go CAPGOPACKAGE + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) build $(GO_BUILD_FLAGS) -mod=vendor -o $@ $< + +captree: ../goapps/captree/captree.go CAPGOPACKAGE + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) build $(GO_BUILD_FLAGS) -mod=vendor -o $@ $< + +ok: ok.go + CC="$(CC)" CGO_ENABLED=0 $(GO) build $(GO_BUILD_FLAGS) -mod=vendor $< + +try-launching: try-launching.go CAPGOPACKAGE ok + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) build $(GO_BUILD_FLAGS) -mod=vendor $< +ifeq ($(CGO_REQUIRED),0) + CC="$(CC)" CGO_ENABLED="1" $(CGO_LDFLAGS_ALLOW) $(GO) build $(GO_BUILD_FLAGS) -mod=vendor -o $@-cgo $< +endif -sudotest: test +psx-signals: psx-signals.go PSXGOPACKAGE + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build $(GO_BUILD_FLAGS) -mod=vendor $< + +ifeq ($(CGO_REQUIRED),0) +psx-signals-cgo: psx-signals.go PSXGOPACKAGE + CC="$(CC)" CGO_ENABLED="1" $(CGO_LDFLAGS_ALLOW) CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build $(GO_BUILD_FLAGS) -mod=vendor -o $@ $< +endif + +b210613: b210613.go CAPGOPACKAGE + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build $(GO_BUILD_FLAGS) -mod=vendor $< + +test: setid gowns captree $(TESTS) + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) test -mod=vendor $(IMPORTDIR)/psx + CC="$(CC)" CGO_ENABLED="$(CGO_REQUIRED)" $(CGO_LDFLAGS_ALLOW) $(GO) test -mod=vendor $(IMPORTDIR)/cap + LD_LIBRARY_PATH=../libcap ./compare-cap + ./psx-signals +ifeq ($(CGO_REQUIRED),0) + $(MAKE) psx-signals-cgo + ./psx-signals-cgo +endif + ./setid --caps=false + ./gowns -- -c "echo gowns runs" + ./captree 0 + +# Note, the user namespace doesn't require sudo, but I wanted to avoid +# requiring that the hosting kernel supports user namespaces for the +# regular test case. +sudotest: test ../progs/tcapsh-static b210613 + ../progs/tcapsh-static --has-b=cap_sys_admin || exit 0 && ./gowns --ns -- -c "echo gowns runs with user namespace" + ./try-launching +ifeq ($(CGO_REQUIRED),0) + ./try-launching-cgo +endif + $(SUDO) ./try-launching +ifeq ($(CGO_REQUIRED),0) + $(SUDO) ./try-launching-cgo +endif + $(SUDO) ../progs/tcapsh-static --cap-uid=$$(id -u) --caps="cap_setpcap=ep" --iab="^cap_setpcap" -- -c ./b210613 +# As of libcap-2.55 We stopped installing the cap and psx packages as +# part of the install. Most distribution's packagers skip the Go +# builds, so it was not well used any way. The new hotness is to just +# use Go modules and download the packages from a tagged release in +# the git repository. For an example of how to do this from scratch: +# +# https://sites.google.com/site/fullycapable/getting-started-with-go/building-go-programs-that-manipulate-capabilities +# +# For those brave souls that do include the Go build (testing) as part +# of their packaging, we reward them with a copy of the captree +# utility! install: all - mkdir -p $(FAKEROOT)$(GOPKGDIR)/libcap/psx - rm -f $(FAKEROOT)$(GOPKGDIR)/libcap/psx/* - install -m 0644 src/libcap/psx/* $(FAKEROOT)$(GOPKGDIR)/libcap/psx/ - mkdir -p $(FAKEROOT)$(GOPKGDIR)/libcap/cap - rm -f $(FAKEROOT)$(GOPKGDIR)/libcap/cap/* - install -m 0644 src/libcap/cap/* $(FAKEROOT)$(GOPKGDIR)/libcap/cap/ + mkdir -p -m 0755 $(FAKEROOT)$(SBINDIR) + install -m 0755 captree $(FAKEROOT)$(SBINDIR) clean: - GOPATH=$(GOPATH) go clean -x -i libcap/cap 2> /dev/null || exit 0 - GOPATH=$(GOPATH) go clean -x -i libcap/psx 2> /dev/null || exit 0 - rm -f *.o *.so mknames web compare-cap *~ - rm -f $(topdir)/cap/*~ $(topdir)/cap/names.go $(topdir)/cap/syscalls*.go - rm -f $(topdir)/psx/*~ - rm -fr pkg src + rm -f *.o *.so *~ mknames ok good-names.go + rm -f web setid gowns captree + rm -f compare-cap try-launching try-launching-cgo + rm -f $(topdir)/cap/*~ $(topdir)/psx/*~ + rm -f b210613 psx-signals psx-signals-cgo + rm -fr vendor CAPGOPACKAGE PSXGOPACKAGE go.sum
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/b210613.go
Added
@@ -0,0 +1,21 @@ +// Program b210613 reproduces the code reported in: +// +// https://bugzilla.kernel.org/show_bug.cgi?id=210613 +// +// This file is evolved directly from the reproducer attached to that +// bug report originally authored by Lorenz Bauer. +package main + +import ( + "fmt" + "log" + + "kernel.org/pub/linux/libs/security/libcap/cap" +) + +func main() { + if err := cap.ModeNoPriv.Set(); err != nil { + log.Fatalf("error dropping privilege: %v", err) + } + fmt.Println("b210613: PASSED") +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/cgo-required.sh -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/cgo-required.sh
Changed
@@ -1,11 +1,16 @@ #!/bin/bash # -# Runtime check for whether or not syscall.PerOSThreadSyscall is +# Runtime check for whether or not syscall.AllThreadsSyscall is # available to the working go runtime or not. If it isn't we always # have to use libcap/psx to get POSIX semantics for syscalls that # change security state. +if [ -n "$1" ]; then + export GO="${1}" +else + export GO=go +fi -if [ -z "$(go doc syscall 2>/dev/null|grep PerOSThreadSyscall)" ]; then +if [ -z "$(${GO} doc syscall 2>/dev/null|grep AllThreadsSyscall)" ]; then echo "1" else echo "0"
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/compare-cap.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/compare-cap.go
Changed
@@ -8,7 +8,7 @@ "syscall" "unsafe" - "libcap/cap" + "kernel.org/pub/linux/libs/security/libcap/cap" ) // #include <stdlib.h> @@ -128,10 +128,10 @@ } } -// tryProcCaps performs a set of convenience functions and compares the -// results with those seen by libcap. At the end of this function, the -// running process has no privileges at all. So exiting is the only -// option. +// tryProcCaps performs a set of convenience functions and compares +// the results with those seen by libcap. At the end of this function, +// the running process has no privileges at all. So exiting the +// program is the only option. func tryProcCaps() { c := cap.GetProc() if v, err := c.GetFlag(cap.Permitted, cap.SETPCAP); err != nil { @@ -173,7 +173,7 @@ for i, mode := range []cap.Mode{cap.ModePure1E, cap.ModePure1EInit, cap.ModeNoPriv} { if err := mode.Set(); err != nil { - log.Fatalf("[%d] failed to set mode to %d (%v): %v", i, mode, mode, err) + log.Fatalf("[%d] in mode=%v and failed to set mode to %d (%v): %v", i, cap.GetMode(), mode, mode, err) } if got := cap.GetMode(); got != mode { log.Fatalf("[%d] unable to recognise mode %d (%v), got: %d (%v)", i, mode, mode, got, got) @@ -184,7 +184,7 @@ } } - // The current process is now without any access to privelege. + // The current process is now without any access to privilege. } func main() { @@ -257,12 +257,12 @@ } // Validate that it can be imported in binary in C - iC := C.cap_copy_int(unsafe.Pointer(&iE[0])) + iC := C.cap_copy_int_check(unsafe.Pointer(&iE[0]), C.ssize_t(len(iE))) if iC == nil { log.Fatal("c failed to import go binary") } defer C.cap_free(unsafe.Pointer(iC)) - fC := C.cap_to_text(cC, &tCLen) + fC := C.cap_to_text(iC, &tCLen) if fC == nil { log.Fatal("basic c init caps -> text failure") } @@ -281,13 +281,104 @@ log.Fatalf("all decode failed in Go: got=%q, want=%q", got, want) } + // Validate some random values stringify consistently between + // libcap.cap_to_text() and (*cap.Set).String(). + mb := cap.MaxBits() + sample := cap.NewSet() + for c := cap.Value(0); c < 7*mb; c += 3 { + n := int(c) + raise, f := c%mb, cap.Flag(c/mb)%3 + sample.SetFlag(f, true, raise) + if v, err := cap.FromText(sample.String()); err != nil { + log.Fatalf("[%d] cap to text for %q not reversible: %v", n, sample, err) + } else if cf, err := v.Compare(sample); err != nil { + log.Fatalf("[%d] FromText generated bad capability from %q: %v", n, sample, err) + } else if cf != 0 { + log.Fatalf("[%d] text import got=%q want=%q", n, v, sample) + } + e, err := sample.Export() + if err != nil { + log.Fatalf("[%d] failed to export %q: %v", n, sample, err) + } + i, err := cap.Import(e) + if err != nil { + log.Fatalf("[%d] failed to import %q: %v", n, sample, err) + } + if cf, err := i.Compare(sample); err != nil { + log.Fatalf("[%d] failed to compare %q vs original:%q", n, i, sample) + } else if cf != 0 { + log.Fatalf("[%d] import got=%q want=%q", n, i, sample) + } + // Confirm that importing this portable binary + // representation in libcap and converting to text, + // generates the same text as Go generates. This was + // broken prior to v0.2.41. + cCap := C.cap_copy_int(unsafe.Pointer(&e[0])) + if cCap == nil { + log.Fatalf("[%d] C import failed for %q export", n, sample) + } + var tCLen C.ssize_t + tC := C.cap_to_text(cCap, &tCLen) + if tC == nil { + log.Fatalf("[%d] basic c init caps -> text failure", n) + } + C.cap_free(unsafe.Pointer(cCap)) + importT := C.GoString(tC) + C.cap_free(unsafe.Pointer(tC)) + if got, want := len(importT), int(tCLen); got != want { + log.Fatalf("[%d] C text generated wrong length: Go=%d, C=%d", n, got, want) + } + if got, want := importT, sample.String(); got != want { + log.Fatalf("[%d] C and Go text rep disparity: C=%q Go=%q", n, got, want) + } + } + + iab, err := cap.IABFromText("cap_chown,!cap_setuid,^cap_setgid") + if err != nil { + log.Fatalf("failed to initialize iab from text: %v", err) + } + cIAB := C.cap_iab_init() + defer C.cap_free(unsafe.Pointer(cIAB)) + for c := cap.MaxBits(); c > 0; { + c-- + if en, err := iab.GetVector(cap.Inh, c); err != nil { + log.Fatalf("failed to read iab.i[%v]", c) + } else if en { + if C.cap_iab_set_vector(cIAB, C.CAP_IAB_INH, C.cap_value_t(int(c)), C.CAP_SET) != 0 { + log.Fatalf("failed to set C's AIB.I %v: %v", c) + } + } + if en, err := iab.GetVector(cap.Amb, c); err != nil { + log.Fatalf("failed to read iab.a[%v]", c) + } else if en { + if C.cap_iab_set_vector(cIAB, C.CAP_IAB_AMB, C.cap_value_t(int(c)), C.CAP_SET) != 0 { + log.Fatalf("failed to set C's AIB.A %v: %v", c) + } + } + if en, err := iab.GetVector(cap.Bound, c); err != nil { + log.Fatalf("failed to read iab.b[%v]", c) + } else if en { + if C.cap_iab_set_vector(cIAB, C.CAP_IAB_BOUND, C.cap_value_t(int(c)), C.CAP_SET) != 0 { + log.Fatalf("failed to set C's AIB.B %v: %v", c) + } + } + } + iabC := C.cap_iab_to_text(cIAB) + if iabC == nil { + log.Fatalf("failed to get text from C for %q", iab) + } + defer C.cap_free(unsafe.Pointer(iabC)) + if got, want := C.GoString(iabC), iab.String(); got != want { + log.Fatalf("IAB for Go and C differ: got=%q, want=%q", got, want) + } + // Next, we attempt to manipulate some file capabilities on // the running program. These are optional, based on whether // the current program is capable enough and do not involve // any cgo calls to libcap. tryFileCaps() - tryProcCaps() - // Since we have no privilege, there is nothing left to do but exit. + // Nothing left to do but exit after this one. + tryProcCaps() log.Printf("compare-cap success!") }
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/go-mod-index.html
Added
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> +<meta name="go-import" content="kernel.org/pub/linux/libs/security/libcap git https://git.kernel.org/pub/scm/libs/libcap/libcap.git"> +<meta http-equiv="refresh" content="10; url=https://sites.google.com/site/fullycapable"> +</head> +<body> + Redirecting in 10 seconds to + the <a href="https://sites.google.com/site/fullycapable">Fully + Capable</a> project page, the home of these Go packages: + <ul> + <li><tt>"kernel.org/pub/linux/libs/security/libcap/psx"</tt></li> + <li><tt>"kernel.org/pub/linux/libs/security/libcap/cap"</tt></li> +</body> +</html>
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/go.mod
Added
@@ -0,0 +1,8 @@ +module main + +go 1.11 + +require ( + kernel.org/pub/linux/libs/security/libcap/cap v1.2.61 + kernel.org/pub/linux/libs/security/libcap/psx v1.2.61 +)
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/go/mknames.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/mknames.go
Changed
@@ -1,4 +1,6 @@ -// Program mknames parses the cap_names.h file and creates an equivalent names.go file. +// Program mknames parses the cap_names.h file and creates an +// equivalent names.go file including comments on each cap.Value from +// the documentation directory. package main import ( @@ -13,6 +15,7 @@ var ( header = flag.String("header", "", "name of header file") + text = flag.String("textdir", "", "directory name for value txt files") ) func main() { @@ -49,17 +52,52 @@ /* ** DO NOT EDIT THIS FILE. IT WAS AUTO-GENERATED BY LIBCAP'S GO BUILDER (mknames.go) ** */ -// NamedCount holds the number of capabilities with official names. +// NamedCount holds the number of capability values with official +// names known at the time this libcap/cap version, was released. The +// "../libcap/cap" package is fully able to manipulate higher numbered +// capability values by numerical value. However, if you find +// cap.NamedCount < cap.MaxBits(), it is probably time to upgrade this +// package on your system. +// +// FWIW the userspace tool '/sbin/capsh' also contains a runtime check +// for the condition that libcap is behind the running kernel in this +// way. const NamedCount = `, len(list), ` -// CHOWN etc., are the named capability bits on this system. The -// canonical source for each name is the "uapi/linux/capabilities.h" -// file, which is hard-coded into this package. +// CHOWN etc., are the named capability values of the Linux +// kernel. The canonical source for each name is the +// "uapi/linux/capabilities.h" file. Some values may not be available +// (yet) where the kernel is older. The actual number of capabities +// supported by the running kernel can be obtained using the +// cap.MaxBits() function. const ( `) bits := make(map[string]string) for i, name := range list { + doc := fmt.Sprintf("%s/%d.txt", *text, i) + content, err := ioutil.ReadFile(doc) + if err != nil { + log.Fatalf("filed to read %q: %v", doc, err) + } + detail := strings.Split(strings.Replace(string(content), "CAP_", "cap.", -1), "\n") + if i != 0 { + fmt.Println() + } v := strings.ToUpper(strings.TrimPrefix(name, "cap_")) + for j, line := range detail { + preamble := "" + offset := 0 + if j == 0 { + if !strings.HasPrefix(line, "Allows ") { + log.Fatalf("line should begin \"Allows \": got %s:%d:%q", doc, j, line) + } + preamble = fmt.Sprint(v, " a") + offset = 1 + } + if len(line) != 0 || j != len(detail)-1 { + fmt.Printf(" // %s%s\n", preamble, line[offset:]) + } + } bits[name] = v if i == 0 { fmt.Println(v, " Value = iota")
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/ok.go
Added
@@ -0,0 +1,9 @@ +// Program ok exits with status zero. We use it as a chroot test. +// To avoid any confusion, it needs to be linked statically. +package main + +import "os" + +func main() { + os.Exit(0) +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/psx-signals.go
Added
@@ -0,0 +1,46 @@ +// Program psx-signals validates that the psx mechanism can coexist +// with Go use of signals. This is an unprivilaged program derived +// from the sample code provided in this bug report: +// +// https://bugzilla.kernel.org/show_bug.cgi?id=210533 +package main + +import ( + "fmt" + "log" + "os" + "os/signal" + "syscall" + "time" + + "kernel.org/pub/linux/libs/security/libcap/psx" +) + +const maxSig = 10 +const prSetKeepCaps = 8 + +func main() { + sig := make(chan os.Signal, maxSig) + signal.Notify(sig, os.Interrupt) + + fmt.Print("Toggling KEEP_CAPS ") + for i := 0; i < maxSig; i++ { + fmt.Print(".") + _, _, err := psx.Syscall3(syscall.SYS_PRCTL, prSetKeepCaps, uintptr(i&1), 0) + if err != 0 { + log.Fatalf("[%d] attempt to set KEEPCAPS (to %d) failed: %v", i, i%2, err) + } + } + + fmt.Println(" done") + fmt.Print("Wait 1 second to see if unwanted signals arrive...") + // Confirm no signals are delivered. + select { + case <-time.After(1 * time.Second): + break + case info := <-sig: + log.Fatalf("signal received: %v", info) + } + fmt.Println(" none arrived") + fmt.Println("PASSED") +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/go/try-launching.go
Added
@@ -0,0 +1,116 @@ +// Program try-launching validates the cap.Launch feature. +package main + +import ( + "fmt" + "log" + "strings" + "syscall" + + "kernel.org/pub/linux/libs/security/libcap/cap" +) + +// tryLaunching attempts to launch a bunch of programs in parallel. It +// first tries some unprivileged launches, and then (if privileged) +// tries some more ambitious ones. +func tryLaunching() { + cwd, err := syscall.Getwd() + if err != nil { + log.Fatalf("no working directory: %v", err) + } + root := cwd[:strings.LastIndex(cwd, "/")] + + hasSysAdmin, _ := cap.GetBound(cap.SYS_ADMIN) + + vs := []struct { + args []string + fail bool + callbackFn func(*syscall.ProcAttr, interface{}) error + chroot string + iab string + uid int + gid int + mode cap.Mode + groups []int + }{ + {args: []string{root + "/go/ok"}}, + { + args: []string{root + "/progs/tcapsh-static", "--dropped=cap_chown", "--is-uid=123", "--is-gid=456", "--has-a=cap_setuid"}, + iab: "!cap_chown,^cap_setuid,cap_sys_admin", + uid: 123, + gid: 456, + groups: []int{1, 2, 3}, + fail: syscall.Getuid() != 0 || !hasSysAdmin, + }, + { + args: []string{"/ok"}, + 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)) + ws := make([]syscall.WaitStatus, len(vs)) + + for i, v := range vs { + e := cap.NewLauncher(v.args[0], v.args, nil) + e.Callback(v.callbackFn) + if v.chroot != "" { + e.SetChroot(v.chroot) + } + if v.uid != 0 { + e.SetUID(v.uid) + } + 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) + } else { + 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 + } + log.Fatalf("[%d] launch %q failed: %v", i, v.args, err) + } + } + + for i, p := range ps { + if p == -1 { + continue + } + if pr, err := syscall.Wait4(p, &ws[i], 0, nil); err != nil { + log.Fatalf("wait4 <%d> failed: %v", p, err) + } else if p != pr { + log.Fatalf("wait4 <%d> returned <%d> instead", p, pr) + } else if ws[i] != 0 { + if vs[i].fail { + continue + } + log.Fatalf("wait4 <%d> status was %d", p, ws[i]) + } + } +} + +func main() { + if cap.LaunchSupported { + // The Go runtime had some OS threading bugs that + // prevented Launch from working. Specifically, the + // launch OS thread would get reused. + tryLaunching() + } + fmt.Println("PASSED") +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/captree
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/captree/captree.go
Added
@@ -0,0 +1,463 @@ +// Program captree explores a process tree rooted in the supplied +// argument(s) and displays a process tree indicating the capabilities +// of all the dependent PID values. +// +// This was inspired by the pstree utility. The key idea here, however, +// is to explore a process tree for capability state. +// +// Each line of output is intended to capture a brief representation +// of the capability state of a process (both *Set and *IAB) and +// for its related threads. +// +// Ex: +// +// $ bash -c 'exec captree $$' +// --captree(9758+{9759,9760,9761,9762}) +// +// In the normal case, such as the above, where the targeted process +// is not privileged, no distracting capability strings are displayed. +// Where a process is thread group leader to a set of other thread +// ids, they are listed as `+{...}`. +// +// For privileged binaries, we have: +// +// $ captree 551 +// --polkitd(551) "=ep" +// :>-gmain{552} "=ep" +// :>-gdbus{555} "=ep" +// +// That is, the text representation of the process capability state is +// displayed in double quotes "..." as a suffix to the process/thread. +// If the name of any thread of this process, or its own capability +// state, is in some way different from the primary process then it is +// displayed on a subsequent line prefixed with ":>-" and threads +// sharing name and capability state are listed on that line. Here we +// have two sub-threads with the same capability state, but unique +// names. +// +// Sometimes members of a process group have different capabilities: +// +// $ captree 1368 +// --dnsmasq(1368) "cap_net_bind_service,cap_net_admin,cap_net_raw=ep" +// +-dnsmasq(1369) "=ep" +// +// Where the A and B components of the IAB tuple are non-default, the +// output also includes these: +// +// $ captree 925 +// --dbus-broker-lau(925) [!cap_sys_rawio,!cap_mknod] +// +-dbus-broker(965) "cap_audit_write=eip" [!cap_sys_rawio,!cap_mknod,cap_audit_write] +// +// That is, the `[...]` appendage captures the IAB text representation +// of that tuple. Note, if only the I part of that tuple is +// non-default, it is already captured in the quoted process +// capability state, so the IAB tuple is omitted. +// +// To view the complete system process map, rooted at the kernel, try +// this: +// +// $ captree 0 +// +// To view a specific binary (as named in /proc/<PID>/status as 'Name: +// ...'), matched by a glob, try this: +// +// $ captree 'cap*ree' +// +// The quotes might be needed to avoid the '*' confusing your shell. +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + + "kernel.org/pub/linux/libs/security/libcap/cap" +) + +var ( + proc = flag.String("proc", "/proc", "root of proc filesystem") + depth = flag.Int("depth", 0, "how many processes deep (0=all)") + verbose = flag.Bool("verbose", false, "display empty capabilities") + color = flag.Bool("color", true, "color targeted PIDs on tty in red") + colour = flag.Bool("colour", true, "colour targeted PIDs on tty in red") +) + +type task struct { + mu sync.Mutex + viewed bool + depth int + pid string + cmd string + cap *cap.Set + iab *cap.IAB + parent string + threads []*task + children []string +} + +func (ts *task) String() string { + return fmt.Sprintf("%s %q [%v] %s %v %v", ts.cmd, ts.cap, ts.iab, ts.parent, ts.threads, ts.children) +} + +var ( + wg sync.WaitGroup + mu sync.Mutex + colored bool +) + +func isATTY() bool { + s, err := os.Stdout.Stat() + if err == nil && (s.Mode()&os.ModeCharDevice) != 0 { + return true + } + return false +} + +func highlight(text string) string { + if colored { + return fmt.Sprint("\033[31m", text, "\033[0m") + } + return text +} + +func (ts *task) fill(pid string, n int, thread bool) { + defer wg.Done() + wg.Add(1) + go func() { + defer wg.Done() + c, _ := cap.GetPID(n) + iab, _ := cap.IABGetPID(n) + ts.mu.Lock() + defer ts.mu.Unlock() + ts.pid = pid + ts.cap = c + ts.iab = iab + }() + + d, err := ioutil.ReadFile(fmt.Sprintf("%s/%s/status", *proc, pid)) + if err != nil { + ts.mu.Lock() + defer ts.mu.Unlock() + ts.cmd = "<zombie>" + ts.parent = "1" + return + } + for _, line := range strings.Split(string(d), "\n") { + if strings.HasPrefix(line, "Name:\t") { + ts.mu.Lock() + ts.cmd = line[6:] + ts.mu.Unlock() + continue + } + if strings.HasPrefix(line, "PPid:\t") { + ppid := line[6:] + if ppid == pid { + continue + } + ts.mu.Lock() + ts.parent = ppid + ts.mu.Unlock() + } + } + if thread { + return + } + + threads, err := ioutil.ReadDir(fmt.Sprintf("%s/%s/task", *proc, pid)) + if err != nil { + return + } + var ths []*task + for _, t := range threads { + tid := t.Name() + if tid == pid { + continue + } + n, err := strconv.ParseInt(pid, 10, 64) + if err != nil { + continue + } + thread := &task{} + wg.Add(1) + go thread.fill(tid, int(n), true) + ths = append(ths, thread) + } + ts.mu.Lock() + defer ts.mu.Unlock() + ts.threads = ths +} + +var empty = cap.NewSet() +var noiab = cap.IABInit() +
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/captree/go.mod
Added
@@ -0,0 +1,5 @@ +module captree + +go 1.16 + +require kernel.org/pub/linux/libs/security/libcap/cap v1.2.61
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/gowns
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/gowns/go.mod
Added
@@ -0,0 +1,5 @@ +module gowns + +go 1.15 + +require kernel.org/pub/linux/libs/security/libcap/cap v1.2.61
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/gowns/gowns.go
Added
@@ -0,0 +1,253 @@ +// Program gowns is a small program to explore and demonstrate using +// Go to Wrap a child in a NameSpace under Linux. +// +// Note, this program is under active development and should not be +// considered stable. That is, it is more a worked example and may +// change command line arguments and behavior from release to release. +// Should it become stable, I'll remove this comment. +package main + +import ( + "errors" + "flag" + "fmt" + "log" + "os" + "strings" + "syscall" + + "kernel.org/pub/linux/libs/security/libcap/cap" +) + +// nsDetail is how we summarize the type of namespace we want to +// enter. +type nsDetail struct { + // uid holds the uid for the base user in this namespace (defaults to getuid). + uid int + + // uidMap holds the namespace mapping of uid values. + uidMap []syscall.SysProcIDMap + + // gid holds the gid for the base user in this namespace (defaults to getgid). + gid int + + // uidMap holds the namespace mapping of gid values. + gidMap []syscall.SysProcIDMap +} + +var ( + baseID = flag.Int("base", -1, "base id for uids and gids (-1 = invoker's uid)") + uid = flag.Int("uid", -1, "uid of the hosting user") + gid = flag.Int("gid", -1, "gid of the hosting user") + iab = flag.String("iab", "", "IAB string for inheritable capabilities") + mode = flag.String("mode", "", "force a libcap mode (capsh --modes for list)") + + ns = flag.Bool("ns", false, "enable user namespace features") + uids = flag.String("uids", "", "comma separated UID ranges to map contiguously (req. CAP_SETUID)") + gids = flag.String("gids", "", "comma separated GID ranges to map contiguously (req. CAP_SETGID)") + + shell = flag.String("shell", "/bin/bash", "shell to be launched") + debug = flag.Bool("verbose", false, "more verbose output") +) + +// r holds a base and count for a contiguous range. +type r struct { + base, count int +} + +// ranges unpacks numerical ranges. +func ranges(s string) []r { + if s == "" { + return nil + } + var rs []r + for _, n := range strings.Split(s, ",") { + var base, upper int + if _, err := fmt.Sscanf(n, "%d-%d", &base, &upper); err == nil { + if upper < base { + log.Fatalf("invalid range: [%d-%d]", base, upper) + } + rs = append(rs, r{ + base: base, + count: 1 + upper - base, + }) + } else if _, err := fmt.Sscanf(n, "%d", &base); err == nil { + rs = append(rs, r{ + base: base, + count: 1, + }) + } else { + log.Fatalf("unable to parse range [%s]", n) + } + } + return rs +} + +// restart launches the program again with the remaining arguments. +func restart() { + log.Fatalf("failed to restart: flags: %q %q", os.Args[0], flag.Args()[1:]) +} + +// errUnableToSetup is how nsSetup fails. +var errUnableToSetup = errors.New("data was not in supported format") + +// nsSetup is the callback used to enter the namespace for the user +// via callback in the cap.Launcher mechanism. +func nsSetup(pa *syscall.ProcAttr, data interface{}) error { + nsD, ok := data.(nsDetail) + if !ok { + return errUnableToSetup + } + + if pa.Sys == nil { + pa.Sys = &syscall.SysProcAttr{} + } + pa.Sys.Cloneflags |= syscall.CLONE_NEWUSER + pa.Sys.UidMappings = nsD.uidMap + pa.Sys.GidMappings = nsD.gidMap + return nil +} + +func parseRanges(detail *nsDetail, ids string, id int) []syscall.SysProcIDMap { + base := *baseID + if base < 0 { + base = detail.uid + } + + list := []syscall.SysProcIDMap{ + syscall.SysProcIDMap{ + ContainerID: base, + HostID: id, + Size: 1, + }, + } + + base++ + for _, next := range ranges(ids) { + list = append(list, + syscall.SysProcIDMap{ + ContainerID: base, + HostID: next.base, + Size: next.count, + }) + base += next.count + } + return list +} + +func main() { + flag.Parse() + + detail := nsDetail{ + gid: syscall.Getgid(), + } + + thisUID := syscall.Getuid() + switch *uid { + case -1: + detail.uid = thisUID + default: + detail.uid = *uid + } + detail.uidMap = parseRanges(&detail, *uids, detail.uid) + + thisGID := syscall.Getgid() + switch *gid { + case -1: + detail.gid = thisGID + default: + detail.gid = *gid + } + detail.gidMap = parseRanges(&detail, *gids, detail.gid) + + unparsed := flag.Args() + + arg0 := *shell + skip := 0 + var w *cap.Launcher + if len(unparsed) > 0 { + switch unparsed[0] { + case "==": + arg0 = os.Args[0] + skip++ + } + } + + w = cap.NewLauncher(arg0, append([]string{arg0}, unparsed[skip:]...), nil) + if *ns { + // Include the namespace setup callback with the launcher. + w.Callback(nsSetup) + } + + if thisUID != detail.uid { + w.SetUID(detail.uid) + } + + if thisGID != detail.gid { + w.SetGroups(detail.gid, nil) + } + + if *iab != "" { + ins, err := cap.IABFromText(*iab) + if err != nil { + log.Fatalf("--iab=%q parsing issue: %v", err) + } + w.SetIAB(ins) + } + + if *mode != "" { + for m := cap.Mode(1); ; m++ {
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/setid
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/setid/go.mod
Added
@@ -0,0 +1,8 @@ +module setid + +go 1.11 + +require ( + kernel.org/pub/linux/libs/security/libcap/cap v1.2.61 + kernel.org/pub/linux/libs/security/libcap/psx v1.2.61 +)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/setid/setid.go
Added
@@ -0,0 +1,151 @@ +// Program setid demonstrates how the to use the cap and/or psx packages to +// change the uid, gids of a program. +// +// A long writeup explaining how to use it in various different ways +// is available: +// +// https://sites.google.com/site/fullycapable/Home/using-go-to-set-uid-and-gids +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "strconv" + "strings" + "syscall" + "unsafe" + + "kernel.org/pub/linux/libs/security/libcap/cap" + "kernel.org/pub/linux/libs/security/libcap/psx" +) + +var ( + uid = flag.Int("uid", -1, "specify a uid with a value other than (euid)") + gid = flag.Int("gid", -1, "specify a gid with a value other than (egid)") + drop = flag.Bool("drop", true, "drop privilege once IDs have been changed") + suppl = flag.String("suppl", "", "comma separated list of groups") + withCaps = flag.Bool("caps", true, "raise capabilities to setuid/setgid") +) + +// setIDWithCaps uses the cap.SetUID and cap.SetGroups functions. +func setIDsWithCaps(setUID, setGID int, gids []int) { + if err := cap.SetGroups(setGID, gids...); err != nil { + log.Fatalf("group setting failed: %v", err) + } + if err := cap.SetUID(setUID); err != nil { + log.Fatalf("user setting failed: %v", err) + } +} + +func main() { + flag.Parse() + + showIDs("before", false, syscall.Getuid(), syscall.Getgid()) + + gids := splitToInts() + setGID := *gid + if *gid == -1 { + setGID = syscall.Getegid() + } + setUID := *uid + if *uid == -1 { + setUID = syscall.Getuid() + } + + if *withCaps { + setIDsWithCaps(setUID, setGID, gids) + } else { + if _, _, err := psx.Syscall3(syscall.SYS_SETGID, uintptr(setGID), 0, 0); err != 0 { + log.Fatalf("failed to setgid(%d): %v", setGID, err) + } + if len(gids) != 0 { + gids32 := []int32{int32(setGID)} + for _, g := range gids { + gids32 = append(gids32, int32(g)) + } + if _, _, err := psx.Syscall3(syscall.SYS_SETGROUPS, uintptr(unsafe.Pointer(&gids32[0])), 0, 0); err != 0 { + log.Fatalf("failed to setgroups(%d, %v): %v", setGID, gids32, err) + } + } + if _, _, err := psx.Syscall3(syscall.SYS_SETUID, uintptr(setUID), 0, 0); err != 0 { + log.Fatalf("failed to setgid(%d): %v", setUID, err) + } + } + + if *drop { + if err := cap.NewSet().SetProc(); err != nil { + log.Fatalf("unable to drop privilege: %v", err) + } + } + + showIDs("after", true, setUID, setGID) +} + +// splitToInts parses a comma separated string to a slice of integers. +func splitToInts() (ret []int) { + if *suppl == "" { + return + } + a := strings.Split(*suppl, ",") + for _, s := range a { + n, err := strconv.Atoi(s) + if err != nil { + log.Fatalf("bad supplementary group [%q]: %v", s, err) + } + ret = append(ret, n) + } + return +} + +// dumpStatus explores the current process /proc/task/* status files +// for matching values. +func dumpStatus(testCase string, validate bool, filter, expect string) bool { + fmt.Printf("%s:\n", testCase) + var failed bool + pid := syscall.Getpid() + fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid)) + if err != nil { + log.Fatal(err) + } + for _, f := range fs { + tf := fmt.Sprintf("/proc/%s/status", f.Name()) + d, err := ioutil.ReadFile(tf) + if err != nil { + fmt.Println(tf, err) + failed = true + continue + } + lines := strings.Split(string(d), "\n") + for _, line := range lines { + if strings.HasPrefix(line, filter) { + fails := line != expect + failure := "" + if fails && validate { + failed = fails + failure = " (bad)" + } + fmt.Printf("%s %s%s\n", tf, line, failure) + break + } + } + } + return failed +} + +// showIDs dumps the thread map out of the /proc/<proc>/tasks +// filesystem to confirm that all of the threads associated with the +// process have the same uid/gid values. Note, the code does not +// attempt to validate the supplementary groups at present. +func showIDs(test string, validate bool, wantUID, wantGID int) { + fmt.Printf("%s capability state: %q\n", test, cap.GetProc()) + + failed := dumpStatus(test+" gid", validate, "Gid:", fmt.Sprintf("Gid:\t%d\t%d\t%d\t%d", wantGID, wantGID, wantGID, wantGID)) + + failed = dumpStatus(test+" uid", validate, "Uid:", fmt.Sprintf("Uid:\t%d\t%d\t%d\t%d", wantUID, wantUID, wantUID, wantUID)) || failed + + if validate && failed { + log.Fatal("did not observe desired *id state") + } +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/web
Added
+(directory)
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/web/README
Added
@@ -0,0 +1,18 @@ +This sample program needs to be built as follows (when built with Go +prior to 1.15): + + CGO_LDFLAGS_ALLOW="-Wl,-?-wrap[=,][^-.@][^,]*" go build web.go + +go1.15+ does not require the CGO_LDFLAGS_ALLOW variable and can build +this code with + + go build web.go + +A more complete walk through of what this code does is provided here: + + https://sites.google.com/site/fullycapable/getting-started-with-go/building-go-programs-that-manipulate-capabilities + +Go compilers prior to go1.11.13 are not expected to work. Report more +recent issues to: + + https://bugzilla.kernel.org/buglist.cgi?component=libcap&list_id=1065141&product=Tools&resolution=---
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/web/go.mod
Added
@@ -0,0 +1,5 @@ +module web + +go 1.11 + +require kernel.org/pub/linux/libs/security/libcap/cap v1.2.61
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/goapps/web/web.go
Added
@@ -0,0 +1,130 @@ +// Program web provides an example of a webserver using capabilities to +// bind to a privileged port, and then drop all capabilities before +// handling the first web request. +// +// This program can be compiled CGO_ENABLED=0 with the go1.16+ +// toolchain. +// +// Go versions prior to 1.16 use some cgo support provided by the +// "kernel.org/pub/linux/libs/security/libcap/psx" package. +// +// To set this up, compile and empower this binary as follows (the +// README contains a pointer to a full writeup for building this +// package - go versions prior to 1.15 need some environment variable +// workarounds): +// +// go build web.go +// sudo setcap cap_setpcap,cap_net_bind_service=p web +// ./web --port=80 +// +// Make requests using wget and observe the log of web: +// +// wget -o/dev/null -O/dev/stdout localhost:80 +package main + +import ( + "flag" + "fmt" + "log" + "net" + "net/http" + "runtime" + "syscall" + + "kernel.org/pub/linux/libs/security/libcap/cap" +) + +var ( + port = flag.Int("port", 0, "port to listen on") + skipPriv = flag.Bool("skip", false, "skip raising the effective capability - will fail for low ports") +) + +// ensureNotEUID aborts the program if it is running setuid something, +// or being invoked by root. That is, the preparer isn't setting up +// the program correctly. +func ensureNotEUID() { + euid := syscall.Geteuid() + uid := syscall.Getuid() + egid := syscall.Getegid() + gid := syscall.Getgid() + if uid != euid || gid != egid { + log.Fatalf("go runtime is setuid uids:(%d vs %d), gids(%d vs %d)", uid, euid, gid, egid) + } + if uid == 0 { + log.Fatalf("go runtime is running as root - cheating") + } +} + +// listen creates a listener by raising effective privilege only to +// bind to address and then lowering that effective privilege. +func listen(network, address string) (net.Listener, error) { + if *skipPriv { + return net.Listen(network, address) + } + + orig := cap.GetProc() + defer orig.SetProc() // restore original caps on exit. + + c, err := orig.Dup() + if err != nil { + return nil, fmt.Errorf("failed to dup caps: %v", err) + } + + if on, _ := c.GetFlag(cap.Permitted, cap.NET_BIND_SERVICE); !on { + return nil, fmt.Errorf("insufficient privilege to bind to low ports - want %q, have %q", cap.NET_BIND_SERVICE, c) + } + + if err := c.SetFlag(cap.Effective, true, cap.NET_BIND_SERVICE); err != nil { + return nil, fmt.Errorf("unable to set capability: %v", err) + } + + if err := c.SetProc(); err != nil { + return nil, fmt.Errorf("unable to raise capabilities %q: %v", c, err) + } + return net.Listen(network, address) +} + +// Handler is used to abstract the ServeHTTP function. +type Handler struct{} + +// ServeHTTP says hello from a single Go hardware thread and reveals +// its capabilities. +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + runtime.LockOSThread() + // Get some numbers consistent to the current execution, so + // the returned web page demonstrates that the code execution + // is bouncing around on different kernel thread ids. + p := syscall.Getpid() + t := syscall.Gettid() + c := cap.GetProc() + runtime.UnlockOSThread() + + log.Printf("Saying hello from proc: %d->%d, caps=%q", p, t, c) + fmt.Fprintf(w, "Hello from proc: %d->%d, caps=%q\n", p, t, c) +} + +func main() { + flag.Parse() + + if *port == 0 { + log.Fatal("please supply --port value") + } + + ensureNotEUID() + + ls, err := listen("tcp", fmt.Sprintf(":%d", *port)) + if err != nil { + log.Fatalf("aborting: %v", err) + } + defer ls.Close() + + if !*skipPriv { + if err := cap.ModeNoPriv.Set(); err != nil { + log.Fatalf("unable to drop all privilege: %v", err) + } + } + + if err := http.Serve(ls, &Handler{}); err != nil { + log.Fatalf("server failed: %v", err) + } +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/gomods.sh
Added
@@ -0,0 +1,11 @@ +#!/bin/bash + +version="${1}" +if [[ -z "${version}" ]]; then + echo "usage: supply a cap/psx module version to target" + exit 1 +fi + +for x in $(find . -name 'go.mod'); do + sed -i -e 's@kernel.org/\([^ ]*\) v.*$@kernel.org/\1 '"${version}@" "${x}" +done
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/kdebug/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/kdebug/Makefile
Changed
@@ -1,9 +1,17 @@ topdir=$(shell pwd)/.. include ../Make.Rules -test: +test: exit + rm -f interactive ./test-kernel.sh +shell: exit + touch interactive + ./test-kernel.sh + +exit: exit.c + $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ --static + all: @echo cd to kdebug to test a kernel build @@ -11,4 +19,4 @@ clean: $(LOCALCLEAN) - rm -f fs.conf initramfs.img + rm -f fs.conf initramfs.img exit interactive
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/kdebug/exit.c
Added
@@ -0,0 +1,36 @@ +/* + * See https://stackoverflow.com/questions/42208228/how-to-automatically-close-the-execution-of-the-qemu-after-end-of-process + */ +#include <stdio.h> +#include <stdlib.h> +#include <sys/io.h> +#include <unistd.h> + +#define SHUTDOWN_PORT 0x604 +#define EXIT_PORT 0x501 + +static void clean_exit(void) { + ioperm(SHUTDOWN_PORT, 16, 1); + outw(0x2000, SHUTDOWN_PORT); +} + +int main(int argc, char **argv) { + int status; + if (argc != 2) { + clean_exit(); + } + status = atoi(argv[1]); + printf("exiting with status %d (in three seconds)\n", status); + sleep(3); + if (!status) { + clean_exit(); + } + ioperm(EXIT_PORT, 8, 1); + /* + * status returned is 1+(2*orig_status) + */ + outb(status-1, EXIT_PORT); + printf("didn't exit.. did you include '-device isa-debug-exit'" + " in qemu command?\n"); + exit(1); +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/kdebug/test-init.sh -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/kdebug/test-init.sh
Changed
@@ -10,5 +10,10 @@ echo Hello, World cd /root -./quicktest.sh -sh -i +if [ -f ./interactive ]; then + ./quicktest.sh + sh -i +else + ./quicktest.sh || ./exit 1 +fi +./exit
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/kdebug/test-kernel.sh -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/kdebug/test-kernel.sh
Changed
@@ -13,7 +13,9 @@ } pushd .. -make || die "failed to make libcap tree" +make all test || die "failed to make all test of libcap tree" +make -C progs tcapsh-static || die "failed to make progs/tcapsh-static" +make -C tests uns_test popd # Assumes desired make *config (eg. make defconfig) is already done. @@ -45,9 +47,22 @@ file /root/getcap $HERE/../progs/getcap 0755 0 0 file /root/capsh $HERE/../progs/capsh 0755 0 0 file /root/getpcaps $HERE/../progs/getpcaps 0755 0 0 +file /root/tcapsh-static $HERE/../progs/tcapsh-static 0755 0 0 +file /root/exit $HERE/exit 0755 0 0 +file /root/uns_test $HERE/../tests/uns_test 0755 0 0 EOF -COMMANDS="ls ln cp dmesg id pwd mkdir rmdir cat rm sh mount umount chmod less vi" +# convenience for some local experiments +if [ -f "$HERE/extras.sh" ]; then + echo "local, uncommitted enhancements to kernel test" + . "$HERE/extras.sh" +fi + +if [ -f "$HERE/interactive" ]; then + echo "file /root/interactive $HERE/interactive 0755 0 0" >> fs.conf +fi + +COMMANDS="awk cat chmod cp dmesg fgrep id less ln ls mkdir mount pwd rm rmdir sh sort umount uniq vi" for f in $COMMANDS; do echo slink /bin/$f /sbin/busybox 0755 0 0 >> fs.conf done @@ -59,9 +74,11 @@ $KBASE/usr/gen_init_cpio fs.conf | gzip -9 > initramfs.img -KERNEL=$KBASE/arch/x86_64/boot/bzImage +KERNEL=$KBASE/arch/$(uname -m)/boot/bzImage qemu-system-$(uname -m) -m 1024 \ -kernel $KERNEL \ -initrd initramfs.img \ - -append "$APPEND" + -append "$APPEND" \ + -smp sockets=2,dies=1,cores=4 \ + -device isa-debug-exit
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/kdebug/test-passwd -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/kdebug/test-passwd
Changed
@@ -1,2 +1,3 @@ root:x:0:0:root:/root:/bin/bash +luser:x:1:1:Luser:/:/bin/bash nobody:x:99:99:Nobody:/:/sbin/nologin
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/.gitignore -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/.gitignore
Changed
@@ -4,7 +4,12 @@ libcap.a libcap.so* libpsx.a +libpsx.so* _makenames cap_test libcap.pc libpsx.pc +empty +loader.txt +cap_magic.o +psx_magic.o
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/Makefile
Changed
@@ -6,30 +6,58 @@ # # Library version # -LIBNAME=$(LIBTITLE).so +CAPLIBNAME=$(LIBTITLE).so STACAPLIBNAME=$(LIBTITLE).a # -STAPSXLIBNAME=libpsx.a +PSXTITLE=libpsx +PSXLIBNAME=$(PSXTITLE).so +STAPSXLIBNAME=$(PSXTITLE).a CAPFILES=cap_alloc cap_proc cap_extint cap_flag cap_text cap_file -PSXFILES=psx +CAPMAGICOBJ=cap_magic.o +PSXFILES=../psx/psx +PSXMAGICOBJ=psx_magic.o + +# Always build libcap sources this way: +CFLAGS += -fPIC + +# The linker magic needed to build a dynamic library as independently +# executable +MAGIC=-Wl,-e,__so_start INCLS=libcap.h cap_names.h $(INCS) +GPERF_OUTPUT = _caps_output.gperf + CAPOBJS=$(addsuffix .o, $(CAPFILES)) +MAJCAPLIBNAME=$(CAPLIBNAME).$(VERSION) +MINCAPLIBNAME=$(MAJCAPLIBNAME).$(MINOR) + PSXOBJS=$(addsuffix .o, $(PSXFILES)) +MAJPSXLIBNAME=$(PSXLIBNAME).$(VERSION) +MINPSXLIBNAME=$(MAJPSXLIBNAME).$(MINOR) -MAJLIBNAME=$(LIBNAME).$(VERSION) -MINLIBNAME=$(MAJLIBNAME).$(MINOR) -GPERF_OUTPUT = _caps_output.gperf +all: pcs $(STACAPLIBNAME) +ifeq ($(SHARED),yes) + $(MAKE) $(CAPLIBNAME) +endif +ifeq ($(PTHREADS),yes) + $(MAKE) $(STAPSXLIBNAME) +ifeq ($(SHARED),yes) + $(MAKE) $(PSXLIBNAME) +endif +endif -all: $(MINLIBNAME) $(STACAPLIBNAME) libcap.pc libpsx.pc $(STAPSXLIBNAME) +pcs: $(LIBTITLE).pc +ifeq ($(PTHREADS),yes) + $(MAKE) $(PSXTITLE).pc +endif ifeq ($(BUILD_GPERF),yes) USE_GPERF_OUTPUT = $(GPERF_OUTPUT) INCLUDE_GPERF_OUTPUT = -DINCLUDE_GPERF_OUTPUT='"$(GPERF_OUTPUT)"' endif -libcap.pc: libcap.pc.in +$(LIBTITLE).pc: $(LIBTITLE).pc.in sed -e 's,@prefix@,$(prefix),' \ -e 's,@exec_prefix@,$(exec_prefix),' \ -e 's,@libdir@,$(LIBDIR),' \ @@ -38,7 +66,7 @@ -e 's,@deps@,$(DEPS),' \ $< >$@ -libpsx.pc: libpsx.pc.in +$(PSXTITLE).pc: $(PSXTITLE).pc.in sed -e 's,@prefix@,$(prefix),' \ -e 's,@exec_prefix@,$(exec_prefix),' \ -e 's,@libdir@,$(LIBDIR),' \ @@ -48,7 +76,7 @@ $< >$@ _makenames: _makenames.c cap_names.list.h - $(BUILD_CC) $(BUILD_CFLAGS) $< -o $@ + $(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $< -o $@ cap_names.h: _makenames ./_makenames > cap_names.h @@ -57,55 +85,144 @@ perl -e 'print "struct __cap_token_s { const char *name; int index; };\n%{\nconst struct __cap_token_s *__cap_lookup_name(const char *, size_t);\n%}\n%%\n"; while ($$l = <>) { $$l =~ s/[\{\"]//g; $$l =~ s/\}.*// ; print $$l; }' < $< | gperf --ignore-case --language=ANSI-C --readonly --null-strings --global-table --hash-function-name=__cap_hash_name --lookup-function-name="__cap_lookup_name" -c -t -m20 $(INDENT) > $@ sed -e 's/unsigned int len/size_t len/' -i $@ -cap_names.list.h: Makefile $(KERNEL_HEADERS)/linux/capability.h - @echo "=> making $@ from $(KERNEL_HEADERS)/linux/capability.h" - perl -e 'while ($$l=<>) { if ($$l =~ /^\#define[ \t](CAP[_A-Z]+)[ \t]+([0-9]+)\s+$$/) { $$tok=$$1; $$val=$$2; $$tok =~ tr/A-Z/a-z/; print "{\"$$tok\",$$val},\n"; } }' $(KERNEL_HEADERS)/linux/capability.h | fgrep -v 0x > $@ +# Intention is that libcap keeps up with torvalds' tree, as reflected +# by this maintained version of the kernel header. libcap dynamically +# trims the meaning of "all" capabilities down to that of the running +# kernel as of 2.30. +UAPI_HEADER := $(topdir)/libcap/include/uapi/linux/capability.h +cap_names.list.h: Makefile $(UAPI_HEADER) + @echo "=> making $@ from $(UAPI_HEADER)" + perl -e 'while ($$l=<>) { if ($$l =~ /^\#define[ \t](CAP[_A-Z]+)[ \t]+([0-9]+)\s+$$/) { $$tok=$$1; $$val=$$2; $$tok =~ tr/A-Z/a-z/; print "{\"$$tok\",$$val},\n"; } }' $(UAPI_HEADER) | fgrep -v 0x > $@ $(STACAPLIBNAME): $(CAPOBJS) $(AR) rcs $@ $^ $(RANLIB) $@ -$(STAPSXLIBNAME): $(PSXOBJS) - $(AR) rcs $@ $^ +$(STAPSXLIBNAME): $(PSXOBJS) include/sys/psx_syscall.h + $(AR) rcs $@ $(PSXOBJS) $(RANLIB) $@ -$(MINLIBNAME): $(CAPOBJS) - $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJLIBNAME) -o $@ $^ - ln -sf $(MINLIBNAME) $(MAJLIBNAME) - ln -sf $(MAJLIBNAME) $(LIBNAME) +ifeq ($(SHARED),yes) + +loader.txt: empty + $(OBJCOPY) --dump-section .interp=$@ $< /dev/null + +cap_magic.o: execable.h execable.c loader.txt libcap.h + $(CC) $(CFLAGS) $(CPPFLAGS) -DLIBRARY_VERSION=\"$(LIBTITLE)-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat loader.txt)\" -include ./libcap.h -c execable.c -o $@ + +$(CAPLIBNAME) $(MAJCAPLIBNAME) $(MINCAPLIBNAME): $(CAPOBJS) $(CAPMAGICOBJ) + $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJCAPLIBNAME) -o $(MINCAPLIBNAME) $^ $(MAGIC) + ln -sf $(MINCAPLIBNAME) $(MAJCAPLIBNAME) + ln -sf $(MAJCAPLIBNAME) $(CAPLIBNAME) + +psx_magic.o: execable.h psx_exec.c loader.txt + $(CC) $(CFLAGS) $(CPPFLAGS) -DLIBRARY_VERSION=\"$(PSXTITLE)-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat loader.txt)\" -c psx_exec.c -o $@ + +$(PSXLIBNAME) $(MAJPSXLIBNAME) $(MINPSXLIBNAME): $(PSXOBJS) include/sys/psx_syscall.h $(PSXMAGICOBJ) + $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(MAJPSXLIBNAME) -o $(MINPSXLIBNAME) $(PSXOBJS) $(PSXMAGICOBJ) $(MAGIC) $(PSXLINKFLAGS) + ln -sf $(MINPSXLIBNAME) $(MAJPSXLIBNAME) + ln -sf $(MAJPSXLIBNAME) $(PSXLIBNAME) +endif %.o: %.c $(INCLS) - $(CC) $(CFLAGS) $(IPATH) -c $< -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ cap_text.o: cap_text.c $(USE_GPERF_OUTPUT) $(INCLS) - $(CC) $(CFLAGS) $(IPATH) $(INCLUDE_GPERF_OUTPUT) -c $< -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDE_GPERF_OUTPUT) -c $< -o $@ + +cap_test: cap_test.c $(INCLS) $(CAPOBJS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(CAPOBJS) -o $@ + +libcapsotest: $(CAPLIBNAME) + ./$(CAPLIBNAME) + ./$(CAPLIBNAME) --usage + ./$(CAPLIBNAME) --help + ./$(CAPLIBNAME) --summary -cap_test: cap_test.c libcap.h - $(CC) $(CFLAGS) $(IPATH) $< -o $@ +libpsxsotest: $(PSXLIBNAME) + ./$(PSXLIBNAME) test: cap_test ./cap_test +ifeq ($(SHARED),yes) + $(MAKE) libcapsotest +ifeq ($(PTHREADS),yes) + $(MAKE) libpsxsotest +endif +endif -install: all - mkdir -p -m 0755 $(FAKEROOT)$(INCDIR)/sys - install -m 0644 include/sys/capability.h $(FAKEROOT)$(INCDIR)/sys - install -m 0644 include/sys/psx_syscall.h $(FAKEROOT)$(INCDIR)/sys - mkdir -p -m 0755 $(FAKEROOT)$(LIBDIR) +sudotest: + @echo no sudotests for libcap + +install: install-static +ifeq ($(SHARED),yes) + $(MAKE) install-shared +endif + +install-static: install-static-cap +ifeq ($(PTHREADS),yes) + $(MAKE) install-static-psx +endif + +install-shared: install-shared-cap +ifeq ($(PTHREADS),yes) + $(MAKE) install-shared-psx +endif + +install-cap: install-static-cap +ifeq ($(SHARED),yes) + $(MAKE) install-shared-cap +endif + +install-psx: install-static-psx +ifeq ($(SHARED),yes) + $(MAKE) install-shared-psx +endif
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/_makenames.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/_makenames.c
Changed
@@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-8 Andrew G. Morgan <morgan@kernel.org> + * Copyright (c) 1997-8,2020 Andrew G. Morgan <morgan@kernel.org> * * This is a file to make the capability <-> string mappings for * libcap. @@ -8,7 +8,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/capability.h> /* * #include 'sed' generated array @@ -22,17 +21,39 @@ {NULL, -1} }; -/* this should be more than big enough (factor of three at least) */ -const char *pointers[8*sizeof(struct __user_cap_data_struct)]; +/* + * recalloc uses realloc to grow some memory but it resets the + * indicated extended empty space. + */ +static void *recalloc(void *p, int was, int is) { + char *n = realloc(p, is); + if (!n) { + fputs("out of memory", stderr); + exit(1); + } + memset(n+was, 0, is-was); + return n; +} int main(void) { int i, maxcaps=0, maxlength=0; + const char **pointers = NULL; + int pointers_avail = 0; for ( i=0; list[i].index >= 0 && list[i].name; ++i ) { if (maxcaps <= list[i].index) { maxcaps = list[i].index + 1; } + if (pointers == NULL || list[i].index >= pointers_avail) { + int was = pointers_avail * sizeof(char *); + pointers_avail = 2 * list[i].index + 1; + pointers = recalloc(pointers, was, pointers_avail * sizeof(char *)); + if (pointers == NULL) { + perror("unable to continue"); + exit(1); + } + } pointers[list[i].index] = list[i].name; int n = strlen(list[i].name); if (n > maxlength) { @@ -49,19 +70,21 @@ "#define __CAP_NAME_SIZE %d\n" "\n" "#ifdef LIBCAP_PLEASE_INCLUDE_ARRAY\n" - " char const *_cap_names[__CAP_BITS] = {\n", maxcaps, maxlength+1); + "#define LIBCAP_CAP_NAMES { \\\n", maxcaps, maxlength+1); for (i=0; i<maxcaps; ++i) { - if (pointers[i]) - printf(" /* %d */\t\"%s\",\n", i, pointers[i]); - else - printf(" /* %d */\tNULL,\t\t/* - presently unused */\n", i); + if (pointers[i]) { + printf(" /* %d */\t\"%s\", \\\n", i, pointers[i]); + } else { + printf(" /* %d */\tNULL,\t\t/* - presently unused */ \\\n", i); + } } - printf(" };\n" + printf(" }\n" "#endif /* LIBCAP_PLEASE_INCLUDE_ARRAY */\n" "\n" "/* END OF FILE */\n"); + free(pointers); exit(0); }
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_alloc.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_alloc.c
Changed
@@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-8,2019 Andrew G Morgan <morgan@kernel.org> + * Copyright (c) 1997-8,2019,2021 Andrew G Morgan <morgan@kernel.org> * * This file deals with allocation and deallocation of internal * capability sets as specified by POSIX.1e (formerlly, POSIX 6). @@ -8,41 +8,63 @@ #include "libcap.h" /* - * This gets set via the pre-main() executed constructor function below it. + * Make start up atomic. + */ +static __u8 __libcap_mutex; + +/* + * These get set via the pre-main() executed constructor function below it. */ static cap_value_t _cap_max_bits; -__attribute__((constructor (300))) static void _initialize_libcap(void) { +__attribute__((constructor (300))) void _libcap_initialize() +{ + _cap_mu_lock(&__libcap_mutex); if (_cap_max_bits) { + _cap_mu_unlock(&__libcap_mutex); return; } cap_set_syscall(NULL, NULL); _binary_search(_cap_max_bits, cap_get_bound, 0, __CAP_MAXBITS, __CAP_BITS); + _cap_mu_unlock(&__libcap_mutex); } -cap_value_t cap_max_bits(void) { +cap_value_t cap_max_bits(void) +{ return _cap_max_bits; } /* - * Obtain a blank set of capabilities + * capability allocation is all done in terms of this structure. */ +struct _cap_alloc_s { + __u32 magic; + __u32 size; + union { + struct _cap_struct set; + struct cap_iab_s iab; + struct cap_launch_s launcher; + } u; +}; +/* + * Obtain a blank set of capabilities + */ cap_t cap_init(void) { - __u32 *raw_data; + struct _cap_alloc_s *raw_data; cap_t result; - raw_data = calloc(1, sizeof(__u32) + sizeof(*result)); + raw_data = calloc(1, sizeof(struct _cap_alloc_s)); if (raw_data == NULL) { _cap_debug("out of memory"); errno = ENOMEM; return NULL; } + raw_data->magic = CAP_T_MAGIC; + raw_data->size = sizeof(struct _cap_alloc_s); - *raw_data = CAP_T_MAGIC; - result = (cap_t) (raw_data + 1); - + result = &raw_data->u.set; result->head.version = _LIBCAP_CAPABILITY_VERSION; capget(&result->head, NULL); /* load the kernel-capability version */ @@ -72,34 +94,45 @@ * This is an internal library function to duplicate a string and * tag the result as something cap_free can handle. */ - char *_libcap_strdup(const char *old) { - __u32 *raw_data; + struct _cap_alloc_s *header; + char *raw_data; + size_t len; if (old == NULL) { errno = EINVAL; return NULL; } + len = strlen(old) + 1 + 2*sizeof(__u32); + if (len < sizeof(struct _cap_alloc_s)) { + len = sizeof(struct _cap_alloc_s); + } + if ((len & 0xffffffff) != len) { + _cap_debug("len is too long for libcap to manage"); + errno = EINVAL; + return NULL; + } - raw_data = malloc( sizeof(__u32) + strlen(old) + 1 ); + raw_data = calloc(1, len); if (raw_data == NULL) { errno = ENOMEM; return NULL; } - - *(raw_data++) = CAP_S_MAGIC; - strcpy((char *) raw_data, old); - - return ((char *) raw_data); + header = (void *) raw_data; + header->magic = CAP_S_MAGIC; + header->size = (__u32) len; + + raw_data += 2*sizeof(__u32); + strcpy(raw_data, old); + return raw_data; } /* * This function duplicates an internal capability set with - * malloc()'d memory. It is the responsibility of the user to call + * calloc()'d memory. It is the responsibility of the user to call * cap_free() to liberate it. */ - cap_t cap_dup(cap_t cap_d) { cap_t result; @@ -116,39 +149,155 @@ return NULL; } + _cap_mu_lock(&cap_d->mutex); memcpy(result, cap_d, sizeof(*cap_d)); + _cap_mu_unlock(&cap_d->mutex); + _cap_mu_unlock(&result->mutex); return result; } +cap_iab_t cap_iab_init(void) +{ + struct _cap_alloc_s *base = calloc(1, sizeof(struct _cap_alloc_s)); + if (base == NULL) { + _cap_debug("out of memory"); + return NULL; + } + base->magic = CAP_IAB_MAGIC; + base->size = sizeof(struct _cap_alloc_s); + return &base->u.iab; +} /* - * Scrub and then liberate an internal capability set. + * This function duplicates an internal iab tuple with calloc()'d + * memory. It is the responsibility of the user to call cap_free() to + * liberate it. */ +cap_iab_t cap_iab_dup(cap_iab_t iab) +{ + cap_iab_t result; + + if (!good_cap_iab_t(iab)) { + _cap_debug("bad argument"); + errno = EINVAL; + return NULL; + } + result = cap_iab_init(); + if (result == NULL) { + _cap_debug("out of memory"); + return NULL; + } + + _cap_mu_lock(&iab->mutex); + memcpy(result, iab, sizeof(*iab)); + _cap_mu_unlock(&iab->mutex); + _cap_mu_unlock(&result->mutex); + + return result; +} + +/* + * cap_new_launcher allocates some memory for a launcher and + * initializes it. To actually launch a program with this launcher, + * use cap_launch(). By default, the launcher is a no-op from a + * security perspective and will act just as fork()/execve() + * would. Use cap_launcher_setuid() etc to override this. + */ +cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv, + const char * const *envp) +{
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_extint.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_extint.c
Changed
@@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-8 Andrew G Morgan <morgan@kernel.org> + * Copyright (c) 1997-8,2021 Andrew G. Morgan <morgan@kernel.org> * * This file deals with exchanging internal and external * representations of capability sets. @@ -15,6 +15,11 @@ #define CAP_EXT_MAGIC_SIZE 4 const static __u8 external_magic[CAP_EXT_MAGIC_SIZE+1] = CAP_EXT_MAGIC; +/* + * This is the largest size libcap can currently export. + * cap_size() may return something smaller depending on the + * content of its argument cap_t. + */ struct cap_ext_struct { __u8 magic[CAP_EXT_MAGIC_SIZE]; __u8 length_of_capset; @@ -26,12 +31,54 @@ }; /* - * return size of external capability set + * minimum exported flag size: libcap2 has always exported with flags + * this size. */ +static size_t _libcap_min_ext_flag_size = CAP_SET_SIZE < 8 ? CAP_SET_SIZE : 8; -ssize_t cap_size(cap_t caps) +static ssize_t _cap_size_locked(cap_t cap_d) { - return ssizeof(struct cap_ext_struct); + size_t j, used; + for (j=used=0; j<CAP_SET_SIZE; j+=sizeof(__u32)) { + int i; + __u32 val = 0; + for (i=0; i<NUMBER_OF_CAP_SETS; ++i) { + val |= cap_d->u[j/sizeof(__u32)].flat[i]; + } + if (val == 0) { + continue; + } + if (val > 0x0000ffff) { + if (val > 0x00ffffff) { + used = j+4; + } else { + used = j+3; + } + } else if (val > 0x000000ff) { + used = j+2; + } else { + used = j+1; + } + } + if (used < _libcap_min_ext_flag_size) { + used = _libcap_min_ext_flag_size; + } + return (ssize_t)(CAP_EXT_MAGIC_SIZE + 1+ NUMBER_OF_CAP_SETS * used); +} + +/* + * return size of external capability set + */ +ssize_t cap_size(cap_t cap_d) +{ + size_t used; + if (!good_cap_t(cap_d)) { + return ssizeof(struct cap_ext_struct); + } + _cap_mu_lock(&cap_d->mutex); + used = _cap_size_locked(cap_d); + _cap_mu_unlock(&cap_d->mutex); + return used; } /* @@ -43,42 +90,58 @@ ssize_t cap_copy_ext(void *cap_ext, cap_t cap_d, ssize_t length) { struct cap_ext_struct *result = (struct cap_ext_struct *) cap_ext; + ssize_t csz, len_set; int i; /* valid arguments? */ - if (!good_cap_t(cap_d) || length < ssizeof(struct cap_ext_struct) - || cap_ext == NULL) { + if (!good_cap_t(cap_d) || cap_ext == NULL) { errno = EINVAL; return -1; } + _cap_mu_lock(&cap_d->mutex); + csz = _cap_size_locked(cap_d); + if (csz > length) { + errno = EINVAL; + _cap_mu_unlock_return(&cap_d->mutex, -1); + } + len_set = (csz - (CAP_EXT_MAGIC_SIZE+1))/NUMBER_OF_CAP_SETS; + /* fill external capability set */ memcpy(&result->magic, external_magic, CAP_EXT_MAGIC_SIZE); - result->length_of_capset = CAP_SET_SIZE; + result->length_of_capset = len_set; for (i=0; i<NUMBER_OF_CAP_SETS; ++i) { size_t j; - for (j=0; j<CAP_SET_SIZE; ) { + for (j=0; j<len_set; ) { __u32 val; val = cap_d->u[j/sizeof(__u32)].flat[i]; - result->bytes[j++][i] = val & 0xFF; - result->bytes[j++][i] = (val >>= 8) & 0xFF; - result->bytes[j++][i] = (val >>= 8) & 0xFF; - result->bytes[j++][i] = (val >> 8) & 0xFF; + result->bytes[j++][i] = val & 0xFF; + if (j < len_set) { + result->bytes[j++][i] = (val >>= 8) & 0xFF; + } + if (j < len_set) { + result->bytes[j++][i] = (val >>= 8) & 0xFF; + } + if (j < len_set) { + result->bytes[j++][i] = (val >> 8) & 0xFF; + } } } /* All done: return length of external representation */ - return (ssizeof(struct cap_ext_struct)); + _cap_mu_unlock_return(&cap_d->mutex, csz); } /* * Import an external representation to produce an internal rep. * the internal rep should be liberated with cap_free(). + * + * Note, this function assumes that cap_ext has a valid length. That + * is, feeding garbage to this function will likely crash the program. */ - cap_t cap_copy_int(const void *cap_ext) { const struct cap_ext_struct *export = @@ -121,3 +184,24 @@ return cap_d; } +/* + * This function is the same as cap_copy_int() although it requires an + * extra argument that is the length of the cap_ext data. Before + * running cap_copy_int() the function validates that length is + * consistent with the stated length. It returns NULL on error. + */ +cap_t cap_copy_int_check(const void *cap_ext, ssize_t length) +{ + const struct cap_ext_struct *export = + (const struct cap_ext_struct *) cap_ext; + + if (length < 1+CAP_EXT_MAGIC_SIZE) { + errno = EINVAL; + return NULL; + } + if (length < 1+CAP_EXT_MAGIC_SIZE + export->length_of_capset * NUMBER_OF_CAP_SETS) { + errno = EINVAL; + return NULL; + } + return cap_copy_int(cap_ext); +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_file.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_file.c
Changed
@@ -1,10 +1,12 @@ /* * Copyright (c) 1997,2007,2016 Andrew G Morgan <morgan@kernel.org> * - * This file deals with setting capabilities on files. + * This file deals with getting/setting capabilities from/on files. */ +#ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE +#endif #include <sys/types.h> #include <byteswap.h> @@ -25,6 +27,22 @@ extern int removexattr(const char *, const char *); extern int fremovexattr(int, const char *); +/* + * This public API was moved to include/uapi/linux/xattr.h . For just + * these definitions, it isn't really worth managing this in our build + * system with yet another copy of a header file. We just, provide + * fallback definitions here. + */ +#ifndef XATTR_CAPS_SUFFIX +#define XATTR_CAPS_SUFFIX "capability" +#endif +#ifndef XATTR_SECURITY_PREFIX +#define XATTR_SECURITY_PREFIX "security." +#endif +#ifndef XATTR_NAME_CAPS +#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX +#endif + #include "libcap.h" #ifdef VFS_CAP_U32 @@ -109,6 +127,7 @@ errno = EINVAL; return -1; } + _cap_mu_lock(&cap_d->mutex); switch (cap_d->head.version) { case _LINUX_CAPABILITY_VERSION_1: @@ -126,14 +145,14 @@ default: errno = EINVAL; - return -1; + _cap_mu_unlock_return(&cap_d->mutex, -1); } if (cap_d->rootid != 0) { if (cap_d->head.version < _LINUX_CAPABILITY_VERSION_3) { _cap_debug("namespaces with non-0 rootid unsupported by kernel"); errno = EINVAL; - return -1; + _cap_mu_unlock_return(&cap_d->mutex, -1); } magic = VFS_CAP_REVISION_3; tocopy = VFS_CAP_U32_3; @@ -154,7 +173,7 @@ * System does not support these capabilities */ errno = EINVAL; - return -1; + _cap_mu_unlock_return(&cap_d->mutex, -1); } i++; } @@ -170,7 +189,7 @@ & (cap_d->u[i].flat[CAP_PERMITTED] | cap_d->u[i].flat[CAP_INHERITABLE]))) { errno = EINVAL; - return -1; + _cap_mu_unlock_return(&cap_d->mutex, -1); } } @@ -180,7 +199,7 @@ rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE); } - return 0; /* success */ + _cap_mu_unlock_return(&cap_d->mutex, 0); /* success */ } /* @@ -251,7 +270,15 @@ uid_t cap_get_nsowner(cap_t cap_d) { - return cap_d->rootid; + uid_t nsowner; + if (!good_cap_t(cap_d)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&cap_d->mutex); + nsowner = cap_d->rootid; + _cap_mu_unlock(&cap_d->mutex); + return nsowner; } /* @@ -319,13 +346,17 @@ } /* - * Set rootid for the file capability sets. + * Set nsowner for the file capability set. */ - -int cap_set_nsowner(cap_t cap_d, uid_t rootid) +int cap_set_nsowner(cap_t cap_d, uid_t rootuid) { - cap_d->rootid = rootid; - return 0; + if (!good_cap_t(cap_d)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&cap_d->mutex); + cap_d->rootid = rootuid; + _cap_mu_unlock_return(&cap_d->mutex, 0); } #else /* ie. ndef VFS_CAP_U32 */ @@ -360,10 +391,10 @@ return -1; } -void cap_set_nsowner(cap_t cap_d, uid_t rootid) +int cap_set_nsowner(cap_t cap_d, uid_t rootuid) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } #endif /* def VFS_CAP_U32 */
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_flag.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_flag.c
Changed
@@ -1,8 +1,10 @@ /* - * Copyright (c) 1997-8,2008 Andrew G. Morgan <morgan@kernel.org> + * Copyright (c) 1997-8,2008,20-21 Andrew G. Morgan <morgan@kernel.org> * * This file deals with flipping of capabilities on internal * capability sets as specified by POSIX.1e (formerlly, POSIX 6). + * + * It also contains similar code for bit flipping cap_iab_t values. */ #include "libcap.h" @@ -12,7 +14,6 @@ * returned as the contents of *raised. The capability is from one of * the sets stored in cap_d as specified by set and value */ - int cap_get_flag(cap_t cap_d, cap_value_t value, cap_flag_t set, cap_flag_value_t *raised) { @@ -23,7 +24,9 @@ if (raised && good_cap_t(cap_d) && value >= 0 && value < __CAP_MAXBITS && set >= 0 && set < NUMBER_OF_CAP_SETS) { + _cap_mu_lock(&cap_d->mutex); *raised = isset_cap(cap_d,value,set) ? CAP_SET:CAP_CLEAR; + _cap_mu_unlock(&cap_d->mutex); return 0; } else { _cap_debug("invalid arguments"); @@ -49,6 +52,7 @@ && (set >= 0) && (set < NUMBER_OF_CAP_SETS) && (raise == CAP_SET || raise == CAP_CLEAR) ) { int i; + _cap_mu_lock(&cap_d->mutex); for (i=0; i<no_values; ++i) { if (array_values[i] < 0 || array_values[i] >= __CAP_MAXBITS) { _cap_debug("weird capability (%d) - skipped", array_values[i]); @@ -62,14 +66,12 @@ } } } + _cap_mu_unlock(&cap_d->mutex); return 0; - } else { - _cap_debug("invalid arguments"); errno = EINVAL; return -1; - } } @@ -80,16 +82,14 @@ int cap_clear(cap_t cap_d) { if (good_cap_t(cap_d)) { - + _cap_mu_lock(&cap_d->mutex); memset(&(cap_d->u), 0, sizeof(cap_d->u)); + _cap_mu_unlock(&cap_d->mutex); return 0; - } else { - _cap_debug("invalid pointer"); errno = EINVAL; return -1; - } } @@ -106,9 +106,11 @@ if (good_cap_t(cap_d)) { unsigned i; + _cap_mu_lock(&cap_d->mutex); for (i=0; i<_LIBCAP_CAPABILITY_U32S; i++) { cap_d->u[i].flat[flag] = 0; } + _cap_mu_unlock(&cap_d->mutex); return 0; } /* @@ -125,7 +127,6 @@ /* * Compare two capability sets */ - int cap_compare(cap_t a, cap_t b) { unsigned i; @@ -137,6 +138,15 @@ return -1; } + /* + * To avoid a deadlock corner case, we operate on an unlocked + * private copy of b + */ + b = cap_dup(b); + if (b == NULL) { + return -1; + } + _cap_mu_lock(&a->mutex); for (i=0, result=0; i<_LIBCAP_CAPABILITY_U32S; i++) { result |= ((a->u[i].flat[CAP_EFFECTIVE] != b->u[i].flat[CAP_EFFECTIVE]) @@ -146,5 +156,214 @@ | ((a->u[i].flat[CAP_PERMITTED] != b->u[i].flat[CAP_PERMITTED]) ? LIBCAP_PER : 0); } + _cap_mu_unlock(&a->mutex); + cap_free(b); + return result; +} + +/* + * cap_fill_flag copies a bit-vector of capability state in one cap_t from one + * flag to another flag of another cap_t. + */ +int cap_fill_flag(cap_t cap_d, cap_flag_t to, cap_t ref, cap_flag_t from) +{ + int i; + cap_t orig; + + if (!good_cap_t(cap_d) || !good_cap_t(ref)) { + errno = EINVAL; + return -1; + } + + if (to < CAP_EFFECTIVE || to > CAP_INHERITABLE || + from < CAP_EFFECTIVE || from > CAP_INHERITABLE) { + errno = EINVAL; + return -1; + } + + orig = cap_dup(ref); + if (orig == NULL) { + return -1; + } + + _cap_mu_lock(&cap_d->mutex); + for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) { + cap_d->u[i].flat[to] = orig->u[i].flat[from]; + } + _cap_mu_unlock(&cap_d->mutex); + + cap_free(orig); + return 0; +} + +/* + * cap_fill copies a bit-vector of capability state in a cap_t from + * one flag to another. + */ +int cap_fill(cap_t cap_d, cap_flag_t to, cap_flag_t from) +{ + return cap_fill_flag(cap_d, to, cap_d, from); +} + +/* + * cap_iab_get_vector reads the single bit value from an IAB vector set. + */ +cap_flag_value_t cap_iab_get_vector(cap_iab_t iab, cap_iab_vector_t vec, + cap_value_t bit) +{ + if (!good_cap_iab_t(iab) || bit >= cap_max_bits()) { + return 0; + } + + unsigned o = (bit >> 5); + __u32 mask = 1u << (bit & 31); + cap_flag_value_t ret; + + _cap_mu_lock(&iab->mutex); + switch (vec) { + case CAP_IAB_INH: + ret = !!(iab->i[o] & mask); + break; + case CAP_IAB_AMB: + ret = !!(iab->a[o] & mask); + break; + case CAP_IAB_BOUND: + ret = !!(iab->nb[o] & mask); + break; + default: + ret = 0; + } + _cap_mu_unlock(&iab->mutex); + + return ret; +} + +/* + * cap_iab_set_vector sets the bits in an IAB to the value + * raised. Note, setting A implies setting I too, lowering I implies + * lowering A too. The B bits are, however, independently settable. + */
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_proc.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_proc.c
Changed
@@ -1,17 +1,22 @@ /* - * Copyright (c) 1997-8,2007,11,19,20 Andrew G Morgan <morgan@kernel.org> + * Copyright (c) 1997-8,2007,11,19-21 Andrew G Morgan <morgan@kernel.org> * * This file deals with getting and setting capabilities on processes. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif +#include <errno.h> +#include <fcntl.h> /* Obtain O_* constant definitions */ +#include <grp.h> #include <sys/prctl.h> -#include <sys/psx_syscall.h> #include <sys/securebits.h> #include <sys/syscall.h> #include <unistd.h> -#include <grp.h> +#include <sys/types.h> +#include <sys/wait.h> #include <linux/limits.h> @@ -24,8 +29,8 @@ * using pthreads. */ -static long int _cap_syscall(long int syscall_nr, - long int arg1, long int arg2, long int arg3) +static long int _cap_syscall3(long int syscall_nr, + long int arg1, long int arg2, long int arg3) { return syscall(syscall_nr, arg1, arg2, arg3); } @@ -37,10 +42,32 @@ return syscall(syscall_nr, arg1, arg2, arg3, arg4, arg5, arg6); } -static long int (*_libcap_wsyscall3)(long int, long int, long int, long int) - = _cap_syscall; -static long int (*_libcap_wsyscall6)(long int, long int, long int, long int, - long int, long int, long int) = _cap_syscall6; +/* + * to keep the structure of the code conceptually similar in C and Go + * implementations, we introduce this abstraction for invoking state + * writing system calls. In psx+pthreaded code, the fork + * implementation provided by nptl ensures that we can consistently + * use the multithreaded syscalls even in the child after a fork(). + */ +struct syscaller_s { + long int (*three)(long int syscall_nr, + long int arg1, long int arg2, long int arg3); + long int (*six)(long int syscall_nr, + long int arg1, long int arg2, long int arg3, + long int arg4, long int arg5, long int arg6); +}; + +/* use this syscaller for multi-threaded code */ +static struct syscaller_s multithread = { + .three = _cap_syscall3, + .six = _cap_syscall6 +}; + +/* use this syscaller for single-threaded code */ +static struct syscaller_s singlethread = { + .three = _cap_syscall3, + .six = _cap_syscall6 +}; /* * This gets reset to 0 if we are *not* linked with libpsx. @@ -48,7 +75,7 @@ static int _libcap_overrode_syscalls = 1; /* - * psx_load_syscalls() is weakly defined so we can have it overriden + * psx_load_syscalls() is weakly defined so we can have it overridden * by libpsx if that library is linked. Specifically, when libcap * calls psx_load_sycalls() it is prepared to override the default * values for the syscalls that libcap uses to change security state. @@ -56,13 +83,24 @@ * no-op. However, if libpsx is linked, the one present in that * library (not being weak) will replace this one and the * _libcap_overrode_syscalls value isn't forced to zero. + * + * Note: we hardcode the prototype for the psx_load_syscalls() + * function here so the compiler isn't worried. If we force the build + * to include the header, we are close to requiring the optional + * libpsx to be linked. */ -__attribute__((weak)) void psx_load_syscalls(long int (**syscall_fn)(long int, long int, long int, long int), long int (**syscall6_fn)(long int, - long int, long int, long int, - long int, long int, long int)) + long int, long int, long int, + long int, long int, long int)); + +__attribute__((weak)) +void psx_load_syscalls(long int (**syscall_fn)(long int, + long int, long int, long int), + long int (**syscall6_fn)(long int, + long int, long int, long int, + long int, long int, long int)) { _libcap_overrode_syscalls = 0; } @@ -79,36 +117,37 @@ long int, long int, long int)) { if (new_syscall == NULL) { - psx_load_syscalls(&_libcap_wsyscall3, &_libcap_wsyscall6); + psx_load_syscalls(&multithread.three, &multithread.six); } else { - _libcap_wsyscall3 = new_syscall; - _libcap_wsyscall6 = new_syscall6; + multithread.three = new_syscall; + multithread.six = new_syscall6; } } -static int _libcap_capset(cap_user_header_t header, const cap_user_data_t data) +static int _libcap_capset(struct syscaller_s *sc, + cap_user_header_t header, const cap_user_data_t data) { if (_libcap_overrode_syscalls) { - return _libcap_wsyscall3(SYS_capset, - (long int) header, (long int) data, 0); + return sc->three(SYS_capset, (long int) header, (long int) data, 0); } return capset(header, data); } -static int _libcap_wprctl3(long int pr_cmd, long int arg1, long int arg2) +static int _libcap_wprctl3(struct syscaller_s *sc, + long int pr_cmd, long int arg1, long int arg2) { if (_libcap_overrode_syscalls) { - return _libcap_wsyscall3(SYS_prctl, pr_cmd, arg1, arg2); + return sc->three(SYS_prctl, pr_cmd, arg1, arg2); } return prctl(pr_cmd, arg1, arg2, 0, 0, 0); } -static int _libcap_wprctl6(long int pr_cmd, long int arg1, long int arg2, +static int _libcap_wprctl6(struct syscaller_s *sc, + long int pr_cmd, long int arg1, long int arg2, long int arg3, long int arg4, long int arg5) { if (_libcap_overrode_syscalls) { - return _libcap_wsyscall6(SYS_prctl, pr_cmd, arg1, arg2, - arg3, arg4, arg5); + return sc->six(SYS_prctl, pr_cmd, arg1, arg2, arg3, arg4, arg5); } return prctl(pr_cmd, arg1, arg2, arg3, arg4, arg5); } @@ -135,8 +174,7 @@ return result; } -int cap_set_proc(cap_t cap_d) -{ +static int _cap_set_proc(struct syscaller_s *sc, cap_t cap_d) { int retval; if (!good_cap_t(cap_d)) { @@ -145,11 +183,18 @@ } _cap_debug("setting process capabilities"); - retval = _libcap_capset(&cap_d->head, &cap_d->u[0].set); + _cap_mu_lock(&cap_d->mutex); + retval = _libcap_capset(sc, &cap_d->head, &cap_d->u[0].set); + _cap_mu_unlock(&cap_d->mutex); return retval; } +int cap_set_proc(cap_t cap_d) +{ + return _cap_set_proc(&multithread, cap_d); +} + /* the following two functions are not required by POSIX */ /* read the caps on a specific process */ @@ -165,9 +210,11 @@ _cap_debug("getting process capabilities for proc %d", pid); + _cap_mu_lock(&cap_d->mutex); cap_d->head.pid = pid; error = capget(&cap_d->head, &cap_d->u[0].set); cap_d->head.pid = 0; + _cap_mu_unlock(&cap_d->mutex);
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_test.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_test.c
Changed
@@ -1,12 +1,17 @@ +#define _GNU_SOURCE +#include <stdio.h> + #include "libcap.h" static cap_value_t top; -static int cf(cap_value_t x) { +static int cf(cap_value_t x) +{ return top - x - 1; } -static int test_cap_bits(void) { +static int test_cap_bits(void) +{ static cap_value_t vs[] = { 5, 6, 11, 12, 15, 16, 17, 38, 41, 63, 64, __CAP_MAXBITS+3, 0, -1 }; @@ -15,25 +20,262 @@ for (i = 0; vs[i] >= 0; i++) { cap_value_t ans; - top = i; - _binary_search(ans, cf, 0, __CAP_MAXBITS, 0); + top = vs[i]; + _binary_search(ans, cf, 0, __CAP_MAXBITS, -1); if (ans != top) { - if (top > __CAP_MAXBITS && ans == __CAP_MAXBITS) { - } else { - printf("test_cap_bits miscompared [%d] top=%d - got=%d\n", - i, top, ans); - failed = -1; + if (top == 0 && ans == -1) { + continue; + } + if (top > __CAP_MAXBITS && ans == -1) { + continue; } + printf("test_cap_bits miscompared [%d] top=%d - got=%d\n", + i, top, ans); + failed = -1; } } return failed; } +static int test_cap_flags(void) +{ + cap_t c, d; + cap_flag_t f = CAP_INHERITABLE, t; + cap_value_t v; + int retval = 0; + + c = cap_init(); + if (c == NULL) { + printf("test_flags failed to allocate a set\n"); + return -1; + } + if (cap_compare(c, NULL) != -1) { + printf("compare to NULL should give invalid\n"); + return -1; + } + if (cap_compare(NULL, c) != -1) { + printf("compare with NULL should give invalid\n"); + return -1; + } + + for (v = 0; v < __CAP_MAXBITS; v += 3) { + if (cap_set_flag(c, CAP_INHERITABLE, 1, &v, CAP_SET)) { + printf("unable to set inheritable bit %d\n", v); + retval = -1; + goto drop_c; + } + } + + d = cap_dup(c); + for (t = CAP_EFFECTIVE; t <= CAP_INHERITABLE; t++) { + if (cap_fill(c, t, f)) { + printf("cap_fill failed %d -> %d\n", f, t); + retval = -1; + goto drop_d; + } + if (cap_clear_flag(c, f)) { + printf("cap_fill unable to clear flag %d\n", f); + retval = -1; + goto drop_d; + } + f = t; + } + if (cap_compare(c, d)) { + printf("permuted cap_fill()ing failed to perform net no-op\n"); + retval = -1; + } + if (cap_fill_flag(NULL, CAP_EFFECTIVE, c, CAP_INHERITABLE) == 0) { + printf("filling NULL flag should fail\n"); + retval = -1; + } + if (cap_fill_flag(d, CAP_PERMITTED, c, CAP_INHERITABLE) != 0) { + perror("filling PERMITEED flag should work"); + retval = -1; + } + if (cap_fill_flag(c, CAP_PERMITTED, d, CAP_PERMITTED) != 0) { + perror("filling PERMITTED flag from another cap_t should work"); + retval = -1; + } + if (cap_compare(c, d)) { + printf("permuted cap_fill()ing failed to perform net no-op\n"); + retval = -1; + } + +drop_d: + if (cap_free(d) != 0) { + perror("failed to free d"); + retval = -1; + } +drop_c: + if (cap_free(c) != 0) { + perror("failed to free c"); + retval = -1; + } + return retval; +} + +static int test_short_bits(void) +{ + int result = 0; + char *tmp; + int n = asprintf(&tmp, "%d", __CAP_MAXBITS); + if (n <= 0) { + return -1; + } + if (strlen(tmp) > __CAP_NAME_SIZE) { + printf("cap_to_text buffer size reservation needs fixing (%ld > %d)\n", + strlen(tmp), __CAP_NAME_SIZE); + result = -1; + } + free(tmp); + return result; +} + +static int noop(void *data) +{ + return -1; +} + +static int test_alloc(void) +{ + int retval = 0; + cap_t c; + cap_iab_t iab; + cap_launch_t launcher; + char *old_root; + + printf("test_alloc\n"); + fflush(stdout); + + c = cap_init(); + if (c == NULL) { + perror("failed to allocate a cap_t"); + fflush(stderr); + return -1; + } + + iab = cap_iab_init(); + if (iab == NULL) { + perror("failed to allocate a cap_iab_t"); + fflush(stderr); + retval = -1; + goto drop_c; + } + + launcher = cap_func_launcher(noop); + if (launcher == NULL) { + perror("failde to allocate a launcher"); + fflush(stderr); + retval = -1; + goto drop_iab; + } + + cap_launcher_set_chroot(launcher, "/tmp"); + if (cap_launcher_set_iab(launcher, iab) != NULL) { + printf("unable to replace iab in launcher\n"); + fflush(stdout); + retval = -1; + goto drop_iab; + } + + iab = cap_launcher_set_iab(launcher, cap_iab_init()); + if (iab == NULL) { + printf("unable to recover iab in launcher\n"); + fflush(stdout); + retval = -1; + goto drop_launcher; + } + + old_root = cap_proc_root("blah"); + if (old_root != NULL) { + printf("bad initial proc_root [%s]\n", old_root);
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/cap_text.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/cap_text.c
Changed
@@ -1,17 +1,22 @@ /* - * Copyright (c) 1997-8,2007-8,2019 Andrew G Morgan <morgan@kernel.org> + * Copyright (c) 1997-8,2007-8,2019,2021 Andrew G Morgan <morgan@kernel.org> * Copyright (c) 1997 Andrew Main <zefram@dcs.warwick.ac.uk> * * This file deals with exchanging internal and textual * representations of capability sets. */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif + #include <stdio.h> #define LIBCAP_PLEASE_INCLUDE_ARRAY #include "libcap.h" +static char const *_cap_names[__CAP_BITS] = LIBCAP_CAP_NAMES; + #include <ctype.h> #include <limits.h> @@ -57,8 +62,9 @@ } /* - * forceall forces all of the named capabilities to be assigned the - * masked value, and zeroed otherwise. + * forceall forces all of the kernel named capabilities to be assigned + * the masked value, and zeroed otherwise. Note, if the kernel is ahead + * of libcap, the upper bits will be referred to by number. */ static void forceall(__u32 *flat, __u32 value, unsigned blks) { @@ -94,7 +100,7 @@ return n; } else { int c; - unsigned len; + size_t len; for (len=0; (c = str.constp[len]); ++len) { if (!(isalpha(c) || (c == '_'))) { @@ -112,13 +118,16 @@ } #else /* ie., ndef GPERF_DOWNCASE */ char const *s; - unsigned n; - - for (n = cap_max_bits(); n--; ) + unsigned n = cap_max_bits(); + if (n > __CAP_BITS) { + n = __CAP_BITS; + } + while (n--) { if (_cap_names[n] && (s = namcmp(str.constp, _cap_names[n]))) { *strp = s; return n; } + } #endif /* def GPERF_DOWNCASE */ return -1; /* No definition available */ @@ -151,6 +160,7 @@ cap_blks = _LINUX_CAPABILITY_U32S_3; break; default: + cap_free(res); errno = EINVAL; return NULL; } @@ -210,7 +220,7 @@ /* cycle through list of actions */ do { - _cap_debug("next char = `%c'", *str); + _cap_debug("next char = '%c'", *str); if (*str && !isspace(*str)) { switch (*str++) { /* Effective, Inheritable, Permitted */ case 'e': @@ -300,20 +310,19 @@ */ char *cap_to_name(cap_value_t cap) { - if ((cap < 0) || (cap >= __CAP_BITS)) { -#if UINT_MAX != 4294967295U -# error Recompile with correctly sized numeric array -#endif - char *tmp, *result; + char *tmp, *result; - asprintf(&tmp, "%u", cap); - result = _libcap_strdup(tmp); - free(tmp); - - return result; - } else { + if ((cap >= 0) && (cap < __CAP_BITS)) { return _libcap_strdup(_cap_names[cap]); } + if (asprintf(&tmp, "%u", cap) <= 0) { + _cap_debug("asprintf filed"); + return NULL; + } + + result = _libcap_strdup(tmp); + free(tmp); + return result; } /* @@ -339,12 +348,18 @@ return f; } +/* + * This code assumes that the longest named capability is longer than + * the decimal text representation of __CAP_MAXBITS. This is very true + * at the time of writing and likely to remain so. However, we have + * a test in cap_text to validate it at build time. + */ #define CAP_TEXT_BUFFER_ZONE 100 char *cap_to_text(cap_t caps, ssize_t *length_p) { char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE]; - char *p; + char *p, *base; int histo[8]; int m, t; unsigned n; @@ -375,6 +390,7 @@ m = t; /* blank is not a valid capability set */ + base = buf; p = sprintf(buf, "=%s%s%s", (m & LIBCAP_EFF) ? "e" : "", (m & LIBCAP_INH) ? "i" : "", @@ -388,6 +404,9 @@ for (n = 0; n < cmb; n++) { if (getstateflags(caps, n) == t) { char *this_cap_name = cap_to_name(n); + if (this_cap_name == NULL) { + return NULL; + } if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) { cap_free(this_cap_name); errno = ERANGE; @@ -400,7 +419,16 @@ p--; n = t & ~m; if (n) { - p += sprintf(p, "+%s%s%s", + char op = '+'; + if (base[0] == '=' && base[1] == ' ') { + /* + * Special case all lowered default "= foo,...+eip + * ..." as "foo,...=eip ...". (Equivalent but shorter.) + */ + base += 2; + op = '='; + } + p += sprintf(p, "%c%s%s%s", op, (n & LIBCAP_EFF) ? "e" : "", (n & LIBCAP_INH) ? "i" : "", (n & LIBCAP_PER) ? "p" : ""); @@ -431,6 +459,9 @@ for (n = cmb; n < __CAP_MAXBITS; n++) { if (getstateflags(caps, n) == t) { char *this_cap_name = cap_to_name(n); + if (this_cap_name == NULL) { + return NULL; + } if ((strlen(this_cap_name) + (p - buf)) > CAP_TEXT_SIZE) { cap_free(this_cap_name); errno = ERANGE; @@ -451,12 +482,12 @@ } } - _cap_debug("%s", buf); + _cap_debug("%s", base); if (length_p) { - *length_p = p - buf; + *length_p = p - base; } - return (_libcap_strdup(buf)); + return (_libcap_strdup(base)); } /* @@ -476,3 +507,262 @@ return "UNKNOWN"; } } +
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/empty.c
Added
@@ -0,0 +1 @@ +int main(int argc, char **argv) { return 0; }
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/execable.c
Added
@@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/capability.h> + +#include "execable.h" + +static void usage(int status) +{ + printf("\nusage: libcap.so [--help|--usage|--summary]\n"); + exit(status); +} + +static void summary(void) +{ + cap_value_t bits = cap_max_bits(), c; + cap_mode_t mode = cap_get_mode(); + + printf("\nCurrent mode: %s\n", cap_mode_name(mode)); + printf("Number of cap values known to: this libcap=%d, running kernel=%d\n", + CAP_LAST_CAP+1, bits); + if (bits > CAP_LAST_CAP+1) { + printf("=> Consider upgrading libcap to name:"); + for (c = CAP_LAST_CAP+1; c < bits; c++) { + printf(" %d", c); + } + } else if (bits < CAP_LAST_CAP+1) { + printf("=> Newer kernels also provide support for:"); + for (c = bits; c <= CAP_LAST_CAP; c++) { + char *name = cap_to_name(c); + printf(" %s", name); + cap_free(name); + } + } + printf("\n"); +} + +SO_MAIN(int argc, char **argv) +{ + int i; + const char *cmd = "This library"; + + if (argv != NULL && argv[0] != NULL) { + cmd = argv[0]; + } + printf("%s is the shared library version: " LIBRARY_VERSION ".\n" + "See the License file for distribution information.\n" + "More information on this library is available from:\n" + "\n" + " https://sites.google.com/site/fullycapable/\n", cmd); + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--usage") || !strcmp(argv[i], "--help")) { + usage(0); + } + if (!strcmp(argv[i], "--summary")) { + summary(); + continue; + } + usage(1); + } +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/execable.h
Added
@@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021 Andrew G. Morgan <morgan@kernel.org> + * + * Some header magic to help make a shared object run-able as a stand + * alone executable binary. + * + * This is a slightly more sophisticated implementation than the + * answer I posted here: + * + * https://stackoverflow.com/a/68339111/14760867 + * + * Compile your shared library with: + * + * -DSHARED_LOADER="\"ld-linux...\"" (loader for your target system) + * ... + * --entry=__so_start + */ +#include <stdlib.h> +#include <string.h> + +#ifdef __EXECABLE_H +#error "only include execable.h once" +#endif +#define __EXECABLE_H + +const char __execable_dl_loader[] __attribute((section(".interp"))) = + SHARED_LOADER ; + +static void __execable_parse_args(int *argc_p, char ***argv_p) +{ + int argc = 0; + char **argv = NULL; + FILE *f = fopen("/proc/self/cmdline", "rb"); + if (f != NULL) { + char *mem = NULL, *p; + size_t size = 32, offset; + for (offset=0; ; size *= 2) { + char *new_mem = realloc(mem, size+1); + if (new_mem == NULL) { + perror("unable to parse arguments"); + if (mem != NULL) { + free(mem); + } + exit(1); + } + mem = new_mem; + offset += fread(mem+offset, 1, size-offset, f); + if (offset < size) { + size = offset; + mem[size] = '\0'; + break; + } + } + fclose(f); + for (argc=1, p=mem+size-2; p >= mem; p--) { + argc += (*p == '\0'); + } + argv = calloc(argc+1, sizeof(char *)); + if (argv == NULL) { + perror("failed to allocate memory for argv"); + free(mem); + exit(1); + } + for (p=mem, argc=0, offset=0; offset < size; argc++) { + argv[argc] = mem+offset; + offset += strlen(mem+offset)+1; + } + } + *argc_p = argc; + *argv_p = argv; +} + +/* + * Linux x86 ABI requires the stack be 16 byte aligned. Keep things + * simple and just force it. + */ +#if defined(__i386__) || defined(__x86_64__) +#define __SO_FORCE_ARG_ALIGNMENT __attribute__((force_align_arg_pointer)) +#else +#define __SO_FORCE_ARG_ALIGNMENT +#endif /* def some x86 */ + +/* + * Permit the compiler to override this one. + */ +#ifndef EXECABLE_INITIALIZE +#define EXECABLE_INITIALIZE do { } while(0) +#endif /* ndef EXECABLE_INITIALIZE */ + +/* + * Note, to avoid any runtime confusion, SO_MAIN is a void static + * function. + */ +#define SO_MAIN \ +static void __execable_main(int, char**); \ +extern void __so_start(void); \ +__SO_FORCE_ARG_ALIGNMENT \ +void __so_start(void) \ +{ \ + int argc; \ + char **argv; \ + __execable_parse_args(&argc, &argv); \ + EXECABLE_INITIALIZE; \ + __execable_main(argc, argv); \ + if (argc != 0) { \ + free(argv[0]); \ + free(argv); \ + } \ + exit(0); \ +} \ +static void __execable_main
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/include/sys/.gitignore
Added
@@ -0,0 +1 @@ +psx_syscall.h
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/include/sys/capability.h -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/include/sys/capability.h
Changed
@@ -2,7 +2,7 @@ * <sys/capability.h> * * Copyright (C) 1997 Aleph One - * Copyright (C) 1997-8,2008,2019 Andrew G. Morgan <morgan@kernel.org> + * Copyright (C) 1997,8, 2008,19,20 Andrew G. Morgan <morgan@kernel.org> * * defunct POSIX.1e Standard: 25.2 Capabilities <sys/capability.h> */ @@ -54,14 +54,58 @@ extern cap_value_t cap_max_bits(void); /* + * cap_proc_root reads and (optionally: when root != NULL) changes + * libcap's notion of where the "/proc" filesystem is mounted. When + * the return value is NULL, it should be interpreted as the + * value "/proc". + * + * Note, this is a global value and not considered thread safe to + * write - so the client should take suitable care when changing + * it. + * + * Further, libcap will allocate a memory copy for storing the + * replacement root, and it is this kind of memory that is returned. + * So, when changing the value, the caller should + * cap_free(the-return-value) else cause a memory leak. + * + * Note, the library uses a destructor to clean up the live allocated + * value of the working setting. + */ +extern char *cap_proc_root(const char *root); + +/* * Set identifiers */ typedef enum { - CAP_EFFECTIVE=0, /* Specifies the effective flag */ - CAP_PERMITTED=1, /* Specifies the permitted flag */ - CAP_INHERITABLE=2 /* Specifies the inheritable flag */ + CAP_EFFECTIVE = 0, /* Specifies the effective flag */ + CAP_PERMITTED = 1, /* Specifies the permitted flag */ + CAP_INHERITABLE = 2 /* Specifies the inheritable flag */ } cap_flag_t; +typedef enum { + CAP_IAB_INH = 2, + CAP_IAB_AMB = 3, + CAP_IAB_BOUND = 4 +} cap_iab_vector_t; + +/* + * An opaque generalization of the inheritable bits that includes both + * what ambient bits to raise and what bounding bits to *lower* (aka + * drop). None of these bits once set, using cap_iab_set(), affect + * the running process but are consulted, through the execve() system + * call, by the kernel. Note, the ambient bits ('A') of the running + * process are fragile with respect to other aspects of the "posix" + * (cap_t) operations: most importantly, 'A' cannot ever hold bits not + * present in the intersection of 'pI' and 'pP'. The kernel + * immediately drops all ambient caps whenever such a situation + * arises. Typically, the ambient bits are used to support a naive + * capability inheritance model - at odds with the POSIX (sic) model + * of inheritance where inherited (pI) capabilities need to also be + * wanted by the executed binary (fI) in order to become raised + * through exec. + */ +typedef struct cap_iab_s *cap_iab_t; + /* * These are the states available to each capability */ @@ -73,7 +117,6 @@ /* * User-space capability manipulation routines */ - typedef unsigned cap_mode_t; #define CAP_MODE_UNCERTAIN ((cap_mode_t) 0) #define CAP_MODE_NOPRIV ((cap_mode_t) 1) @@ -81,9 +124,11 @@ #define CAP_MODE_PURE1E ((cap_mode_t) 3) /* libcap/cap_alloc.c */ -extern cap_t cap_dup(cap_t); -extern int cap_free(void *); -extern cap_t cap_init(void); +extern cap_t cap_dup(cap_t); +extern int cap_free(void *); +extern cap_t cap_init(void); +extern cap_iab_t cap_iab_dup(cap_iab_t); +extern cap_iab_t cap_iab_init(void); /* libcap/cap_flag.c */ extern int cap_get_flag(cap_t, cap_value_t, cap_flag_t, cap_flag_value_t *); @@ -91,6 +136,20 @@ cap_flag_value_t); extern int cap_clear(cap_t); extern int cap_clear_flag(cap_t, cap_flag_t); +extern int cap_fill_flag(cap_t cap_d, cap_flag_t to, + cap_t ref, cap_flag_t from); +extern int cap_fill(cap_t, cap_flag_t, cap_flag_t); + +#define CAP_DIFFERS(result, flag) (((result) & (1 << (flag))) != 0) +extern int cap_compare(cap_t, cap_t); +#define CAP_IAB_DIFFERS(result, vector) (((result) & (1 << (vector))) != 0) +extern int cap_iab_compare(cap_iab_t, cap_iab_t); + +extern cap_flag_value_t cap_iab_get_vector(cap_iab_t, cap_iab_vector_t, + cap_value_t); +extern int cap_iab_set_vector(cap_iab_t, cap_iab_vector_t, cap_value_t, + cap_flag_value_t); +extern int cap_iab_fill(cap_iab_t, cap_iab_vector_t, cap_t, cap_flag_t); /* libcap/cap_file.c */ extern cap_t cap_get_fd(int); @@ -115,9 +174,10 @@ #define CAP_AMBIENT_SUPPORTED() (cap_get_ambient(CAP_CHOWN) >= 0) /* libcap/cap_extint.c */ -extern ssize_t cap_size(cap_t); -extern ssize_t cap_copy_ext(void *, cap_t, ssize_t); -extern cap_t cap_copy_int(const void *); +extern ssize_t cap_size(cap_t cap_d); +extern ssize_t cap_copy_ext(void *cap_ext, cap_t cap_d, ssize_t length); +extern cap_t cap_copy_int(const void *cap_ext); +extern cap_t cap_copy_int_check(const void *cap_ext, ssize_t length); /* libcap/cap_text.c */ extern cap_t cap_from_text(const char *); @@ -125,8 +185,8 @@ extern int cap_from_name(const char *, cap_value_t *); extern char * cap_to_name(cap_value_t); -#define CAP_DIFFERS(result, flag) (((result) & (1 << (flag))) != 0) -extern int cap_compare(cap_t, cap_t); +extern char * cap_iab_to_text(cap_iab_t iab); +extern cap_iab_t cap_iab_from_text(const char *text); /* libcap/cap_proc.c */ extern void cap_set_syscall(long int (*new_syscall)(long int, @@ -142,9 +202,32 @@ extern unsigned cap_get_secbits(void); extern int cap_set_secbits(unsigned bits); +extern int cap_prctl(long int pr_cmd, long int arg1, long int arg2, + long int arg3, long int arg4, long int arg5); +extern int cap_prctlw(long int pr_cmd, long int arg1, long int arg2, + long int arg3, long int arg4, long int arg5); extern int cap_setuid(uid_t uid); extern int cap_setgroups(gid_t gid, size_t ngroups, const gid_t groups[]); +extern cap_iab_t cap_iab_get_proc(void); +extern cap_iab_t cap_iab_get_pid(pid_t); +extern int cap_iab_set_proc(cap_iab_t iab); + +typedef struct cap_launch_s *cap_launch_t; + +extern cap_launch_t cap_new_launcher(const char *arg0, const char * const *argv, + const char * const *envp); +extern cap_launch_t cap_func_launcher(int (callback_fn)(void *detail)); +extern int cap_launcher_callback(cap_launch_t attr, + int (callback_fn)(void *detail)); +extern int cap_launcher_setuid(cap_launch_t attr, uid_t uid); +extern int cap_launcher_setgroups(cap_launch_t attr, gid_t gid, + int ngroups, const gid_t *groups); +extern int cap_launcher_set_mode(cap_launch_t attr, cap_mode_t flavor); +extern cap_iab_t cap_launcher_set_iab(cap_launch_t attr, cap_iab_t iab); +extern int cap_launcher_set_chroot(cap_launch_t attr, const char *chroot); +extern pid_t cap_launch(cap_launch_t attr, void *detail); + /* * system calls - look to libc for function to system call * mapping. Note, libcap does not use capset directly, but permits the
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/include/uapi/linux/capability.h -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/include/uapi/linux/capability.h
Changed
@@ -331,6 +331,8 @@ #define CAP_AUDIT_CONTROL 30 +/* Set capabilities on files. */ + #define CAP_SETFCAP 31 /* Override MAC access. @@ -366,8 +368,50 @@ #define CAP_AUDIT_READ 37 +/* Allow system performance and observability privileged operations using + * perf_events, i915_perf and other kernel subsystems. */ + +#define CAP_PERFMON 38 + +/* + * CAP_BPF allows the following BPF operations: + * - Creating all types of BPF maps + * - Advanced verifier features + * - Indirect variable access + * - Bounded loops + * - BPF to BPF function calls + * - Scalar precision tracking + * - Larger complexity limits + * - Dead code elimination + * - And potentially other features + * - Loading BPF Type Format (BTF) data + * - Retrieve xlated and JITed code of BPF programs + * - Use bpf_spin_lock() helper + * + * CAP_PERFMON relaxes the verifier checks further: + * - BPF progs can use of pointer-to-integer conversions + * - speculation attack hardening measures are bypassed + * - bpf_probe_read to read arbitrary kernel memory is allowed + * - bpf_trace_printk to print kernel memory is allowed + * + * CAP_SYS_ADMIN is required to use bpf_probe_write_user. + * + * CAP_SYS_ADMIN is required to iterate system wide loaded + * programs, maps, links, BTFs and convert their IDs to file descriptors. + * + * CAP_PERFMON and CAP_BPF are required to load tracing programs. + * CAP_NET_ADMIN and CAP_BPF are required to load networking programs. + */ + +#define CAP_BPF 39 + +/* Allow checkpoint/restore related operations */ +/* Allow PID selection during clone3() */ +/* Allow writing to ns_last_pid */ + +#define CAP_CHECKPOINT_RESTORE 40 -#define CAP_LAST_CAP CAP_AUDIT_READ +#define CAP_LAST_CAP CAP_CHECKPOINT_RESTORE #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/include/uapi/linux/securebits.h -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/include/uapi/linux/securebits.h
Changed
@@ -22,7 +22,7 @@ #define SECBIT_NOROOT_LOCKED (issecure_mask(SECURE_NOROOT_LOCKED)) /* When set, setuid to/from uid 0 does not trigger capability-"fixup". - When unset, to provide compatiblility with old programs relying on + When unset, to provide compatibility with old programs relying on set*uid to gain/lose privilege, transitions to/from uid 0 cause capabilities to be gained/lost. */ #define SECURE_NO_SETUID_FIXUP 2
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/libcap/libcap.h -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/libcap.h
Changed
@@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Andrew G Morgan <morgan@kernel.org> + * Copyright (c) 1997,2020 Andrew G Morgan <morgan@kernel.org> * * This file contains internal definitions for the various functions in * this small capability library. @@ -9,6 +9,7 @@ #define LIBCAP_H #include <errno.h> +#include <sched.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -28,7 +29,7 @@ #ifndef _LINUX_CAPABILITY_U32S_1 # define _LINUX_CAPABILITY_U32S_1 1 -#endif /* ndef _LINUX_CAPABILITY_U32S */ +#endif /* ndef _LINUX_CAPABILITY_U32S_1 */ /* * Do we match the local kernel? @@ -113,6 +114,7 @@ #define CAP_T_MAGIC 0xCA90D0 struct _cap_struct { + __u8 mutex; struct __user_cap_header_struct head; union { struct __user_cap_data_struct set; @@ -121,12 +123,41 @@ uid_t rootid; }; +/* + * Elementary exclusive locking primatives for situations where + * linking with pthreads needs it, but such linking is not common. + * + * _cap_mu_blocked(x) attempts to lock x but if already locked, returns true + * _cap_mu_lock(x) attempts to lock and waits until the lock is granted + * _cap_mu_unlock(x) unconditionally unlocks the lock + * _cap_mu_unlock_return(x, y) unlock lock x and return value y + */ +#define _cap_mu_blocked(x) \ + __atomic_test_and_set((void *)(x), __ATOMIC_SEQ_CST) +#define _cap_mu_lock(x) \ + while (_cap_mu_blocked(x)) sched_yield() +#define _cap_mu_unlock(x) \ + __atomic_clear((void *) (x), __ATOMIC_SEQ_CST) +#define _cap_mu_unlock_return(x, y) \ + do { _cap_mu_unlock(x); return (y); } while (0) + /* the maximum bits supportable */ #define __CAP_MAXBITS (__CAP_BLKS * 32) /* string magic for cap_free */ #define CAP_S_MAGIC 0xCA95D0 +/* iab set magic for cap_free */ +#define CAP_IAB_MAGIC 0xCA91AB + +/* launcher magic for cap_free */ +#define CAP_LAUNCH_MAGIC 0xCA91AC + +#define magic_of(x) ((x) ? *(-2 + (const __u32 *) x) : 0) +#define good_cap_t(x) (CAP_T_MAGIC == magic_of(x)) +#define good_cap_iab_t(x) (CAP_IAB_MAGIC == magic_of(x)) +#define good_cap_launch_t(x) (CAP_LAUNCH_MAGIC == magic_of(x)) + /* * kernel API cap set abstraction */ @@ -136,14 +167,6 @@ #define isset_cap(y, x, set) ((y)->u[(x) >> 5].flat[set] & (1u << ((x)&31))) /* - * Private definitions for internal use by the library. - */ - -#define __libcap_check_magic(c,magic) ((c) && *(-1+(__u32 *)(c)) == (magic)) -#define good_cap_t(c) __libcap_check_magic(c, CAP_T_MAGIC) -#define good_cap_string(c) __libcap_check_magic(c, CAP_S_MAGIC) - -/* * These match CAP_DIFFERS() expectations */ #define LIBCAP_EFF (1 << CAP_EFFECTIVE) @@ -179,6 +202,9 @@ #endif /* DEBUG */ extern char *_libcap_strdup(const char *text); +extern void _libcap_initialize(void); + +#define EXECABLE_INITIALIZE _libcap_initialize() /* * These are semi-public prototypes, they will only be defined in @@ -219,7 +245,75 @@ min = mid + 1; \ } \ } \ - val = min ? min : fallback; \ + val = min ? (min <= high ? min : fallback) : fallback; \ } while(0) +/* + * cap_iab_s holds a collection of inheritable capability bits. The i + * bits are inheritable (these are the same as those in cap_t), the a + * bits are ambient bits (which cannot be a superset of i&p), and nb + * are the bits that will be dropped from the bounding set when + * applied. + */ +struct cap_iab_s { + __u8 mutex; + __u32 i[_LIBCAP_CAPABILITY_U32S]; + __u32 a[_LIBCAP_CAPABILITY_U32S]; + __u32 nb[_LIBCAP_CAPABILITY_U32S]; +}; + +#define LIBCAP_IAB_I_FLAG (1U << CAP_IAB_INH) +#define LIBCAP_IAB_A_FLAG (1U << CAP_IAB_AMB) +#define LIBCAP_IAB_IA_FLAG (LIBCAP_IAB_I_FLAG | LIBCAP_IAB_A_FLAG) +#define LIBCAP_IAB_NB_FLAG (1U << CAP_IAB_BOUND) + +/* + * The following support launching another process without destroying + * the state of the current process. This is especially useful for + * multithreaded applications. + */ +struct cap_launch_s { + __u8 mutex; + /* + * Once forked but before active privilege is changed, this + * function (if non-NULL) is called. + */ + int (*custom_setup_fn)(void *detail); + + /* + * user and groups to be used by the forked child. + */ + int change_uids; + uid_t uid; + + int change_gids; + gid_t gid; + int ngroups; + const gid_t *groups; + + /* + * mode holds the preferred capability mode. Any non-uncertain + * setting here will require an empty ambient set. + */ + int change_mode; + cap_mode_t mode; + + /* + * i,a,[n]b caps. These bitmaps hold all of the capability sets that + * cap_launch will affect. nb holds values to be lowered in the bounding + * set. + */ + struct cap_iab_s *iab; + + /* chroot holds a preferred chroot for the launched child. */ + char *chroot; + + /* + * execve style arguments + */ + const char *arg0; + const char *const *argv; + const char *const *envp; +}; + #endif /* LIBCAP_H */
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/libcap/psx_exec.c
Added
@@ -0,0 +1,15 @@ +#include <stdio.h> +#include "execable.h" + +SO_MAIN(int argc, char **argv) +{ + const char *cmd = "This library"; + if (argv != NULL && argv[0] != NULL) { + cmd = argv[0]; + } + printf("%s is the shared library version: " LIBRARY_VERSION ".\n" + "See the License file for distribution information.\n" + "More information on this library is available from:\n" + "\n" + " https://sites.google.com/site/fullycapable/\n", cmd); +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/pam_cap/.gitignore -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/.gitignore
Changed
@@ -1,3 +1,6 @@ pam_cap.so testlink test_pam_cap +lazylink.so +pam_cap_linkopts +LIBCAP
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/pam_cap/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/Makefile
Changed
@@ -3,6 +3,9 @@ topdir=$(shell pwd)/.. include ../Make.Rules +# Always build pam_cap sources this way: +CFLAGS += -fPIC + all: pam_cap.so $(MAKE) testlink @@ -10,34 +13,78 @@ mkdir -p -m 0755 $(FAKEROOT)$(LIBDIR)/security install -m 0755 pam_cap.so $(FAKEROOT)$(LIBDIR)/security -# Note (as the author of much of the Linux-PAM library, I am confident -# that this next line does *not* require -lpam on it.) If you think it -# does, *verify that it does*, and if you observe that it fails as -# written (and you know why it fails), email me and explain why. Thanks! - -pam_cap.so: pam_cap.o - $(LD) -o pam_cap.so $< $(LIBCAPLIB) $(LDFLAGS) - -pam_cap.o: pam_cap.c - $(CC) $(CFLAGS) $(IPATH) -c $< -o $@ - -test_pam_cap: test_pam_cap.c pam_cap.c - $(CC) $(CFLAGS) $(IPATH) -o $@ test_pam_cap.c $(LIBCAPLIB) $(LDFLAGS) --static - -testlink: test.c pam_cap.o - $(CC) $(CFLAGS) -o $@ $+ -lpam -ldl $(LIBCAPLIB) $(LDFLAGS) - -test: pam_cap.so - make testlink - -sudotest: test test_pam_cap - sudo ./test_pam_cap root 0x0 0x0 0x0 config=./capability.conf - sudo ./test_pam_cap root 0x0 0x0 0x0 config=./sudotest.conf - sudo ./test_pam_cap alpha 0x0 0x0 0x0 config=./capability.conf - sudo ./test_pam_cap alpha 0x0 0x1 0x80 config=./sudotest.conf - sudo ./test_pam_cap beta 0x0 0x1 0x0 config=./sudotest.conf - sudo ./test_pam_cap gamma 0x0 0x0 0x81 config=./sudotest.conf - sudo ./test_pam_cap delta 0x41 0x80 0x41 config=./sudotest.conf +../libcap/loader.txt: + $(MAKE) -C ../libcap loader.txt + +execable.o: execable.c ../libcap/execable.h ../libcap/loader.txt + $(CC) $(CFLAGS) $(CPPFLAGS) -DLIBCAP_VERSION=\"libcap-$(VERSION).$(MINOR)\" -DSHARED_LOADER=\"$(shell cat ../libcap/loader.txt)\" -c execable.c -o $@ + +LIBCAP: + $(MAKE) -C ../libcap all + touch $@ + +pam_cap.so: pam_cap.o execable.o pam_cap_linkopts LIBCAP + cat pam_cap_linkopts | xargs -e $(LD) $(LDFLAGS) -o $@ pam_cap.o execable.o $(LIBCAPLIB) + +# Some distributions force link everything at compile time, and don't +# take advantage of libpam's dlopen runtime options to resolve ill +# defined symbols from its own linkage as needed. (As the original +# author of that part of libpam, I consider this force linking +# premature optimization.) We debugged its consequences to pam_cap.so +# as part of: +# +# https://bugzilla.kernel.org/show_bug.cgi?id=214023 +# +# If the current build environment is one of those, or we can't +# reliably prove it isn't, extend the link options for pam_cap.so to +# force linkage against libpam and the gazillion other things libpam +# is linked against... +# +# If you want to force this behavior one way or the other, use the +# make FORCELINKPAM=yes or FORCELINKPAM=no override. +ifeq ($(FORCELINKPAM),yes) +pam_cap_linkopts: Makefile + echo "-Wl,-e,__so_start -lpam" > $@ +else +ifeq ($(FORCELINKPAM),no) +pam_cap_linkopts: Makefile + echo "-Wl,-e,__so_start" > $@ +else +pam_cap_linkopts: lazylink.so + echo "-Wl,-e,__so_start" > $@ + ./lazylink.so || echo "-lpam" >> $@ + +lazylink.so: lazylink.c ../libcap/execable.h ../libcap/loader.txt + $(LD) -o $@ $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) lazylink.c -DSHARED_LOADER=\"$(shell cat ../libcap/loader.txt)\" -Wl,-e,__so_start +endif +endif + +../libcap/libcap.a: + $(MAKE) -C ../libcap libcap.a + +# Avoid $(LDFLAGS) here to avoid conflicts with --static for a in-tree +# test binary. +test_pam_cap: test_pam_cap.c pam_cap.c ../libcap/libcap.a + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ test_pam_cap.c $(LIBCAPLIB) --static + +testlink: test.o pam_cap.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ -lpam -ldl $(LIBCAPLIB) + +test: testlink test_pam_cap pam_cap.so + ./test_pam_cap + LD_LIBRARY_PATH=../libcap ./pam_cap.so + LD_LIBRARY_PATH=../libcap ./pam_cap.so --help + @echo "module can be run as an executable!" + +sudotest: test_pam_cap + $(SUDO) ./test_pam_cap root 0x0 0x0 0x0 config=./capability.conf + $(SUDO) ./test_pam_cap root 0x0 0x0 0x0 config=./sudotest.conf + $(SUDO) ./test_pam_cap alpha 0x0 0x0 0x0 config=./capability.conf + $(SUDO) ./test_pam_cap alpha 0x0 0x1 0x80 config=./sudotest.conf + $(SUDO) ./test_pam_cap beta 0x0 0x1 0x0 config=./sudotest.conf + $(SUDO) ./test_pam_cap gamma 0x0 0x0 0x81 config=./sudotest.conf + $(SUDO) ./test_pam_cap delta 0x41 0x80 0x41 config=./sudotest.conf clean: - rm -f *.o *.so testlink test_pam_cap *~ + rm -f *.o *.so testlink lazylink.so test_pam_cap pam_cap_linkopts *~ + rm -f LIBCAP
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/pam_cap/capability.conf -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/capability.conf
Changed
@@ -6,14 +6,26 @@ # # In order to use this module, it must have been linked with libcap # and thus you'll know about Linux's capability support. -# [If you don't know about libcap, the sources for it are here: +# [If you don't know about libcap, read more about it here: # -# http://www.kernel.org/pub/linux/libs/security/linux-privs/ +# https://sites.google.com/site/fullycapable/ +# +# There is a page devoted to pam_cap.so here: +# +# https://sites.google.com/site/fullycapable/pam_cap-so # # .] # # Here are some sample lines (remove the preceding '#' if you want to -# use them +# use them. +# +# The pam_cap.so module accepts the following arguments: +# +# debug - be more verbose logging things (unused by pam_cap for now) +# config=<file> - override the default config for the module with file +# keepcaps - workaround for applications that setuid without this +# autoauth - if you want pam_cap.so to always succeed for the auth phase +# default=<iab> - provide a fallback IAB value if there is no '*' rule ## user 'morgan' gets the CAP_SETFCAP inheritable capability (commented out!) #cap_setfcap morgan @@ -24,20 +36,23 @@ ## 'everyone else' gets no inheritable capabilities (restrictive config) none * -## if there is no '*' entry, all users not explicitly mentioned will -## get all available capabilities. This is a permissive default, and -## possibly not what you want... On first reading, you might think this -## is a security problem waiting to happen, but it defaults to not being -## so in this sample file! Further, by 'get', we mean 'get in their inheritable -## set'. That is, if you look at a random process, even one run by root, -## you will see it has no inheritable capabilities (by default): +## if there is no '*' entry, and no "default=<iab>" pam_cap.so module +## argument to fallback on, all users not explicitly mentioned will +## get all currently available inheritable capabilities. This is a +## permissive default, and possibly not what you want... On first +## reading, you might think this is a security problem waiting to +## happen, but it defaults to not being so in this sample file! +## Further, by 'get', we mean 'get in their IAB sets'. That is, if you +## look at a random process, even one run by root, you will see it has +## no IAB capabilities (by default): ## ## $ /sbin/capsh --decode=$(grep CapInh /proc/1/status|awk '{print $2}') ## 0000000000000000= ## -## The pam_cap module simply alters the value of this capability -## set. Including the 'none *' forces use of this module with an -## unspecified user to have their inheritable set forced to zero. +## The pam_cap module simply alters the value of the inheritable +## capability vactors (IAB). Including the 'none *' forces use of this +## module with an unspecified user to have their inheritable set +## forced to zero. ## ## Omitting the line will cause the inheritable set to be unmodified ## from what the parent process had (which is generally 0 unless the
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/execable.c
Added
@@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Andrew G. Morgan <morgan@kernel.org> + * + * The purpose of this file is to provide an executable mode for the + * pam_cap.so binary. If you run it directly, all it does is print + * version information. + * + * It accepts the optional --help argument which causes the executable + * to display a summary of all the supported, pam stacked, module + * arguments. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../libcap/execable.h" + +SO_MAIN(int argc, char **argv) +{ + const char *cmd = "<pam_cap.so>"; + if (argv != NULL) { + cmd = argv[0]; + } + + printf( + "%s (version " LIBCAP_VERSION ") is a PAM module to specify\n" + "inheritable (IAB) capabilities via the libpam authentication\n" + "abstraction. See the libcap License file for licensing information.\n" + "\n" + "Release notes and feature documentation for libcap and pam_cap.so\n" + "can be found at:\n" + "\n" + " https://sites.google.com/site/fullycapable/\n", cmd); + if (argc <= 1) { + return; + } + + if (argc > 2 || argv[1] == NULL || strcmp(argv[1], "--help")) { + printf("\n%s only supports the optional argument --help\n", cmd); + exit(1); + } + + printf("\n" + "%s supports the following module arguments:\n" + "\n" + "debug - verbose logging (ignored for now)\n" + "config=<file> - override the default config with file\n" + "keepcaps - workaround for apps that setuid without this\n" + "autoauth - pam_cap.so to always succeed for the 'auth' phase\n" + "default=<iab> - fallback IAB value if there is no '*' rule\n" + "defer - apply IAB value at pam_exit (not via setcred)\n", + cmd); +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/lazylink.c
Added
@@ -0,0 +1,20 @@ +/* + * Test if the provided LDFLAGS support lazy linking + */ +#include <stdio.h> +#include <stdlib.h> + +#include "../libcap/execable.h" + +extern int nothing_sets_this(void); +extern void nothing_uses_this(void); + +void nothing_uses_this(void) +{ + nothing_sets_this(); +} + +SO_MAIN(int argc, char **argv) +{ + exit(0); +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/pam_cap/pam_cap.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/pam_cap.c
Changed
@@ -1,13 +1,15 @@ /* - * Copyright (c) 1999,2007,2019 Andrew G. Morgan <morgan@kernel.org> + * Copyright (c) 1999,2007,2019-21 Andrew G. Morgan <morgan@kernel.org> * * The purpose of this module is to enforce inheritable, bounding and * ambient capability sets for a specified user. */ -/* #define DEBUG */ +/* #define PAM_DEBUG */ +#ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE +#endif #include <errno.h> #include <grp.h> @@ -19,6 +21,7 @@ #include <string.h> #include <syslog.h> #include <sys/capability.h> +#include <sys/prctl.h> #include <sys/types.h> #include <linux/limits.h> @@ -29,10 +32,18 @@ #define CAP_FILE_BUFFER_SIZE 4096 #define CAP_FILE_DELIMITERS " \t\n" +/* + * pam_cap_s is used to summarize argument values in a parsed form. + */ struct pam_cap_s { int debug; + int keepcaps; + int autoauth; + int defer; const char *user; const char *conf_filename; + const char *fallback; + pam_handle_t *pamh; }; /* @@ -58,6 +69,9 @@ } *groups = calloc(ngrps, sizeof(char *)); + if (*groups == NULL) { + return -1; + } int g_n = 0, i; for (i = 0; i < ngrps; i++) { const struct group *g = getgrgid(grps[i]); @@ -72,7 +86,7 @@ return 0; } -/* obtain the inheritable capabilities for the current user */ +/* obtain the desired IAB capabilities for the current user */ static char *read_capabilities_for_user(const char *user, const char *source) { @@ -173,6 +187,51 @@ } /* + * This is the "defer" cleanup function that actually applies the IAB + * tuple. This happens really late in the PAM session, hopefully after + * the application has performed its setuid() function. + */ +static void iab_apply(pam_handle_t *pamh, void *data, int error_status) +{ + cap_iab_t iab = data; + int retval = error_status & ~(PAM_DATA_REPLACE|PAM_DATA_SILENT); + +#ifdef PAM_DEBUG + { + cap_t c = cap_get_proc(); + cap_iab_t tu = cap_iab_get_proc(); + char *tc, *ttu; + tc = cap_to_text(c, NULL); + ttu = cap_iab_to_text(tu); + + D(("iab_apply with uid=%d,euid=%d and error_status=0x%08x \"%s\", [%s]", + getuid(), geteuid(), error_status, tc, ttu)); + + cap_free(ttu); + cap_free(tc); + cap_free(tu); + cap_free(c); + } +#endif + + data = NULL; + if (error_status & PAM_DATA_REPLACE) { + goto done; + } + + if (retval != PAM_SUCCESS || !(error_status & PAM_DATA_SILENT)) { + goto done; + } + + if (cap_iab_set_proc(iab) != 0) { + D(("IAB setting failed")); + } + +done: + cap_free(iab); +} + +/* * Set capabilities for current process to match the current * permitted+executable sets combined with the configured inheritable * set. @@ -182,11 +241,7 @@ cap_t cap_s; char *conf_caps; int ok = 0; - int has_ambient = 0, has_bound = 0; - int *bound = NULL, *ambient = NULL; - cap_flag_value_t had_setpcap = 0; - cap_value_t max_caps = 0; - const cap_value_t wanted_caps[] = { CAP_SETPCAP }; + cap_iab_t iab; cap_s = cap_get_proc(); if (cap_s == NULL) { @@ -194,21 +249,17 @@ strerror(errno))); return 0; } - if (cap_get_flag(cap_s, CAP_SETPCAP, CAP_EFFECTIVE, &had_setpcap)) { - D(("failed to read a e capability: %s", strerror(errno))); - goto cleanup_cap_s; - } - if (cap_set_flag(cap_s, CAP_EFFECTIVE, 1, wanted_caps, CAP_SET) != 0) { - D(("unable to raise CAP_SETPCAP: %s", strerrno(errno))); - goto cleanup_cap_s; - } conf_caps = read_capabilities_for_user(cs->user, cs->conf_filename ? cs->conf_filename:USER_CAP_FILE ); if (conf_caps == NULL) { D(("no capabilities found for user [%s]", cs->user)); - goto cleanup_cap_s; + if (cs->fallback == NULL) { + goto cleanup_cap_s; + } + conf_caps = strdup(cs->fallback); + D(("user [%s] received fallback caps [%s]", cs->user, conf_caps)); } ssize_t conf_caps_length = strlen(conf_caps); @@ -218,151 +269,57 @@ * likely to be the same as none for sensible system defaults. */ ok = 1; - goto cleanup_caps; - } - - if (cap_set_proc(cap_s) != 0) { - D(("unable to use CAP_SETPCAP: %s", strerrno(errno))); - goto cleanup_caps; - } - if (cap_reset_ambient() == 0) { - /* Ambient set fully declared by this config. */ - has_ambient = 1; + goto cleanup_conf; } if (!strcmp(conf_caps, "none")) { - /* clearing CAP_INHERITABLE will also clear the ambient caps. */ + /* clearing CAP_INHERITABLE will also clear the ambient caps, + * but for legacy reasons we do not alter the bounding set. */ cap_clear_flag(cap_s, CAP_INHERITABLE); - } else { - /* - * we know we have to perform some capability operations and - * we need to know how many capabilities there are to do it - * successfully. - */ - while (cap_get_bound(max_caps) >= 0) { - max_caps++; - } - if (max_caps != cap_max_bits()) { - D(("this vintage of libcap cannot be trusted; give up")); - goto cleanup_caps; - } - has_bound = (max_caps != 0); - if (has_bound) { - bound = calloc(max_caps, sizeof(int)); - if (has_ambient) { - /* In kernel lineage, bound came first. */ - ambient = calloc(max_caps, sizeof(int)); - } - } -
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/pam_cap/test_pam_cap.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/pam_cap/test_pam_cap.c
Changed
@@ -5,6 +5,11 @@ * it. */ +#define _DEFAULT_SOURCE + +#include <unistd.h> +#include <sys/types.h> + #include "./pam_cap.c" const char *test_groups[] = { @@ -46,6 +51,17 @@ return 0; } +int pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data, + void (*cleanup)(pam_handle_t *pamh, void *data, + int error_status)) { + if (cleanup != iab_apply) { + errno = EINVAL; + return -1; + } + cap_free(data); + return -1; +} + int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) { int i,j; for (i = 0; i < n_users; i++) { @@ -121,12 +137,111 @@ cap_free(prev); } +struct vargs { + struct pam_cap_s cs; + const char *args[5]; +}; + +static int test_arg_parsing(void) { + static struct vargs vs[] = { + { + { 1, 0, 0, 0, NULL, NULL, NULL }, + { "debug", NULL } + }, + { + { 0, 1, 0, 0, NULL, NULL, NULL }, + { "keepcaps", NULL } + }, + { + { 0, 0, 1, 0, NULL, NULL, NULL }, + { "autoauth", NULL } + }, + { + { 1, 0, 1, 0, NULL, NULL, NULL }, + { "autoauth", "debug", NULL } + }, + { + { 0, 0, 0, 0, NULL, "/over/there", NULL }, + { "config=/over/there", NULL } + }, + { + { 0, 0, 0, 0, NULL, NULL, "^cap_setfcap" }, + { "default=^cap_setfcap", NULL } + }, + { + { 0, 0, 0, 1, NULL, NULL, NULL }, + { "defer", NULL } + }, + { + { 0, 0, 0, 0, NULL, NULL, NULL }, + { NULL } + } + }; + int i; + + for (i=0; ; i++) { + int argc; + const char **argv; + struct vargs *v; + + v = &vs[i]; + argv = v->args; + + for (argc = 0; argv[argc] != NULL; argc++); + + struct pam_cap_s cs; + parse_args(argc, argv, &cs); + + if (cs.debug != v->cs.debug) { + printf("test_arg_parsing[%d]: debug=%d, wanted debug=%d\n", + i, cs.debug, v->cs.debug); + return 1; + } + if (cs.keepcaps != v->cs.keepcaps) { + printf("test_arg_parsing[%d]: keepcaps=%d, wanted keepcaps=%d\n", + i, cs.keepcaps, v->cs.keepcaps); + return 1; + } + if (cs.autoauth != v->cs.autoauth) { + printf("test_arg_parsing[%d]: autoauth=%d, wanted autoauth=%d\n", + i, cs.autoauth, v->cs.autoauth); + return 1; + } + if (cs.conf_filename != v->cs.conf_filename && + strcmp(cs.conf_filename, v->cs.conf_filename)) { + printf("test_arg_parsing[%d]: conf_filename=[%s], wanted=[%s]\n", + i, cs.conf_filename, v->cs.conf_filename); + return 1; + } + if (cs.fallback != v->cs.fallback && + strcmp(cs.fallback, v->cs.fallback)) { + printf("test_arg_parsing[%d]: fallback=[%s], wanted=[%s]\n", + i, cs.fallback, v->cs.fallback); + return 1; + } + + if (argc == 0) { + break; + } + } + return 0; +} + /* * args: user a b i config-args... */ int main(int argc, char *argv[]) { unsigned long int before[3], change[3], after[3]; + if (test_arg_parsing()) { + printf("failed to parse arguments\n"); + exit(1); + } + if (read_capabilities_for_user("morgan", "/dev/null") != NULL) { + printf("/dev/null should return no capabilities\n"); + exit(1); + } + /* * Start out with a cleared inheritable set. */ @@ -134,6 +249,16 @@ cap_clear_flag(orig, CAP_INHERITABLE); cap_set_proc(orig); + if (getuid() != 0) { + cap_free(orig); + printf("test_pam_cap: OK! (Skipping privileged tests (uid!=0))\n"); + exit(0); + } + if (argc == 1) { + printf("test_pam_cap: OK (kick the tires test)\n"); + exit(0); + } + change[A] = strtoul(argv[2], NULL, 0); change[B] = strtoul(argv[3], NULL, 0); change[I] = strtoul(argv[4], NULL, 0);
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/.gitignore -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/.gitignore
Changed
@@ -1,6 +1,8 @@ capsh +tcapsh-static getcap getpcaps setcap verify-caps compare-cap +uns_test
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/Makefile
Changed
@@ -4,41 +4,67 @@ # # Programs: all of the examples that we will compile # -PROGS=getpcaps capsh getcap setcap +PROGS=getpcaps getcap setcap BUILD=$(PROGS) -ifneq ($(DYNAMIC),yes) -LDFLAGS += --static -endif +all: $(BUILD) capsh -DEPS=../libcap/libcap.a ../libcap/libpsx.a +ifeq ($(DYNAMIC),yes) +LDPATH = LD_LIBRARY_PATH=../libcap +DEPS = ../libcap/libcap.so +else +# For this build variant override the LDFLAGS to link statically from +# libraries within the build tree. If you never want this, use +# make DYNAMIC=yes ... +LDFLAGS = --static +DEPS = ../libcap/libcap.a +endif -all: $(BUILD) +../libcap/libcap.a: + $(MAKE) -C ../libcap libcap.a -$(DEPS): - make -C ../libcap all +../libcap/libcap.so: + $(MAKE) -C ../libcap libcap.so $(BUILD): %: %.o $(DEPS) - $(CC) $(CFLAGS) -o $@ $< $(LIBCAPLIB) $(LDFLAGS) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBCAPLIB) %.o: %.c $(INCS) - $(CC) $(IPATH) $(CFLAGS) -c $< -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ install: all mkdir -p -m 0755 $(FAKEROOT)$(SBINDIR) - for p in $(PROGS) ; do \ + for p in $(PROGS) capsh ; do \ install -m 0755 $$p $(FAKEROOT)$(SBINDIR) ; \ done ifeq ($(RAISE_SETFCAP),yes) $(FAKEROOT)$(SBINDIR)/setcap cap_setfcap=i $(FAKEROOT)$(SBINDIR)/setcap endif -test: $(PROGS) +test: + @echo "no program tests without privilege, try 'make sudotest'" + +capshdoc.c.cf: capshdoc.c ./mkcapshdoc.sh + ./mkcapshdoc.sh > $@ + diff -u capshdoc.c $@ || (rm $@ ; exit 1) + +capsh: capsh.c capshdoc.c.cf capshdoc.h $(DEPS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(CAPSH_SHELL) $(LDFLAGS) -o $@ $< capshdoc.c $(LIBCAPLIB) + +# Statically linked with minimal linkage flags to enable running in a +# chroot and in other in-tree testing contexts. +tcapsh-static: capsh.c capshdoc.c.cf capshdoc.h $(DEPS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(CAPSH_SHELL) -o $@ $< capshdoc.c $(LIBCAPLIB) --static + +uns_test: ../tests/uns_test.c + $(MAKE) -C ../tests uns_test + cp ../tests/uns_test . -sudotest: test - sudo ./quicktest.sh +sudotest: tcapsh-static uns_test capsh setcap getcap getpcaps tcapsh-static + $(SUDO) $(LDPATH) ./quicktest.sh clean: $(LOCALCLEAN) - rm -f *.o $(BUILD) tcapsh ping hack.sh compare-cap + rm -f *.o $(BUILD) privileged ping hack.sh compare-cap uns_test + rm -f capsh tcapsh* capshdoc.*.cf
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/capsh.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/capsh.c
Changed
@@ -1,15 +1,22 @@ /* * Copyright (c) 2008-11,16,19,2020 Andrew G. Morgan <morgan@kernel.org> * - * This is a simple 'bash' wrapper program that can be used to - * raise and lower both the bset and pI capabilities before invoking - * /bin/bash (hardcoded right now). + * 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). */ +#ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #include <stdio.h> #include <string.h> @@ -25,8 +32,43 @@ #include <sys/wait.h> #include <unistd.h> +#ifndef SHELL +#define SHELL "/bin/bash" +#endif /* ndef SHELL */ + +#include "./capshdoc.h" + #define MAX_GROUPS 100 /* max number of supplementary groups for user */ +/* parse a non-negative integer with some error handling */ +static unsigned long nonneg_uint(const char *text, const char *prefix, int *ok) +{ + char *remains; + unsigned long value; + ssize_t len = strlen(text); + + if (len == 0 || *text == '-') { + goto fail; + } + value = strtoul(text, &remains, 0); + if (*remains) { + goto fail; + } + if (ok != NULL) { + *ok = 1; + } + return value; + +fail: + if (ok == NULL) { + fprintf(stderr, "%s: want non-negative integer, got \"%s\"\n", + prefix, text); + exit(1); + } + *ok = 0; + return 0; +} + static char *binary(unsigned long value) { static char string[8*sizeof(unsigned long) + 1]; @@ -70,32 +112,65 @@ } } +static void display_current(void) +{ + cap_t all; + char *text; + + all = cap_get_proc(); + if (all == NULL) { + perror("failed to get process capabilities"); + exit(1); + } + text = cap_to_text(all, NULL); + printf("Current: %s\n", text); + cap_free(text); + cap_free(all); +} + +static void display_current_iab(void) +{ + cap_iab_t iab; + char *text; + + iab = cap_iab_get_proc(); + if (iab == NULL) { + perror("failed to get IAB for process"); + exit(1); + } + text = cap_iab_to_text(iab); + if (text == NULL) { + perror("failed to obtain text for IAB"); + cap_free(iab); + exit(1); + } + printf("Current IAB: %s\n", text); + cap_free(text); + cap_free(iab); +} + /* arg_print displays the current capability state of the process */ static void arg_print(void) { long set; int status, j; - cap_t all; - char *text; const char *sep; struct group *g; gid_t groups[MAX_GROUPS], gid; uid_t uid, euid; struct passwd *u, *eu; - all = cap_get_proc(); - text = cap_to_text(all, NULL); - printf("Current: %s\n", text); - cap_free(text); - cap_free(all); - + display_current(); display_prctl_set("Bounding", cap_get_bound); display_prctl_set("Ambient", cap_get_ambient); + display_current_iab(); + 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"); @@ -145,29 +220,42 @@ static const cap_value_t raise_setpcap[1] = { CAP_SETPCAP }; static const cap_value_t raise_chroot[1] = { CAP_SYS_CHROOT }; -static void push_pcap(cap_t *orig_p, cap_t *raised_for_setpcap_p) +static cap_t will_need_setpcap(int strict) { - /* - * We need to do this here because --inh=XXX may have reset - * orig and it isn't until we are within the --drop code that - * we know what the prevailing (orig) pI value is. - */ - *orig_p = cap_get_proc(); - if (NULL == *orig_p) { + cap_flag_value_t enabled; + cap_t raised = NULL; + + if (strict) { + return NULL; + } + + raised = cap_get_proc(); + if (raised == NULL) { perror("Capabilities not available"); exit(1); } - - *raised_for_setpcap_p = cap_dup(*orig_p); - if (NULL == *raised_for_setpcap_p) { - fprintf(stderr, "modification requires CAP_SETPCAP\n"); + if (cap_get_flag(raised, CAP_SETPCAP, CAP_EFFECTIVE, &enabled) != 0) { + perror("Unable to check CAP_EFFECTIVE CAP_SETPCAP value"); exit(1); } - if (cap_set_flag(*raised_for_setpcap_p, CAP_EFFECTIVE, 1, - raise_setpcap, CAP_SET) != 0) { - perror("unable to select CAP_SETPCAP"); + if (enabled != CAP_SET) { + cap_set_flag(raised, CAP_EFFECTIVE, 1, raise_setpcap, CAP_SET); + } else { + /* no need to raise - since already raised */ + cap_free(raised); + raised = NULL; + } + return raised; +} + +static void push_pcap(int strict, cap_t *orig_p, cap_t *raised_for_setpcap_p) +{ + *orig_p = cap_get_proc(); + if (NULL == *orig_p) { + perror("Capabilities not available"); exit(1); }
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/capshdoc.c
Added
@@ -0,0 +1,418 @@ +#include <stdio.h> + +#include "./capshdoc.h" + +/* + * A line by line explanation of each named capability value + */ +static const char *explanation0[] = { /* cap_chown = 0 */ + "Allows a process to arbitrarily change the user and", + "group ownership of a file.", + NULL +}; +static const char *explanation1[] = { /* cap_dac_override = 1 */ + "Allows a process to override of all Discretionary", + "Access Control (DAC) access, including ACL execute", + "access. That is read, write or execute files that the", + "process would otherwise not have access to. This", + "excludes DAC access covered by CAP_LINUX_IMMUTABLE.", + NULL +}; +static const char *explanation2[] = { /* cap_dac_read_search = 2 */ + "Allows a process to override all DAC restrictions", + "limiting the read and search of files and", + "directories. This excludes DAC access covered by", + "CAP_LINUX_IMMUTABLE.", + NULL +}; +static const char *explanation3[] = { /* cap_fowner = 3 */ + "Allows a process to perform operations on files, even", + "where file owner ID should otherwise need be equal to", + "the UID, except where CAP_FSETID is applicable. It", + "doesn't override MAC and DAC restrictions.", + NULL +}; +static const char *explanation4[] = { /* cap_fsetid = 4 */ + "Allows a process to set the S_ISUID and S_ISUID bits of", + "the file permissions, even when the process' effective", + "UID or GID/supplementary GIDs do not match that of the", + "file.", + NULL +}; +static const char *explanation5[] = { /* cap_kill = 5 */ + "Allows a process to send a kill(2) signal to any other", + "process - overriding the limitation that there be a", + "[E]UID match between source and target process.", + NULL +}; +static const char *explanation6[] = { /* cap_setgid = 6 */ + "Allows a process to freely manipulate its own GIDs:", + " - arbitrarily set the GID, EGID, REGID, RESGID values", + " - arbitrarily set the supplementary GIDs", + " - allows the forging of GID credentials passed over a", + " socket", + NULL +}; +static const char *explanation7[] = { /* cap_setuid = 7 */ + "Allows a process to freely manipulate its own UIDs:", + " - arbitrarily set the UID, EUID, REUID and RESUID", + " values", + " - allows the forging of UID credentials passed over a", + " socket", + NULL +}; +static const char *explanation8[] = { /* cap_setpcap = 8 */ + "Allows a process to freely manipulate its inheritable", + "capabilities.", + "", + "Linux supports the POSIX.1e Inheritable set, the POXIX.1e (X", + "vector) known in Linux as the Bounding vector, as well as", + "the Linux extension Ambient vector.", + "", + "This capability permits dropping bits from the Bounding", + "vector (ie. raising B bits in the libcap IAB", + "representation). It also permits the process to raise", + "Ambient vector bits that are both raised in the Permitted", + "and Inheritable sets of the process. This capability cannot", + "be used to raise Permitted bits, Effective bits beyond those", + "already present in the process' permitted set, or", + "Inheritable bits beyond those present in the Bounding", + "vector.", + "", + "[Historical note: prior to the advent of file capabilities", + "(2008), this capability was suppressed by default, as its", + "unsuppressed behavior was not auditable: it could", + "asynchronously grant its own Permitted capabilities to and", + "remove capabilities from other processes arbitrarily. The", + "former leads to undefined behavior, and the latter is better", + "served by the kill system call.]", + NULL +}; +static const char *explanation9[] = { /* cap_linux_immutable = 9 */ + "Allows a process to modify the S_IMMUTABLE and", + "S_APPEND file attributes.", + NULL +}; +static const char *explanation10[] = { /* cap_net_bind_service = 10 */ + "Allows a process to bind to privileged ports:", + " - TCP/UDP sockets below 1024", + " - ATM VCIs below 32", + NULL +}; +static const char *explanation11[] = { /* cap_net_broadcast = 11 */ + "Allows a process to broadcast to the network and to", + "listen to multicast.", + NULL +}; +static const char *explanation12[] = { /* cap_net_admin = 12 */ + "Allows a process to perform network configuration", + "operations:", + " - interface configuration", + " - administration of IP firewall, masquerading and", + " accounting", + " - setting debug options on sockets", + " - modification of routing tables", + " - setting arbitrary process, and process group", + " ownership on sockets", + " - binding to any address for transparent proxying", + " (this is also allowed via CAP_NET_RAW)", + " - setting TOS (Type of service)", + " - setting promiscuous mode", + " - clearing driver statistics", + " - multicasing", + " - read/write of device-specific registers", + " - activation of ATM control sockets", + NULL +}; +static const char *explanation13[] = { /* cap_net_raw = 13 */ + "Allows a process to use raw networking:", + " - RAW sockets", + " - PACKET sockets", + " - binding to any address for transparent proxying", + " (also permitted via CAP_NET_ADMIN)", + NULL +}; +static const char *explanation14[] = { /* cap_ipc_lock = 14 */ + "Allows a process to lock shared memory segments for IPC", + "purposes. Also enables mlock and mlockall system", + "calls.", + NULL +}; +static const char *explanation15[] = { /* cap_ipc_owner = 15 */ + "Allows a process to override IPC ownership checks.", + NULL +}; +static const char *explanation16[] = { /* cap_sys_module = 16 */ + "Allows a process to initiate the loading and unloading", + "of kernel modules. This capability can effectively", + "modify kernel without limit.", + NULL +}; +static const char *explanation17[] = { /* cap_sys_rawio = 17 */ + "Allows a process to perform raw IO:", + " - permit ioper/iopl access", + " - permit sending USB messages to any device via", + " /dev/bus/usb", + NULL +}; +static const char *explanation18[] = { /* cap_sys_chroot = 18 */ + "Allows a process to perform a chroot syscall to change", + "the effective root of the process' file system:", + "redirect to directory \"/\" to some other location.", + NULL +}; +static const char *explanation19[] = { /* cap_sys_ptrace = 19 */ + "Allows a process to perform a ptrace() of any other", + "process.", + NULL +}; +static const char *explanation20[] = { /* cap_sys_pacct = 20 */ + "Allows a process to configure process accounting.", + NULL +}; +static const char *explanation21[] = { /* cap_sys_admin = 21 */ + "Allows a process to perform a somewhat arbitrary", + "grab-bag of privileged operations. Over time, this", + "capability should weaken as specific capabilities are", + "created for subsets of CAP_SYS_ADMINs functionality:", + " - configuration of the secure attention key", + " - administration of the random device", + " - examination and configuration of disk quotas", + " - setting the domainname", + " - setting the hostname", + " - calling bdflush()", + " - mount() and umount(), setting up new SMB connection", + " - some autofs root ioctls", + " - nfsservctl", + " - VM86_REQUEST_IRQ", + " - to read/write pci config on alpha", + " - irix_prctl on mips (setstacksize)", + " - flushing all cache on m68k (sys_cacheflush)", + " - removing semaphores", + " - Used instead of CAP_CHOWN to \"chown\" IPC message", + " queues, semaphores and shared memory", + " - locking/unlocking of shared memory segment", + " - turning swap on/off", + " - forged pids on socket credentials passing", + " - setting readahead and flushing buffers on block", + " devices", + " - setting geometry in floppy driver",
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/capshdoc.h
Added
@@ -0,0 +1,7 @@ +#ifdef CAPSHDOC +#error "don't include this twice" +#endif +#define CAPSHDOC + +extern const char **explanations[]; +extern const int capsh_doc_limit;
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/getcap.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/getcap.c
Changed
@@ -1,9 +1,10 @@ /* - * Copyright (c) 1997,2007 Andrew G. Morgan <morgan@kernel.org> + * Copyright (c) 1997,2007 Andrew G. Morgan <morgan@kernel.org> * * This displays the capabilities of a given file. */ +#undef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #include <errno.h> @@ -22,14 +23,14 @@ static int recursive = 0; static int namespace = 0; -static void usage(void) +static void usage(int code) { fprintf(stderr, - "usage: getcap [-v] [-r] [-h] [-n] <filename> [<filename> ...]\n" - "\n" - "\tdisplays the capabilities on the queried file(s).\n" + "usage: getcap [-h] [-l] [-n] [-r] [-v] <filename> [<filename> ...]\n" + "\n" + "\tdisplays the capabilities on the queried file(s).\n" ); - exit(1); + exit(code); } static int do_getcap(const char *fname, const struct stat *stbuf, @@ -48,8 +49,8 @@ cap_d = cap_get_file(fname); if (cap_d == NULL) { - if (errno != ENODATA) { - fprintf(stderr, "Failed to get capabilities of file `%s' (%s)\n", + if (errno != ENODATA && errno != ENOTSUP) { + fprintf(stderr, "Failed to get capabilities of file '%s' (%s)\n", fname, strerror(errno)); } else if (verbose) { printf("%s\n", fname); @@ -60,7 +61,7 @@ result = cap_to_text(cap_d, NULL); if (!result) { fprintf(stderr, - "Failed to get capabilities of human readable format at `%s' (%s)\n", + "Failed to get capabilities of human readable format at '%s' (%s)\n", fname, strerror(errno)); cap_free(cap_d); return 0; @@ -81,7 +82,7 @@ { int i, c; - while ((c = getopt(argc, argv, "rvhn")) > 0) { + while ((c = getopt(argc, argv, "rvhnl")) > 0) { switch(c) { case 'r': recursive = 1; @@ -92,21 +93,28 @@ case 'n': namespace = 1; break; + case 'h': + usage(0); + case 'l': + printf("%s see LICENSE file for details.\n" + "Copyright (c) 1997,2007,2021 Andrew G. Morgan" + " <morgan@kernel.org>\n", argv[0]); + exit(0); default: - usage(); + usage(1); } } if (!argv[optind]) - usage(); + usage(1); for (i=optind; argv[i] != NULL; i++) { struct stat stbuf; - - if (lstat(argv[i], &stbuf) != 0) { - fprintf(stderr, "%s (%s)\n", argv[i], strerror(errno)); + char *arg = argv[i]; + if (lstat(arg, &stbuf) != 0) { + fprintf(stderr, "%s (%s)\n", arg, strerror(errno)); } else if (recursive) { - nftw(argv[i], do_getcap, 20, FTW_PHYS); + nftw(arg, do_getcap, 20, FTW_PHYS); } else { int tflag = S_ISREG(stbuf.st_mode) ? FTW_F : (S_ISLNK(stbuf.st_mode) ? FTW_SL : FTW_NS);
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/getpcaps.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/getpcaps.c
Changed
@@ -11,43 +11,55 @@ #include <stdlib.h> #include <sys/capability.h> -static void usage(int exiter) +static void usage(int code) { fprintf(stderr, "usage: getcaps <pid> [<pid> ...]\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 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 <morgan@kernel.org>]\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" + " --iab show IAB of process too.\n" + " --license display license info\n"); + exit(code); } int main(int argc, char **argv) { int retval = 0; int verbose = 0; + int iab = 0; + cap_iab_t noiab = cap_iab_init(); if (argc < 2) { usage(1); } for ( ++argv; --argc > 0; ++argv ) { - ssize_t length; 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], "--license")) { + printf("%s see LICENSE file for details.\n" + "[Copyright (c) 1997-8,2007,19,21" + " Andrew G. Morgan <morgan@kernel.org>]\n", + argv[0]); + exit(0); } else if (!strcmp(argv[0], "--verbose")) { verbose = 1; continue; } else if (!strcmp(argv[0], "--ugly") || !strcmp(argv[0], "--legacy")) { verbose = 2; continue; + } else if (!strcmp(argv[0], "--iab")) { + iab = 1; + continue; } pid = atoi(argv[0]); @@ -59,8 +71,32 @@ retval = 1; continue; } else { - char *result = cap_to_text(cap_d, &length); - if (verbose == 1) { + char *result = cap_to_text(cap_d, NULL); + if (iab) { + printf("%s:", *argv); + if (verbose || strcmp("=", result) != 0) { + printf(" \"%s\"", result); + } + cap_iab_t iab_val = cap_iab_get_pid(pid); + if (iab_val == NULL) { + fprintf(stderr, " no IAB value for %d\n", pid); + exit(1); + } + int cf = cap_iab_compare(noiab, iab_val); + if (verbose || + CAP_IAB_DIFFERS(cf, CAP_IAB_AMB) || + CAP_IAB_DIFFERS(cf, CAP_IAB_BOUND)) { + char *iab_text = cap_iab_to_text(iab_val); + if (iab_text == NULL) { + perror(" no text for IAB"); + exit(1); + } + printf(" [%s]", iab_text); + cap_free(iab_text); + } + cap_free(iab_val); + printf("\n"); + } else if (verbose == 1) { printf("Capabilities for '%s': %s\n", *argv, result); } else if (verbose == 2) { fprintf(stderr, "Capabilities for `%s': %s\n", *argv, result);
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/mkcapshdoc.sh
Added
@@ -0,0 +1,38 @@ +#!/bin/bash +# This script generates some C code for inclusion in the capsh binary. +# The Makefile generally only generates the .c code and compares it +# with the checked in code in the progs directory. + +cat<<EOF +#include <stdio.h> + +#include "./capshdoc.h" + +/* + * A line by line explanation of each named capability value + */ +EOF + +let x=0 +while [ -f "../doc/values/${x}.txt" ]; do + name=$(fgrep ",${x}}" ../libcap/cap_names.list.h|sed -e 's/{"//' -e 's/",/ = /' -e 's/},//') + echo "static const char *explanation${x}[] = { /* ${name} */" + sed -e 's/"/\\"/g' -e 's/^/ "/' -e 's/$/",/' "../doc/values/${x}.txt" + let x=1+${x} + echo " NULL" + echo "};" +done + +cat<<EOF +const char **explanations[] = { +EOF +let y=0 +while [ "${y}" -lt "${x}" ]; do + echo " explanation${y}," + let y=1+${y} +done +cat<<EOF +}; + +const int capsh_doc_limit = ${x}; +EOF
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/quicktest.sh -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/quicktest.sh
Changed
@@ -1,7 +1,7 @@ #!/bin/bash # # Run through a series of tests to try out the various capability -# manipulations posible through exec. +# manipulations possible through exec. # # [Run this as root in a root-enabled process tree.] @@ -43,9 +43,17 @@ } pass_capsh --print +pass_capsh --current + +# 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 +cp ./tcapsh-static ./privileged && /bin/chmod -s ./privileged if [ $? -ne 0 ]; then echo "Failed to copy capsh for capability manipulation" exit 1 @@ -70,27 +78,30 @@ fail_capsh --mode=NOPRIV --print --mode=PURE1E fail_capsh --user=nobody --mode=NOPRIV --print -- ./privileged +# simple IAB setting (no ambient) in pure1e mode. +pass_capsh --mode=PURE1E --iab='!%cap_chown,cap_setuid' + # Explore keep_caps support pass_capsh --keep=0 --keep=1 --keep=0 --keep=1 --print /bin/rm -f tcapsh -/bin/cp capsh tcapsh +/bin/cp tcapsh-static tcapsh /bin/chown root.root tcapsh /bin/chmod u+s tcapsh /bin/ls -l tcapsh -# leverage keep caps to maintain capabilities accross a change of euid +# leverage keep caps to maintain capabilities across a change of euid # from setuid root to capable luser (as per wireshark/dumpcap 0.99.7) # This test is subtle. It is testing that a change to self, dropping # euid=0 back to that of the luser keeps capabilities. -pass_capsh --uid=500 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --print --uid=500 --print --caps=\"cap_net_raw,cap_net_admin=pie\" --print" +pass_capsh --uid=1 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_bind_service=ip\" --print --uid=1 --print --caps=\"cap_net_raw,cap_net_bind_service=pie\" --print" # this test is a change of user to a new user, note we need to raise # the cap_setuid capability (libcap has a function for that) in this case. -pass_capsh --uid=500 -- -c "./tcapsh --caps=\"cap_net_raw,cap_net_admin=ip cap_setuid=p\" --print --cap-uid=501 --print --caps=\"cap_net_raw,cap_net_admin=pie\" --print" +pass_capsh --uid=1 -- -c "./tcapsh --caps=\"cap_net_raw,cap_net_bind_service=ip cap_setuid=p\" --print --cap-uid=2 --print --caps=\"cap_net_raw,cap_net_bind_service=pie\" --print" # This fails, on 2.6.24, but shouldn't -pass_capsh --uid=500 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_admin=ip\" --uid=500 --forkfor=10 --caps= --print --killit=9 --print" +pass_capsh --uid=1 -- -c "./tcapsh --keep=1 --caps=\"cap_net_raw,cap_net_bind_service=ip\" --uid=1 --forkfor=10 --caps= --print --killit=9 --print" # only continue with these if --secbits is supported ./capsh --secbits=0x2f > /dev/null 2>&1 @@ -119,7 +130,22 @@ pass_capsh --secbits=0x2f --print -- -c "./privileged --uid=$nouid" # observe that the bounding set can be used to suppress this forced capability -fail_capsh --drop=cap_setuid --secbits=0x2f --print -- -c "./privileged --uid=$nouid" +fail_capsh --drop=cap_setuid --secbits=0x2f --print -- \ + -c "./privileged --uid=$nouid" + +# observe that effective cap_setpcap is required to drop bset +fail_capsh --caps="=ep cap_setpcap-ep" --drop=cap_setuid --current +pass_capsh --strict --caps="cap_setpcap=ep" --drop=cap_setuid --current +fail_capsh --strict --caps="cap_setpcap=p" --drop=cap_setuid --current +fail_capsh --strict --caps="=ep cap_setpcap-e" --drop=cap_setuid --current + +# observe that effective cap_setpcap is required to raise non-p bits +fail_capsh --strict --caps="cap_setpcap=p" --inh=cap_chown --current +# non-strict mode and capsh figures it out +pass_capsh --caps="cap_setpcap=p" --inh=cap_chown --current + +# permitted bits can be raised in inheritable flag without being effective. +pass_capsh --strict --caps="cap_chown=p" --inh=cap_chown --current # change the way the capability is obtained (make it inheritable) ./setcap cap_setuid,cap_setgid=ei ./privileged @@ -127,7 +153,7 @@ # Note, the bounding set (edited with --drop) only limits p # capabilities, not i's. pass_capsh --secbits=47 --inh=cap_setuid,cap_setgid --drop=cap_setuid \ - --uid=500 --print -- -c "./privileged --uid=$nouid" + --uid=1 --print -- -c "./privileged --uid=$nouid" # test that we do not support capabilities on setuid shell-scripts /bin/cat > hack.sh <<EOF @@ -145,7 +171,7 @@ exit 0 EOF /bin/chmod +xs hack.sh -./capsh --uid=500 --inh=none --print -- ./hack.sh +./capsh --uid=1 --inh=none --print -- ./hack.sh status=$? /bin/rm -f ./hack.sh if [ $status -ne 0 ]; then @@ -163,7 +189,7 @@ # Verify we can chroot pass_capsh --chroot=$(/bin/pwd) -pass_capsh --chroot=$(/bin/pwd) == +pass_capsh -- -c "./tcapsh-static --chroot=$(/bin/pwd) ==" fail_capsh --chroot=$(/bin/pwd) -- -c "echo oops" ./capsh --has-ambient @@ -188,19 +214,37 @@ exit 1 EOF /bin/chmod +x hack.sh - pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- ./hack.sh + pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- \ + ./hack.sh /bin/rm -f hack.sh # Next force the privileged binary to have an empty capability set. # This is sort of the opposite of privileged - it should ensure that - # the file can never aquire privilege by the ambient method. + # the file can never acquire privilege by the ambient method. ./setcap = ./privileged - fail_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- -c "./privileged --print --uid=500" + fail_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- \ + -c "./privileged --print --uid=1" + + pass_capsh --keep=1 --uid=$nouid --strict \ + --caps="cap_setuid=p cap_setpcap=ep" \ + --inh=cap_setuid --addamb=cap_setuid --current + + # No effective capabilities are needed to raise or lower ambient values. + pass_capsh --keep=1 --uid=$nouid --strict --caps="cap_setuid=p" \ + --inh=cap_setuid --addamb=cap_setuid --current + pass_capsh --keep=1 --uid=$nouid --strict --iab="!^cap_setuid" \ + --caps="cap_setuid=pi" --current --delamb=cap_setuid --current + # finally remove the capability from the privileged binary and try again. ./setcap -r ./privileged - pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- -c "./privileged --print --uid=500" + pass_capsh --keep=1 --uid=$nouid --inh=cap_setuid --addamb=cap_setuid -- \ + -c "./privileged --print --uid=1" + + # validate IAB setting with an ambient capability + pass_capsh --iab='!%cap_chown,^cap_setpcap,cap_setuid' + fail_capsh --mode=PURE1E --iab='!%cap_chown,^cap_setuid' fi /bin/rm -f ./privileged @@ -209,10 +253,10 @@ # nsprivileged capsh will have an ns rootid value (this is # the same setup as an earlier test but with a ns file cap). rm -f nsprivileged -cp ./capsh ./nsprivileged && /bin/chmod -s ./nsprivileged -./setcap -n 500 all=ep ./nsprivileged +cp ./tcapsh-static ./nsprivileged && /bin/chmod -s ./nsprivileged +./setcap -n 1 all=ep ./nsprivileged if [ $? -eq 0 ]; then - ./getcap -n ./nsprivileged | fgrep "[rootid=500]" + ./getcap -n ./nsprivileged | fgrep "[rootid=1]" if [ $? -ne 0 ]; then echo "FAILED setting ns rootid on file" exit 1 @@ -235,12 +279,22 @@ echo "FAILED to execute go binary" exit 1 fi - LD_LIBRARY_PATH=../libcap ./compare-cap 2>&1 | grep "skipping file cap tests" + LD_LIBRARY_PATH=../libcap ./compare-cap 2>&1 | \ + grep "skipping file cap tests" if [ $? -eq 0 ]; then echo "FAILED not engaging file cap tests" fi echo "PASSED" else - echo "no Go support compiled" + echo "no Go support compiled, so skipping Go tests" fi rm -f compare-cap + +echo "attempt to exploit kernel bug" +./uns_test +if [ $? -ne 0 ]; then + echo "upgrade your kernel" + exit 1 +fi + +echo "ALL TESTS PASSED!"
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/progs/setcap.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/progs/setcap.c
Changed
@@ -1,5 +1,5 @@ /* - * Copyright (c) 1997,2007-8 Andrew G. Morgan <morgan@kernel.org> + * Copyright (c) 1997,2007-8,2020,21 Andrew G. Morgan <morgan@kernel.org> * * This sets/verifies the capabilities of a given file. */ @@ -11,18 +11,57 @@ #include <sys/capability.h> #include <unistd.h> -static void usage(void) +static void usage(int status) { fprintf(stderr, - "usage: setcap [-q] [-v] [-n <rootid>] (-r|-|<caps>) <filename> " + "usage: setcap [-h] [-q] [-v] [-n <rootid>] (-r|-|<caps>) <filename> " "[ ... (-r|-|<capsN>) <filenameN> ]\n" "\n" " Note <filename> must be a regular (non-symlink) file.\n" + " -r remove capability from file\n" + " - read capability text from stdin\n" + " <capsN> cap_from_text(3) formatted file capability\n" + " [ Note: capsh --suggest=\"something...\" might help you pick. ]" + "\n" + " -h this message and exit status 0\n" + " -q quietly\n" + " -v validate supplied capability matches file\n" + " -n <rootid> write a user namespace (!= 0) limited capability\n" + " --license display the license info\n" ); - exit(1); + exit(status); +} + +/* parse a positive integer with some error handling */ +static unsigned long pos_uint(const char *text, const char *prefix, int *ok) +{ + char *remains; + unsigned long value; + ssize_t len = strlen(text); + + if (len == 0 || *text == '-') { + goto fail; + } + value = strtoul(text, &remains, 0); + if (*remains || value == 0) { + goto fail; + } + if (ok != NULL) { + *ok = 1; + } + return value; + +fail: + if (ok == NULL) { + fprintf(stderr, "%s: want positive integer, got \"%s\"\n", + prefix, text); + exit(1); + } + *ok = 0; + return 0; } -#define MAXCAP 2048 +#define MAXCAP 2048 static int read_caps(int quiet, const char *filename, char *buffer) { @@ -65,8 +104,8 @@ cap_value_t capflag; uid_t rootid = 0, f_rootid; - if (argc < 3) { - usage(); + if (argc < 2) { + usage(1); } mycaps = cap_get_proc(); @@ -75,39 +114,50 @@ " (old libcap?)\n"); } + cap_t cap_d = NULL; while (--argc > 0) { const char *text; - cap_t cap_d; + + cap_free(cap_d); + cap_d = NULL; if (!strcmp(*++argv, "-q")) { quiet = 1; continue; } + if (!strcmp("--license", *argv)) { + printf( + "%s see LICENSE file for details.\n" + "Copyright (c) 1997,2007-8,2020-21 Andrew G. Morgan" + " <morgan@kernel.org>\n", argv[0]); + exit(0); + } + if (!strcmp(*argv, "-h")) { + usage(0); + } if (!strcmp(*argv, "-v")) { verify = 1; continue; } if (!strcmp(*argv, "-n")) { if (argc < 2) { - fprintf(stderr, "usage: .. -n <rootid> .. - rootid!=0 file caps"); + fprintf(stderr, + "usage: .. -n <rootid> .. - rootid!=0 file caps"); exit(1); } --argc; - rootid = (uid_t) atoi(*++argv); - if (rootid+1 < 2) { - fprintf(stderr, "invalid rootid!=0 of '%s'", *argv); - exit(1); - } + rootid = (uid_t) pos_uint(*++argv, "bad ns rootid", NULL); continue; } if (!strcmp(*argv, "-r")) { + cap_free(cap_d); cap_d = NULL; } else { if (!strcmp(*argv,"-")) { retval = read_caps(quiet, *argv, buffer); if (retval) - usage(); + usage(1); text = buffer; } else { text = *argv; @@ -116,7 +166,7 @@ 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"); @@ -124,17 +174,15 @@ } #ifdef DEBUG { - ssize_t length; - const char *result; - - result = cap_to_text(cap_d, &length); + char *result = cap_to_text(cap_d, NULL); fprintf(stderr, "caps set to: [%s]\n", result); + cap_free(result) } #endif } if (--argc <= 0) - usage(); + usage(1); /* * Set the filesystem capability for this file. */ @@ -143,13 +191,20 @@ int cmp; if (cap_d == NULL) { - cap_d = cap_from_text("="); + cap_d = cap_init(); + if (cap_d == NULL) { + perror("unable to obtain empty capability"); + exit(1); + } } cap_on_file = cap_get_file(*++argv); - if (cap_on_file == NULL) { - cap_on_file = cap_from_text("="); + cap_on_file = cap_init(); + if (cap_on_file == NULL) { + perror("unable to use missing capability"); + exit(1); + } } cmp = cap_compare(cap_on_file, cap_d); @@ -194,6 +249,7 @@ if (retval != 0) { int explained = 0; int oerrno = errno; + int somebits = 0; #ifdef linux cap_value_t cap;
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/License
Added
@@ -0,0 +1,396 @@ +Unless otherwise *explicitly* stated, the following text describes the +licensed conditions under which the contents of this libcap/psx release +may be used and distributed. + +The licensed conditions are one or the other of these two Licenses: + + - BSD 3-clause + - GPL v2.0 + +------------------------------------------------------------------------- +BSD 3-clause: +------------- + +Redistribution and use in source and binary forms of libcap/psx, with +or without modification, are permitted provided that the following +conditions are met: + +1. Redistributions of source code must retain any existing copyright + notice, and this entire permission notice in its entirety, + including the disclaimer of warranties. + +2. Redistributions in binary form must reproduce all prior and current + copyright notices, this list of conditions, and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +3. The name of any author may not be used to endorse or promote + products derived from this software without their specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +------------------------------------------------------------------------- +GPL v2.0: +--------- + +ALTERNATIVELY, this product may be distributed under the terms of the +GNU General Public License (v2.0 - see below), in which case the +provisions of the GNU GPL are required INSTEAD OF the above +restrictions. (This clause is necessary due to a potential conflict +between the GNU GPL and the restrictions contained in a BSD-style +copyright.) + +------------------------- +Full text of gpl-2.0.txt: +------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/README
Added
@@ -0,0 +1,28 @@ +Package "psx" provides an API for invoking system calls in a way that +each system call is mirrored on all OS threads of the combined Go/CGo +runtime. Since the Go runtime treats OS threads as interchangeable, a +feature like this is needed to meaningfully change process privilege +(including dropping privilege) in a Go program running on Linux. This +package is required by: + + "kernel.org/pub/linux/libs/security/libcap/cap" + +When compiled CGO_ENABLED=0, the functionality requires go1.16+ to +build. That release of Go introduced syscall.AllThreadsSyscall*() +APIs. When compiled this way, the "psx" package functions +psx.Syscall3() and psx.Syscall6() are aliased to +syscall.AllThreadsSyscall() and syscall.AllThreadsSyscall6() +respectively. + +When compiled CGO_ENABLED=1, the functionality is implemented by C +code, [lib]psx, which is distributed with libcap. + +The official release announcement site for libcap and libpsx is: + + https://sites.google.com/site/fullycapable/ + +Like libcap/libpsx itself, the "psx" package is distributed with a +"you choose" License. Specifically: BSD three clause, or GPL2. See the +License file. + +Andrew G. Morgan <morgan@kernel.org>
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/doc.go
Added
@@ -0,0 +1,60 @@ +// Package psx provides support for system calls that are run +// simultaneously on all threads under Linux. +// +// This property can be used to work around a historical lack of +// native Go support for such a feature. Something that is the subject +// of: +// +// https://github.com/golang/go/issues/1435 +// +// The package works differently depending on whether or not +// CGO_ENABLED is 0 or 1. +// +// In the former case, psx is a low overhead wrapper for the two +// native go calls: syscall.AllThreadsSyscall() and +// syscall.AllThreadsSyscall6() introduced in go1.16. We provide this +// wrapping to minimize client source code changes when compiling with +// or without CGo enabled. +// +// In the latter case, and toolchains prior to go1.16, it works via +// CGo wrappers for system call functions that call the C [lib]psx +// functions of these names. This ensures that the system calls +// execute simultaneously on all the pthreads of the Go (and CGo) +// combined runtime. +// +// With CGo, the psx support works in the following way: the pthread +// that is first asked to execute the syscall does so, and determines +// if it succeeds or fails. If it fails, it returns immediately +// without attempting the syscall on other pthreads. If the initial +// attempt succeeds, however, then the runtime is stopped in order for +// the same system call to be performed on all the remaining pthreads +// of the runtime. Once all pthreads have completed the syscall, the +// return codes are those obtained by the first pthread's invocation +// of the syscall. +// +// Note, there is no need to use this variant of syscall where the +// syscalls only read state from the kernel. However, since Go's +// runtime freely migrates code execution between pthreads, support of +// this type is required for any successful attempt to fully drop or +// modify the privilege of a running Go program under Linux. +// +// More info on how Linux privilege works and examples of using this +// package can be found here: +// +// https://sites.google.com/site/fullycapable +// +// WARNING: For older go toolchains (prior to go1.15), correct +// compilation of this package may require an extra workaround step: +// +// The workaround is to build with the following CGO_LDFLAGS_ALLOW in +// effect (here the syntax is that of bash for defining an environment +// variable): +// +// export CGO_LDFLAGS_ALLOW="-Wl,-?-wrap[=,][^-.@][^,]*" +// +// +// Copyright (c) 2019,20 Andrew G. Morgan <morgan@kernel.org> +// +// The psx package is licensed with a (you choose) BSD 3-clause or +// GPL2. See LICENSE file for details. +package psx // import "kernel.org/pub/linux/libs/security/libcap/psx"
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/go.mod
Added
@@ -0,0 +1,3 @@ +module kernel.org/pub/linux/libs/security/libcap/psx + +go 1.11
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/psx.c
Added
@@ -0,0 +1,648 @@ +/* + * Copyright (c) 2019-21 Andrew G Morgan <morgan@kernel.org> + * + * This file contains a collection of routines that perform thread + * synchronization to ensure that a whole process is running as a + * single privilege entity - independent of the number of pthreads. + * + * The whole file would be unnecessary if glibc exported an explicit + * psx_syscall()-like function that leveraged the nptl:setxid + * mechanism to synchronize thread state over the whole process. + */ +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <errno.h> +#include <pthread.h> +#include <sched.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/syscall.h> + +#include "psx_syscall.h" + +/* + * psx_load_syscalls() can be weakly defined in dependent libraries to + * provide a mechanism for a library to optionally leverage this psx + * mechanism. Specifically, when libcap calls psx_load_sycalls() it + * provides a weakly declared default that maps its system calls to + * the regular system call functions. However, when linked with psx, + * this function here overrides the syscalls to be the psx ones. + */ +void psx_load_syscalls(long int (**syscall_fn)(long int, + long int, long int, long int), + long int (**syscall6_fn)(long int, + long int, long int, long int, + long int, long int, long int)) +{ + *syscall_fn = psx_syscall3; + *syscall6_fn = psx_syscall6; +} + +/* + * type to keep track of registered threads. + */ +typedef struct registered_thread_s { + struct registered_thread_s *next, *prev; + pthread_t thread; + pthread_mutex_t mu; + int pending; + int gone; +} registered_thread_t; + +static pthread_once_t psx_tracker_initialized = PTHREAD_ONCE_INIT; + +typedef enum { + _PSX_IDLE = 0, + _PSX_SETUP = 1, + _PSX_SYSCALL = 2, + _PSX_CREATE = 3, + _PSX_INFORK = 4, + _PSX_EXITING = 5, +} psx_tracker_state_t; + +/* + * This global structure holds the global coordination state for + * libcap's psx_posix_syscall() support. + */ +static struct psx_tracker_s { + int has_forked; + + pthread_mutex_t state_mu; + pthread_cond_t cond; /* this is only used to wait on 'state' changes */ + psx_tracker_state_t state; + int initialized; + int psx_sig; + + struct { + long syscall_nr; + long arg1, arg2, arg3, arg4, arg5, arg6; + int six; + int active; + } cmd; + + struct sigaction sig_action; + struct sigaction chained_action; + registered_thread_t *root; +} psx_tracker; + +/* + * psx_action_key is used for thread local storage of the thread's + * registration. + */ +pthread_key_t psx_action_key; + +/* + * psx_do_registration called locked and creates a tracker entry for + * the current thread with a TLS specific key pointing at the threads + * specific tracker. + */ +static void *psx_do_registration(void) { + registered_thread_t *node = calloc(1, sizeof(registered_thread_t)); + if (node == NULL) { + perror("unable to register psx handler"); + _exit(1); + } + pthread_mutex_init(&node->mu, NULL); + node->thread = pthread_self(); + pthread_setspecific(psx_action_key, node); + node->next = psx_tracker.root; + if (node->next) { + node->next->prev = node; + } + psx_tracker.root = node; + return node; +} + +/* + * psx_posix_syscall_actor performs the system call on the targeted + * thread and signals it is no longer pending. + */ +static void psx_posix_syscall_actor(int signum, siginfo_t *info, void *ignore) { + /* bail early if this isn't something we recognize */ + if (signum != psx_tracker.psx_sig || !psx_tracker.cmd.active || + info == NULL || info->si_code != SI_TKILL || info->si_pid != getpid()) { + if (psx_tracker.chained_action.sa_sigaction != 0) { + psx_tracker.chained_action.sa_sigaction(signum, info, ignore); + } + return; + } + + if (!psx_tracker.cmd.six) { + (void) syscall(psx_tracker.cmd.syscall_nr, + psx_tracker.cmd.arg1, + psx_tracker.cmd.arg2, + psx_tracker.cmd.arg3); + } else { + (void) syscall(psx_tracker.cmd.syscall_nr, + psx_tracker.cmd.arg1, + psx_tracker.cmd.arg2, + psx_tracker.cmd.arg3, + psx_tracker.cmd.arg4, + psx_tracker.cmd.arg5, + psx_tracker.cmd.arg6); + } + + /* + * This handler can only be called on registered threads which + * have had this specific defined at start-up. (But see the + * subsequent test.) + */ + registered_thread_t *ref = pthread_getspecific(psx_action_key); + if (ref) { + pthread_mutex_lock(&ref->mu); + ref->pending = 0; + pthread_mutex_unlock(&ref->mu); + } /* + * else thread must be dying and its psx_action_key has already + * been cleaned up. + */ +} + +/* + * Some forward declarations for the initialization + * psx_syscall_start() routine. + */ +static void _psx_prepare_fork(void); +static void _psx_fork_completed(void); +static void _psx_forked_child(void); +int __wrap_pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); + +/* + * psx requires this function to be provided by the linkage wrapping. + */ +extern int __real_pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); + +/* + * psx_confirm_sigaction reconfirms that the psx handler is the first + * handler to respond to the psx signal. It assumes that + * psx_tracker.psx_sig has been set. + */ +static void psx_confirm_sigaction(void) { + sigset_t mask, orig; + struct sigaction existing_sa; + + /* + * Block interrupts while potentially rewriting the handler. + */ + sigemptyset(&mask); + sigaddset(&mask, psx_tracker.psx_sig);
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/psx/psx.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/psx.go
Changed
@@ -1,37 +1,35 @@ -// Package psx provides Go wrappers for two system call functions that -// work by calling the C libpsx functions of these names. -package psx - -import ( - "syscall" -) +// +build linux,!cgo +// +build go1.16 -// #cgo LDFLAGS: -lpsx -lpthread -Wl,-wrap,pthread_create +package psx // import "kernel.org/pub/linux/libs/security/libcap/psx" + +import "syscall" + +// Documentation for these functions are provided in the psx_cgo.go +// file. + +//go:uintptrescapes + +// Syscall3 performs a 3 argument syscall. Syscall3 differs from +// syscall.[Raw]Syscall() insofar as it is simultaneously executed on +// every thread of the combined Go and CGo runtimes. It works +// differently depending on whether CGO_ENABLED is 1 or 0 at compile +// time. // -// #include <errno.h> -// #include <sys/psx_syscall.h> +// If CGO_ENABLED=1 it uses the libpsx function C.psx_syscall3(). // -// long __errno_too() { return errno ; } -import "C" - -// Syscall3 performs a 3 argument syscall using the libpsx C function -// psx_syscall3(). +// If CGO_ENABLED=0 it redirects to the go1.16+ +// syscall.AllThreadsSyscall() function. func Syscall3(syscallnr, arg1, arg2, arg3 uintptr) (uintptr, uintptr, syscall.Errno) { - v := C.psx_syscall3(C.long(syscallnr), C.long(arg1), C.long(arg2), C.long(arg3)) - var errno syscall.Errno - if v < 0 { - errno = syscall.Errno(C.__errno_too()) - } - return uintptr(v), uintptr(v), errno + return syscall.AllThreadsSyscall(syscallnr, arg1, arg2, arg3) } -// Syscall6 performs a 6 argument syscall using the libpsx C function -// psx_syscall6() +//go:uintptrescapes + +// Syscall6 performs a 6 argument syscall on every thread of the +// combined Go and CGo runtimes. Other than the number of syscall +// arguments, its behavior is identical to that of Syscall3() - see +// above for the full documentation. func Syscall6(syscallnr, arg1, arg2, arg3, arg4, arg5, arg6 uintptr) (uintptr, uintptr, syscall.Errno) { - v := C.psx_syscall6(C.long(syscallnr), C.long(arg1), C.long(arg2), C.long(arg3), C.long(arg4), C.long(arg5), C.long(arg6)) - var errno syscall.Errno - if v < 0 { - errno = syscall.Errno(C.__errno_too()) - } - return uintptr(v), uintptr(v), errno + return syscall.AllThreadsSyscall6(syscallnr, arg1, arg2, arg3, arg4, arg5, arg6) }
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/psx_cgo.go
Added
@@ -0,0 +1,79 @@ +// +build linux,cgo + +package psx // import "kernel.org/pub/linux/libs/security/libcap/psx" + +import ( + "runtime" + "syscall" +) + +// #cgo LDFLAGS: -lpthread -Wl,-wrap,pthread_create +// +// #include <errno.h> +// #include "psx_syscall.h" +// +// long __errno_too(long set_errno) { +// long v = errno; +// if (set_errno >= 0) { +// errno = set_errno; +// } +// return v; +// } +import "C" + +// setErrno returns the current C.errno value and, if v >= 0, sets the +// CGo errno for a random pthread to value v. If you want some +// consistency, this needs to be called from runtime.LockOSThread() +// code. This function is only defined for testing purposes. The psx.c +// code should properly handle the case that a non-zero errno is saved +// and restored independently of what these Syscall[36]() functions +// observe. +func setErrno(v int) int { + return int(C.__errno_too(C.long(v))) +} + +//go:uintptrescapes + +// Syscall3 performs a 3 argument syscall. Syscall3 differs from +// syscall.[Raw]Syscall() insofar as it is simultaneously executed on +// every thread of the combined Go and CGo runtimes. It works +// differently depending on whether CGO_ENABLED is 1 or 0 at compile +// time. +// +// If CGO_ENABLED=1 it uses the libpsx function C.psx_syscall3(). +// +// If CGO_ENABLED=0 it redirects to the go1.16+ +// syscall.AllThreadsSyscall() function. +func Syscall3(syscallnr, arg1, arg2, arg3 uintptr) (uintptr, uintptr, syscall.Errno) { + // We lock to the OSThread here because we may need errno to + // be the one for this thread. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + v := C.psx_syscall3(C.long(syscallnr), C.long(arg1), C.long(arg2), C.long(arg3)) + var errno syscall.Errno + if v < 0 { + errno = syscall.Errno(C.__errno_too(-1)) + } + return uintptr(v), uintptr(v), errno +} + +//go:uintptrescapes + +// Syscall6 performs a 6 argument syscall on every thread of the +// combined Go and CGo runtimes. Other than the number of syscall +// arguments, its behavior is identical to that of Syscall3() - see +// above for the full documentation. +func Syscall6(syscallnr, arg1, arg2, arg3, arg4, arg5, arg6 uintptr) (uintptr, uintptr, syscall.Errno) { + // We lock to the OSThread here because we may need errno to + // be the one for this thread. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + v := C.psx_syscall6(C.long(syscallnr), C.long(arg1), C.long(arg2), C.long(arg3), C.long(arg4), C.long(arg5), C.long(arg6)) + var errno syscall.Errno + if v < 0 { + errno = syscall.Errno(C.__errno_too(-1)) + } + return uintptr(v), uintptr(v), errno +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/psx_cgo_test.go
Added
@@ -0,0 +1,40 @@ +// +build cgo + +package psx + +import ( + "runtime" + "syscall" + "testing" +) + +// The man page for errno indicates that it is never set to zero, so +// validate that it retains its value over a successful Syscall[36]() +// and is overwritten on a failing syscall. +func TestErrno(t *testing.T) { + // This testing is much easier if we don't have to guess which + // thread is running this Go code. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // Start from a known bad state and clean up afterwards. + setErrno(int(syscall.EPERM)) + defer setErrno(0) + + v3, _, errno := Syscall3(syscall.SYS_GETUID, 0, 0, 0) + if errno != 0 { + t.Fatalf("psx getuid failed: %v", errno) + } + v6, _, errno := Syscall6(syscall.SYS_GETUID, 0, 0, 0, 0, 0, 0) + if errno != 0 { + t.Fatalf("psx getuid failed: %v", errno) + } + + if v3 != v6 { + t.Errorf("psx getuid failed to match v3=%d, v6=%d", v3, v6) + } + + if v := setErrno(-1); v != int(syscall.EPERM) { + t.Errorf("psx changes prevailing errno got=%v(%d) want=%v", syscall.Errno(v), v, syscall.EPERM) + } +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/psx_syscall.h
Added
@@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019 Andrew G. Morgan <morgan@kernel.org> + * + * This header, and the -lpsx library, provide a number of things to + * support POSIX semantics for syscalls associated with the pthread + * library. Linking this code is tricky and is done as follows: + * + * ld ... -lpsx -lpthread --wrap=pthread_create + * or, gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create + * + * glibc provides a subset of this functionality natively through the + * nptl:setxid mechanism and could implement psx_syscall() directly + * using that style of functionality but, as of 2019-11-30, the setxid + * mechanism is limited to 9 specific set*() syscalls that do not + * support the syscall6 API (needed for prctl functions and the ambient + * capabilities set for example). + */ + +#ifndef _SYS_PSX_SYSCALL_H +#define _SYS_PSX_SYSCALL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <pthread.h> + +/* + * psx_syscall performs the specified syscall on all psx registered + * threads. The mechanism by which this occurs is much less efficient + * than a standard system call on Linux, so it should only be used + * when POSIX semantics are required to change process relevant + * security state. + * + * Glibc has native support for POSIX semantics on setgroups() and the + * 8 set*[gu]id() functions. So, there is no need to use psx_syscall() + * for these calls. This call exists for all the other system calls + * that need to maintain parity on all pthreads of a program. + * + * Some macrology is used to allow the caller to provide only as many + * arguments as needed, thus psx_syscall() cannot be used as a + * function pointer. For those situations, we define psx_syscall3() + * and psx_syscall6(). + */ +#define psx_syscall(syscall_nr, ...) \ + __psx_syscall(syscall_nr, __VA_ARGS__, (long int) 6, (long int) 5, \ + (long int) 4, (long int) 3, (long int) 2, \ + (long int) 1, (long int) 0) +long int __psx_syscall(long int syscall_nr, ...); +long int psx_syscall3(long int syscall_nr, + long int arg1, long int arg2, long int arg3); +long int psx_syscall6(long int syscall_nr, + long int arg1, long int arg2, long int arg3, + long int arg4, long int arg5, long int arg6); + +/* + * This function should be used by systems to obtain pointers to the + * two syscall functions provided by the PSX library. A linkage trick + * is to define this function as weak in a library that can optionally + * use libpsx and then, should the caller link -lpsx, that library can + * implicitly use these POSIX semantics syscalls. See libcap for an + * example of this usage. + */ +void psx_load_syscalls(long int (**syscall_fn)(long int, + long int, long int, long int), + long int (**syscall6_fn)(long int, + long int, long int, long int, + long int, long int, long int)); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_PSX_SYSCALL_H */
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/psx/psx_test.go -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/psx/psx_test.go
Changed
@@ -1,6 +1,7 @@ package psx import ( + "runtime" "syscall" "testing" ) @@ -32,3 +33,36 @@ t.Errorf("malformed capget did not return -1, got=%d", got) } } + +// killAThread locks the goroutine to a thread and exits. This has the +// effect of making the go runtime terminate the thread. +func killAThread(c <-chan struct{}) { + runtime.LockOSThread() + <-c +} + +// Test to confirm no regression against: +// +// https://github.com/golang/go/issues/42494 +func TestThreadChurn(t *testing.T) { + const prSetKeepCaps = 8 + + for j := 0; j < 4; j++ { + kill := (j & 1) != 0 + sysc := (j & 2) != 0 + t.Logf("[%d] testing kill=%v, sysc=%v", j, kill, sysc) + for i := 50; i > 0; i-- { + if kill { + c := make(chan struct{}) + go killAThread(c) + close(c) + } + if sysc { + if _, _, e := Syscall3(syscall.SYS_PRCTL, prSetKeepCaps, uintptr(i&1), 0); e != 0 { + t.Fatalf("[%d] psx:prctl(SET_KEEPCAPS, %d) failed: %v", i, i&1, syscall.Errno(e)) + } + } + } + t.Logf("[%d] PASSED kill=%v, sysc=%v", j, kill, sysc) + } +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/tests/.gitignore -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/.gitignore
Changed
@@ -1,3 +1,8 @@ +noop psx_test -psx_test_wrap libcap_psx_test +libcap_launch_test +libcap_psx_launch_test +exploit +noexploit +uns_test
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/tests/Makefile -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/Makefile
Changed
@@ -1,38 +1,121 @@ # -# defines +# NOTE the built tests are all designed to be run from this +# working directory when built DYNAMIC=yes. That is, they +# link to the shared libraries in ../libcap/ . # topdir=$(shell pwd)/.. include ../Make.Rules # -DEPS=../libcap/libcap.a ../libcap/libpsx.a +all: + @echo leave test building to test target -all: psx_test psx_test_wrap libcap_psx_test +install: + @echo nothing to install from tests -$(DEPS): - make -C ../libcap all - -test: run_psx_test run_libcap_psx_test +ifeq ($(DYNAMIC),yes) +LINKEXTRA=-Wl,-rpath,../libcap +DEPS=../libcap/libcap.so +ifeq ($(PTHREADS),yes) +DEPS += ../libcap/libpsx.so +endif +else +# For this build variant override the LDFLAGS to link statically from +# libraries within the build tree. If you never want this, use +# make DYNAMIC=yes ... +LDFLAGS = --static +DEPS=../libcap/libcap.a +ifeq ($(PTHREADS),yes) +DEPS += ../libcap/libpsx.a +endif +endif + +../libcap/libcap.so: + $(MAKE) -C ../libcap libcap.so + +../libcap/libcap.a: + $(MAKE) -C ../libcap libcap.a + +ifeq ($(PTHREADS),yes) +../libcap/libpsx.so: + $(MAKE) -C ../libcap libpsx.so + +../libcap/libpsx.a: + $(MAKE) -C ../libcap libpsx.a +endif + +../progs/tcapsh-static: + $(MAKE) -C ../progs tcapsh-static + +test: +ifeq ($(PTHREADS),yes) + $(MAKE) run_psx_test run_libcap_psx_test +endif sudotest: test + $(MAKE) run_uns_test + $(MAKE) run_libcap_launch_test +ifeq ($(PTHREADS),yes) + $(MAKE) run_libcap_psx_launch_test run_exploit_test +endif -install: all - -run_psx_test: psx_test psx_test_wrap +# unprivileged +run_psx_test: psx_test ./psx_test - ./psx_test_wrap psx_test: psx_test.c $(DEPS) - $(CC) $(CFLAGS) $(IPATH) -DNOWRAP $< -o $@ $(LIBPSXLIB) - -psx_test_wrap: psx_test.c $(DEPS) - $(CC) $(CFLAGS) $(IPATH) $< -o $@ $(LIBPSXLIB) -Wl,-wrap,pthread_create + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LINKEXTRA) $(LIBPSXLIB) run_libcap_psx_test: libcap_psx_test ./libcap_psx_test libcap_psx_test: libcap_psx_test.c $(DEPS) - $(CC) $(CFLAGS) $(IPATH) $< -o $@ $(LIBCAPLIB) $(LIBPSXLIB) -Wl,-wrap,pthread_create --static + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LINKEXTRA) $(LIBCAPLIB) $(LIBPSXLIB) + +# privileged +uns_test: uns_test.c $(DEPS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LINKEXTRA) $(LIBCAPLIB) + +run_uns_test: uns_test + echo exit | $(SUDO) ./uns_test + +run_libcap_launch_test: libcap_launch_test noop ../progs/tcapsh-static + $(SUDO) ./libcap_launch_test + +run_libcap_psx_launch_test: libcap_psx_launch_test ../progs/tcapsh-static + $(SUDO) ./libcap_psx_launch_test + +libcap_launch_test: libcap_launch_test.c $(DEPS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LINKEXTRA) $(LIBCAPLIB) + +# This varies only slightly from the above insofar as it currently +# only links in the pthreads fork support. TODO() we need to change +# the source to do something interesting with pthreads. +libcap_psx_launch_test: libcap_launch_test.c $(DEPS) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DWITH_PTHREADS $< -o $@ $(LINKEXTRA) $(LIBCAPLIB) $(LIBPSXLIB) + + +# This test demonstrates that libpsx is needed to secure multithreaded +# programs that link against libcap. +run_exploit_test: exploit noexploit + @echo exploit should succeed + $(SUDO) ./exploit ; if [ $$? -ne 0 ]; then exit 0; else exit 1 ; fi + @echo exploit should fail + $(SUDO) ./noexploit ; if [ $$? -eq 0 ]; then exit 0; else exit 1 ; fi + +exploit: exploit.o $(DEPS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LINKEXTRA) $(LIBCAPLIB) -lpthread + +# Note, for some reason, the order of libraries is important to avoid +# the exploit working for dynamic linking. +noexploit: exploit.o $(DEPS) + $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ $(LINKEXTRA) $(LIBPSXLIB) $(LIBCAPLIB) + +# This one runs in a chroot with no shared library files. +noop: noop.c + $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ --static clean: - rm -f psx_test psx_test_wrap libcap_psx_test + rm -f psx_test libcap_psx_test libcap_launch_test uns_test *~ + rm -f libcap_launch_test libcap_psx_launch_test core noop + rm -f exploit noexploit exploit.o
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/exploit.c
Added
@@ -0,0 +1,159 @@ +/* + * Copyright (c) 2020 Andrew G Morgan <morgan@kernel.org> + * + * This program exploit demonstrates why libcap alone in a + * multithreaded C/C++ program is inherently vulnerable to privilege + * escalation. + * + * The code also serves as a demonstration of how linking with libpsx + * can eliminate this vulnerability by maintaining a process wide + * common security state. + * + * The basic idea (which is well known and why POSIX stipulates "posix + * semantics" for security relevant state at the abstraction of a + * process) is that, because of shared memory, if a single thread alone + * is vulnerable to code injection, then it can cause any other thread + * to execute arbitrary code. As such, if all but one thread drops + * privilege, privilege escalation is somewhat trivial. + */ + +/* as per "man sigaction" */ +#define _POSIX_C_SOURCE 200809L + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/capability.h> +#include <sys/types.h> + +/* thread coordination */ +pthread_mutex_t mu; +pthread_cond_t cond; +int hits; + +/* evidence of highest privilege attained */ +ssize_t greatest_len; +char *text; + +/* + * interrupt handler - potentially watching for an opportunity to + * perform an exploit when invoked as a privileged thread. + */ +static void handler(int signum, siginfo_t *info, void *ignore) { + ssize_t length; + char *working; + pthread_mutex_lock(&mu); + + cap_t caps = cap_get_proc(); + working = cap_to_text(caps, &length); + if (length > greatest_len) { + /* + * This is where the exploit code might go. + */ + cap_free(text); + text = working; + greatest_len = length; + } + cap_free(caps); + hits++; + + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mu); + +} + +/* + * privileged thread code (imagine it doing whatever needs privilege). + */ +static void *victim(void *args) { + pthread_mutex_lock(&mu); + hits = 1; + printf("started privileged thread\n"); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mu); + + pthread_mutex_lock(&mu); + while (hits < 2) { + pthread_cond_wait(&cond, &mu); + } + pthread_mutex_unlock(&mu); + + return NULL; +} + +int main(int argc, char **argv) { + pthread_t peer; + cap_t caps = cap_init(); + struct sigaction sig_action; + + printf("program starting\n"); + if (pthread_create(&peer, NULL, victim, NULL)) { + perror("unable to start the victim thread"); + exit(1); + } + + /* + * Wait until the peer thread is fully up. + */ + pthread_mutex_lock(&mu); + while (hits < 1) { + pthread_cond_wait(&cond, &mu); + } + pthread_mutex_unlock(&mu); + + printf("dropping privilege from main process thread\n"); + + if (cap_set_proc(caps)) { + perror("unable to drop capabilities from main process thread"); + exit(1); + } + cap_free(caps); + + /* confirm the low privilege of the process' main thread */ + + caps = cap_get_proc(); + text = cap_to_text(caps, &greatest_len); + cap_free(caps); + + printf("no privilege in main process thread: len:%ld, caps:\"%s\"\n", + greatest_len, text); + if (greatest_len != 1) { + printf("failed to lower privilege as expected\n"); + exit(1); + } + + /* + * So, we have confirmed that this running thread has no + * privilege. From this thread we setup an interrupt handler and + * then trigger it on the privileged peer thread. + */ + + sig_action.sa_sigaction = &handler; + sigemptyset(&sig_action.sa_mask); + sig_action.sa_flags = SA_SIGINFO | SA_RESTART;; + sigaction(SIGRTMIN, &sig_action, NULL); + + pthread_kill(peer, SIGRTMIN); + + /* + * Wait for the thread to exit. + */ + pthread_join(peer, NULL); + + /* + * Let's see how we did with the exploit. + */ + + printf("greatest privilege in main process thread: len:%ld, caps:\"%s\"\n", + greatest_len, text); + + cap_free(text); + if (greatest_len != 1) { + printf("exploit succeeded\n"); + exit(1); + } + + printf("exploit failed\n"); + exit(0); +}
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/libcap_launch_test.c
Added
@@ -0,0 +1,233 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/capability.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +/* + * tests for cap_launch. + */ + +#define MORE_THAN_ENOUGH 20 +#define NO_MORE 1 + +struct test_case_s { + int pass_on; + const char *chroot; + uid_t uid; + gid_t gid; + int ngroups; + const gid_t groups[MORE_THAN_ENOUGH]; + const char *args[MORE_THAN_ENOUGH]; + const char **envp; + const char *iab; + cap_mode_t mode; + int launch_abort; + int result; + int (*callback_fn)(void *detail); +}; + +#ifdef WITH_PTHREADS +#include <pthread.h> +#else /* WITH_PTHREADS */ +#endif /* WITH_PTHREADS */ + +/* + * clean_out drops all process capabilities. + */ +static int clean_out(void *data) { + cap_t empty; + empty = cap_init(); + if (cap_set_proc(empty) != 0) { + _exit(1); + } + cap_free(empty); + return 0; +} + +int main(int argc, char **argv) { + static struct test_case_s vs[] = { + { + .args = { "../progs/tcapsh-static", "--", "-c", "echo hello" }, + .result = 0 + }, + { + .args = { "../progs/tcapsh-static", "--", "-c", "echo hello" }, + .callback_fn = &clean_out, + .result = 0 + }, + { + .callback_fn = &clean_out, + .result = 0 + }, + { + .args = { "../progs/tcapsh-static", "--is-uid=123" }, + .result = 256 + }, + { + .args = { "/", "won't", "work" }, + .launch_abort = 1, + }, + { + .args = { "../progs/tcapsh-static", "--is-uid=123" }, + .uid = 123, + .result = 0, + }, + { + .args = { "../progs/tcapsh-static", "--is-uid=123" }, + .callback_fn = &clean_out, + .uid = 123, + .launch_abort = 1, + }, + { + .args = { "../progs/tcapsh-static", "--is-gid=123" }, + .result = 0, + .gid = 123, + .ngroups = 1, + .groups = { 456 }, + .iab = "", + }, + { + .args = { "../progs/tcapsh-static", "--dropped=cap_chown", + "--has-i=cap_chown" }, + .result = 0, + .iab = "!%cap_chown" + }, + { + .args = { "../progs/tcapsh-static", "--dropped=cap_chown", + "--has-i=cap_chown", "--is-uid=234", + "--has-a=cap_chown", "--has-p=cap_chown" }, + .uid = 234, + .result = 0, + .iab = "!^cap_chown" + }, + { + .args = { "../progs/tcapsh-static", "--inmode=NOPRIV", + "--has-no-new-privs" }, + .result = 0, + .mode = CAP_MODE_NOPRIV + }, + { + .args = { "/noop" }, + .result = 0, + .chroot = ".", + }, + { + .pass_on = NO_MORE + }, + }; + + cap_t orig = cap_get_proc(); + if (orig == NULL) { + perror("failed to get process capabilities"); + exit(1); + } + + int success = 1, i; + for (i=0; vs[i].pass_on != NO_MORE; i++) { + cap_launch_t attr = NULL; + const struct test_case_s *v = &vs[i]; + if (cap_launch(attr, NULL) != -1) { + perror("NULL launch didn't fail"); + exit(1); + } + printf("[%d] test should %s\n", i, + v->result || v->launch_abort ? "generate error" : "work"); + if (v->args[0] != NULL) { + attr = cap_new_launcher(v->args[0], v->args, v->envp); + if (attr == NULL) { + perror("failed to obtain launcher"); + exit(1); + } + if (v->callback_fn != NULL) { + cap_launcher_callback(attr, v->callback_fn); + } + } else { + attr = cap_func_launcher(v->callback_fn); + } + if (v->chroot) { + cap_launcher_set_chroot(attr, v->chroot); + } + if (v->uid) { + cap_launcher_setuid(attr, v->uid); + } + if (v->gid) { + cap_launcher_setgroups(attr, v->gid, v->ngroups, v->groups); + } + if (v->iab) { + cap_iab_t iab = cap_iab_from_text(v->iab); + if (iab == NULL) { + fprintf(stderr, "[%d] failed to decode iab [%s]", i, v->iab); + perror(":"); + success = 0; + continue; + } + cap_iab_t old = cap_launcher_set_iab(attr, iab); + if (cap_free(old)) { + fprintf(stderr, "[%d] failed to decode iab [%s]", i, v->iab); + perror(":"); + success = 0; + continue; + } + } + if (v->mode) { + cap_launcher_set_mode(attr, v->mode); + } + + pid_t child = cap_launch(attr, NULL); + + if (child <= 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(""); + success = 0; + } + int result; + int ret = waitpid(child, &result, 0); + if (ret != child) { + fprintf(stderr, "[%d] failed to wait: ", i); + perror(""); + success = 0;
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/tests/libcap_psx_test.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/libcap_psx_test.c
Changed
@@ -1,12 +1,65 @@ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <errno.h> #include <pthread.h> #include <stdio.h> +#include <stdlib.h> #include <sys/capability.h> #include <sys/psx_syscall.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> -int main(int argc, char **argv) { - printf("hello libcap and libpsx\n"); - psx_register(pthread_self()); +static void *thread_fork_exit(void *data) { + usleep(1234); + pid_t pid = fork(); cap_t start = cap_get_proc(); + if (start == NULL) { + perror("FAILED: unable to start"); + exit(1); + } + if (pid == 0) { + if (cap_set_proc(start)) { + perror("setting empty caps failed"); + exit(1); + } + exit(0); + } + int res; + if (waitpid(pid, &res, 0) != pid || res != 0) { + printf("FAILED: pid=%d wait returned %d and/or error: %d\n", + pid, res, errno); + exit(1); + } cap_set_proc(start); - return 0; + cap_free(start); + return NULL; +} + +int main(int argc, char **argv) { + int i; + printf("hello libcap and libpsx "); + fflush(stdout); + cap_t start = cap_get_proc(); + if (start == NULL) { + perror("FAILED: to actually start"); + exit(1); + } + pthread_t ignored[10]; + for (i = 0; i < 10; i++) { + pthread_create(&ignored[i], NULL, thread_fork_exit, NULL); + } + for (i = 0; i < 10; i++) { + printf("."); /* because of fork, this may print double */ + fflush(stdout); /* try to limit the above effect */ + if (cap_set_proc(start)) { + perror("failed to set proc"); + exit(1); + } + usleep(1000); + } + printf(" PASSED\n"); + exit(0); }
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/noop.c
Added
@@ -0,0 +1,5 @@ +#include <stdlib.h> + +int main(int argc, char *argv[]) { + exit(0); +}
View file
_service:tar_scm_kernel_repo:libcap-2.32.tar.gz/tests/psx_test.c -> _service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/psx_test.c
Changed
@@ -1,17 +1,34 @@ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + #include <pthread.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <sys/prctl.h> #include <sys/psx_syscall.h> #include <sys/syscall.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +typedef union tp { + long long unsigned raw; + pthread_t pt; +} thread_ptr; static void say_hello_expecting(const char *title, int n, int kept) { int keeper = prctl(PR_GET_KEEPCAPS); - printf("hello, %s<%d> %lx (keepcaps=%d vs. want=%d)\n", - title, n, pthread_self(), keeper, kept); + thread_ptr tp; + tp.pt = pthread_self(); + + printf("hello [%d], %s<%d> %llx (keepcaps=%d vs. want=%d)\n", + getpid(), title, n, tp.raw, keeper, kept); if (keeper != kept) { - printf("--> FAILURE %s thread=%lx has wrong keepcaps: got=%d want=%d\n", - title, pthread_self(), keeper, kept); + printf("--> FAILURE %s thread=%llx has wrong keepcaps: got=%d want=%d\n", + title, tp.raw, keeper, kept); exit(1); } } @@ -30,21 +47,24 @@ pthread_mutex_lock(&mu); started++; + int this_step = step+1; pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mu); - int this_step = step+1; + pthread_mutex_lock(&mu); do { while (this_step > step) { pthread_cond_wait(&cond, &mu); } - this_step++; - say_hello_expecting("thread", count, global_kept); replies++; pthread_cond_broadcast(&cond); - } while (++count != 3); + pthread_mutex_unlock(&mu); + this_step++; + pthread_mutex_lock(&mu); + } while (++count != 3); pthread_mutex_unlock(&mu); return NULL; @@ -53,8 +73,18 @@ int main(int argc, char **argv) { pthread_t tid[3]; int i; + pid_t child = 0; + char * const stop_argv[3] = { argv[0], strdup("stop"), NULL }; + + if (argc != 1) { + printf("child %d starting\n", getpid()); + usleep(2000); + printf("child %d exiting\n", getpid()); + exit(0); + } + for (i = 0; i<10; i++) { - printf("iteration: %d\n", i); + printf("iteration [%d]: %d\n", getpid(), i); pthread_mutex_lock(&mu); global_kept = !global_kept; @@ -63,8 +93,11 @@ pthread_mutex_unlock(&mu); psx_syscall(SYS_prctl, PR_SET_KEEPCAPS, global_kept); + + pthread_mutex_lock(&mu); step++; pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mu); say_hello_expecting("main", i, global_kept); @@ -75,22 +108,27 @@ pthread_mutex_unlock(&mu); if (i < 3) { - launched++; - if (i == 1) { - /* Confirm this works whether or not we are WRAPPING. */ - psx_pthread_create(&tid[i], NULL, say_hello, NULL); - } else if (i < 3) { -#ifdef NOWRAP - psx_pthread_create(&tid[i], NULL, say_hello, NULL); -#else - pthread_create(&tid[i], NULL, say_hello, NULL); -#endif + if (!child) { + child = fork(); + if (!child) { + usleep(2000); + execve(argv[0], stop_argv, NULL); + perror("failed to exec"); + exit(1); + } else { + printf("pid=%d forked -> %d\n", getpid(), child); + } } + launched++; + pthread_create(&tid[i], NULL, say_hello, NULL); /* Confirm that the thread is started. */ pthread_mutex_lock(&mu); while (started < launched) { + printf("[%d] started=%d vs %d\n", getpid(), started, launched); pthread_cond_wait(&cond, &mu); } + printf("[%d] started=%d vs %d\n", getpid(), started, launched); + pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mu); } else if (i < 6) { /* Confirm one thread has finished. */ @@ -99,10 +137,14 @@ } } + if (child) { + int status; + waitpid(child, &status, 0); + if (status) { + printf("child %d FAILED: %d\n", child, status); + exit(1); + } + } printf("%s PASSED\n", argv[0]); exit(0); } - -#ifdef NOWRAP -PSX_NO_LINKER_WRAPPING -#endif
View file
_service:tar_scm_kernel_repo:libcap-2.61.tar.gz/tests/uns_test.c
Added
@@ -0,0 +1,171 @@ +/* + * Try unsharing where we remap the root user by rotating uids (0,1,2) + * and the corresponding gids too. + */ + +#define _GNU_SOURCE + +#include <errno.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/capability.h> +#include <sys/mman.h> +#include <sys/prctl.h> +#include <sys/wait.h> +#include <unistd.h> + +#define STACK_RESERVED 10*1024 + +struct my_pipe { + int to[2]; + int from[2]; +}; + +static int child(void *data) { + struct my_pipe *fdsp = data; + static const char * const args[] = {"bash", NULL}; + + close(fdsp->to[1]); + close(fdsp->from[0]); + if (write(fdsp->from[1], "1", 1) != 1) { + fprintf(stderr, "failed to confirm setuid(1)\n"); + exit(1); + } + close(fdsp->from[1]); + + char datum[1]; + if (read(fdsp->to[0], datum, 1) != 1) { + fprintf(stderr, "failed to wait for parent\n"); + exit(1); + } + close(fdsp->to[0]); + if (datum[0] == '!') { + /* parent failed */ + exit(0); + } + + setsid(); + + execv("/bin/bash", (const void *) args); + perror("execv failed"); + exit(1); +} + +int main(int argc, char **argv) +{ + static const char *file_formats[] = { + "/proc/%d/uid_map", + "/proc/%d/gid_map" + }; + static const char id_map[] = "0 1 1\n1 2 1\n2 0 1\n3 3 49999997\n"; + cap_value_t fscap = CAP_SETFCAP; + cap_t orig = cap_get_proc(); + cap_flag_value_t present; + + if (cap_get_flag(orig, CAP_SYS_ADMIN, CAP_EFFECTIVE, &present) != 0) { + perror("failed to read a capability flag"); + exit(1); + } + if (present != CAP_SET) { + fprintf(stderr, + "environment missing cap_sys_admin - exploit not testable\n"); + exit(0); + } + + /* Run with this one lowered */ + cap_set_flag(orig, CAP_EFFECTIVE, 1, &fscap, CAP_CLEAR); + + struct my_pipe fds; + if (pipe(&fds.from[0]) || pipe(&fds.to[0])) { + perror("no pipes"); + exit(1); + } + + char *stack = mmap(NULL, STACK_RESERVED, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE|MAP_STACK, -1, 0); + if (stack == MAP_FAILED) { + perror("no map for stack"); + exit(1); + } + + if (cap_setuid(1)) { + perror("failed to cap_setuid(1)"); + exit(1); + } + + if (cap_set_proc(orig)) { + perror("failed to raise caps again"); + exit(1); + } + + pid_t pid = clone(&child, stack+STACK_RESERVED, CLONE_NEWUSER|SIGCHLD, &fds); + if (pid == -1) { + perror("clone failed"); + exit(1); + } + + close(fds.from[1]); + close(fds.to[0]); + + if (cap_setuid(0)) { + perror("failed to cap_setuid(0)"); + exit(1); + } + + if (cap_set_proc(orig)) { + perror("failed to raise caps again"); + exit(1); + } + + char datum[1]; + if (read(fds.from[0], datum, 1) != 1 || datum[0] != '1') { + fprintf(stderr, "failed to read child status\n"); + exit(1); + } + close(fds.from[0]); + + int i; + for (i=0; i<2; i++) { + char *map_file; + if (asprintf(&map_file, file_formats[i], pid) < 0) { + perror("allocate string"); + exit(1); + } + + FILE *f = fopen(map_file, "w"); + free(map_file); + if (f == NULL) { + perror("fopen failed"); + exit(1); + } + int len = fwrite(id_map, 1, strlen(id_map), f); + if (len != strlen(id_map)) { + goto bailok; + } + if (fclose(f)) { + goto bailok; + } + } + + if (write(fds.to[1], ".", 1) != 1) { + perror("failed to write '.'"); + exit(1); + } + close(fds.to[1]); + + fprintf(stderr, "user namespace launched exploit worked - upgrade kernel\n"); + if (wait(NULL) == pid) { + exit(1); + } + perror("launch failed"); + exit(1); + +bailok: + fprintf(stderr, "exploit attempt failed\n"); + if (write(fds.to[1], "!", 1) != 1) { + perror("failed to inform child [ignored]"); + } + exit(0); +}
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.