aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2020-07-05 12:50:08 -0700
committerAndrew G. Morgan <morgan@kernel.org>2020-07-05 12:50:08 -0700
commit42afb6ac6b92e4694b97fef5ab1d1fc87d4be0e9 (patch)
treeffe4b8b8ada64856c85738357db869dc6d235f68
parent5457efd92c533259eecde426d9e6bb6abb270d89 (diff)
downloadplatform_external_libcap-42afb6ac6b92e4694b97fef5ab1d1fc87d4be0e9.tar.gz
platform_external_libcap-42afb6ac6b92e4694b97fef5ab1d1fc87d4be0e9.tar.bz2
platform_external_libcap-42afb6ac6b92e4694b97fef5ab1d1fc87d4be0e9.zip
Fix a rare deadlock in cap.Launch().
The main functional change with this commit is to fix this bug: https://bugzilla.kernel.org/show_bug.cgi?id=208445 Also, include better documentation for the "cap" module. Now that it is a proper Go module, it is starting to show up on the automated golang module sites (such as pkg.go.dev) and I thought it deserved more of an intro comment. Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
-rw-r--r--cap/cap.go41
-rw-r--r--cap/launch.go35
2 files changed, 49 insertions, 27 deletions
diff --git a/cap/cap.go b/cap/cap.go
index 976b302..21c286b 100644
--- a/cap/cap.go
+++ b/cap/cap.go
@@ -1,22 +1,35 @@
-// Package cap is the Linux capabilities user space API (libcap)
+// Package cap provides the Linux Capabilities userspace library API
// bindings in native Go.
//
-// For cgo linked binaries, behind the scenes, the package
-// "kernel.org/pub/linux/libs/security/libcap/psx" is used to broker
-// the POSIX semantics system calls that manipulate thread state
-// uniformly over the whole process runtime.
+// Capabilities are a feature of the Linux kernel that allow fine
+// grain permissions to perform privileged operations. Privileged
+// operations are required to do irregular system level operations
+// from code. You can read more about how Capabilities are intended to
+// work here:
//
-// If the Go runtime syscall interface contains the linux variant
-// syscall.AllThreadsSyscall() API (it is not in go1.15beta1 for
-// example) then this package can use that to invoke capability
-// setting system calls for pure Go binaries. To force this behavior
-// use the CGO_ENABLED=0 environment variable and, for now, a build
-// tag:
+// https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/33528.pdf
//
-// CGO_ENABLED=0 go build -tags allthreadssyscall ...
+// This package supports native Go bindings for all the features
+// described in that paper as well as supporting subsequent changes to
+// the kernel for other styles of inheritable Capability.
//
-// If syscall.AllThreadsSyscall() is not present, the ".../libcap/cap"
-// package will failover to using ".../libcap/psx".
+// See https://sites.google.com/site/fullycapable/ for recent updates
+// and information on how to file bugs.
+//
+// For CGo linked binaries, behind the scenes, the package
+// "kernel.org/pub/linux/libs/security/libcap/psx" is used to perform
+// POSIX semantics system calls that manipulate thread state
+// 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.15beta1
+// 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 for pure Go binaries. In such an
+// enhanced Go runtime, to force this behavior, use the CGO_ENABLED=0
+// environment variable and, for now, a build tag:
+//
+// CGO_ENABLED=0 go build -tags allthreadssyscall ...
//
// Copyright (c) 2019,20 Andrew G. Morgan <morgan@kernel.org>
package cap // import "kernel.org/pub/linux/libs/security/libcap/cap"
diff --git a/cap/launch.go b/cap/launch.go
index f4327c2..3d9c81b 100644
--- a/cap/launch.go
+++ b/cap/launch.go
@@ -126,31 +126,40 @@ var lName = []byte("cap-launcher\000")
const prSetName = 15
//go:uintptrescapes
-func launch(result chan<- lResult, attr *Launcher, data interface{}) {
- defer close(result)
+func launch(result chan<- lResult, attr *Launcher, data interface{}, quit chan<- struct{}) {
+ if quit != nil {
+ defer close(quit)
+ }
pid := syscall.Getpid()
// Wait until we are not scheduled on the parent thread. We
// will exit this thread once the child has launched, and
// don't want other goroutines to use this thread afterwards.
- for {
- runtime.LockOSThread()
- tid := syscall.Gettid()
- if tid != pid {
- break
- }
+ runtime.LockOSThread()
+ tid := syscall.Gettid()
+ if tid == pid {
+ // Force the go runtime to find a new thread to run on.
+ quit := make(chan struct{})
+ go launch(result, attr, data, quit)
+
+ // Wait for that go routine to complete.
+ <-quit
runtime.UnlockOSThread()
- runtime.Gosched()
+ return
}
// By never releasing the LockOSThread here, we guarantee that
- // the runtime will terminate this OS thread once this
+ // the runtime will terminate the current OS thread once this
// function returns.
- // Name the launcher thread - transient, but helps if the
- // callbackFn or something else hangs up.
+ // Name the launcher thread - transient, but helps to debug if
+ // the callbackFn or something else hangs up.
singlesc.prctlrcall(prSetName, uintptr(unsafe.Pointer(&lName[0])), 0)
+ // Provide a way to serialize the caller on the thread
+ // completing.
+ defer close(result)
+
pa := &syscall.ProcAttr{
Files: []uintptr{0, 1, 2},
}
@@ -225,7 +234,7 @@ func (attr *Launcher) Launch(data interface{}) (int, error) {
defer scwMu.Unlock()
result := make(chan lResult)
- go launch(result, attr, data)
+ go launch(result, attr, data, nil)
for {
select {
case v, ok := <-result: