Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libcap for openSUSE:Factory checked in at 2021-02-07 15:13:35 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libcap (Old) and /work/SRC/openSUSE:Factory/.libcap.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libcap" Sun Feb 7 15:13:35 2021 rev:42 rq:867074 version:2.47 Changes: -------- --- /work/SRC/openSUSE:Factory/libcap/libcap.changes 2021-01-22 21:48:51.525554206 +0100 +++ /work/SRC/openSUSE:Factory/.libcap.new.28504/libcap.changes 2021-02-07 15:13:38.233361949 +0100 @@ -1,0 +2,9 @@ +Wed Jan 27 07:53:21 UTC 2021 - Dirk M??ller <dmuel...@suse.com> + +- update to 2.47: + * Restructured gowns to default to uid base of getuid(). + * Augment NOPRIV libcap mode with the sticky NO_NEW_PRIVS prctl bit. + * Improve the usage and diagnostic message for setcap + * Documentation fixes, license declarations, example updates + +------------------------------------------------------------------- Old: ---- libcap-2.46.tar.xz New: ---- libcap-2.47.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libcap.spec ++++++ --- /var/tmp/diff_new_pack.qLqqWP/_old 2021-02-07 15:13:39.037362809 +0100 +++ /var/tmp/diff_new_pack.qLqqWP/_new 2021-02-07 15:13:39.041362813 +0100 @@ -17,7 +17,7 @@ Name: libcap -Version: 2.46 +Version: 2.47 Release: 0 Summary: Library for Capabilities (linux-privs) Support License: BSD-3-Clause AND GPL-2.0-only ++++++ libcap-2.46.tar.xz -> libcap-2.47.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/Make.Rules new/libcap-2.47/Make.Rules --- old/libcap-2.46/Make.Rules 2020-12-13 00:54:26.000000000 +0100 +++ new/libcap-2.47/Make.Rules 2021-01-24 03:06:05.000000000 +0100 @@ -1,7 +1,7 @@ # Common version number defines for libcap LIBTITLE=libcap VERSION=2 -MINOR=46 +MINOR=47 # ## Optional prefixes: @@ -43,9 +43,9 @@ PKGCONFIGDIR=$(LIBDIR)/pkgconfig GOPKGDIR=$(prefix)/share/gocode/src -# Go modules have their own semantics. I plan to leave this value at 0 -# and keep it there. The Go packages should always remain backwardly -# compatible, but I may have to up it if Go's syntax changes in a +# Once go1.16 is released, I plan to set this value to 1 and keep it +# there. The Go packages should always remain backwardly compatible, +# but I may have to up it if Go's syntax dramatically changes in a # backwards incompatible manner. (Let's hope not.) GOMAJOR=0 @@ -113,10 +113,6 @@ CGO_LDFLAGS := -L$(topdir)/libcap CGO_LDFLAGS_ALLOW := -Wl,-?-wrap[=,][^-.@][^,]* CGO_REQUIRED=$(shell $(topdir)/go/cgo-required.sh) -ifeq ($(CGO_REQUIRED),0) -# Hopefully this will not be needed at some point. -GOBUILDTAG=-tags allthreadssyscall -endif endif endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/cap/cap.go new/libcap-2.47/cap/cap.go --- old/libcap-2.46/cap/cap.go 2020-12-11 06:35:28.000000000 +0100 +++ new/libcap-2.47/cap/cap.go 2021-01-24 03:01:25.000000000 +0100 @@ -42,17 +42,14 @@ // uniformly over the whole Go (and CGo linked) process runtime. // // Note, if the Go runtime syscall interface contains the Linux -// variant syscall.AllThreadsSyscall() API (it is not in go1.15 -// for example, but see https://github.com/golang/go/issues/1435 for -// current status) then this present package can use that to invoke -// Capability setting system calls in pure Go binaries. In such an -// enhanced Go runtime, to force this behavior, use the CGO_ENABLED=0 -// environment variable and, for now, a build tag: +// variant syscall.AllThreadsSyscall() API (it debuted in go1.16 see +// https://github.com/golang/go/issues/1435 for its history) then +// the "psx" package will use that to invoke Capability setting system +// calls in pure Go binaries. In such an enhanced Go runtime, to force +// this behavior, use the CGO_ENABLED=0 environment variable. // -// CGO_ENABLED=0 go build -tags allthreadssyscall ... // -// -// Copyright (c) 2019,20 Andrew G. Morgan <mor...@kernel.org> +// Copyright (c) 2019-21 Andrew G. Morgan <mor...@kernel.org> // // The cap and psx packages are licensed with a (you choose) BSD // 3-clause or GPL2. See LICENSE file for details. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/cap/convenience.go new/libcap-2.47/cap/convenience.go --- old/libcap-2.46/cap/convenience.go 2020-08-02 03:31:08.000000000 +0200 +++ new/libcap-2.47/cap/convenience.go 2020-12-29 02:01:07.000000000 +0100 @@ -36,6 +36,7 @@ prSetKeepCaps = 8 prGetSecureBits = 27 prSetSecureBits = 28 + prSetNoNewPrivs = 38 ) // GetSecbits returns the current setting of the process' Secbits. @@ -163,6 +164,9 @@ } w.ClearFlag(Permitted) + // For good measure. + sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0) + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/cap/go.mod new/libcap-2.47/cap/go.mod --- old/libcap-2.46/cap/go.mod 2020-12-13 00:55:02.000000000 +0100 +++ new/libcap-2.47/cap/go.mod 2021-01-24 03:07:25.000000000 +0100 @@ -2,4 +2,4 @@ go 1.11 -require kernel.org/pub/linux/libs/security/libcap/psx v0.2.46 +require kernel.org/pub/linux/libs/security/libcap/psx v0.2.47 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/cap/launch.go new/libcap-2.47/cap/launch.go --- old/libcap-2.46/cap/launch.go 2020-07-16 04:31:24.000000000 +0200 +++ new/libcap-2.47/cap/launch.go 2020-12-24 01:46:18.000000000 +0100 @@ -106,18 +106,18 @@ var ErrNoLaunch = errors.New("launch not supported") // ErrAmbiguousChroot indicates that the Launcher is being used in -// addition to callback supplied Chroot. The former should be used +// addition to a callback supplied Chroot. The former should be used // exclusively for this. var ErrAmbiguousChroot = errors.New("use Launcher for chroot") // ErrAmbiguousIDs indicates that the Launcher is being used in -// addition to callback supplied Credentials. The former should be +// addition to a callback supplied Credentials. The former should be // used exclusively for this. var ErrAmbiguousIDs = errors.New("use Launcher for uids and gids") // ErrAmbiguousAmbient indicates that the Launcher is being used in -// addition callback supplied ambient set and the former should be -// used exclusively in a Launch call. +// addition to a callback supplied ambient set and the former should +// be used exclusively in a Launch call. var ErrAmbiguousAmbient = errors.New("use Launcher for ambient caps") // lName is the name we temporarily give to the launcher thread. Note, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/cap/text.go new/libcap-2.47/cap/text.go --- old/libcap-2.46/cap/text.go 2020-07-25 04:28:01.000000000 +0200 +++ new/libcap-2.47/cap/text.go 2020-12-24 01:46:18.000000000 +0100 @@ -187,7 +187,7 @@ // // "=p all+ei" "all=pie" "=pi all+e" "=eip" // -// "cap_chown=p cap_setuid=i" "cap_chown=ip-p" "cap_chown=i" +// "cap_setuid=p cap_chown=i" "cap_chown=ip-p" "cap_chown=i" // // "cap_chown=-p" "all=" "cap_setuid=pie-pie" "=" // diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/contrib/seccomp/explore.go new/libcap-2.47/contrib/seccomp/explore.go --- old/libcap-2.46/contrib/seccomp/explore.go 1970-01-01 01:00:00.000000000 +0100 +++ new/libcap-2.47/contrib/seccomp/explore.go 2021-01-24 03:01:25.000000000 +0100 @@ -0,0 +1,276 @@ +// Program explore is evolved from the code discussed in more depth +// here: +// +// https://github.com/golang/go/issues/3405 +// +// The code here demonstrates that while PR_SET_NO_NEW_PRIVS only +// applies to the calling thread, since +// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=103502a35cfce0710909da874f092cb44823ca03 +// the seccomp filter application forces the setting to be mirrored on +// all the threads of a process. +// +// Based on the command line options, we can manipulate the program to +// behave in various ways. Example command lines: +// +// sudo ./explore +// sudo ./explore --kill=false +// sudo ./explore --kill=false --errno=0 +// +// Supported Go toolchains are after go1.10. Those prior to go1.15 +// require this environment variable to be set to build successfully: +// +// export CGO_LDFLAGS_ALLOW="-Wl,-?-wrap[=,][^-.@][^,]*" +// +// Go toolchains go1.16+ can be compiled CGO_ENABLED=0 too, +// demonstrating native nocgo support for seccomp features. +package main + +import ( + "flag" + "fmt" + "log" + "runtime" + "syscall" + "time" + "unsafe" + + "kernel.org/pub/linux/libs/security/libcap/psx" +) + +var ( + withPSX = flag.Bool("psx", false, "use the psx mechanism to invoke prctl syscall") + delays = flag.Bool("delays", false, "use this to pause the program at various places") + kill = flag.Bool("kill", true, "kill the process if setuid attempted") + errno = flag.Int("errno", int(syscall.ENOTSUP), "if kill is false, block syscall and return this errno") +) + +const ( + PR_SET_NO_NEW_PRIVS = 38 + + SYS_SECCOMP = 317 // x86_64 syscall number + SECCOMP_SET_MODE_FILTER = 1 // uses user-supplied filter. + SECCOMP_FILTER_FLAG_TSYNC = (1 << 0) // mirror filtering on all threads. + SECCOMP_RET_ERRNO = 0x00050000 // returns an errno + SECCOMP_RET_DATA = 0x0000ffff // mask for RET data payload (ex. errno) + SECCOMP_RET_KILL_PROCESS = 0x80000000 // kill the whole process immediately + SECCOMP_RET_TRAP = 0x00030000 // disallow and force a SIGSYS + SECCOMP_RET_ALLOW = 0x7fff0000 + + BPF_LD = 0x00 + BPF_JMP = 0x05 + BPF_RET = 0x06 + + BPF_W = 0x00 + + BPF_ABS = 0x20 + BPF_JEQ = 0x10 + + BPF_K = 0x00 + + AUDIT_ARCH_X86_64 = 3221225534 // HACK: I don't understand this value + ARCH_NR = AUDIT_ARCH_X86_64 + + syscall_nr = 0 +) + +// SockFilter is a single filter block. +type SockFilter struct { + // Code is the filter code instruction. + Code uint16 + // Jt is the target for a true result from the code execution. + Jt uint8 + // Jf is the target for a false result from the code execution. + Jf uint8 + // K is a generic multiuse field + K uint32 +} + +// SockFProg is a +type SockFProg struct { + // Len is the number of contiguous SockFilter blocks that can + // be found at *Filter. + Len uint16 + // Filter is the address of the first SockFilter block of a + // program sequence. + Filter *SockFilter +} + +type SockFilterSlice []SockFilter + +func BPF_STMT(code uint16, k uint32) SockFilter { + return SockFilter{code, 0, 0, k} +} + +func BPF_JUMP(code uint16, k uint32, jt uint8, jf uint8) SockFilter { + return SockFilter{code, jt, jf, k} +} + +func ValidateArchitecture() []SockFilter { + return []SockFilter{ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 4), // HACK: I don't understand this 4. + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL_PROCESS), + } +} + +func ExamineSyscall() []SockFilter { + return []SockFilter{ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr), + } +} + +func AllowSyscall(syscallNum uint32) []SockFilter { + return []SockFilter{ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscallNum, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), + } +} + +func DisallowSyscall(syscallNum, errno uint32) []SockFilter { + return []SockFilter{ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscallNum, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(errno&SECCOMP_RET_DATA)), + } +} + +func KillProcess() []SockFilter { + return []SockFilter{ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL_PROCESS), + } +} + +func NotifyProcessAndDie() []SockFilter { + return []SockFilter{ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP), + } +} + +func TrapOnSyscall(syscallNum uint32) []SockFilter { + return []SockFilter{ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscallNum, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP), + } +} + +func AllGood() []SockFilter { + return []SockFilter{ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), + } +} + +// prctl executes the prctl - unless the --psx commandline argument is +// used, this is on a single thread. +//go:uintptrescapes +func prctl(option, arg1, arg2, arg3, arg4, arg5 uintptr) error { + var e syscall.Errno + if *withPSX { + _, _, e = psx.Syscall6(syscall.SYS_PRCTL, option, arg1, arg2, arg3, arg4, arg5) + } else { + _, _, e = syscall.RawSyscall6(syscall.SYS_PRCTL, option, arg1, arg2, arg3, arg4, arg5) + } + if e != 0 { + return e + } + if *delays { + fmt.Println("prctl'd - check now") + time.Sleep(1 * time.Minute) + } + return nil +} + +// seccomp_set_mode_filter is our wrapper for performing our seccomp system call. +//go:uintptrescapes +func seccomp_set_mode_filter(prog *SockFProg) error { + if _, _, e := syscall.RawSyscall(SYS_SECCOMP, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, uintptr(unsafe.Pointer(prog))); e != 0 { + return e + } + return nil +} + +var empty func() + +func lockProcessThread(pick bool) { + // Make sure we are + pid := uintptr(syscall.Getpid()) + runtime.LockOSThread() + for { + tid, _, _ := syscall.RawSyscall(syscall.SYS_GETTID, 0, 0, 0) + if (tid == pid) == pick { + fmt.Println("validated TID:", tid, "== PID:", pid, "is", pick) + break + } + runtime.UnlockOSThread() + go func() { + time.Sleep(1 * time.Microsecond) + }() + runtime.Gosched() + runtime.LockOSThread() + } +} + +// applyPolicy uploads the program sequence. +func applyPolicy(prog *SockFProg) { + // Without PSX we can't guarantee the thread we execute the + // seccomp call on will be the same one that we disabled new + // privs on. With PSX, the disabling of new privs is mirrored + // on all threads. + if !*withPSX { + lockProcessThread(false) + defer runtime.UnlockOSThread() + } + + // This is required to load a filter without privilege. + if err := prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0); err != nil { + log.Fatalf("Prctl(PR_SET_NO_NEW_PRIVS): %v", err) + } + + fmt.Println("Applying syscall policy...") + if err := seccomp_set_mode_filter(prog); err != nil { + log.Fatalf("seccomp_set_mode_filter: %v", err) + } + fmt.Println("...Policy applied") +} + +func main() { + flag.Parse() + + if *delays { + fmt.Println("check first", syscall.Getpid()) + time.Sleep(60 * time.Second) + } + + var filter []SockFilter + filter = append(filter, ValidateArchitecture()...) + + // Grab the system call number. + filter = append(filter, ExamineSyscall()...) + + // List disallowed syscalls. + for _, x := range []uint32{ + syscall.SYS_SETUID, + } { + if *kill { + filter = append(filter, TrapOnSyscall(x)...) + } else { + filter = append(filter, DisallowSyscall(x, uint32(*errno))...) + } + } + + filter = append(filter, AllGood()...) + + prog := &SockFProg{ + Len: uint16(len(filter)), + Filter: &filter[0], + } + + applyPolicy(prog) + + // Ensure we are running on the TID=PID. + lockProcessThread(true) + + log.Print("Now it is time to try to run something privileged...") + if _, _, e := syscall.RawSyscall(syscall.SYS_SETUID, 1, 0, 0); e != 0 { + log.Fatalf("setuid failed with an error: %v", e) + } + log.Print("Looked like that worked, but it really didn't: uid == ", syscall.Getuid(), " != 1") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/contrib/seccomp/go.mod new/libcap-2.47/contrib/seccomp/go.mod --- old/libcap-2.46/contrib/seccomp/go.mod 1970-01-01 01:00:00.000000000 +0100 +++ new/libcap-2.47/contrib/seccomp/go.mod 2021-01-24 03:08:01.000000000 +0100 @@ -0,0 +1,5 @@ +module explore + +go 1.14 + +require kernel.org/pub/linux/libs/security/libcap/psx v0.2.47 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/go/Makefile new/libcap-2.47/go/Makefile --- old/libcap-2.46/go/Makefile 2020-12-12 08:57:35.000000000 +0100 +++ new/libcap-2.47/go/Makefile 2020-12-24 01:46:18.000000000 +0100 @@ -54,7 +54,7 @@ GO111MODULE=off CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(GOPATH) $(GO) build $< web: ../goapps/web/web.go $(CAPGOPACKAGE) - GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $(GOBUILDTAG) $< + GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $< ifeq ($(RAISE_GO_FILECAP),yes) make -C ../progs setcap sudo ../progs/setcap cap_setpcap,cap_net_bind_service=p web @@ -62,16 +62,16 @@ endif setid: ../goapps/setid/setid.go $(CAPGOPACKAGE) $(PSXGOPACKAGE) - GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $(GOBUILDTAG) $< + GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $< gowns: ../goapps/gowns/gowns.go $(CAPGOPACKAGE) - GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $(GOBUILDTAG) $< + GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@ $< ok: ok.go GO111MODULE=off CGO_ENABLED=0 GOPATH=$(GOPATH) $(GO) build $< try-launching: try-launching.go $(CAPGOPACKAGE) ok - GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build $(GOBUILDTAG) $< + GO111MODULE=off CGO_ENABLED="$(CGO_REQUIRED)" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build $< ifeq ($(CGO_REQUIRED),0) GO111MODULE=off CGO_ENABLED="1" CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" GOPATH=$(GOPATH) $(GO) build -o $@-cgo $< endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/go/try-launching.go new/libcap-2.47/go/try-launching.go --- old/libcap-2.46/go/try-launching.go 2020-09-07 23:08:11.000000000 +0200 +++ new/libcap-2.47/go/try-launching.go 2020-12-29 02:01:07.000000000 +0100 @@ -28,6 +28,7 @@ iab string uid int gid int + mode cap.Mode groups []int }{ {args: []string{root + "/go/ok"}}, @@ -44,6 +45,11 @@ chroot: root + "/go", fail: syscall.Getuid() != 0, }, + { + args: []string{root + "/progs/tcapsh-static", "--inmode=NOPRIV", "--has-no-new-privs"}, + mode: cap.ModeNoPriv, + fail: syscall.Getuid() != 0, + }, } ps := make([]int, len(vs)) @@ -61,6 +67,9 @@ if v.gid != 0 { e.SetGroups(v.gid, v.groups) } + if v.mode != 0 { + e.SetMode(v.mode) + } if v.iab != "" { if iab, err := cap.IABFromText(v.iab); err != nil { log.Fatalf("failed to parse iab=%q: %v", v.iab, err) @@ -68,6 +77,7 @@ e.SetIAB(iab) } } + log.Printf("[%d] trying: %q\n", i, v.args) if ps[i], err = e.Launch(nil); err != nil { if v.fail { continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/goapps/gowns/go.mod new/libcap-2.47/goapps/gowns/go.mod --- old/libcap-2.46/goapps/gowns/go.mod 2020-12-13 00:55:39.000000000 +0100 +++ new/libcap-2.47/goapps/gowns/go.mod 2021-01-24 03:08:53.000000000 +0100 @@ -2,4 +2,4 @@ go 1.15 -require kernel.org/pub/linux/libs/security/libcap/cap v0.2.46 +require kernel.org/pub/linux/libs/security/libcap/cap v0.2.47 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/goapps/gowns/gowns.go new/libcap-2.47/goapps/gowns/gowns.go --- old/libcap-2.46/goapps/gowns/gowns.go 2020-12-12 08:20:40.000000000 +0100 +++ new/libcap-2.47/goapps/gowns/gowns.go 2021-01-24 03:01:25.000000000 +0100 @@ -1,5 +1,5 @@ // Program gowns is a small program to explore and demonstrate using -// GO to Wrap a child in a NameSpace under Linux. +// Go to Wrap a child in a NameSpace under Linux. package main import ( @@ -17,17 +17,25 @@ // nsDetail is how we summarize the type of namespace we want to // enter. type nsDetail struct { - // uid holds the uid for "root" in this namespace. + // uid holds the uid for the base user in this namespace (defaults to getuid). uid int - // gid holds the gid for "root" in this namespace. + + // uidMap holds the namespace mapping of uid values. + uidMap []syscall.SysProcIDMap + + // gid holds the gid for the base user in this namespace (defaults to getgid). gid int + + // uidMap holds the namespace mapping of gid values. + gidMap []syscall.SysProcIDMap } var ( - uid = flag.Int("uid", -1, "uid of the hosting user") - gid = flag.Int("gid", -1, "gid of the hosting user") - iab = flag.String("iab", "", "IAB string for inheritable capabilities") - mode = flag.String("mode", "", "force a libcap mode (capsh --modes for list)") + baseID = flag.Int("base", -1, "base id for uids and gids (-1 = invoker's uid)") + uid = flag.Int("uid", -1, "uid of the hosting user") + gid = flag.Int("gid", -1, "gid of the hosting user") + iab = flag.String("iab", "", "IAB string for inheritable capabilities") + mode = flag.String("mode", "", "force a libcap mode (capsh --modes for list)") ns = flag.Bool("ns", false, "enable user namespace features") uids = flag.String("uids", "", "comma separated UID ranges to map contiguously (req. CAP_SETUID)") @@ -81,70 +89,73 @@ // nsSetup is the callback used to enter the namespace for the user // via callback in the cap.Launcher mechanism. func nsSetup(pa *syscall.ProcAttr, data interface{}) error { - have := cap.GetProc() nsD, ok := data.(nsDetail) if !ok { return errUnableToSetup } - sys := pa.Sys - if sys == nil { - sys = &syscall.SysProcAttr{} - pa.Sys = sys + if pa.Sys == nil { + pa.Sys = &syscall.SysProcAttr{} } - sys.Cloneflags |= syscall.CLONE_NEWUSER - sys.UidMappings = append(pa.Sys.UidMappings, - syscall.SysProcIDMap{ - ContainerID: 0, - HostID: nsD.uid, - Size: 1, - }) - if able, err := have.GetFlag(cap.Effective, cap.SETUID); err != nil { - log.Fatalf("cap package SETUID error: %v", err) - } else if able { - base := 1 - for _, next := range ranges(*uids) { - sys.UidMappings = append(pa.Sys.UidMappings, - syscall.SysProcIDMap{ - ContainerID: base, - HostID: next.base, - Size: next.count, - }) - base += next.count - } + pa.Sys.Cloneflags |= syscall.CLONE_NEWUSER + pa.Sys.UidMappings = nsD.uidMap + pa.Sys.GidMappings = nsD.gidMap + return nil +} + +func parseRanges(detail *nsDetail, ids string, id int) []syscall.SysProcIDMap { + base := *baseID + if base < 0 { + base = detail.uid } - sys.GidMappings = append(pa.Sys.GidMappings, + list := []syscall.SysProcIDMap{ syscall.SysProcIDMap{ - ContainerID: 0, - HostID: nsD.gid, + ContainerID: base, + HostID: id, Size: 1, - }) - if able, err := have.GetFlag(cap.Effective, cap.SETGID); err != nil { - log.Fatalf("cap package SETGID error: %v", err) - } else if able { - base := 1 - for _, next := range ranges(*gids) { - sys.GidMappings = append(pa.Sys.GidMappings, - syscall.SysProcIDMap{ - ContainerID: base, - HostID: next.base, - Size: next.count, - }) - base += next.count - } + }, } - return nil + + base++ + for _, next := range ranges(ids) { + fmt.Println("next:", next) + list = append(list, + syscall.SysProcIDMap{ + ContainerID: base, + HostID: next.base, + Size: next.count, + }) + base += next.count + } + return list } func main() { flag.Parse() detail := nsDetail{ - uid: syscall.Getuid(), gid: syscall.Getgid(), } + thisUID := syscall.Getuid() + switch *uid { + case -1: + detail.uid = thisUID + default: + detail.uid = *uid + } + detail.uidMap = parseRanges(&detail, *uids, detail.uid) + + thisGID := syscall.Getgid() + switch *gid { + case -1: + detail.gid = thisGID + default: + detail.gid = *gid + } + detail.gidMap = parseRanges(&detail, *gids, detail.gid) + unparsed := flag.Args() arg0 := *shell @@ -164,13 +175,11 @@ w.Callback(nsSetup) } - have := cap.GetProc() - if *uid >= 0 { - detail.uid = *uid - cap.SetUID(detail.uid) + if thisUID != detail.uid { + w.SetUID(detail.uid) } - if *gid >= 0 { - detail.gid = *gid + + if thisGID != detail.gid { w.SetGroups(detail.gid, nil) } @@ -195,6 +204,7 @@ // The launcher can enable more functionality if involked with // effective capabilities. + have := cap.GetProc() for _, c := range []cap.Value{cap.SETUID, cap.SETGID} { if canDo, err := have.GetFlag(cap.Permitted, c); err != nil { log.Fatalf("failed to explore process capabilities, %q for %q", have, c) @@ -205,12 +215,12 @@ } } if err := have.SetProc(); err != nil { - log.Fatalf("privilege assertion failed: %v", err) + log.Fatalf("privilege assertion %q failed: %v", have, err) } if *debug { if *ns { - fmt.Println("launching:", detail.uid, "-> root ...") + fmt.Println("launching namespace") } else { fmt.Println("launching without namespace") } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/goapps/setid/go.mod new/libcap-2.47/goapps/setid/go.mod --- old/libcap-2.46/goapps/setid/go.mod 2020-12-13 00:55:58.000000000 +0100 +++ new/libcap-2.47/goapps/setid/go.mod 2021-01-24 03:08:38.000000000 +0100 @@ -3,6 +3,6 @@ go 1.11 require ( - kernel.org/pub/linux/libs/security/libcap/cap v0.2.46 - kernel.org/pub/linux/libs/security/libcap/psx v0.2.46 + kernel.org/pub/linux/libs/security/libcap/cap v0.2.47 + kernel.org/pub/linux/libs/security/libcap/psx v0.2.47 ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/goapps/web/go.mod new/libcap-2.47/goapps/web/go.mod --- old/libcap-2.46/goapps/web/go.mod 2020-12-13 00:56:36.000000000 +0100 +++ new/libcap-2.47/goapps/web/go.mod 2021-01-24 03:08:24.000000000 +0100 @@ -2,4 +2,4 @@ go 1.11 -require kernel.org/pub/linux/libs/security/libcap/cap v0.2.46 +require kernel.org/pub/linux/libs/security/libcap/cap v0.2.47 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/libcap/cap_proc.c new/libcap-2.47/libcap/cap_proc.c --- old/libcap-2.46/libcap/cap_proc.c 2020-07-19 23:39:03.000000000 +0200 +++ new/libcap-2.47/libcap/cap_proc.c 2020-12-29 02:01:07.000000000 +0100 @@ -390,7 +390,7 @@ } /* - * Set the security mode of the current process. + * Set the secbits of the current process. */ int cap_set_secbits(unsigned bits) { @@ -398,6 +398,14 @@ } /* + * Attempt to raise the no new privs prctl value. + */ +static void _cap_set_no_new_privs(struct syscaller_s *sc) +{ + (void) _libcap_wprctl6(sc, PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0); +} + +/* * Some predefined constants */ #define CAP_SECURED_BITS_BASIC \ @@ -448,7 +456,11 @@ (void) _cap_drop_bound(sc, c); } (void) cap_clear_flag(working, CAP_PERMITTED); + + /* for good measure */ + _cap_set_no_new_privs(sc); break; + default: errno = EINVAL; ret = -1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/progs/capsh.c new/libcap-2.47/progs/capsh.c --- old/libcap-2.46/progs/capsh.c 2020-11-03 02:58:32.000000000 +0100 +++ new/libcap-2.47/progs/capsh.c 2020-12-29 02:01:07.000000000 +0100 @@ -1,9 +1,10 @@ /* * Copyright (c) 2008-11,16,19,2020 Andrew G. Morgan <mor...@kernel.org> * - * This is a simple 'bash' (-DSHELL) wrapper program that can be used - * to raise and lower both the bset and pI capabilities before - * invoking /bin/bash. + * This is a multifunction shell wrapper tool that can be used to + * launch capable files in various ways with a variety of settings. It + * also supports some testing modes, which are used extensively as + * part of the libcap build system. * * The --print option can be used as a quick test whether various * capability manipulations work as expected (or not). @@ -107,8 +108,9 @@ set = cap_get_secbits(); if (set >= 0) { const char *b = binary(set); /* verilog convention for binary string */ - printf("Securebits: 0%lo/0x%lx/%u'b%s\n", set, set, - (unsigned) strlen(b), b); + printf("Securebits: 0%lo/0x%lx/%u'b%s (no-new-privs=%d)\n", set, set, + (unsigned) strlen(b), b, + prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0, 0)); printf(" secure-noroot: %s (%s)\n", (set & SECBIT_NOROOT) ? "yes":"no", (set & SECBIT_NOROOT_LOCKED) ? "locked":"unlocked"); @@ -909,47 +911,66 @@ exit(1); } cap_free(iab); + } else if (!strcmp("--no-new-privs", argv[i])) { + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0, 0) != 0) { + perror("unable to set no-new-privs"); + exit(1); + } + } else if (!strcmp("--has-no-new-privs", argv[i])) { + if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0, 0) != 1) { + fprintf(stderr, "no-new-privs not set\n"); + exit(1); + } + } else if (!strcmp("--license", argv[i])) { + printf( + "%s has a you choose license: BSD 3-clause or GPL2\n" + "Copyright (c) 2008-11,16,19,2020 Andrew G. Morgan" + " <mor...@kernel.org>\n", argv[0]); + exit(0); } else { usage: printf("usage: %s [args ...]\n" - " --help this message (or try 'man capsh')\n" - " --print display capability relevant state\n" - " --decode=xxx decode a hex string to a list of caps\n" - " --supports=xxx exit 1 if capability xxx unsupported\n" - " --has-p=xxx exit 1 if capability xxx not permitted\n" - " --has-i=xxx exit 1 if capability xxx not inheritable\n" - " --drop=xxx remove xxx,.. capabilities from bset\n" - " --dropped=xxx exit 1 unless bounding cap xxx dropped\n" - " --has-ambient exit 1 unless ambient vector supported\n" " --has-a=xxx exit 1 if capability xxx not ambient\n" + " --has-ambient exit 1 unless ambient vector supported\n" " --addamb=xxx add xxx,... capabilities to ambient set\n" - " --delamb=xxx remove xxx,... capabilities from ambient\n" - " --noamb reset (drop) all ambient capabilities\n" + " --cap-uid=<n> use libcap cap_setuid() to change uid\n" " --caps=xxx set caps as per cap_from_text()\n" - " --inh=xxx set xxx,.. inheritable set\n" - " --secbits=<n> write a new value for securebits\n" + " --chroot=path chroot(2) to this path\n" + " --decode=xxx decode a hex string to a list of caps\n" + " --delamb=xxx remove xxx,... capabilities from ambient\n" + " --forkfor=<n> fork and make child sleep for <n> sec\n" + " --gid=<n> set gid to <n> (hint: id <username>)\n" + " --groups=g,... set the supplemental groups\n" + " --has-p=xxx exit 1 if capability xxx not permitted\n" + " --has-i=xxx exit 1 if capability xxx not inheritable\n" + " --has-no-new-privs exit 1 if privs not limited\n" + " --help, -h this message (or try 'man capsh')\n" " --iab=... use cap_iab_from_text() to set iab\n" - " --keep=<n> set keep-capability bit to <n>\n" - " --uid=<n> set uid to <n> (hint: id <username>)\n" - " --cap-uid=<n> libcap cap_setuid() to change uid\n" + " --inh=xxx set xxx,.. inheritable set\n" + " --inmode=<xxx> exit 1 if current mode is not <xxx>\n" " --is-uid=<n> exit 1 if uid != <n>\n" - " --gid=<n> set gid to <n> (hint: id <username>)\n" " --is-gid=<n> exit 1 if gid != <n>\n" - " --groups=g,... set the supplemental groups\n" - " --user=<name> set uid,gid and groups to that of user\n" - " --chroot=path chroot(2) to this path\n" + " --keep=<n> set keep-capability bit to <n>\n" + " --killit=<n> send signal(n) to child\n" + " --license display license info\n" " --modes list libcap named capability modes\n" " --mode=<xxx> set capability mode to <xxx>\n" - " --inmode=<xxx> exit 1 if current mode is not <xxx>\n" - " --killit=<n> send signal(n) to child\n" - " --forkfor=<n> fork and make child sleep for <n> sec\n" + " --no-new-privs set sticky process privilege limiter\n" + " --noamb reset (drop) all ambient capabilities\n" + " --print display capability relevant state\n" + " --secbits=<n> write a new value for securebits\n" " --shell=/xx/yy use /xx/yy instead of " SHELL " for --\n" + " --supports=xxx exit 1 if capability xxx unsupported\n" + " --uid=<n> set uid to <n> (hint: id <username>)\n" + " --user=<name> set uid,gid and groups to that of user\n" " == re-exec(capsh) with args as for --\n" " -- remaining arguments are for " SHELL "\n" " (without -- [%s] will simply exit(0))\n", argv[0], argv[0]); - - exit(strcmp("--help", argv[i]) != 0); + if (strcmp("--help", argv[1]) && strcmp("-h", argv[1])) { + exit(1); + } + exit(0); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/progs/getcap.c new/libcap-2.47/progs/getcap.c --- old/libcap-2.46/progs/getcap.c 2020-07-01 04:43:01.000000000 +0200 +++ new/libcap-2.47/progs/getcap.c 2020-12-29 02:01:07.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997,2007 Andrew G. Morgan <mor...@kernel.org> + * Copyright (c) 1997,2007 Andrew G. Morgan <mor...@kernel.org> * * This displays the capabilities of a given file. */ @@ -23,14 +23,14 @@ static int recursive = 0; static int namespace = 0; -static void usage(void) +static void usage(int code) { fprintf(stderr, - "usage: getcap [-v] [-r] [-h] [-n] <filename> [<filename> ...]\n" - "\n" - "\tdisplays the capabilities on the queried file(s).\n" + "usage: getcap [-h] [-l] [-n] [-r] [-v] <filename> [<filename> ...]\n" + "\n" + "\tdisplays the capabilities on the queried file(s).\n" ); - exit(1); + exit(code); } static int do_getcap(const char *fname, const struct stat *stbuf, @@ -82,7 +82,7 @@ { int i, c; - while ((c = getopt(argc, argv, "rvhn")) > 0) { + while ((c = getopt(argc, argv, "rvhnl")) > 0) { switch(c) { case 'r': recursive = 1; @@ -93,13 +93,20 @@ case 'n': namespace = 1; break; + case 'h': + usage(0); + case 'l': + printf("%s has a you choose license: BSD 3-clause or GPL2\n" + "Copyright (c) 1997,2007 Andrew G. Morgan" + " <mor...@kernel.org>\n", argv[0]); + exit(0); default: - usage(); + usage(1); } } if (!argv[optind]) - usage(); + usage(1); for (i=optind; argv[i] != NULL; i++) { struct stat stbuf; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/progs/getpcaps.c new/libcap-2.47/progs/getpcaps.c --- old/libcap-2.46/progs/getpcaps.c 2020-07-01 04:43:01.000000000 +0200 +++ new/libcap-2.47/progs/getpcaps.c 2020-12-29 02:01:07.000000000 +0100 @@ -11,19 +11,19 @@ #include <stdlib.h> #include <sys/capability.h> -static void usage(int exiter) +static void usage(int code) { fprintf(stderr, "usage: getcaps <pid> [<pid> ...]\n\n" " This program displays the capabilities on the queried process(es).\n" -" The capabilities are displayed in the cap_from_text(3) format.\n\n" -" Optional arguments:\n" -" --help or --usage display this message.\n" -" --verbose use a more verbose output format.\n" -" --ugly or --legacy use the archaic legacy output format.\n\n" -"[Copyright (c) 1997-8,2007,2019 Andrew G. Morgan <mor...@kernel.org>]\n" - ); - exit(exiter); + " The capabilities are displayed in the cap_from_text(3) format.\n" + "\n" + " Optional arguments:\n" + " --help, -h or --usage display this message.\n" + " --verbose use a more verbose output format.\n" + " --ugly or --legacy use the archaic legacy output format.\n" + " --license display license info\n"); + exit(code); } int main(int argc, char **argv) @@ -40,8 +40,14 @@ int pid; cap_t cap_d; - if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "--usage")) { + if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "--usage") || + !strcmp(argv[0], "-h")) { usage(0); + } else if (!strcmp(argv[0], "--license")) { + printf("%s has a you choose license: BSD 3-clause or GPL2\n" +"[Copyright (c) 1997-8,2007,2019 Andrew G. Morgan <mor...@kernel.org>]\n", + argv[0]); + exit(0); } else if (!strcmp(argv[0], "--verbose")) { verbose = 1; continue; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/progs/setcap.c new/libcap-2.47/progs/setcap.c --- old/libcap-2.46/progs/setcap.c 2020-07-01 04:43:01.000000000 +0200 +++ new/libcap-2.47/progs/setcap.c 2020-12-29 02:01:07.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997,2007-8 Andrew G. Morgan <mor...@kernel.org> + * Copyright (c) 1997,2007-8,2020 Andrew G. Morgan <mor...@kernel.org> * * This sets/verifies the capabilities of a given file. */ @@ -11,15 +11,24 @@ #include <sys/capability.h> #include <unistd.h> -static void usage(void) +static void usage(int status) { fprintf(stderr, - "usage: setcap [-q] [-v] [-n <rootid>] (-r|-|<caps>) <filename> " + "usage: setcap [-h] [-q] [-v] [-n <rootid>] (-r|-|<caps>) <filename> " "[ ... (-r|-|<capsN>) <filenameN> ]\n" "\n" " Note <filename> must be a regular (non-symlink) file.\n" + " -r remove capability from file\n" + " - read capability text from stdin\n" + " <capsN> cap_from_text(3) formatted file capability\n" + "\n" + " -h this message and exit status 0\n" + " -q quietly\n" + " -v validate supplied capability matches file\n" + " -n <rootid> write a user namespace limited capability\n" + " --license display the license info\n" ); - exit(1); + exit(status); } #define MAXCAP 2048 @@ -65,8 +74,8 @@ cap_value_t capflag; uid_t rootid = 0, f_rootid; - if (argc < 3) { - usage(); + if (argc < 2) { + usage(1); } mycaps = cap_get_proc(); @@ -83,6 +92,16 @@ quiet = 1; continue; } + if (!strcmp("--license", *argv)) { + printf( + "%s has a you choose license: BSD 3-clause or GPL2\n" + "Copyright (c) 1997,2007-8,2020 Andrew G. Morgan" + " <mor...@kernel.org>\n", argv[0]); + exit(0); + } + if (!strcmp(*argv, "-h")) { + usage(0); + } if (!strcmp(*argv, "-v")) { verify = 1; continue; @@ -107,7 +126,7 @@ if (!strcmp(*argv,"-")) { retval = read_caps(quiet, *argv, buffer); if (retval) - usage(); + usage(1); text = buffer; } else { text = *argv; @@ -116,7 +135,7 @@ cap_d = cap_from_text(text); if (cap_d == NULL) { perror("fatal error"); - usage(); + usage(1); } if (cap_set_nsowner(cap_d, rootid)) { perror("unable to set nsowner"); @@ -134,7 +153,7 @@ } if (--argc <= 0) - usage(); + usage(1); /* * Set the filesystem capability for this file. */ @@ -194,6 +213,7 @@ if (retval != 0) { int explained = 0; int oerrno = errno; + int somebits = 0; #ifdef linux cap_value_t cap; cap_flag_value_t per_state; @@ -201,24 +221,28 @@ for (cap = 0; cap_get_flag(cap_d, cap, CAP_PERMITTED, &per_state) != -1; cap++) { - cap_flag_value_t inh_state, eff_state; + cap_flag_value_t inh_state, eff_state, combined; cap_get_flag(cap_d, cap, CAP_INHERITABLE, &inh_state); cap_get_flag(cap_d, cap, CAP_EFFECTIVE, &eff_state); - if ((inh_state | per_state) != eff_state) { - fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n" - " exactly match the union of selected permitted and inheritable bits.\n"); + combined = (inh_state | per_state); + somebits |= !!eff_state; + if (combined != eff_state) { explained = 1; break; } } + if (somebits && explained) { + fprintf(stderr, "NOTE: Under Linux, effective file capabilities must either be empty, or\n" + " exactly match the union of selected permitted and inheritable bits.\n"); + } #endif /* def linux */ - + fprintf(stderr, "Failed to set capabilities on file `%s' (%s)\n", argv[0], strerror(oerrno)); if (!explained) { - usage(); + usage(1); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/psx/psx.go new/libcap-2.47/psx/psx.go --- old/libcap-2.46/psx/psx.go 2020-12-12 08:57:35.000000000 +0100 +++ new/libcap-2.47/psx/psx.go 2020-12-24 01:46:18.000000000 +0100 @@ -1,5 +1,5 @@ // +build linux,!cgo -// +build go1.16 allthreadssyscall +// +build go1.16 package psx // import "kernel.org/pub/linux/libs/security/libcap/psx" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libcap-2.46/tests/libcap_launch_test.c new/libcap-2.47/tests/libcap_launch_test.c --- old/libcap-2.46/tests/libcap_launch_test.c 2020-10-18 22:55:28.000000000 +0200 +++ new/libcap-2.47/tests/libcap_launch_test.c 2020-12-29 02:01:07.000000000 +0100 @@ -70,7 +70,8 @@ .iab = "!^cap_chown" }, { - .args = { "../progs/tcapsh-static", "--inmode=NOPRIV" }, + .args = { "../progs/tcapsh-static", "--inmode=NOPRIV", + "--has-no-new-privs" }, .result = 0, .mode = CAP_MODE_NOPRIV },