diff options
author | dec05eba <dec05eba@protonmail.com> | 2024-02-10 19:05:02 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2024-02-11 02:11:41 +0100 |
commit | 667a6b3b1bc20516d1bf7d8a4611cd3a4d3f3bc6 (patch) | |
tree | 2770b29323939cec51670dd0d1aebd39a8041914 /depends/libcap |
Initial commit, done
Diffstat (limited to 'depends/libcap')
25 files changed, 5517 insertions, 0 deletions
diff --git a/depends/libcap/Make.Rules b/depends/libcap/Make.Rules new file mode 100644 index 0000000..721fc7a --- /dev/null +++ b/depends/libcap/Make.Rules @@ -0,0 +1,201 @@ +# Common version number defines for libcap +LIBTITLE=libcap +VERSION=2 +MINOR=69 + +# +## Optional prefixes: +# + +# common 'packaging' directory + +FAKEROOT=$(DESTDIR) + +# Autoconf-style prefixes are activated when $(prefix) is defined. +# Otherwise binaries and libraries are installed in /{lib,sbin}/, +# header files in /usr/include/ and documentation in /usr/man/man?/. +# These choices are motivated by the fact that getcap and setcap are +# administrative operations that could be needed to recover a system. + +ifndef lib +lib=$(shell ldd /usr/bin/ld|grep -E "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) +inc_prefix=$(lib_prefix) +man_prefix=$(prefix)/share +else +prefix=/usr +exec_prefix= +lib_prefix=$(exec_prefix) +inc_prefix=$(prefix) +man_prefix=$(prefix)/share +endif + +# Target directories + +MANDIR=$(man_prefix)/man +SBINDIR=$(exec_prefix)/$(sbin) +INCDIR=$(inc_prefix)/include +LIBDIR=$(lib_prefix)/$(lib) +PKGCONFIGDIR=$(LIBDIR)/pkgconfig +GOPKGDIR=$(prefix)/share/gocode/src + +# 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 +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_SED ?= sed +BUILD_GREP ?= grep +BUILD_EGREP ?= $(BUILD_GREP) -E +BUILD_FGREP ?= $(BUILD_GREP) -F + +# Plan to eventually redefine BUILD_GPERF to be the actual gperf tool +# alias as per above. Typical distributions are upto a year behind +# HEAD so we'll not do that before 2023-01-01. +ifdef BUILD_GPERF +$(error BUILD_GPERF is now reserved, please use USE_GPERF=yes or no instead) +endif + +USE_GPERF ?= $(shell which gperf >/dev/null 2>/dev/null && echo yes) + +LIBCAPLIB := -L$(topdir)/libcap -lcap +PSXLINKFLAGS := -lpthread -Wl,-wrap,pthread_create +LIBPSXLIB := -L$(topdir)/libcap -lpsx $(PSXLINKFLAGS) + +INCS=$(topdir)/libcap/include/sys/capability.h +INDENT := $(shell if [ -n "$$(which indent 2>/dev/null)" ]; then echo "| indent -kr" ; 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) +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 := $(LIBCAP_INCLUDES) +CGO_LDFLAGS := -L$(topdir)/libcap +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 +# certain users say) to make it useful for specially blessed users. +# +# make RAISE_SETFCAP=yes install +# +# 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 looked alarmingly like these distributions were recreating +# the environment for what became known as the sendmail-capabilities +# bug from 2000: +# +# https://sites.google.com/site/fullycapable/Home/thesendmailcapabilitiesissue +# +# they are also nullifying the difference between a p-bit and an i-bit. +# +# Folk really should read this document, which explains there is a really +# important difference being lost here: +# +# https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/33528.pdf +# +# 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 mechanism. +RAISE_SETFCAP := no + +# If set to yes, this will cause the go "web" demo app to force the needed p +# bit to be able to bind to port 80 without running as root. +RAISE_GO_FILECAP := no + +# Global cleanup stuff + +LOCALCLEAN=rm -f *~ core +DISTCLEAN=@find . \( -name '*.orig' -o -name '*.rej' \) | xargs rm -f diff --git a/depends/libcap/libcap/.gitignore b/depends/libcap/libcap/.gitignore new file mode 100644 index 0000000..a0771d4 --- /dev/null +++ b/depends/libcap/libcap/.gitignore @@ -0,0 +1,15 @@ +cap_names.h +cap_names.list.h +_caps_output.gperf +libcap.a +libcap.so* +libpsx.a +libpsx.so* +_makenames +cap_test +libcap.pc +libpsx.pc +empty +loader.txt +cap_magic.o +psx_magic.o diff --git a/depends/libcap/libcap/Makefile b/depends/libcap/libcap/Makefile new file mode 100644 index 0000000..f5dde3e --- /dev/null +++ b/depends/libcap/libcap/Makefile @@ -0,0 +1,235 @@ +# +# defines +# +topdir=$(shell pwd)/.. +include ../Make.Rules +# +# Library version +# +CAPLIBNAME=$(LIBTITLE).so +STACAPLIBNAME=$(LIBTITLE).a +# +PSXTITLE=libpsx +PSXLIBNAME=$(PSXTITLE).so +STAPSXLIBNAME=$(PSXTITLE).a + +CAPFILES=cap_alloc cap_proc cap_extint cap_flag cap_text cap_file +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) + +all: pcs $(STACAPLIBNAME) +ifeq ($(SHARED),yes) + $(MAKE) $(CAPLIBNAME) +endif +ifeq ($(PTHREADS),yes) + $(MAKE) $(STAPSXLIBNAME) +ifeq ($(SHARED),yes) + $(MAKE) $(PSXLIBNAME) +endif +endif + +pcs: $(LIBTITLE).pc +ifeq ($(PTHREADS),yes) + $(MAKE) $(PSXTITLE).pc +endif + +ifeq ($(USE_GPERF),yes) +USE_GPERF_OUTPUT = $(GPERF_OUTPUT) +INCLUDE_GPERF_OUTPUT = -DINCLUDE_GPERF_OUTPUT='"$(GPERF_OUTPUT)"' +endif + +$(LIBTITLE).pc: $(LIBTITLE).pc.in + $(BUILD_SED) -e 's,@prefix@,$(prefix),' \ + -e 's,@exec_prefix@,$(exec_prefix),' \ + -e 's,@libdir@,$(LIBDIR),' \ + -e 's,@includedir@,$(inc_prefix)/include,' \ + -e 's,@VERSION@,$(VERSION).$(MINOR),' \ + -e 's,@deps@,$(DEPS),' \ + $< >$@ + +$(PSXTITLE).pc: $(PSXTITLE).pc.in + $(BUILD_SED) -e 's,@prefix@,$(prefix),' \ + -e 's,@exec_prefix@,$(exec_prefix),' \ + -e 's,@libdir@,$(LIBDIR),' \ + -e 's,@includedir@,$(inc_prefix)/include,' \ + -e 's,@VERSION@,$(VERSION).$(MINOR),' \ + -e 's,@deps@,$(DEPS),' \ + $< >$@ + +_makenames: _makenames.c cap_names.list.h + $(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $< -o $@ + +cap_names.h: _makenames + ./_makenames > cap_names.h + +$(GPERF_OUTPUT): cap_names.list.h cap_names.header Makefile + (cat cap_names.header ; $(BUILD_SED) -e 's/[\{\}"]//g' -e 's/,$$//' cap_names.list.h) | 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) > $@ + $(BUILD_SED) -e 's/unsigned int len/size_t len/' -i $@ + +# 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. That is, all production kernels should be equal +# to or behind libcap. +# +# Note "./libcap.so --summary" should explain how the built libcap.so +# compares to the running kernel. +UAPI_HEADER := $(topdir)/libcap/include/uapi/linux/capability.h +cap_names.list.h: Makefile $(UAPI_HEADER) + @echo "=> making $@ from $(UAPI_HEADER)" + $(BUILD_EGREP) '^#define\s+CAP_([^\s]+)\s+[0-9]+\s*$$' include/uapi/linux/capability.h | $(BUILD_SED) -e 's/^#define\s\+/{"/' -e 's/\s*$$/},/' -e 's/\s\+/",/' -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' > $@ + +$(STACAPLIBNAME): $(CAPOBJS) + $(AR) rcs $@ $^ + $(RANLIB) $@ + +$(STAPSXLIBNAME): $(PSXOBJS) include/sys/psx_syscall.h + $(AR) rcs $@ $(PSXOBJS) + $(RANLIB) $@ + +ifeq ($(SHARED),yes) + +empty: empty.c + $(CC) -o $@ $< + +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) $(CPPFLAGS) -c $< -o $@ + +cap_text.o: cap_text.c $(USE_GPERF_OUTPUT) $(INCLS) + $(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 + +libpsxsotest: $(PSXLIBNAME) + ./$(PSXLIBNAME) + +test: cap_test + ./cap_test +ifeq ($(SHARED),yes) + $(MAKE) libcapsotest +ifeq ($(PTHREADS),yes) + $(MAKE) libpsxsotest +endif +endif + +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 + +install-static-cap: install-common-cap $(STACAPLIBNAME) + install -m 0644 $(STACAPLIBNAME) $(FAKEROOT)$(LIBDIR)/$(STACAPLIBNAME) + +install-shared-cap: install-common-cap $(MINCAPLIBNAME) + install -m 0755 $(MINCAPLIBNAME) $(FAKEROOT)$(LIBDIR)/$(MINCAPLIBNAME) + ln -sf $(MINCAPLIBNAME) $(FAKEROOT)$(LIBDIR)/$(MAJCAPLIBNAME) + ln -sf $(MAJCAPLIBNAME) $(FAKEROOT)$(LIBDIR)/$(CAPLIBNAME) +ifeq ($(FAKEROOT),) + -/sbin/ldconfig +endif + +install-static-psx: install-common-psx $(STAPSXLIBNAME) + install -m 0644 $(STAPSXLIBNAME) $(FAKEROOT)$(LIBDIR)/$(STAPSXLIBNAME) + +install-shared-psx: install-common-psx $(MINPSXLIBNAME) + install -m 0755 $(MINPSXLIBNAME) $(FAKEROOT)$(LIBDIR)/$(MINPSXLIBNAME) + ln -sf $(MINPSXLIBNAME) $(FAKEROOT)$(LIBDIR)/$(MAJPSXLIBNAME) + ln -sf $(MAJPSXLIBNAME) $(FAKEROOT)$(LIBDIR)/$(PSXLIBNAME) +ifeq ($(FAKEROOT),) + -/sbin/ldconfig +endif + +install-common-cap: install-common $(LIBTITLE).pc + install -m 0644 include/sys/capability.h $(FAKEROOT)$(INCDIR)/sys + install -m 0644 $(LIBTITLE).pc $(FAKEROOT)$(PKGCONFIGDIR)/$(LIBTITLE).pc + +include/sys/psx_syscall.h: ../psx/psx_syscall.h + rm -f $@ + ln -s ../../../psx/psx_syscall.h $@ + +install-common-psx: install-common $(PSXTITLE).pc include/sys/psx_syscall.h + install -m 0644 include/sys/psx_syscall.h $(FAKEROOT)$(INCDIR)/sys + install -m 0644 $(PSXTITLE).pc $(FAKEROOT)$(PKGCONFIGDIR)/$(PSXTITLE).pc + +install-common: + mkdir -p -m 0755 $(FAKEROOT)$(INCDIR)/sys + mkdir -p -m 0755 $(FAKEROOT)$(PKGCONFIGDIR) + mkdir -p -m 0755 $(FAKEROOT)$(LIBDIR) + +clean: + $(LOCALCLEAN) + rm -f $(CAPOBJS) $(CAPLIBNAME)* $(STACAPLIBNAME) $(LIBTITLE).pc + rm -f $(PSXOBJS) $(PSXLIBNAME)* $(STAPSXLIBNAME) $(PSXTITLE).pc + rm -f cap_names.h cap_names.list.h _makenames $(GPERF_OUTPUT) cap_test + rm -f include/sys/psx_syscall.h + rm -f $(CAPMAGICOBJ) $(PSXMAGICOBJ) empty loader.txt + cd include/sys && $(LOCALCLEAN) diff --git a/depends/libcap/libcap/_makenames.c b/depends/libcap/libcap/_makenames.c new file mode 100644 index 0000000..30eb080 --- /dev/null +++ b/depends/libcap/libcap/_makenames.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1997-8,2020 Andrew G. Morgan <morgan@kernel.org> + * + * This is a file to make the capability <-> string mappings for + * libcap. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* + * #include 'sed' generated array + */ + +struct { + const char *name; + int index; +} const list[] = { +#include "cap_names.list.h" + {NULL, -1} +}; + +/* + * 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) { + maxlength = n; + } + } + + printf("/*\n" + " * DO NOT EDIT: this file is generated automatically from\n" + " *\n" + " * <uapi/linux/capability.h>\n" + " */\n\n" + "#define __CAP_BITS %d\n" + "#define __CAP_NAME_SIZE %d\n" + "\n" + "#ifdef LIBCAP_PLEASE_INCLUDE_ARRAY\n" + "#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); + } + } + + printf(" }\n" + "#endif /* LIBCAP_PLEASE_INCLUDE_ARRAY */\n" + "\n" + "/* END OF FILE */\n"); + + free(pointers); + exit(0); +} diff --git a/depends/libcap/libcap/cap_alloc.c b/depends/libcap/libcap/cap_alloc.c new file mode 100644 index 0000000..504abd2 --- /dev/null +++ b/depends/libcap/libcap/cap_alloc.c @@ -0,0 +1,307 @@ +/* + * 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). + */ + +#include "libcap.h" + +/* + * 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__((visibility ("hidden"))) +__attribute__((constructor (300))) void _libcap_initialize(void) +{ + int errno_saved = errno; + _cap_mu_lock(&__libcap_mutex); + if (!_cap_max_bits) { + cap_set_syscall(NULL, NULL); + _binary_search(_cap_max_bits, cap_get_bound, 0, __CAP_MAXBITS, + __CAP_BITS); + } + _cap_mu_unlock(&__libcap_mutex); + errno = errno_saved; +} + +cap_value_t cap_max_bits(void) +{ + return _cap_max_bits; +} + +/* + * 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) +{ + struct _cap_alloc_s *raw_data; + cap_t 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); + + result = &raw_data->u.set; + result->head.version = _LIBCAP_CAPABILITY_VERSION; + capget(&result->head, NULL); /* load the kernel-capability version */ + + switch (result->head.version) { +#ifdef _LINUX_CAPABILITY_VERSION_1 + case _LINUX_CAPABILITY_VERSION_1: + break; +#endif +#ifdef _LINUX_CAPABILITY_VERSION_2 + case _LINUX_CAPABILITY_VERSION_2: + break; +#endif +#ifdef _LINUX_CAPABILITY_VERSION_3 + case _LINUX_CAPABILITY_VERSION_3: + break; +#endif + default: /* No idea what to do */ + cap_free(result); + result = NULL; + break; + } + + return result; +} + +/* + * This is an internal library function to duplicate a string and + * tag the result as something cap_free can handle. + */ +__attribute__((visibility ("hidden"))) char *_libcap_strdup(const char *old) +{ + struct _cap_alloc_s *header; + char *raw_data; + size_t len; + + if (old == NULL) { + errno = EINVAL; + return NULL; + } + + len = strlen(old); + if ((len & 0x3fffffff) != len) { + _cap_debug("len is too long for libcap to manage"); + errno = EINVAL; + return NULL; + } + len += 1 + 2*sizeof(__u32); + if (len < sizeof(struct _cap_alloc_s)) { + len = sizeof(struct _cap_alloc_s); + } + + raw_data = calloc(1, len); + if (raw_data == NULL) { + errno = ENOMEM; + return NULL; + } + 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 + * 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; + + if (!good_cap_t(cap_d)) { + _cap_debug("bad argument"); + errno = EINVAL; + return NULL; + } + + result = cap_init(); + if (result == NULL) { + _cap_debug("out of memory"); + 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; +} + +/* + * 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) +{ + struct _cap_alloc_s *data = calloc(1, sizeof(struct _cap_alloc_s)); + if (data == NULL) { + _cap_debug("out of memory"); + return NULL; + } + data->magic = CAP_LAUNCH_MAGIC; + data->size = sizeof(struct _cap_alloc_s); + + struct cap_launch_s *attr = &data->u.launcher; + attr->arg0 = arg0; + attr->argv = argv; + attr->envp = envp; + return attr; +} + +/* + * cap_func_launcher allocates some memory for a launcher and + * initializes it. The purpose of this launcher, unlike one created + * with cap_new_launcher(), is to execute some function code from a + * forked copy of the program. The forked process will exit when the + * callback function, func, returns. + */ +cap_launch_t cap_func_launcher(int (callback_fn)(void *detail)) +{ + struct _cap_alloc_s *data = calloc(1, sizeof(struct _cap_alloc_s)); + if (data == NULL) { + _cap_debug("out of memory"); + return NULL; + } + data->magic = CAP_LAUNCH_MAGIC; + data->size = sizeof(struct _cap_alloc_s); + + struct cap_launch_s *attr = &data->u.launcher; + attr->custom_setup_fn = callback_fn; + return attr; +} + +/* + * Scrub and then liberate the recognized allocated object. + */ +int cap_free(void *data_p) +{ + if (!data_p) { + return 0; + } + + /* confirm alignment */ + if ((sizeof(uintptr_t)-1) & (uintptr_t) data_p) { + _cap_debug("whatever we're cap_free()ing it isn't aligned right: %p", + data_p); + errno = EINVAL; + return -1; + } + + void *base = (void *) (-2 + (__u32 *) data_p); + struct _cap_alloc_s *data = base; + switch (data->magic) { + case CAP_T_MAGIC: + _cap_mu_lock(&data->u.set.mutex); + break; + case CAP_S_MAGIC: + case CAP_IAB_MAGIC: + break; + case CAP_LAUNCH_MAGIC: + if (data->u.launcher.iab != NULL) { + _cap_mu_unlock(&data->u.launcher.iab->mutex); + if (cap_free(data->u.launcher.iab) != 0) { + return -1; + } + } + data->u.launcher.iab = NULL; + if (cap_free(data->u.launcher.chroot) != 0) { + return -1; + } + data->u.launcher.chroot = NULL; + break; + default: + _cap_debug("don't recognize what we're supposed to liberate"); + errno = EINVAL; + return -1; + } + + /* + * operate here with respect to base, to avoid tangling with the + * automated buffer overflow detection. + */ + memset(base, 0, data->size); + free(base); + data_p = NULL; + data = NULL; + base = NULL; + return 0; +} diff --git a/depends/libcap/libcap/cap_extint.c b/depends/libcap/libcap/cap_extint.c new file mode 100644 index 0000000..462cc65 --- /dev/null +++ b/depends/libcap/libcap/cap_extint.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1997-8,2021 Andrew G. Morgan <morgan@kernel.org> + * + * This file deals with exchanging internal and external + * representations of capability sets. + */ + +#include "libcap.h" + +/* + * External representation for capabilities. (exported as a fixed + * length) + */ +#define CAP_EXT_MAGIC "\220\302\001\121" +#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; + /* + * note, we arrange these so the caps are stacked with byte-size + * resolution + */ + __u8 bytes[CAP_SET_SIZE][NUMBER_OF_CAP_SETS]; +}; + +/* + * 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; + +static ssize_t _cap_size_locked(cap_t cap_d) +{ + 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; +} + +/* + * Copy the internal (cap_d) capability set into an external + * representation. The external representation is portable to other + * Linux architectures. + */ + +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) || 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 = len_set; + + for (i=0; i<NUMBER_OF_CAP_SETS; ++i) { + size_t j; + for (j=0; j<len_set; ) { + __u32 val; + + val = cap_d->u[j/sizeof(__u32)].flat[i]; + + 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 */ + _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 = + (const struct cap_ext_struct *) cap_ext; + cap_t cap_d; + int set, blen; + + /* Does the external representation make sense? */ + if ((export == NULL) + || memcmp(export->magic, external_magic, CAP_EXT_MAGIC_SIZE)) { + errno = EINVAL; + return NULL; + } + + /* Obtain a new internal capability set */ + if (!(cap_d = cap_init())) + return NULL; + + blen = export->length_of_capset; + for (set=0; set<NUMBER_OF_CAP_SETS; ++set) { + unsigned blk; + int bno = 0; + for (blk=0; blk<(CAP_SET_SIZE/sizeof(__u32)); ++blk) { + __u32 val = 0; + + if (bno != blen) + val = export->bytes[bno++][set]; + if (bno != blen) + val |= export->bytes[bno++][set] << 8; + if (bno != blen) + val |= export->bytes[bno++][set] << 16; + if (bno != blen) + val |= export->bytes[bno++][set] << 24; + + cap_d->u[blk].flat[set] = val; + } + } + + /* all done */ + 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); +} diff --git a/depends/libcap/libcap/cap_file.c b/depends/libcap/libcap/cap_file.c new file mode 100644 index 0000000..0bc07f7 --- /dev/null +++ b/depends/libcap/libcap/cap_file.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1997,2007,2016 Andrew G Morgan <morgan@kernel.org> + * + * This file deals with getting/setting capabilities from/on files. + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <sys/types.h> +#include <byteswap.h> +#include <sys/stat.h> +#include <unistd.h> + +/* + * We hardcode the prototypes for the Linux system calls here since + * there are no libcap library APIs that expose the user to these + * details, and that way we don't need to force clients to link any + * other libraries to access them. + */ +extern ssize_t getxattr(const char *, const char *, void *, size_t); +extern ssize_t fgetxattr(int, const char *, void *, size_t); +extern int setxattr(const char *, const char *, const void *, size_t, int); +extern int fsetxattr(int, const char *, const void *, size_t, int); +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 + +#if VFS_CAP_U32 != __CAP_BLKS +# error VFS representation of capabilities is not the same size as kernel +#endif + +#if __BYTE_ORDER == __BIG_ENDIAN +#define FIXUP_32BITS(x) bswap_32(x) +#else +#define FIXUP_32BITS(x) (x) +#endif + +static cap_t _fcaps_load(struct vfs_ns_cap_data *rawvfscap, cap_t result, + int bytes) +{ + __u32 magic_etc; + unsigned tocopy, i; + + magic_etc = FIXUP_32BITS(rawvfscap->magic_etc); + switch (magic_etc & VFS_CAP_REVISION_MASK) { + case VFS_CAP_REVISION_1: + tocopy = VFS_CAP_U32_1; + bytes -= XATTR_CAPS_SZ_1; + break; + + case VFS_CAP_REVISION_2: + tocopy = VFS_CAP_U32_2; + bytes -= XATTR_CAPS_SZ_2; + break; + + case VFS_CAP_REVISION_3: + tocopy = VFS_CAP_U32_3; + bytes -= XATTR_CAPS_SZ_3; + result->rootid = FIXUP_32BITS(rawvfscap->rootid); + break; + + default: + cap_free(result); + result = NULL; + return result; + } + + /* + * Verify that we loaded exactly the right number of bytes + */ + if (bytes != 0) { + cap_free(result); + result = NULL; + return result; + } + + for (i=0; i < tocopy; i++) { + result->u[i].flat[CAP_INHERITABLE] + = FIXUP_32BITS(rawvfscap->data[i].inheritable); + result->u[i].flat[CAP_PERMITTED] + = FIXUP_32BITS(rawvfscap->data[i].permitted); + if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) { + result->u[i].flat[CAP_EFFECTIVE] + = result->u[i].flat[CAP_INHERITABLE] + | result->u[i].flat[CAP_PERMITTED]; + } + } + while (i < __CAP_BLKS) { + result->u[i].flat[CAP_INHERITABLE] + = result->u[i].flat[CAP_PERMITTED] + = result->u[i].flat[CAP_EFFECTIVE] = 0; + i++; + } + + return result; +} + +static int _fcaps_save(struct vfs_ns_cap_data *rawvfscap, cap_t cap_d, + int *bytes_p) +{ + __u32 eff_not_zero, magic; + unsigned tocopy, i; + + if (!good_cap_t(cap_d)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&cap_d->mutex); + + switch (cap_d->head.version) { + case _LINUX_CAPABILITY_VERSION_1: + magic = VFS_CAP_REVISION_1; + tocopy = VFS_CAP_U32_1; + *bytes_p = XATTR_CAPS_SZ_1; + break; + + case _LINUX_CAPABILITY_VERSION_2: + case _LINUX_CAPABILITY_VERSION_3: + magic = VFS_CAP_REVISION_2; + tocopy = VFS_CAP_U32_2; + *bytes_p = XATTR_CAPS_SZ_2; + break; + + default: + errno = EINVAL; + _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; + _cap_mu_unlock_return(&cap_d->mutex, -1); + } + magic = VFS_CAP_REVISION_3; + tocopy = VFS_CAP_U32_3; + *bytes_p = XATTR_CAPS_SZ_3; + rawvfscap->rootid = FIXUP_32BITS(cap_d->rootid); + } + + _cap_debug("setting named file capabilities"); + + for (eff_not_zero = 0, i = 0; i < tocopy; i++) { + eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE]; + } + while (i < __CAP_BLKS) { + if ((cap_d->u[i].flat[CAP_EFFECTIVE] + || cap_d->u[i].flat[CAP_INHERITABLE] + || cap_d->u[i].flat[CAP_PERMITTED])) { + /* + * System does not support these capabilities + */ + errno = EINVAL; + _cap_mu_unlock_return(&cap_d->mutex, -1); + } + i++; + } + + for (i=0; i < tocopy; i++) { + rawvfscap->data[i].permitted + = FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]); + rawvfscap->data[i].inheritable + = FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]); + + if (eff_not_zero + && ((~(cap_d->u[i].flat[CAP_EFFECTIVE])) + & (cap_d->u[i].flat[CAP_PERMITTED] + | cap_d->u[i].flat[CAP_INHERITABLE]))) { + errno = EINVAL; + _cap_mu_unlock_return(&cap_d->mutex, -1); + } + } + + if (eff_not_zero == 0) { + rawvfscap->magic_etc = FIXUP_32BITS(magic); + } else { + rawvfscap->magic_etc = FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE); + } + + _cap_mu_unlock_return(&cap_d->mutex, 0); /* success */ +} + +/* + * Get the capabilities of an open file, as specified by its file + * descriptor. + */ + +cap_t cap_get_fd(int fildes) +{ + cap_t result; + + /* allocate a new capability set */ + result = cap_init(); + if (result) { + struct vfs_ns_cap_data rawvfscap; + int sizeofcaps; + + _cap_debug("getting fildes capabilities"); + + /* fill the capability sets via a system call */ + sizeofcaps = fgetxattr(fildes, XATTR_NAME_CAPS, + &rawvfscap, sizeof(rawvfscap)); + if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) { + cap_free(result); + result = NULL; + } else { + result = _fcaps_load(&rawvfscap, result, sizeofcaps); + } + } + + return result; +} + +/* + * Get the capabilities from a named file. + */ + +cap_t cap_get_file(const char *filename) +{ + cap_t result; + + /* allocate a new capability set */ + result = cap_init(); + if (result) { + struct vfs_ns_cap_data rawvfscap; + int sizeofcaps; + + _cap_debug("getting filename capabilities"); + + /* fill the capability sets via a system call */ + sizeofcaps = getxattr(filename, XATTR_NAME_CAPS, + &rawvfscap, sizeof(rawvfscap)); + if (sizeofcaps < ssizeof(rawvfscap.magic_etc)) { + cap_free(result); + result = NULL; + } else { + result = _fcaps_load(&rawvfscap, result, sizeofcaps); + } + } + + return result; +} + +/* + * Get rootid as seen in the current user namespace for the file capability + * sets. + */ + +uid_t cap_get_nsowner(cap_t cap_d) +{ + 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; +} + +/* + * Set the capabilities of an open file, as specified by its file + * descriptor. + */ + +int cap_set_fd(int fildes, cap_t cap_d) +{ + struct vfs_ns_cap_data rawvfscap; + int sizeofcaps; + struct stat buf; + + if (fstat(fildes, &buf) != 0) { + _cap_debug("unable to stat file descriptor %d", fildes); + return -1; + } + if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) { + _cap_debug("file descriptor %d for non-regular file", fildes); + errno = EINVAL; + return -1; + } + + if (cap_d == NULL) { + _cap_debug("deleting fildes capabilities"); + return fremovexattr(fildes, XATTR_NAME_CAPS); + } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) { + return -1; + } + + _cap_debug("setting fildes capabilities"); + + return fsetxattr(fildes, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0); +} + +/* + * Set the capabilities of a named file. + */ + +int cap_set_file(const char *filename, cap_t cap_d) +{ + struct vfs_ns_cap_data rawvfscap; + int sizeofcaps; + struct stat buf; + + if (lstat(filename, &buf) != 0) { + _cap_debug("unable to stat file [%s]", filename); + return -1; + } + if (S_ISLNK(buf.st_mode) || !S_ISREG(buf.st_mode)) { + _cap_debug("file [%s] is not a regular file", filename); + errno = EINVAL; + return -1; + } + + if (cap_d == NULL) { + _cap_debug("removing filename capabilities"); + return removexattr(filename, XATTR_NAME_CAPS); + } else if (_fcaps_save(&rawvfscap, cap_d, &sizeofcaps) != 0) { + return -1; + } + + _cap_debug("setting filename capabilities"); + return setxattr(filename, XATTR_NAME_CAPS, &rawvfscap, sizeofcaps, 0); +} + +/* + * Set nsowner for the file capability set. + */ +int cap_set_nsowner(cap_t cap_d, uid_t rootuid) +{ + 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 */ + +cap_t cap_get_fd(int fildes) +{ + errno = EINVAL; + return NULL; +} + +cap_t cap_get_file(const char *filename) +{ + errno = EINVAL; + return NULL; +} + +uid_t cap_get_nsowner(cap_t cap_d) +{ + errno = EINVAL; + return -1; +} + +int cap_set_fd(int fildes, cap_t cap_d) +{ + errno = EINVAL; + return -1; +} + +int cap_set_file(const char *filename, cap_t cap_d) +{ + errno = EINVAL; + return -1; +} + +int cap_set_nsowner(cap_t cap_d, uid_t rootuid) +{ + errno = EINVAL; + return -1; +} + +#endif /* def VFS_CAP_U32 */ diff --git a/depends/libcap/libcap/cap_flag.c b/depends/libcap/libcap/cap_flag.c new file mode 100644 index 0000000..94afd1e --- /dev/null +++ b/depends/libcap/libcap/cap_flag.c @@ -0,0 +1,369 @@ +/* + * 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" + +/* + * Return the state of a specified capability flag. The state is + * 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) +{ + /* + * Do we have a set and a place to store its value? + * Is it a known capability? + */ + + 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"); + errno = EINVAL; + return -1; + } +} + +/* + * raise/lower a selection of capabilities + */ + +int cap_set_flag(cap_t cap_d, cap_flag_t set, + int no_values, const cap_value_t *array_values, + cap_flag_value_t raise) +{ + /* + * Do we have a set and a place to store its value? + * Is it a known capability? + */ + + if (good_cap_t(cap_d) && no_values > 0 && no_values < __CAP_MAXBITS + && (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]); + } else { + int value = array_values[i]; + + if (raise == CAP_SET) { + cap_d->raise_cap(value,set); + } else { + cap_d->lower_cap(value,set); + } + } + } + _cap_mu_unlock(&cap_d->mutex); + return 0; + } else { + _cap_debug("invalid arguments"); + errno = EINVAL; + return -1; + } +} + +/* + * Reset the capability to be empty (nothing raised) + */ + +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; + } +} + +/* + * Reset the all of the capability bits for one of the flag sets + */ + +int cap_clear_flag(cap_t cap_d, cap_flag_t flag) +{ + switch (flag) { + case CAP_EFFECTIVE: + case CAP_PERMITTED: + case CAP_INHERITABLE: + 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; + } + /* + * fall through + */ + + default: + _cap_debug("invalid pointer"); + errno = EINVAL; + return -1; + } +} + +/* + * Compare two capability sets + */ +int cap_compare(cap_t a, cap_t b) +{ + unsigned i; + int result; + + if (!(good_cap_t(a) && good_cap_t(b))) { + _cap_debug("invalid arguments"); + errno = EINVAL; + 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]) + ? LIBCAP_EFF : 0) + | ((a->u[i].flat[CAP_INHERITABLE] != b->u[i].flat[CAP_INHERITABLE]) + ? LIBCAP_INH : 0) + | ((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. + */ +int cap_iab_set_vector(cap_iab_t iab, cap_iab_vector_t vec, cap_value_t bit, + cap_flag_value_t raised) +{ + if (!good_cap_iab_t(iab) || (raised >> 1) || bit >= cap_max_bits()) { + errno = EINVAL; + return -1; + } + + unsigned o = (bit >> 5); + __u32 on = 1u << (bit & 31); + __u32 mask = ~on; + + _cap_mu_lock(&iab->mutex); + switch (vec) { + case CAP_IAB_INH: + iab->i[o] = (iab->i[o] & mask) | (raised ? on : 0); + iab->a[o] &= iab->i[o]; + break; + case CAP_IAB_AMB: + iab->a[o] = (iab->a[o] & mask) | (raised ? on : 0); + iab->i[o] |= iab->a[o]; + break; + case CAP_IAB_BOUND: + iab->nb[o] = (iab->nb[o] & mask) | (raised ? on : 0); + break; + default: + errno = EINVAL; + _cap_mu_unlock_return(&iab->mutex, -1); + } + + _cap_mu_unlock(&iab->mutex); + return 0; +} + +/* + * cap_iab_fill copies a bit-vector of capability state from a cap_t + * to a cap_iab_t. Note, because the bounding bits in an iab are to be + * dropped when applied, the copying process, when to a CAP_IAB_BOUND + * vector involves inverting the bits. Also, adjusting I will mask + * bits in A, and adjusting A may implicitly raise bits in I. + */ +int cap_iab_fill(cap_iab_t iab, cap_iab_vector_t vec, + cap_t cap_d, cap_flag_t flag) +{ + int i, ret = 0; + + if (!good_cap_t(cap_d) || !good_cap_iab_t(iab)) { + errno = EINVAL; + return -1; + } + + switch (flag) { + case CAP_EFFECTIVE: + case CAP_INHERITABLE: + case CAP_PERMITTED: + break; + default: + errno = EINVAL; + return -1; + } + + /* + * Make a private copy so we don't need to hold two locks at once + * avoiding a recipe for a deadlock. + */ + cap_d = cap_dup(cap_d); + if (cap_d == NULL) { + return -1; + } + + _cap_mu_lock(&iab->mutex); + for (i = 0; !ret && i < _LIBCAP_CAPABILITY_U32S; i++) { + switch (vec) { + case CAP_IAB_INH: + iab->i[i] = cap_d->u[i].flat[flag]; + iab->a[i] &= iab->i[i]; + break; + case CAP_IAB_AMB: + iab->a[i] = cap_d->u[i].flat[flag]; + iab->i[i] |= cap_d->u[i].flat[flag]; + break; + case CAP_IAB_BOUND: + iab->nb[i] = ~cap_d->u[i].flat[flag]; + break; + default: + errno = EINVAL; + ret = -1; + break; + } + } + _cap_mu_unlock(&iab->mutex); + + cap_free(cap_d); + return ret; +} + +/* + * cap_iab_compare compares two iab tuples. + */ +int cap_iab_compare(cap_iab_t a, cap_iab_t b) +{ + int j, result; + if (!(good_cap_iab_t(a) && good_cap_iab_t(b))) { + _cap_debug("invalid arguments"); + errno = EINVAL; + return -1; + } + b = cap_iab_dup(b); + if (b == NULL) { + return -1; + } + + _cap_mu_lock(&a->mutex); + for (j=0, result=0; j<_LIBCAP_CAPABILITY_U32S; j++) { + result |= + (a->i[j] == b->i[j] ? 0 : (1 << CAP_IAB_INH)) | + (a->a[j] == b->a[j] ? 0 : (1 << CAP_IAB_AMB)) | + (a->nb[j] == b->nb[j] ? 0 : (1 << CAP_IAB_BOUND)); + } + _cap_mu_unlock(&a->mutex); + cap_free(b); + + return result; +} diff --git a/depends/libcap/libcap/cap_names.header b/depends/libcap/libcap/cap_names.header new file mode 100644 index 0000000..8d64f64 --- /dev/null +++ b/depends/libcap/libcap/cap_names.header @@ -0,0 +1,5 @@ +struct __cap_token_s { const char *name; int index; }; +%{ +const struct __cap_token_s *__cap_lookup_name(const char *, size_t); +%} +%% diff --git a/depends/libcap/libcap/cap_proc.c b/depends/libcap/libcap/cap_proc.c new file mode 100644 index 0000000..24bc274 --- /dev/null +++ b/depends/libcap/libcap/cap_proc.c @@ -0,0 +1,1122 @@ +/* + * 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/securebits.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "libcap.h" + +/* + * libcap uses this abstraction for all system calls that change + * kernel managed capability state. This permits the user to redirect + * it for testing and also to better implement posix semantics when + * using pthreads. + */ + +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); +} + +static long int _cap_syscall6(long int syscall_nr, + long int arg1, long int arg2, long int arg3, + long int arg4, long int arg5, long int arg6) +{ + return syscall(syscall_nr, arg1, arg2, arg3, arg4, arg5, arg6); +} + +/* + * 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. + */ +static int _libcap_overrode_syscalls = 1; + +/* + * 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. + * As can be seen here this present function is mostly a + * 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. + */ +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)); + +__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; +} + +/* + * cap_set_syscall overrides the state setting syscalls that libcap does. + * Generally, you don't need to call this manually: libcap tries hard to + * set things up appropriately. + */ +void cap_set_syscall(long int (*new_syscall)(long int, + long int, long int, long int), + long int (*new_syscall6)(long int, long int, + long int, long int, + long int, long int, + long int)) { + if (new_syscall == NULL) { + psx_load_syscalls(&multithread.three, &multithread.six); + } else { + multithread.three = new_syscall; + multithread.six = new_syscall6; + } +} + +static int _libcap_capset(struct syscaller_s *sc, + cap_user_header_t header, const cap_user_data_t data) +{ + if (_libcap_overrode_syscalls) { + return sc->three(SYS_capset, (long int) header, (long int) data, 0); + } + return capset(header, data); +} + +static int _libcap_wprctl3(struct syscaller_s *sc, + long int pr_cmd, long int arg1, long int arg2) +{ + if (_libcap_overrode_syscalls) { + int result; + result = sc->three(SYS_prctl, pr_cmd, arg1, arg2); + if (result >= 0) { + return result; + } + errno = -result; + return -1; + } + return prctl(pr_cmd, arg1, arg2, 0, 0, 0); +} + +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) { + int result; + result = sc->six(SYS_prctl, pr_cmd, arg1, arg2, arg3, arg4, arg5); + if (result >= 0) { + return result; + } + errno = -result; + return -1; + } + return prctl(pr_cmd, arg1, arg2, arg3, arg4, arg5); +} + +/* + * cap_get_proc obtains the capability set for the current process. + */ +cap_t cap_get_proc(void) +{ + cap_t result; + + /* allocate a new capability set */ + result = cap_init(); + if (result) { + _cap_debug("getting current process' capabilities"); + + /* fill the capability sets via a system call */ + if (capget(&result->head, &result->u[0].set)) { + cap_free(result); + result = NULL; + } + } + + return result; +} + +static int _cap_set_proc(struct syscaller_s *sc, cap_t cap_d) { + int retval; + + if (!good_cap_t(cap_d)) { + errno = EINVAL; + return -1; + } + + _cap_debug("setting process capabilities"); + _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 */ + +int capgetp(pid_t pid, cap_t cap_d) +{ + int error; + + if (!good_cap_t(cap_d)) { + errno = EINVAL; + return -1; + } + + _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); + + return error; +} + +/* allocate space for and return capabilities of target process */ + +cap_t cap_get_pid(pid_t pid) +{ + cap_t result; + + result = cap_init(); + if (result) { + if (capgetp(pid, result) != 0) { + int my_errno; + + my_errno = errno; + cap_free(result); + errno = my_errno; + result = NULL; + } + } + + return result; +} + +/* + * set the caps on a specific process/pg etc.. The kernel has long + * since deprecated this asynchronous interface. DON'T EXPECT THIS TO + * EVER WORK AGAIN. + */ + +int capsetp(pid_t pid, cap_t cap_d) +{ + int error; + + if (!good_cap_t(cap_d)) { + errno = EINVAL; + return -1; + } + + _cap_debug("setting process capabilities for proc %d", pid); + _cap_mu_lock(&cap_d->mutex); + cap_d->head.pid = pid; + error = capset(&cap_d->head, &cap_d->u[0].set); + cap_d->head.version = _LIBCAP_CAPABILITY_VERSION; + cap_d->head.pid = 0; + _cap_mu_unlock(&cap_d->mutex); + + return error; +} + +/* the kernel api requires unsigned long arguments */ +#define pr_arg(x) ((unsigned long) x) + +/* get a capability from the bounding set */ + +int cap_get_bound(cap_value_t cap) +{ + return prctl(PR_CAPBSET_READ, pr_arg(cap), pr_arg(0)); +} + +static int _cap_drop_bound(struct syscaller_s *sc, cap_value_t cap) +{ + return _libcap_wprctl3(sc, PR_CAPBSET_DROP, pr_arg(cap), pr_arg(0)); +} + +/* drop a capability from the bounding set */ + +int cap_drop_bound(cap_value_t cap) { + return _cap_drop_bound(&multithread, cap); +} + +/* get a capability from the ambient set */ + +int cap_get_ambient(cap_value_t cap) +{ + int result; + result = prctl(PR_CAP_AMBIENT, pr_arg(PR_CAP_AMBIENT_IS_SET), + pr_arg(cap), pr_arg(0), pr_arg(0)); + if (result < 0) { + errno = -result; + return -1; + } + return result; +} + +static int _cap_set_ambient(struct syscaller_s *sc, + cap_value_t cap, cap_flag_value_t set) +{ + int val; + switch (set) { + case CAP_SET: + val = PR_CAP_AMBIENT_RAISE; + break; + case CAP_CLEAR: + val = PR_CAP_AMBIENT_LOWER; + break; + default: + errno = EINVAL; + return -1; + } + return _libcap_wprctl6(sc, PR_CAP_AMBIENT, pr_arg(val), pr_arg(cap), + pr_arg(0), pr_arg(0), pr_arg(0)); +} + +/* + * cap_set_ambient modifies a single ambient capability value. + */ +int cap_set_ambient(cap_value_t cap, cap_flag_value_t set) +{ + return _cap_set_ambient(&multithread, cap, set); +} + +static int _cap_reset_ambient(struct syscaller_s *sc) +{ + int olderrno = errno; + cap_value_t c; + int result = 0; + + for (c = 0; !result; c++) { + result = cap_get_ambient(c); + if (result == -1) { + errno = olderrno; + return 0; + } + } + + return _libcap_wprctl6(sc, PR_CAP_AMBIENT, + pr_arg(PR_CAP_AMBIENT_CLEAR_ALL), + pr_arg(0), pr_arg(0), pr_arg(0), pr_arg(0)); +} + +/* + * cap_reset_ambient erases all ambient capabilities - this reads the + * ambient caps before performing the erase to workaround the corner + * case where the set is empty already but the ambient cap API is + * locked. + */ +int cap_reset_ambient(void) +{ + return _cap_reset_ambient(&multithread); +} + +/* + * Read the security mode of the current process. + */ +unsigned cap_get_secbits(void) +{ + return (unsigned) prctl(PR_GET_SECUREBITS, pr_arg(0), pr_arg(0)); +} + +static int _cap_set_secbits(struct syscaller_s *sc, unsigned bits) +{ + return _libcap_wprctl3(sc, PR_SET_SECUREBITS, bits, 0); +} + +/* + * Set the secbits of the current process. + */ +int cap_set_secbits(unsigned bits) +{ + return _cap_set_secbits(&multithread, bits); +} + +/* + * Attempt to raise the no new privs prctl value. + */ +static void _cap_set_no_new_privs(struct syscaller_s *sc) +{ + (void) _libcap_wprctl6(sc, PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0); +} + +/* + * cap_prctl performs a prctl() 6 argument call on the current + * thread. Use cap_prctlw() if you want to perform a POSIX semantics + * prctl() system call. + */ +int cap_prctl(long int pr_cmd, long int arg1, long int arg2, + long int arg3, long int arg4, long int arg5) +{ + return prctl(pr_cmd, arg1, arg2, arg3, arg4, arg5); +} + +/* + * cap_prctlw performs a POSIX semantics prctl() call. That is a 6 arg + * prctl() call that executes on all available threads when libpsx is + * linked. The suffix 'w' refers to the fact one only ever needs to + * invoke this is if the call will write some kernel state. + */ +int cap_prctlw(long int pr_cmd, long int arg1, long int arg2, + long int arg3, long int arg4, long int arg5) +{ + return _libcap_wprctl6(&multithread, pr_cmd, arg1, arg2, arg3, arg4, arg5); +} + +/* + * Some predefined constants + */ +#define CAP_SECURED_BITS_BASIC \ + (SECBIT_NOROOT | SECBIT_NOROOT_LOCKED | \ + SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED | \ + SECBIT_KEEP_CAPS_LOCKED) + +#define CAP_SECURED_BITS_AMBIENT (CAP_SECURED_BITS_BASIC | \ + SECBIT_NO_CAP_AMBIENT_RAISE | SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED) + +static cap_value_t raise_cap_setpcap[] = {CAP_SETPCAP}; + +static int _cap_set_mode(struct syscaller_s *sc, cap_mode_t flavor) +{ + int ret; + unsigned secbits = CAP_SECURED_BITS_AMBIENT; + cap_t working = cap_get_proc(); + + if (working == NULL) { + _cap_debug("getting current process' capabilities failed"); + return -1; + } + + ret = cap_set_flag(working, CAP_EFFECTIVE, 1, raise_cap_setpcap, CAP_SET) | + _cap_set_proc(sc, working); + if (ret == 0) { + cap_flag_t c; + + switch (flavor) { + case CAP_MODE_NOPRIV: + /* fall through */ + case CAP_MODE_PURE1E_INIT: + (void) cap_clear_flag(working, CAP_INHERITABLE); + /* fall through */ + case CAP_MODE_PURE1E: + if (!CAP_AMBIENT_SUPPORTED()) { + secbits = CAP_SECURED_BITS_BASIC; + } else { + ret = _cap_reset_ambient(sc); + if (ret) { + break; /* ambient dropping failed */ + } + } + ret = _cap_set_secbits(sc, secbits); + if (flavor != CAP_MODE_NOPRIV) { + break; + } + + /* just for "case CAP_MODE_NOPRIV:" */ + + for (c = 0; cap_get_bound(c) >= 0; c++) { + (void) _cap_drop_bound(sc, c); + } + (void) cap_clear_flag(working, CAP_PERMITTED); + + /* for good measure */ + _cap_set_no_new_privs(sc); + break; + case CAP_MODE_HYBRID: + ret = _cap_set_secbits(sc, 0); + break; + default: + errno = EINVAL; + ret = -1; + break; + } + } + + (void) cap_clear_flag(working, CAP_EFFECTIVE); + ret = _cap_set_proc(sc, working) | ret; + (void) cap_free(working); + return ret; +} + +/* + * cap_set_mode locks the overarching capability framework of the + * present process and thus its children to a predefined flavor. Once + * set, these modes cannot be undone by the affected process tree and + * can only be done by "cap_setpcap" permitted processes. Note, a side + * effect of this function, whether it succeeds or fails, is to clear + * at least the CAP_EFFECTIVE flags for the current process. + */ +int cap_set_mode(cap_mode_t flavor) +{ + return _cap_set_mode(&multithread, flavor); +} + +/* + * cap_get_mode attempts to determine what the current capability mode + * is. If it can find no match in the libcap pre-defined modes, it + * returns CAP_MODE_UNCERTAIN. + */ +cap_mode_t cap_get_mode(void) +{ + unsigned secbits = cap_get_secbits(); + + if (secbits == 0) { + return CAP_MODE_HYBRID; + } + if ((secbits & CAP_SECURED_BITS_BASIC) != CAP_SECURED_BITS_BASIC) { + return CAP_MODE_UNCERTAIN; + } + + /* validate ambient is not set */ + int olderrno = errno; + int ret = 0, cf; + cap_value_t c; + for (c = 0; !ret; c++) { + ret = cap_get_ambient(c); + if (ret == -1) { + errno = olderrno; + if (c && secbits != CAP_SECURED_BITS_AMBIENT) { + return CAP_MODE_UNCERTAIN; + } + ret = 0; + break; + } + if (ret) { + return CAP_MODE_UNCERTAIN; + } + } + + /* + * Explore how capabilities differ from empty. + */ + cap_t working = cap_get_proc(); + cap_t empty = cap_init(); + if (working == NULL || empty == NULL) { + _cap_debug("working=%p, empty=%p - need both non-NULL", working, empty); + ret = -1; + } else { + cf = cap_compare(empty, working); + } + cap_free(empty); + cap_free(working); + if (ret != 0) { + return CAP_MODE_UNCERTAIN; + } + + if (CAP_DIFFERS(cf, CAP_INHERITABLE)) { + return CAP_MODE_PURE1E; + } + if (CAP_DIFFERS(cf, CAP_PERMITTED) || CAP_DIFFERS(cf, CAP_EFFECTIVE)) { + return CAP_MODE_PURE1E_INIT; + } + + for (c = 0; ; c++) { + int v = cap_get_bound(c); + if (v == -1) { + break; + } + if (v) { + return CAP_MODE_PURE1E_INIT; + } + } + + return CAP_MODE_NOPRIV; +} + +static int _cap_setuid(struct syscaller_s *sc, uid_t uid) +{ + const cap_value_t raise_cap_setuid[] = {CAP_SETUID}; + cap_t working = cap_get_proc(); + if (working == NULL) { + return -1; + } + + (void) cap_set_flag(working, CAP_EFFECTIVE, + 1, raise_cap_setuid, CAP_SET); + /* + * Note, we are cognizant of not using glibc's setuid in the case + * that we've modified the way libcap is doing setting + * syscalls. This is because prctl needs to be working in a POSIX + * compliant way for the code below to work, so we are either + * all-broken or not-broken and don't allow for "sort of working". + */ + (void) _libcap_wprctl3(sc, PR_SET_KEEPCAPS, 1, 0); + int ret = _cap_set_proc(sc, working); + if (ret == 0) { + if (_libcap_overrode_syscalls) { + ret = sc->three(SYS_setuid, (long int) uid, 0, 0); + if (ret < 0) { + errno = -ret; + ret = -1; + } + } else { + ret = setuid(uid); + } + } + int olderrno = errno; + (void) _libcap_wprctl3(sc, PR_SET_KEEPCAPS, 0, 0); + (void) cap_clear_flag(working, CAP_EFFECTIVE); + (void) _cap_set_proc(sc, working); + (void) cap_free(working); + + errno = olderrno; + return ret; +} + +/* + * cap_setuid attempts to set the uid of the process without dropping + * any permitted capabilities in the process. A side effect of a call + * to this function is that the effective set will be cleared by the + * time the function returns. + */ +int cap_setuid(uid_t uid) +{ + return _cap_setuid(&multithread, uid); +} + +#if defined(__arm__) || defined(__i386__) || \ + defined(__i486__) || defined(__i586__) || defined(__i686__) +#define sys_setgroups_variant SYS_setgroups32 +#else +#define sys_setgroups_variant SYS_setgroups +#endif + +static int _cap_setgroups(struct syscaller_s *sc, + gid_t gid, size_t ngroups, const gid_t groups[]) +{ + const cap_value_t raise_cap_setgid[] = {CAP_SETGID}; + cap_t working = cap_get_proc(); + if (working == NULL) { + return -1; + } + + (void) cap_set_flag(working, CAP_EFFECTIVE, + 1, raise_cap_setgid, CAP_SET); + /* + * Note, we are cognizant of not using glibc's setgid etc in the + * case that we've modified the way libcap is doing setting + * syscalls. This is because prctl needs to be working in a POSIX + * compliant way for the other functions of this file so we are + * all-broken or not-broken and don't allow for "sort of working". + */ + int ret = _cap_set_proc(sc, working); + if (_libcap_overrode_syscalls) { + if (ret == 0) { + ret = sc->three(SYS_setgid, (long int) gid, 0, 0); + } + if (ret == 0) { + ret = sc->three(sys_setgroups_variant, (long int) ngroups, + (long int) groups, 0); + } + if (ret < 0) { + errno = -ret; + ret = -1; + } + } else { + if (ret == 0) { + ret = setgid(gid); + } + if (ret == 0) { + ret = setgroups(ngroups, groups); + } + } + int olderrno = errno; + + (void) cap_clear_flag(working, CAP_EFFECTIVE); + (void) _cap_set_proc(sc, working); + (void) cap_free(working); + + errno = olderrno; + return ret; +} + +/* + * cap_setgroups combines setting the gid with changing the set of + * supplemental groups for a user into one call that raises the needed + * capabilities to do it for the duration of the call. A side effect + * of a call to this function is that the effective set will be + * cleared by the time the function returns. + */ +int cap_setgroups(gid_t gid, size_t ngroups, const gid_t groups[]) +{ + return _cap_setgroups(&multithread, gid, ngroups, groups); +} + +/* + * cap_iab_get_proc returns a cap_iab_t value initialized by the + * current process state related to these iab bits. + */ +cap_iab_t cap_iab_get_proc(void) +{ + cap_iab_t iab; + cap_t current; + + iab = cap_iab_init(); + if (iab == NULL) { + _cap_debug("no memory for IAB tuple"); + return NULL; + } + + current = cap_get_proc(); + if (current == NULL) { + _cap_debug("no memory for cap_t"); + cap_free(iab); + return NULL; + } + + cap_iab_fill(iab, CAP_IAB_INH, current, CAP_INHERITABLE); + cap_free(current); + + cap_value_t c; + for (c = cap_max_bits(); c; ) { + --c; + int o = c >> 5; + __u32 mask = 1U << (c & 31); + if (cap_get_bound(c) == 0) { + iab->nb[o] |= mask; + } + if (cap_get_ambient(c) == 1) { + iab->a[o] |= mask; + } + } + return iab; +} + +/* + * _cap_iab_set_proc sets the iab collection using the requested syscaller. + * The iab value is locked by the caller. + */ +static int _cap_iab_set_proc(struct syscaller_s *sc, cap_iab_t iab) +{ + int ret, i, raising = 0; + cap_value_t c; + cap_t working, temp = cap_get_proc(); + + if (temp == NULL) { + return -1; + } + + for (i = 0; i < _LIBCAP_CAPABILITY_U32S; i++) { + __u32 newI = iab->i[i]; + __u32 oldIP = temp->u[i].flat[CAP_INHERITABLE] | + temp->u[i].flat[CAP_PERMITTED]; + raising |= (newI & ~oldIP) | iab->a[i] | iab->nb[i]; + temp->u[i].flat[CAP_INHERITABLE] = newI; + + } + + working = cap_dup(temp); + if (working == NULL) { + ret = -1; + goto defer; + } + if (raising) { + ret = cap_set_flag(working, CAP_EFFECTIVE, + 1, raise_cap_setpcap, CAP_SET); + if (ret) { + goto defer; + } + } + if ((ret = _cap_set_proc(sc, working))) { + goto defer; + } + if ((ret = _cap_reset_ambient(sc))) { + goto done; + } + + for (c = cap_max_bits(); c-- != 0; ) { + unsigned offset = c >> 5; + __u32 mask = 1U << (c & 31); + if (iab->a[offset] & mask) { + ret = _cap_set_ambient(sc, c, CAP_SET); + if (ret) { + goto done; + } + } + if (iab->nb[offset] & mask) { + /* drop the bounding bit */ + ret = _cap_drop_bound(sc, c); + if (ret) { + goto done; + } + } + } + +done: + (void) cap_set_proc(temp); + +defer: + cap_free(working); + cap_free(temp); + + return ret; +} + +/* + * cap_iab_set_proc sets the iab capability vectors of the current + * process. + */ +int cap_iab_set_proc(cap_iab_t iab) +{ + int retval; + if (!good_cap_iab_t(iab)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&iab->mutex); + retval = _cap_iab_set_proc(&multithread, iab); + _cap_mu_unlock(&iab->mutex); + return retval; +} + +/* + * cap_launcher_callback primes the launcher with a callback that will + * be invoked after the fork() but before any privilege has changed + * and before the execve(). This can be used to augment the state of + * the child process within the cap_launch() process. You can cancel + * any callback associated with a launcher by calling this function + * with a callback_fn value NULL. + * + * If the callback function returns anything other than 0, it is + * considered to have failed and the launch will be aborted - further, + * errno will be communicated to the parent. + */ +int cap_launcher_callback(cap_launch_t attr, int (callback_fn)(void *detail)) +{ + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&attr->mutex); + attr->custom_setup_fn = callback_fn; + _cap_mu_unlock(&attr->mutex); + return 0; +} + +/* + * cap_launcher_setuid primes the launcher to attempt a change of uid. + */ +int cap_launcher_setuid(cap_launch_t attr, uid_t uid) +{ + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&attr->mutex); + attr->uid = uid; + attr->change_uids = 1; + _cap_mu_unlock(&attr->mutex); + return 0; +} + +/* + * cap_launcher_setgroups primes the launcher to attempt a change of + * gid and groups. + */ +int cap_launcher_setgroups(cap_launch_t attr, gid_t gid, + int ngroups, const gid_t *groups) +{ + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&attr->mutex); + attr->gid = gid; + attr->ngroups = ngroups; + attr->groups = groups; + attr->change_gids = 1; + _cap_mu_unlock(&attr->mutex); + return 0; +} + +/* + * cap_launcher_set_mode primes the launcher to attempt a change of + * mode. + */ +int cap_launcher_set_mode(cap_launch_t attr, cap_mode_t flavor) +{ + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&attr->mutex); + attr->mode = flavor; + attr->change_mode = 1; + _cap_mu_unlock(&attr->mutex); + return 0; +} + +/* + * cap_launcher_set_iab primes the launcher to attempt to change the + * IAB values of the launched child. The launcher locks iab while it + * is owned by the launcher: this prevents the user from + * asynchronously changing its value while it is associated with the + * launcher. + */ +cap_iab_t cap_launcher_set_iab(cap_launch_t attr, cap_iab_t iab) +{ + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return NULL; + } + _cap_mu_lock(&attr->mutex); + cap_iab_t old = attr->iab; + attr->iab = iab; + if (old != NULL) { + _cap_mu_unlock(&old->mutex); + } + if (iab != NULL) { + _cap_mu_lock(&iab->mutex); + } + _cap_mu_unlock(&attr->mutex); + return old; +} + +/* + * cap_launcher_set_chroot sets the intended chroot for the launched + * child. + */ +int cap_launcher_set_chroot(cap_launch_t attr, const char *chroot) +{ + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&attr->mutex); + attr->chroot = _libcap_strdup(chroot); + _cap_mu_unlock(&attr->mutex); + return 0; +} + +static int _cap_chroot(struct syscaller_s *sc, const char *root) +{ + const cap_value_t raise_cap_sys_chroot[] = {CAP_SYS_CHROOT}; + cap_t working = cap_get_proc(); + if (working == NULL) { + return -1; + } + + (void) cap_set_flag(working, CAP_EFFECTIVE, + 1, raise_cap_sys_chroot, CAP_SET); + int ret = _cap_set_proc(sc, working); + if (ret == 0) { + if (_libcap_overrode_syscalls) { + ret = sc->three(SYS_chroot, (long int) root, 0, 0); + if (ret < 0) { + errno = -ret; + ret = -1; + } + } else { + ret = chroot(root); + } + if (ret == 0) { + ret = chdir("/"); + } + } + int olderrno = errno; + (void) cap_clear_flag(working, CAP_EFFECTIVE); + (void) _cap_set_proc(sc, working); + (void) cap_free(working); + + errno = olderrno; + return ret; +} + +/* + * _cap_launch is invoked in the forked child, it cannot return but is + * required to exit, if the execve fails. It will write the errno + * value for any failure over the filedescriptor, fd, and exit with + * status 1. + */ +__attribute__ ((noreturn)) +static void _cap_launch(int fd, cap_launch_t attr, void *detail) { + struct syscaller_s *sc = &singlethread; + int my_errno; + + if (attr->custom_setup_fn && attr->custom_setup_fn(detail)) { + goto defer; + } + if (attr->arg0 == NULL) { + /* handle the successful cap_func_launcher completion */ + exit(0); + } + + if (attr->change_uids && _cap_setuid(sc, attr->uid)) { + goto defer; + } + if (attr->change_gids && + _cap_setgroups(sc, attr->gid, attr->ngroups, attr->groups)) { + goto defer; + } + if (attr->change_mode && _cap_set_mode(sc, attr->mode)) { + goto defer; + } + if (attr->iab && _cap_iab_set_proc(sc, attr->iab)) { + goto defer; + } + if (attr->chroot != NULL && _cap_chroot(sc, attr->chroot)) { + goto defer; + } + + /* + * Some type wrangling to work around what the kernel API really + * means: not "const char **". + */ + const void *temp_args = attr->argv; + const void *temp_envp = attr->envp; + + execve(attr->arg0, temp_args, temp_envp); + /* if the exec worked, execution will not reach here */ + +defer: + /* + * getting here means an error has occurred and errno is + * communicated to the parent + */ + my_errno = errno; + for (;;) { + int n = write(fd, &my_errno, sizeof(my_errno)); + if (n < 0 && errno == EAGAIN) { + continue; + } + break; + } + close(fd); + exit(1); +} + +/* + * cap_launch performs a wrapped fork+(callback and/or exec) that + * works in both an unthreaded environment and also where libcap is + * linked with psx+pthreads. The function supports dropping privilege + * in the forked thread, but retaining privilege in the parent + * thread(s). + * + * When applying the IAB vector inside the fork, since the ambient set + * is fragile with respect to changes in I or P, the function + * carefully orders setting of these inheritable characteristics, to + * make sure they stick. + * + * This function will return an error of -1 setting errno if the + * launch failed. + */ +pid_t cap_launch(cap_launch_t attr, void *detail) { + int my_errno; + int ps[2]; + pid_t child; + + if (!good_cap_launch_t(attr)) { + errno = EINVAL; + return -1; + } + _cap_mu_lock(&attr->mutex); + + /* The launch must have a purpose */ + if (attr->custom_setup_fn == NULL && + (attr->arg0 == NULL || attr->argv == NULL)) { + errno = EINVAL; + _cap_mu_unlock_return(&attr->mutex, -1); + } + + if (pipe2(ps, O_CLOEXEC) != 0) { + _cap_mu_unlock_return(&attr->mutex, -1); + } + + child = fork(); + my_errno = errno; + + if (!child) { + close(ps[0]); + prctl(PR_SET_NAME, "cap-launcher", 0, 0, 0); + _cap_launch(ps[1], attr, detail); + /* no return from above function */ + } + + /* child has its own copy, and parent no longer needs it locked. */ + _cap_mu_unlock(&attr->mutex); + close(ps[1]); + if (child < 0) { + goto defer; + } + + /* + * Extend this function's return codes to include setup failures + * in the child. + */ + for (;;) { + int ignored; + int n = read(ps[0], &my_errno, sizeof(my_errno)); + if (n == 0) { + goto defer; + } + if (n < 0 && errno == EAGAIN) { + continue; + } + waitpid(child, &ignored, 0); + child = -1; + my_errno = ECHILD; + break; + } + +defer: + close(ps[0]); + errno = my_errno; + return child; +} diff --git a/depends/libcap/libcap/cap_test.c b/depends/libcap/libcap/cap_test.c new file mode 100644 index 0000000..68b6a13 --- /dev/null +++ b/depends/libcap/libcap/cap_test.c @@ -0,0 +1,299 @@ +#define _GNU_SOURCE +#include <stdio.h> + +#include "libcap.h" + +static cap_value_t top; + +static int cf(cap_value_t x) +{ + return top - x - 1; +} + +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 + }; + int failed = 0; + cap_value_t i; + for (i = 0; vs[i] >= 0; i++) { + cap_value_t ans; + + top = vs[i]; + _binary_search(ans, cf, 0, __CAP_MAXBITS, -1); + if (ans != top) { + 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", + (long int)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); + fflush(stdout); + retval = -1; + } + if (cap_free(old_root)) { + perror("unable to free old proc root"); + fflush(stderr); + retval = -1; + } + if (retval) { + goto drop_launcher; + } + old_root = cap_proc_root("/proc"); + if (strcmp(old_root, "blah") != 0) { + printf("bad proc_root value [%s]\n", old_root); + fflush(stdout); + retval = -1; + } + if (cap_free(old_root)) { + perror("unable to free replacement proc root"); + fflush(stderr); + retval = -1; + } + if (retval) { + goto drop_launcher; + } + +drop_launcher: + printf("test_alloc: drop_launcher\n"); + fflush(stdout); + if (cap_free(launcher)) { + perror("failed to free launcher"); + fflush(stderr); + retval = -1; + } + +drop_iab: + printf("test_alloc: drop_iab\n"); + fflush(stdout); + if (!cap_free(2+(__u32 *) iab)) { + printf("unable to recognize bad cap_iab_t pointer\n"); + fflush(stdout); + retval = -1; + } + if (cap_free(iab)) { + perror("failed to free iab"); + fflush(stderr); + retval = -1; + } + +drop_c: + printf("test_alloc: drop_cap\n"); + fflush(stdout); + if (!cap_free(1+(__u32 *) c)) { + printf("unable to recognize bad cap_t pointer\n"); + fflush(stdout); + retval = -1; + } + if (cap_free(c)) { + perror("failed to free c"); + fflush(stderr); + retval = -1; + } + return retval; +} + +static int test_prctl(void) +{ + int ret, retval=0; + errno = 0; + ret = cap_get_bound((cap_value_t) -1); + if (ret != -1) { + printf("cap_get_bound(-1) did not return error: %d\n", ret); + retval = -1; + } else if (errno != EINVAL) { + perror("cap_get_bound(-1) errno != EINVAL"); + retval = -1; + } + return retval; +} + +int main(int argc, char **argv) { + int result = 0; + + printf("test_cap_bits: being called\n"); + fflush(stdout); + result = test_cap_bits() | result; + printf("test_cap_flags: being called\n"); + fflush(stdout); + result = test_cap_flags() | result; + printf("test_short_bits: being called\n"); + fflush(stdout); + result = test_short_bits() | result; + printf("test_alloc: being called\n"); + fflush(stdout); + result = test_alloc() | result; + printf("test_prctl: being called\n"); + fflush(stdout); + result = test_prctl() | result; + printf("tested\n"); + fflush(stdout); + + if (result) { + printf("cap_test FAILED\n"); + exit(1); + } + printf("cap_test PASS\n"); + exit(0); +} diff --git a/depends/libcap/libcap/cap_text.c b/depends/libcap/libcap/cap_text.c new file mode 100644 index 0000000..7566bd8 --- /dev/null +++ b/depends/libcap/libcap/cap_text.c @@ -0,0 +1,770 @@ +/* + * 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> + +#ifdef INCLUDE_GPERF_OUTPUT +/* we need to include it after #define _GNU_SOURCE is set */ +#include INCLUDE_GPERF_OUTPUT +#endif + +/* Maximum output text length */ +#define CAP_TEXT_SIZE (__CAP_NAME_SIZE * __CAP_MAXBITS) + +/* + * Parse a textual representation of capabilities, returning an internal + * representation. + */ + +#define raise_cap_mask(flat, c) (flat)[CAP_TO_INDEX(c)] |= CAP_TO_MASK(c) + +static void setbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks) +{ + int n; + for (n = blks; n--; ) { + a->u[n].flat[set] |= b[n]; + } +} + +static void clrbits(cap_t a, const __u32 *b, cap_flag_t set, unsigned blks) +{ + int n; + for (n = blks; n--; ) + a->u[n].flat[set] &= ~b[n]; +} + +static char const *namcmp(char const *str, char const *nam) +{ + while (*nam && tolower((unsigned char)*str) == *nam) { + str++; + nam++; + } + if (*nam || isalnum((unsigned char)*str) || *str == '_') + return NULL; + return str; +} + +/* + * 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) +{ + unsigned n; + cap_value_t cmb = cap_max_bits(); + for (n = blks; n--; ) { + unsigned base = 32*n; + __u32 mask = 0; + if (cmb >= base + 32) { + mask = ~0; + } else if (cmb > base) { + mask = (unsigned) ((1ULL << (cmb % 32)) - 1); + } + flat[n] = value & mask; + } + + return; +} + +static int lookupname(char const **strp) +{ + union { + char const *constp; + char *p; + } str; + + str.constp = *strp; + if (isdigit(*str.constp)) { + unsigned long n = strtoul(str.constp, &str.p, 0); + if (n >= __CAP_MAXBITS) + return -1; + *strp = str.constp; + return n; + } else { + int c; + size_t len; + + for (len=0; (c = str.constp[len]); ++len) { + if (!(isalpha(c) || (c == '_'))) { + break; + } + } + +#ifdef GPERF_DOWNCASE + const struct __cap_token_s *token_info; + + token_info = __cap_lookup_name(str.constp, len); + if (token_info != NULL) { + *strp = str.constp + len; + return token_info->index; + } +#else /* ie., ndef GPERF_DOWNCASE */ + char const *s; + 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 */ + } +} + +cap_t cap_from_text(const char *str) +{ + cap_t res; + int n; + unsigned cap_blks; + + if (str == NULL) { + _cap_debug("bad argument"); + errno = EINVAL; + return NULL; + } + + if (!(res = cap_init())) + return NULL; + + switch (res->head.version) { + case _LINUX_CAPABILITY_VERSION_1: + cap_blks = _LINUX_CAPABILITY_U32S_1; + break; + case _LINUX_CAPABILITY_VERSION_2: + cap_blks = _LINUX_CAPABILITY_U32S_2; + break; + case _LINUX_CAPABILITY_VERSION_3: + cap_blks = _LINUX_CAPABILITY_U32S_3; + break; + default: + cap_free(res); + errno = EINVAL; + return NULL; + } + + _cap_debug("%s", str); + + for (;;) { + __u32 list[__CAP_BLKS]; + char op; + int flags = 0, listed=0; + + memset(list, 0, sizeof(__u32)*__CAP_BLKS); + + /* skip leading spaces */ + while (isspace((unsigned char)*str)) + str++; + if (!*str) { + _cap_debugcap("e = ", *res, CAP_EFFECTIVE); + _cap_debugcap("i = ", *res, CAP_INHERITABLE); + _cap_debugcap("p = ", *res, CAP_PERMITTED); + + return res; + } + + /* identify caps specified by this clause */ + if (isalnum((unsigned char)*str) || *str == '_') { + for (;;) { + if (namcmp(str, "all")) { + str += 3; + forceall(list, ~0, cap_blks); + } else { + n = lookupname(&str); + if (n == -1) + goto bad; + raise_cap_mask(list, n); + } + if (*str != ',') + break; + if (!isalnum((unsigned char)*++str) && *str != '_') + goto bad; + } + listed = 1; + } else if (*str == '+' || *str == '-') { + goto bad; /* require a list of capabilities */ + } else { + forceall(list, ~0, cap_blks); + } + + /* identify first operation on list of capabilities */ + op = *str++; + if (op == '=' && (*str == '+' || *str == '-')) { + if (!listed) + goto bad; + op = (*str++ == '+' ? 'P':'M'); /* skip '=' and take next op */ + } else if (op != '+' && op != '-' && op != '=') + goto bad; + + /* cycle through list of actions */ + do { + _cap_debug("next char = '%c'", *str); + if (*str && !isspace(*str)) { + switch (*str++) { /* Effective, Inheritable, Permitted */ + case 'e': + flags |= LIBCAP_EFF; + break; + case 'i': + flags |= LIBCAP_INH; + break; + case 'p': + flags |= LIBCAP_PER; + break; + default: + goto bad; + } + } else if (op != '=') { + _cap_debug("only '=' can be followed by space"); + goto bad; + } + + _cap_debug("how to read?"); + switch (op) { /* how do we interpret the caps? */ + case '=': + case 'P': /* =+ */ + case 'M': /* =- */ + clrbits(res, list, CAP_EFFECTIVE, cap_blks); + clrbits(res, list, CAP_PERMITTED, cap_blks); + clrbits(res, list, CAP_INHERITABLE, cap_blks); + if (op == 'M') + goto minus; + /* fall through */ + case '+': + if (flags & LIBCAP_EFF) + setbits(res, list, CAP_EFFECTIVE, cap_blks); + if (flags & LIBCAP_PER) + setbits(res, list, CAP_PERMITTED, cap_blks); + if (flags & LIBCAP_INH) + setbits(res, list, CAP_INHERITABLE, cap_blks); + break; + case '-': + minus: + if (flags & LIBCAP_EFF) + clrbits(res, list, CAP_EFFECTIVE, cap_blks); + if (flags & LIBCAP_PER) + clrbits(res, list, CAP_PERMITTED, cap_blks); + if (flags & LIBCAP_INH) + clrbits(res, list, CAP_INHERITABLE, cap_blks); + break; + } + + /* new directive? */ + if (*str == '+' || *str == '-') { + if (!listed) { + _cap_debug("for + & - must list capabilities"); + goto bad; + } + flags = 0; /* reset the flags */ + op = *str++; + if (!isalpha(*str)) + goto bad; + } + } while (*str && !isspace(*str)); + _cap_debug("next clause"); + } + +bad: + cap_free(res); + res = NULL; + errno = EINVAL; + return res; +} + +/* + * lookup a capability name and return its numerical value + */ +int cap_from_name(const char *name, cap_value_t *value_p) +{ + int n; + + if (((n = lookupname(&name)) >= 0) && (value_p != NULL)) { + *value_p = (unsigned) n; + } + return -(n < 0); +} + +/* + * Convert a single capability index number into a string representation + */ +char *cap_to_name(cap_value_t cap) +{ + char *tmp, *result; + + 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; +} + +/* + * Convert an internal representation to a textual one. The textual + * representation is stored in static memory. It will be overwritten + * on the next occasion that this function is called. + */ + +static int getstateflags(cap_t caps, int capno) +{ + int f = 0; + + if (isset_cap(caps, capno, CAP_EFFECTIVE)) { + f |= LIBCAP_EFF; + } + if (isset_cap(caps, capno, CAP_PERMITTED)) { + f |= LIBCAP_PER; + } + if (isset_cap(caps, capno, CAP_INHERITABLE)) { + f |= LIBCAP_INH; + } + + 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, *base; + int histo[8]; + int m, t; + unsigned n; + + /* Check arguments */ + if (!good_cap_t(caps)) { + errno = EINVAL; + return NULL; + } + + _cap_debugcap("e = ", *caps, CAP_EFFECTIVE); + _cap_debugcap("i = ", *caps, CAP_INHERITABLE); + _cap_debugcap("p = ", *caps, CAP_PERMITTED); + + memset(histo, 0, sizeof(histo)); + + /* default prevailing state to the named bits */ + cap_value_t cmb = cap_max_bits(); + for (n = 0; n < cmb; n++) + histo[getstateflags(caps, n)]++; + + /* find which combination of capability sets shares the most bits + we bias to preferring non-set (m=0) with the >= 0 test. Failing + to do this causes strange things to happen with older systems + that don't know about bits 32+. */ + for (m=t=7; t--; ) + if (histo[t] >= histo[m]) + 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" : "", + (m & LIBCAP_PER) ? "p" : "" ) + buf; + + for (t = 8; t--; ) { + if (t == m || !histo[t]) { + continue; + } + *p++ = ' '; + 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; + return NULL; + } + p += sprintf(p, "%s,", this_cap_name); + cap_free(this_cap_name); + } + } + p--; + n = t & ~m; + if (n) { + 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" : ""); + } + n = ~t & m; + if (n) { + p += sprintf(p, "-%s%s%s", + (n & LIBCAP_EFF) ? "e" : "", + (n & LIBCAP_INH) ? "i" : "", + (n & LIBCAP_PER) ? "p" : ""); + } + if (p - buf > CAP_TEXT_SIZE) { + errno = ERANGE; + return NULL; + } + } + + /* capture remaining unnamed bits - which must all be +. */ + memset(histo, 0, sizeof(histo)); + for (n = cmb; n < __CAP_MAXBITS; n++) + histo[getstateflags(caps, n)]++; + + for (t = 8; t-- > 1; ) { + if (!histo[t]) { + continue; + } + *p++ = ' '; + 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; + return NULL; + } + p += sprintf(p, "%s,", this_cap_name); + cap_free(this_cap_name); + } + } + p--; + p += sprintf(p, "+%s%s%s", + (t & LIBCAP_EFF) ? "e" : "", + (t & LIBCAP_INH) ? "i" : "", + (t & LIBCAP_PER) ? "p" : ""); + if (p - buf > CAP_TEXT_SIZE) { + errno = ERANGE; + return NULL; + } + } + + _cap_debug("%s", base); + if (length_p) { + *length_p = p - base; + } + + return (_libcap_strdup(base)); +} + +/* + * cap_mode_name returns a text token naming the specified mode. + */ +const char *cap_mode_name(cap_mode_t flavor) { + switch (flavor) { + case CAP_MODE_NOPRIV: + return "NOPRIV"; + case CAP_MODE_PURE1E_INIT: + return "PURE1E_INIT"; + case CAP_MODE_PURE1E: + return "PURE1E"; + case CAP_MODE_UNCERTAIN: + return "UNCERTAIN"; + case CAP_MODE_HYBRID: + return "HYBRID"; + default: + return "UNKNOWN"; + } +} + +/* + * cap_iab_to_text serializes an iab into a canonical text + * representation. + */ +char *cap_iab_to_text(cap_iab_t iab) +{ + char buf[CAP_TEXT_SIZE+CAP_TEXT_BUFFER_ZONE]; + char *p = buf; + cap_value_t c, cmb = cap_max_bits(); + int first = 1; + + if (good_cap_iab_t(iab)) { + _cap_mu_lock(&iab->mutex); + for (c = 0; c < cmb; c++) { + int keep = 0; + int o = c >> 5; + __u32 bit = 1U << (c & 31); + __u32 ib = iab->i[o] & bit; + __u32 ab = iab->a[o] & bit; + __u32 nbb = iab->nb[o] & bit; + if (!(nbb | ab | ib)) { + continue; + } + if (!first) { + *p++ = ','; + } + if (nbb) { + *p++ = '!'; + keep = 1; + } + if (ab) { + *p++ = '^'; + keep = 1; + } else if (nbb && ib) { + *p++ = '%'; + } + if (keep || ib) { + if (c < __CAP_BITS) { + strcpy(p, _cap_names[c]); + } else { + sprintf(p, "%u", c); + } + p += strlen(p); + first = 0; + } + } + _cap_mu_unlock(&iab->mutex); + } + *p = '\0'; + return _libcap_strdup(buf); +} + +cap_iab_t cap_iab_from_text(const char *text) +{ + cap_iab_t iab = cap_iab_init(); + if (iab == NULL) { + return iab; + } + if (text != NULL) { + unsigned flags; + for (flags = 0; *text; text++) { + /* consume prefixes */ + switch (*text) { + case '!': + flags |= LIBCAP_IAB_NB_FLAG; + continue; + case '^': + flags |= LIBCAP_IAB_IA_FLAG; + continue; + case '%': + flags |= LIBCAP_IAB_I_FLAG; + continue; + default: + break; + } + if (!flags) { + flags = LIBCAP_IAB_I_FLAG; + } + + /* consume cap name */ + cap_value_t c = lookupname(&text); + if (c == -1) { + goto cleanup; + } + unsigned o = c >> 5; + __u32 mask = 1U << (c & 31); + if (flags & LIBCAP_IAB_I_FLAG) { + iab->i[o] |= mask; + } + if (flags & LIBCAP_IAB_A_FLAG) { + iab->a[o] |= mask; + } + if (flags & LIBCAP_IAB_NB_FLAG) { + iab->nb[o] |= mask; + } + + /* rest should be end or comma */ + if (*text == '\0') { + break; + } + if (*text != ',') { + goto cleanup; + } + flags = 0; + } + } + return iab; + +cleanup: + cap_free(iab); + errno = EINVAL; + return NULL; +} + +static __u32 _parse_hex32(const char *c) +{ + int i; + __u32 v = 0; + for (i=0; i < 8; i++, c++) { + v <<= 4; + if (*c == 0 || *c < '0') { + return 0; + } else if (*c <= '9') { + v += *c - '0'; + } else if (*c > 'f') { + return 0; + } else if (*c >= 'a') { + v += *c + 10 - 'a'; + } else if (*c < 'A') { + return 0; + } else if (*c <= 'F') { + v += *c + 10 - 'A'; + } else { + return 0; + } + } + return v; +} + +/* + * _parse_vec_string converts the hex dumps in /proc/<pid>/current into + * an array of u32s - masked as per the forceall() mask. + */ +static __u32 _parse_vec_string(__u32 *vals, const char *c, int invert) +{ + int i; + int words = strlen(c)/8; + if (words > _LIBCAP_CAPABILITY_U32S) { + return 0; + } + forceall(vals, ~0, words); + for (i = 0; i < words; i++) { + __u32 val = _parse_hex32(c+8*(words-1-i)); + if (invert) { + val = ~val; + } + vals[i] &= val; + } + return ~0; +} + +/* + * libcap believes this is the root of the mounted "/proc" + * filesystem. (NULL == "/proc".) + */ +static char *_cap_proc_dir; + +/* + * If the constructor is called (see cap_alloc.c) then we'll need the + * corresponding destructor. + */ +__attribute__((destructor (300))) static void _cleanup_libcap(void) +{ + if (_cap_proc_dir == NULL) { + return; + } + cap_free(_cap_proc_dir); + _cap_proc_dir = NULL; +} + +/* + * cap_proc_root reads and (optionally: when root != NULL) changes + * libcap's notion of where the "/proc" filesystem is mounted. It + * defaults to 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 + * memory for storing the replacement root, and it is this memory that + * is returned. So, when changing the value, the caller should + * cap_free(the-return-value) when done with it. + * + * A return value of NULL implies the default is in effect "/proc". + */ +char *cap_proc_root(const char *root) +{ + char *old = _cap_proc_dir; + if (root != NULL) { + _cap_proc_dir = _libcap_strdup(root); + } + return old; +} + +#define PROC_LINE_MAX (8 + 8*_LIBCAP_CAPABILITY_U32S + 100) +/* + * cap_iab_get_pid fills an IAB tuple from the content of + * /proc/<pid>/status. Linux doesn't support syscall access to the + * needed information, so we parse it out of that file. + */ +cap_iab_t cap_iab_get_pid(pid_t pid) +{ + cap_iab_t iab; + char *path; + FILE *file; + char line[PROC_LINE_MAX]; + const char *proc_root = _cap_proc_dir; + + if (proc_root == NULL) { + proc_root = "/proc"; + } + if (asprintf(&path, "%s/%d/status", proc_root, pid) <= 0) { + return NULL; + } + file = fopen(path, "r"); + free(path); + if (file == NULL) { + return NULL; + } + + iab = cap_iab_init(); + uint ok = 0; + if (iab != NULL) { + while (fgets(line, PROC_LINE_MAX-1, file) != NULL) { + if (strncmp("Cap", line, 3) != 0) { + continue; + } + if (strncmp("Inh:\t", line+3, 5) == 0) { + ok = (_parse_vec_string(iab->i, line+8, 0) & + LIBCAP_IAB_I_FLAG) | ok; + continue; + } + if (strncmp("Bnd:\t", line+3, 5) == 0) { + ok = (_parse_vec_string(iab->nb, line+8, 1) & + LIBCAP_IAB_NB_FLAG) | ok; + continue; + } + if (strncmp("Amb:\t", line+3, 5) == 0) { + ok = (_parse_vec_string(iab->a, line+8, 0) & + LIBCAP_IAB_A_FLAG) | ok; + continue; + } + } + } + if (ok != (LIBCAP_IAB_IA_FLAG | LIBCAP_IAB_NB_FLAG)) { + cap_free(iab); + iab = NULL; + } + fclose(file); + return iab; +} diff --git a/depends/libcap/libcap/empty.c b/depends/libcap/libcap/empty.c new file mode 100644 index 0000000..0314ff1 --- /dev/null +++ b/depends/libcap/libcap/empty.c @@ -0,0 +1 @@ +int main(int argc, char **argv) { return 0; } diff --git a/depends/libcap/libcap/execable.c b/depends/libcap/libcap/execable.c new file mode 100644 index 0000000..9f7062e --- /dev/null +++ b/depends/libcap/libcap/execable.c @@ -0,0 +1,64 @@ +#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); + } + } else { + return; + } + 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); + } +} diff --git a/depends/libcap/libcap/execable.h b/depends/libcap/libcap/execable.h new file mode 100644 index 0000000..7a2d247 --- /dev/null +++ b/depends/libcap/libcap/execable.h @@ -0,0 +1,112 @@ +/* + * 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**); \ +__attribute__((visibility ("hidden"))) \ +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 diff --git a/depends/libcap/libcap/include/sys/.gitignore b/depends/libcap/libcap/include/sys/.gitignore new file mode 100644 index 0000000..595fc39 --- /dev/null +++ b/depends/libcap/libcap/include/sys/.gitignore @@ -0,0 +1 @@ +psx_syscall.h diff --git a/depends/libcap/libcap/include/sys/capability.h b/depends/libcap/libcap/include/sys/capability.h new file mode 100644 index 0000000..2db9972 --- /dev/null +++ b/depends/libcap/libcap/include/sys/capability.h @@ -0,0 +1,255 @@ +/* + * <sys/capability.h> + * + * Copyright (C) 1997 Aleph One + * Copyright (C) 1997,8, 2008,19-22 Andrew G. Morgan <morgan@kernel.org> + * + * defunct POSIX.1e Standard: 25.2 Capabilities <sys/capability.h> + */ + +#ifndef _SYS_CAPABILITY_H +#define _SYS_CAPABILITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Provide a programmatic way to #ifdef around features. + */ +#define LIBCAP_MAJOR 2 +#define LIBCAP_MINOR 69 + +/* + * This file complements the kernel file by providing prototype + * information for the user library. + */ + +#include <sys/types.h> +#include <stdint.h> + +#ifndef __user +#define __user +#endif +#include <linux/capability.h> + +/* + * POSIX capability types + */ + +/* + * Opaque capability handle (defined internally by libcap) + * internal capability representation + */ +typedef struct _cap_struct *cap_t; + +/* "external" capability representation is a (void *) */ + +/* + * This is the type used to identify capabilities + */ + +typedef int cap_value_t; + +/* + * libcap initialized first unnamed capability of the running kernel. + * capsh includes a runtime test to flag when this is larger than + * what is known to libcap... Time for a new libcap release! + */ +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_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 + */ +typedef enum { + CAP_CLEAR=0, /* The flag is cleared/disabled */ + CAP_SET=1 /* The flag is set/enabled */ +} cap_flag_value_t; + +/* + * 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) +#define CAP_MODE_PURE1E_INIT ((cap_mode_t) 2) +#define CAP_MODE_PURE1E ((cap_mode_t) 3) +#define CAP_MODE_HYBRID ((cap_mode_t) 4) + +/* libcap/cap_alloc.c */ +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 *); +extern int cap_set_flag(cap_t, cap_flag_t, int, const cap_value_t *, + 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); +extern cap_t cap_get_file(const char *); +extern uid_t cap_get_nsowner(cap_t); +extern int cap_set_fd(int, cap_t); +extern int cap_set_file(const char *, cap_t); +extern int cap_set_nsowner(cap_t, uid_t); + +/* libcap/cap_proc.c */ +extern cap_t cap_get_proc(void); +extern cap_t cap_get_pid(pid_t); +extern int cap_set_proc(cap_t); + +extern int cap_get_bound(cap_value_t); +extern int cap_drop_bound(cap_value_t); +#define CAP_IS_SUPPORTED(cap) (cap_get_bound(cap) >= 0) + +extern int cap_get_ambient(cap_value_t); +extern int cap_set_ambient(cap_value_t, cap_flag_value_t); +extern int cap_reset_ambient(void); +#define CAP_AMBIENT_SUPPORTED() (cap_get_ambient(CAP_CHOWN) >= 0) + +/* libcap/cap_extint.c */ +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 *); +extern char * cap_to_text(cap_t, ssize_t *); +extern int cap_from_name(const char *, cap_value_t *); +extern char * cap_to_name(cap_value_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, + long int, long int, long int), + long int (*new_syscall6)(long int, + long int, long int, long int, + long int, long int, long int)); + +extern int cap_set_mode(cap_mode_t flavor); +extern cap_mode_t cap_get_mode(void); +extern const char *cap_mode_name(cap_mode_t flavor); + +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 + * cap_set_syscall() to redirect the system call function. + */ +extern int capget(cap_user_header_t header, cap_user_data_t data); +extern int capset(cap_user_header_t header, const cap_user_data_t data); + +/* deprecated - use cap_get_pid() */ +extern int capgetp(pid_t pid, cap_t cap_d); + +/* not valid with filesystem capability support - use cap_set_proc() */ +extern int capsetp(pid_t pid, cap_t cap_d); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_CAPABILITY_H */ diff --git a/depends/libcap/libcap/include/sys/securebits.h b/depends/libcap/libcap/include/sys/securebits.h new file mode 100644 index 0000000..14cf3c5 --- /dev/null +++ b/depends/libcap/libcap/include/sys/securebits.h @@ -0,0 +1,22 @@ +/* + * <sys/securebits.h> + * Copyright (C) 2010 Serge Hallyn <serue@us.ibm.com> + */ + +#ifndef _SYS_SECUREBITS_H +#define _SYS_SECUREBITS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __user +#define __user +#endif +#include <linux/securebits.h> + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_SECUREBITS_H */ diff --git a/depends/libcap/libcap/include/uapi/linux/capability.h b/depends/libcap/libcap/include/uapi/linux/capability.h new file mode 100644 index 0000000..56c9180 --- /dev/null +++ b/depends/libcap/libcap/include/uapi/linux/capability.h @@ -0,0 +1,427 @@ +/* + * This is <linux/capability.h> + * + * Andrew G. Morgan <morgan@kernel.org> + * Alexander Kjeldaas <astor@guardian.no> + * with help from Aleph1, Roland Buresund and Andrew Main. + * + * See here for the libcap library ("POSIX draft" compliance): + * + * https://git.kernel.org/pub/scm/libs/libcap/libcap.git/refs/ + * http://www.kernel.org/pub/linux/libs/security/linux-privs/ + */ + +#ifndef _UAPI_LINUX_CAPABILITY_H +#define _UAPI_LINUX_CAPABILITY_H + +#include <stdint.h> +#define __u32 uint32_t +#define __le32 __u32 + +/* User-level do most of the mapping between kernel and user + capabilities based on the version tag given by the kernel. The + kernel might be somewhat backwards compatible, but don't bet on + it. */ + +/* Note, cap_t, is defined by POSIX (draft) to be an "opaque" pointer to + a set of three capability sets. The transposition of 3*the + following structure to such a composite is better handled in a user + library since the draft standard requires the use of malloc/free + etc.. */ + +#define _LINUX_CAPABILITY_VERSION_1 0x19980330 +#define _LINUX_CAPABILITY_U32S_1 1 + +#define _LINUX_CAPABILITY_VERSION_2 0x20071026 /* deprecated - use v3 */ +#define _LINUX_CAPABILITY_U32S_2 2 + +#define _LINUX_CAPABILITY_VERSION_3 0x20080522 +#define _LINUX_CAPABILITY_U32S_3 2 + +typedef struct __user_cap_header_struct { + __u32 version; + int pid; +} *cap_user_header_t; + +typedef struct __user_cap_data_struct { + __u32 effective; + __u32 permitted; + __u32 inheritable; +} *cap_user_data_t; + + +#define VFS_CAP_REVISION_MASK 0xFF000000 +#define VFS_CAP_REVISION_SHIFT 24 +#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK +#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 + +#define VFS_CAP_REVISION_1 0x01000000 +#define VFS_CAP_U32_1 1 +#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1)) + +#define VFS_CAP_REVISION_2 0x02000000 +#define VFS_CAP_U32_2 2 +#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2)) + +#define VFS_CAP_REVISION_3 0x03000000 +#define VFS_CAP_U32_3 VFS_CAP_U32_2 +#define XATTR_CAPS_SZ_3 (sizeof(__le32)+XATTR_CAPS_SZ_2) + +/* + * Kernel capabilities default to v2. The v3 VFS caps are only used, + * at present, for namespace specific filesystem capabilities. + */ +#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 +#define VFS_CAP_U32 VFS_CAP_U32_2 +#define VFS_CAP_REVISION VFS_CAP_REVISION_2 + +#define _VFS_CAP_DATA_HEAD \ + __le32 magic_etc; /* Little endian */ \ + struct { \ + __le32 permitted; /* Little endian */ \ + __le32 inheritable; /* Little endian */ \ + } data[VFS_CAP_U32] + +struct vfs_cap_data { + _VFS_CAP_DATA_HEAD; +}; + +struct vfs_ns_cap_data { + _VFS_CAP_DATA_HEAD; + __le32 rootid; +}; + +#ifndef __KERNEL__ + +/* + * Backwardly compatible definition for source code - trapped in a + * 32-bit world. If you find you need this, please consider using + * libcap to untrap yourself... + */ +#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1 +#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1 + +#endif + + +/** + ** POSIX-draft defined capabilities. + **/ + +/* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this + overrides the restriction of changing file ownership and group + ownership. */ + +#define CAP_CHOWN 0 + +/* Override all DAC access, including ACL execute access if + [_POSIX_ACL] is defined. Excluding DAC access covered by + CAP_LINUX_IMMUTABLE. */ + +#define CAP_DAC_OVERRIDE 1 + +/* Overrides all DAC restrictions regarding read and search on files + and directories, including ACL restrictions if [_POSIX_ACL] is + defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */ + +#define CAP_DAC_READ_SEARCH 2 + +/* Overrides all restrictions about allowed operations on files, where + file owner ID must be equal to the user ID, except where CAP_FSETID + is applicable. It doesn't override MAC and DAC restrictions. */ + +#define CAP_FOWNER 3 + +/* Overrides the following restrictions that the effective user ID + shall match the file owner ID when setting the S_ISUID and S_ISGID + bits on that file; that the effective group ID (or one of the + supplementary group IDs) shall match the file owner ID when setting + the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are + cleared on successful return from chown(2) (not implemented). */ + +#define CAP_FSETID 4 + +/* Overrides the restriction that the real or effective user ID of a + process sending a signal must match the real or effective user ID + of the process receiving the signal. */ + +#define CAP_KILL 5 + +/* Allows setgid(2) manipulation */ +/* Allows setgroups(2) */ +/* Allows forged gids on socket credentials passing. */ + +#define CAP_SETGID 6 + +/* Allows set*uid(2) manipulation (including fsuid). */ +/* Allows forged pids on socket credentials passing. */ + +#define CAP_SETUID 7 + + +/** + ** Linux-specific capabilities + **/ + +/* Without VFS support for capabilities: + * Transfer any capability in your permitted set to any pid, + * remove any capability in your permitted set from any pid + * With VFS support for capabilities (neither of above, but) + * Add any capability from current's capability bounding set + * to the current process' inheritable set + * Allow taking bits out of capability bounding set + * Allow modification of the securebits for a process + */ + +#define CAP_SETPCAP 8 + +/* Allow modification of S_IMMUTABLE and S_APPEND file attributes */ + +#define CAP_LINUX_IMMUTABLE 9 + +/* Allows binding to TCP/UDP sockets below 1024 */ +/* Allows binding to ATM VCIs below 32 */ + +#define CAP_NET_BIND_SERVICE 10 + +/* Allow broadcasting, listen to multicast */ + +#define CAP_NET_BROADCAST 11 + +/* Allow interface configuration */ +/* Allow administration of IP firewall, masquerading and accounting */ +/* Allow setting debug option on sockets */ +/* Allow modification of routing tables */ +/* Allow setting arbitrary process / process group ownership on + sockets */ +/* Allow binding to any address for transparent proxying (also via NET_RAW) */ +/* Allow setting TOS (type of service) */ +/* Allow setting promiscuous mode */ +/* Allow clearing driver statistics */ +/* Allow multicasting */ +/* Allow read/write of device-specific registers */ +/* Allow activation of ATM control sockets */ + +#define CAP_NET_ADMIN 12 + +/* Allow use of RAW sockets */ +/* Allow use of PACKET sockets */ +/* Allow binding to any address for transparent proxying (also via NET_ADMIN) */ + +#define CAP_NET_RAW 13 + +/* Allow locking of shared memory segments */ +/* Allow mlock and mlockall (which doesn't really have anything to do + with IPC) */ + +#define CAP_IPC_LOCK 14 + +/* Override IPC ownership checks */ + +#define CAP_IPC_OWNER 15 + +/* Insert and remove kernel modules - modify kernel without limit */ +#define CAP_SYS_MODULE 16 + +/* Allow ioperm/iopl access */ +/* Allow sending USB messages to any device via /dev/bus/usb */ + +#define CAP_SYS_RAWIO 17 + +/* Allow use of chroot() */ + +#define CAP_SYS_CHROOT 18 + +/* Allow ptrace() of any process */ + +#define CAP_SYS_PTRACE 19 + +/* Allow configuration of process accounting */ + +#define CAP_SYS_PACCT 20 + +/* Allow configuration of the secure attention key */ +/* Allow administration of the random device */ +/* Allow examination and configuration of disk quotas */ +/* Allow setting the domainname */ +/* Allow setting the hostname */ +/* Allow calling bdflush() */ +/* Allow mount() and umount(), setting up new smb connection */ +/* Allow some autofs root ioctls */ +/* Allow nfsservctl */ +/* Allow VM86_REQUEST_IRQ */ +/* Allow to read/write pci config on alpha */ +/* Allow irix_prctl on mips (setstacksize) */ +/* Allow flushing all cache on m68k (sys_cacheflush) */ +/* Allow removing semaphores */ +/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores + and shared memory */ +/* Allow locking/unlocking of shared memory segment */ +/* Allow turning swap on/off */ +/* Allow forged pids on socket credentials passing */ +/* Allow setting readahead and flushing buffers on block devices */ +/* Allow setting geometry in floppy driver */ +/* Allow turning DMA on/off in xd driver */ +/* Allow administration of md devices (mostly the above, but some + extra ioctls) */ +/* Allow tuning the ide driver */ +/* Allow access to the nvram device */ +/* Allow administration of apm_bios, serial and bttv (TV) device */ +/* Allow manufacturer commands in isdn CAPI support driver */ +/* Allow reading non-standardized portions of pci configuration space */ +/* Allow DDI debug ioctl on sbpcd driver */ +/* Allow setting up serial ports */ +/* Allow sending raw qic-117 commands */ +/* Allow enabling/disabling tagged queuing on SCSI controllers and sending + arbitrary SCSI commands */ +/* Allow setting encryption key on loopback filesystem */ +/* Allow setting zone reclaim policy */ + +#define CAP_SYS_ADMIN 21 + +/* Allow use of reboot() */ + +#define CAP_SYS_BOOT 22 + +/* Allow raising priority and setting priority on other (different + UID) processes */ +/* Allow use of FIFO and round-robin (realtime) scheduling on own + processes and setting the scheduling algorithm used by another + process. */ +/* Allow setting cpu affinity on other processes */ + +#define CAP_SYS_NICE 23 + +/* Override resource limits. Set resource limits. */ +/* Override quota limits. */ +/* Override reserved space on ext2 filesystem */ +/* Modify data journaling mode on ext3 filesystem (uses journaling + resources) */ +/* NOTE: ext2 honors fsuid when checking for resource overrides, so + you can override using fsuid too */ +/* Override size restrictions on IPC message queues */ +/* Allow more than 64hz interrupts from the real-time clock */ +/* Override max number of consoles on console allocation */ +/* Override max number of keymaps */ + +#define CAP_SYS_RESOURCE 24 + +/* Allow manipulation of system clock */ +/* Allow irix_stime on mips */ +/* Allow setting the real-time clock */ + +#define CAP_SYS_TIME 25 + +/* Allow configuration of tty devices */ +/* Allow vhangup() of tty */ + +#define CAP_SYS_TTY_CONFIG 26 + +/* Allow the privileged aspects of mknod() */ + +#define CAP_MKNOD 27 + +/* Allow taking of leases on files */ + +#define CAP_LEASE 28 + +/* Allow writing the audit log via unicast netlink socket */ + +#define CAP_AUDIT_WRITE 29 + +/* Allow configuration of audit via unicast netlink socket */ + +#define CAP_AUDIT_CONTROL 30 + +/* Set capabilities on files. */ + +#define CAP_SETFCAP 31 + +/* Override MAC access. + The base kernel enforces no MAC policy. + An LSM may enforce a MAC policy, and if it does and it chooses + to implement capability based overrides of that policy, this is + the capability it should use to do so. */ + +#define CAP_MAC_OVERRIDE 32 + +/* Allow MAC configuration or state changes. + The base kernel requires no MAC configuration. + An LSM may enforce a MAC policy, and if it does and it chooses + to implement capability based checks on modifications to that + policy or the data required to maintain it, this is the + capability it should use to do so. */ + +#define CAP_MAC_ADMIN 33 + +/* Allow configuring the kernel's syslog (printk behaviour) */ + +#define CAP_SYSLOG 34 + +/* Allow triggering something that will wake the system */ + +#define CAP_WAKE_ALARM 35 + +/* Allow preventing system suspends */ + +#define CAP_BLOCK_SUSPEND 36 + +/* Allow reading the audit log via multicast netlink socket */ + +#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_CHECKPOINT_RESTORE + +#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) + +/* + * Bit location of each capability (used by user-space library and kernel) + */ + +#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */ +#define CAP_TO_MASK(x) (1u << ((x) & 31)) /* mask for indexed __u32 */ + +#endif /* _UAPI_LINUX_CAPABILITY_H */ diff --git a/depends/libcap/libcap/include/uapi/linux/prctl.h b/depends/libcap/libcap/include/uapi/linux/prctl.h new file mode 100644 index 0000000..1b6a009 --- /dev/null +++ b/depends/libcap/libcap/include/uapi/linux/prctl.h @@ -0,0 +1,200 @@ +#ifndef _LINUX_PRCTL_H +#define _LINUX_PRCTL_H + +#include <linux/types.h> + +/* Values to pass as first argument to prctl() */ + +#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ + +/* Get/set current->mm->dumpable */ +#define PR_GET_DUMPABLE 3 +#define PR_SET_DUMPABLE 4 + +/* Get/set unaligned access control bits (if meaningful) */ +#define PR_GET_UNALIGN 5 +#define PR_SET_UNALIGN 6 +# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */ +# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */ + +/* Get/set whether or not to drop capabilities on setuid() away from + * uid 0 (as per security/commoncap.c) */ +#define PR_GET_KEEPCAPS 7 +#define PR_SET_KEEPCAPS 8 + +/* Get/set floating-point emulation control bits (if meaningful) */ +#define PR_GET_FPEMU 9 +#define PR_SET_FPEMU 10 +# define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */ +# define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */ + +/* Get/set floating-point exception mode (if meaningful) */ +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +# define PR_FP_EXC_SW_ENABLE 0x80 /* Use FPEXC for FP exception enables */ +# define PR_FP_EXC_DIV 0x010000 /* floating point divide by zero */ +# define PR_FP_EXC_OVF 0x020000 /* floating point overflow */ +# define PR_FP_EXC_UND 0x040000 /* floating point underflow */ +# define PR_FP_EXC_RES 0x080000 /* floating point inexact result */ +# define PR_FP_EXC_INV 0x100000 /* floating point invalid operation */ +# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */ +# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */ +# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */ +# define PR_FP_EXC_PRECISE 3 /* precise exception mode */ + +/* Get/set whether we use statistical process timing or accurate timestamp + * based process timing */ +#define PR_GET_TIMING 13 +#define PR_SET_TIMING 14 +# define PR_TIMING_STATISTICAL 0 /* Normal, traditional, + statistical process timing */ +# define PR_TIMING_TIMESTAMP 1 /* Accurate timestamp based + process timing */ + +#define PR_SET_NAME 15 /* Set process name */ +#define PR_GET_NAME 16 /* Get process name */ + +/* Get/set process endian */ +#define PR_GET_ENDIAN 19 +#define PR_SET_ENDIAN 20 +# define PR_ENDIAN_BIG 0 +# define PR_ENDIAN_LITTLE 1 /* True little endian mode */ +# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ + +/* Get/set process seccomp mode */ +#define PR_GET_SECCOMP 21 +#define PR_SET_SECCOMP 22 + +/* Get/set the capability bounding set (as per security/commoncap.c) */ +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 + +/* Get/set the process' ability to use the timestamp counter instruction */ +#define PR_GET_TSC 25 +#define PR_SET_TSC 26 +# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ +# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ + +/* Get/set securebits (as per security/commoncap.c) */ +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 + +/* + * Get/set the timerslack as used by poll/select/nanosleep + * A value of 0 means "use default" + */ +#define PR_SET_TIMERSLACK 29 +#define PR_GET_TIMERSLACK 30 + +#define PR_TASK_PERF_EVENTS_DISABLE 31 +#define PR_TASK_PERF_EVENTS_ENABLE 32 + +/* + * Set early/late kill mode for hwpoison memory corruption. + * This influences when the process gets killed on a memory corruption. + */ +#define PR_MCE_KILL 33 +# define PR_MCE_KILL_CLEAR 0 +# define PR_MCE_KILL_SET 1 + +# define PR_MCE_KILL_LATE 0 +# define PR_MCE_KILL_EARLY 1 +# define PR_MCE_KILL_DEFAULT 2 + +#define PR_MCE_KILL_GET 34 + +/* + * Tune up process memory map specifics. + */ +#define PR_SET_MM 35 +# define PR_SET_MM_START_CODE 1 +# define PR_SET_MM_END_CODE 2 +# define PR_SET_MM_START_DATA 3 +# define PR_SET_MM_END_DATA 4 +# define PR_SET_MM_START_STACK 5 +# define PR_SET_MM_START_BRK 6 +# define PR_SET_MM_BRK 7 +# define PR_SET_MM_ARG_START 8 +# define PR_SET_MM_ARG_END 9 +# define PR_SET_MM_ENV_START 10 +# define PR_SET_MM_ENV_END 11 +# define PR_SET_MM_AUXV 12 +# define PR_SET_MM_EXE_FILE 13 +# define PR_SET_MM_MAP 14 +# define PR_SET_MM_MAP_SIZE 15 + +/* + * This structure provides new memory descriptor + * map which mostly modifies /proc/pid/stat[m] + * output for a task. This mostly done in a + * sake of checkpoint/restore functionality. + */ +struct prctl_mm_map { + __u64 start_code; /* code section bounds */ + __u64 end_code; + __u64 start_data; /* data section bounds */ + __u64 end_data; + __u64 start_brk; /* heap for brk() syscall */ + __u64 brk; + __u64 start_stack; /* stack starts at */ + __u64 arg_start; /* command line arguments bounds */ + __u64 arg_end; + __u64 env_start; /* environment variables bounds */ + __u64 env_end; + __u64 *auxv; /* auxiliary vector */ + __u32 auxv_size; /* vector size */ + __u32 exe_fd; /* /proc/$pid/exe link file */ +}; + +/* + * Set specific pid that is allowed to ptrace the current task. + * A value of 0 mean "no process". + */ +#define PR_SET_PTRACER 0x59616d61 +# define PR_SET_PTRACER_ANY ((unsigned long)-1) + +#define PR_SET_CHILD_SUBREAPER 36 +#define PR_GET_CHILD_SUBREAPER 37 + +/* + * If no_new_privs is set, then operations that grant new privileges (i.e. + * execve) will either fail or not grant them. This affects suid/sgid, + * file capabilities, and LSMs. + * + * Operations that merely manipulate or drop existing privileges (setresuid, + * capset, etc.) will still work. Drop those privileges if you want them gone. + * + * Changing LSM security domain is considered a new privilege. So, for example, + * asking selinux for a specific new context (e.g. with runcon) will result + * in execve returning -EPERM. + * + * See Documentation/prctl/no_new_privs.txt for more details. + */ +#define PR_SET_NO_NEW_PRIVS 38 +#define PR_GET_NO_NEW_PRIVS 39 + +#define PR_GET_TID_ADDRESS 40 + +#define PR_SET_THP_DISABLE 41 +#define PR_GET_THP_DISABLE 42 + +/* + * Tell the kernel to start/stop helping userspace manage bounds tables. + */ +#define PR_MPX_ENABLE_MANAGEMENT 43 +#define PR_MPX_DISABLE_MANAGEMENT 44 + +#define PR_SET_FP_MODE 45 +#define PR_GET_FP_MODE 46 +# define PR_FP_MODE_FR (1u << 0) /* 64b FP registers */ +# define PR_FP_MODE_FRE (1u << 1) /* 32b compatibility */ + +/* Control the ambient capability set */ +#define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 + +#endif /* _LINUX_PRCTL_H */ diff --git a/depends/libcap/libcap/include/uapi/linux/securebits.h b/depends/libcap/libcap/include/uapi/linux/securebits.h new file mode 100644 index 0000000..e9b1309 --- /dev/null +++ b/depends/libcap/libcap/include/uapi/linux/securebits.h @@ -0,0 +1,60 @@ +#ifndef _UAPI_LINUX_SECUREBITS_H +#define _UAPI_LINUX_SECUREBITS_H + +/* Each securesetting is implemented using two bits. One bit specifies + whether the setting is on or off. The other bit specify whether the + setting is locked or not. A setting which is locked cannot be + changed from user-level. */ +#define issecure_mask(X) (1u << (X)) + +#define SECUREBITS_DEFAULT 0x00000000 + +/* When set UID 0 has no special privileges. When unset, we support + inheritance of root-permissions and suid-root executable under + compatibility mode. We raise the effective and inheritable bitmasks + *of the executable file* if the effective uid of the new process is + 0. If the real uid is 0, we raise the effective (legacy) bit of the + executable file. */ +#define SECURE_NOROOT 0 +#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ + +#define SECBIT_NOROOT (issecure_mask(SECURE_NOROOT)) +#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 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 +#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ + +#define SECBIT_NO_SETUID_FIXUP (issecure_mask(SECURE_NO_SETUID_FIXUP)) +#define SECBIT_NO_SETUID_FIXUP_LOCKED \ + (issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)) + +/* When set, a process can retain its capabilities even after + transitioning to a non-root user (the set-uid fixup suppressed by + bit 2). Bit-4 is cleared when a process calls exec(); setting both + bit 4 and 5 will create a barrier through exec that no exec()'d + child can use this feature again. */ +#define SECURE_KEEP_CAPS 4 +#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ + +#define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS)) +#define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED)) + +/* When set, a process cannot add new capabilities to its ambient set. */ +#define SECURE_NO_CAP_AMBIENT_RAISE 6 +#define SECURE_NO_CAP_AMBIENT_RAISE_LOCKED 7 /* make bit-6 immutable */ + +#define SECBIT_NO_CAP_AMBIENT_RAISE (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE)) +#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED \ + (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED)) + +#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ + issecure_mask(SECURE_NO_SETUID_FIXUP) | \ + issecure_mask(SECURE_KEEP_CAPS) | \ + issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE)) +#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1) + +#endif /* _UAPI_LINUX_SECUREBITS_H */ diff --git a/depends/libcap/libcap/libcap.h b/depends/libcap/libcap/libcap.h new file mode 100644 index 0000000..f4a72fe --- /dev/null +++ b/depends/libcap/libcap/libcap.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 1997,2020 Andrew G Morgan <morgan@kernel.org> + * + * This file contains internal definitions for the various functions in + * this small capability library. + */ + +#ifndef LIBCAP_H +#define LIBCAP_H + +#include <errno.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/capability.h> + +#ifndef __u8 +#define __u8 uint8_t +#endif /* __8 */ + +#ifndef __u32 +#define __u32 uint32_t +#endif /* __u32 */ + +/* include the names for the caps and a definition of __CAP_BITS */ +#include "cap_names.h" + +#ifndef _LINUX_CAPABILITY_U32S_1 +# define _LINUX_CAPABILITY_U32S_1 1 +#endif /* ndef _LINUX_CAPABILITY_U32S_1 */ + +/* + * Do we match the local kernel? + */ + +#if !defined(_LINUX_CAPABILITY_VERSION) + +# error Kernel <linux/capability.h> does not support library +# error file "libcap.h" --> fix and recompile libcap + +#elif !defined(_LINUX_CAPABILITY_VERSION_2) + +# warning Kernel <linux/capability.h> does not support 64-bit capabilities +# warning and libcap is being built with no support for 64-bit capabilities + +# ifndef _LINUX_CAPABILITY_VERSION_1 +# define _LINUX_CAPABILITY_VERSION_1 0x19980330 +# endif + +# _LIBCAP_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1 +# _LIBCAP_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1 + +#elif defined(_LINUX_CAPABILITY_VERSION_3) + +# if (_LINUX_CAPABILITY_VERSION_3 != 0x20080522) +# error Kernel <linux/capability.h> v3 does not match library +# error file "libcap.h" --> fix and recompile libcap +# else +# define _LIBCAP_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3 +# define _LIBCAP_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3 +# endif + +#elif (_LINUX_CAPABILITY_VERSION_2 != 0x20071026) + +# error Kernel <linux/capability.h> does not match library +# error file "libcap.h" --> fix and recompile libcap + +#else + +# define _LIBCAP_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2 +# define _LIBCAP_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_2 + +#endif + +#undef _LINUX_CAPABILITY_VERSION +#undef _LINUX_CAPABILITY_U32S + +/* + * This is a pointer to a struct containing three consecutive + * capability sets in the order of the cap_flag_t type: the are + * effective,inheritable and permitted. This is the type that the + * user-space routines think of as 'internal' capabilities - this is + * the type that is passed to the kernel with the system calls related + * to processes. + */ + +#if defined(VFS_CAP_REVISION_MASK) && !defined(VFS_CAP_U32) +# define VFS_CAP_U32_1 1 +# define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1)) +# define VFS_CAP_U32 VFS_CAP_U32_1 +struct _cap_vfs_cap_data { + __le32 magic_etc; + struct { + __le32 permitted; + __le32 inheritable; + } data[VFS_CAP_U32_1]; +}; +# define vfs_cap_data _cap_vfs_cap_data +#endif + +#ifndef CAP_TO_INDEX +# define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */ +#endif /* ndef CAP_TO_INDEX */ + +#ifndef CAP_TO_MASK +# define CAP_TO_MASK(x) (1 << ((x) & 31)) +#endif /* ndef CAP_TO_MASK */ + +#define NUMBER_OF_CAP_SETS 3 /* effective, inheritable, permitted */ +#define __CAP_BLKS (_LIBCAP_CAPABILITY_U32S) +#define CAP_SET_SIZE (__CAP_BLKS * sizeof(__u32)) + +#define CAP_T_MAGIC 0xCA90D0 +struct _cap_struct { + __u8 mutex; + struct __user_cap_header_struct head; + union { + struct __user_cap_data_struct set; + __u32 flat[NUMBER_OF_CAP_SETS]; + } u[_LIBCAP_CAPABILITY_U32S]; + 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 + */ + +#define raise_cap(x, set) u[(x) >> 5].flat[set] |= (1u << ((x)&31)) +#define lower_cap(x, set) u[(x) >> 5].flat[set] &= ~(1u << ((x)&31)) +#define isset_cap(y, x, set) ((y)->u[(x) >> 5].flat[set] & (1u << ((x)&31))) + +/* + * These match CAP_DIFFERS() expectations + */ +#define LIBCAP_EFF (1 << CAP_EFFECTIVE) +#define LIBCAP_INH (1 << CAP_INHERITABLE) +#define LIBCAP_PER (1 << CAP_PERMITTED) + +/* + * library debugging + */ +#ifdef DEBUG + +#include <stdio.h> +# define _cap_debug(f, x...) do { \ + fprintf(stderr, "%s(%s:%d): ", __FUNCTION__, __FILE__, __LINE__); \ + fprintf(stderr, f, ## x); \ + fprintf(stderr, "\n"); \ +} while (0) + +# define _cap_debugcap(s, c, set) do { \ + unsigned _cap_index; \ + fprintf(stderr, "%s(%s:%d): %s", __FUNCTION__, __FILE__, __LINE__, s); \ + for (_cap_index=_LIBCAP_CAPABILITY_U32S; _cap_index-- > 0; ) { \ + fprintf(stderr, "%08x", (c).u[_cap_index].flat[set]); \ + } \ + fprintf(stderr, "\n"); \ +} while (0) + +#else /* !DEBUG */ + +# define _cap_debug(f, x...) +# define _cap_debugcap(s, c, set) + +#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 + * <sys/capability.h> if _POSIX_SOURCE is not #define'd, so we + * place them here too. + */ + +extern int capget(cap_user_header_t header, cap_user_data_t data); +extern int capgetp(pid_t pid, cap_t cap_d); +extern int capsetp(pid_t pid, cap_t cap_d); + +/* prctl based API for altering character of current process */ +#define PR_GET_KEEPCAPS 7 +#define PR_SET_KEEPCAPS 8 +#define PR_CAPBSET_READ 23 +#define PR_CAPBSET_DROP 24 +#define PR_GET_SECUREBITS 27 +#define PR_SET_SECUREBITS 28 + +/* + * The library compares sizeof() with integer return values. To avoid + * signed/unsigned comparisons, leading to unfortunate + * misinterpretations of -1, we provide a convenient cast-to-signed-integer + * version of sizeof(). + */ +#define ssizeof(x) ((ssize_t) sizeof(x)) + +/* + * Put this here as a macro so we can unit test it. + */ +#define _binary_search(val, fn, low, high, fallback) do { \ + cap_value_t min = low, max = high; \ + while (min <= max) { \ + cap_value_t mid = (min+max) / 2; \ + if (fn(mid) < 0) { \ + max = mid - 1; \ + } else { \ + min = mid + 1; \ + } \ + } \ + 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 */ diff --git a/depends/libcap/libcap/libcap.pc.in b/depends/libcap/libcap/libcap.pc.in new file mode 100644 index 0000000..69cd231 --- /dev/null +++ b/depends/libcap/libcap/libcap.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libcap +Description: libcap - linux capabilities library +Version: @VERSION@ +Libs: -L${libdir} -lcap +Libs.private: @deps@ +Cflags: -I${includedir} diff --git a/depends/libcap/libcap/libpsx.pc.in b/depends/libcap/libcap/libpsx.pc.in new file mode 100644 index 0000000..d032b9f --- /dev/null +++ b/depends/libcap/libcap/libpsx.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libpsx +Description: libpsx - linux posix syscall API for pthreads +Version: @VERSION@ +Libs: -L${libdir} -lpsx -lpthread -Wl,-wrap,pthread_create +Libs.private: @deps@ +Cflags: -I${includedir} diff --git a/depends/libcap/libcap/psx_exec.c b/depends/libcap/libcap/psx_exec.c new file mode 100644 index 0000000..5e7a88f --- /dev/null +++ b/depends/libcap/libcap/psx_exec.c @@ -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); +} |