aboutsummaryrefslogtreecommitdiffstats
path: root/go
diff options
context:
space:
mode:
authorAndrew G. Morgan <morgan@kernel.org>2019-11-30 18:33:42 -0800
committerAndrew G. Morgan <morgan@kernel.org>2019-12-06 23:06:47 -0800
commitb2b267ef1c83f1f3d3105a4bb84f8bebbc130dec (patch)
treed0be8e0daca097a3911006b9eb85fcf4d2607182 /go
parente9f55d90e482f680504487be6b3afb80865691d6 (diff)
downloadplatform_external_libcap-b2b267ef1c83f1f3d3105a4bb84f8bebbc130dec.tar.gz
platform_external_libcap-b2b267ef1c83f1f3d3105a4bb84f8bebbc130dec.tar.bz2
platform_external_libcap-b2b267ef1c83f1f3d3105a4bb84f8bebbc130dec.zip
Add support to libcap for overriding system call functions.
Note, this override only supports the system calls that libcap uses to change kernel state associated with the current process. This is primarily intended to permit the user to use libpsx to force all pthreads to mirror capability and other security relevant state. Use a weak function definition feature of libpsx share_psx_syscall() to transparently arrange for libcap to so force itself to use the psx_syscall() abstraction when linked against -lpsx. This has the effect of using linker magic to make libcap transparently observe POSIX semantics for security state setting operations. That is, when linked as follows: gcc .... -lcap -lpsx -lpthread -Wl,-wrap,pthread_create all pthreads maintain a common security state with respect to the libcap API. This also adds full capability setting support to the Go package libcap/cap via a libcap/psx package which uses cgo+libpsx syscalls that share capabilities over all pthreads including those of the Go runtime. Finally, if Go supports syscall.PosixSyscall() etc. then provide a non-psx mechanism for libcap/cap to "just work" in all Go code. Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
Diffstat (limited to 'go')
-rw-r--r--go/Makefile49
-rwxr-xr-xgo/syscalls.sh67
-rw-r--r--go/web.go20
3 files changed, 101 insertions, 35 deletions
diff --git a/go/Makefile b/go/Makefile
index 0791768..363b664 100644
--- a/go/Makefile
+++ b/go/Makefile
@@ -4,15 +4,33 @@
topdir=$(realpath ..)
include ../Make.Rules
-all:
- $(MAKE) compare-cap
- $(MAKE) web
- ./compare-cap
+GOPATH="$(realpath .)"
+PSXGOPACKAGE=pkg/$(GOOSARCH)/libcap/psx.a
+CAPGOPACKAGE=pkg/$(GOOSARCH)/libcap/cap.a
+
+all: $(PSXGOPACKAGE) $(CAPGOPACKAGE) web compare-cap
+
+# $(MAKE) compare-cap
+# $(MAKE) web
+# ./compare-cap
+
+src/libcap/psx:
+ mkdir -p src/libcap
+ ln -s $(realpath ..)/psx src/libcap/
src/libcap/cap:
mkdir -p src/libcap
ln -s $(realpath ..)/cap src/libcap/
+$(PSXGOPACKAGE): src/libcap/psx ../psx/psx.go ../psx/psx_test.go
+ CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH="$(GOPATH)" go test libcap/psx
+ mkdir -p pkg
+ CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH="$(GOPATH)" go build libcap/psx
+
+$(CAPGOPACKAGE): src/libcap/cap/syscalls.go src/libcap/cap/names.go src/libcap/cap/cap.go src/libcap/cap/text.go
+ CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(realpath .) go test libcap/cap
+ CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(realpath .) go build libcap/cap
+
install: all
# TODO - install the Go package somewhere useful (ex. /usr/share/gocode/src/libcap/cap/ )
@@ -22,25 +40,20 @@ install: all
src/libcap/cap/names.go: ../libcap/cap_names.h src/libcap/cap mknames.go
go run mknames.go --header=$< | gofmt > $@ || rm -f $@
-src/libcap/cap/syscalls.go: src/libcap/cap ./syscalls.sh
- ./syscalls.sh > $@
-
-GOPACKAGE=pkg/$(GOOSARCH)/libcap/cap.a
-$(GOPACKAGE): src/libcap/cap/syscalls.go src/libcap/cap/names.go src/libcap/cap/cap.go src/libcap/cap/text.go
- echo testing Go package
- GOPATH=$(realpath .) go test libcap/cap
- echo building $(GOPACKAGE)
- mkdir -p pkg
+src/libcap/cap/syscalls.go: ./syscalls.sh src/libcap/cap
+ ./syscalls.sh src/libcap/cap
# Compile and run something with this package and compare it to libcap.
-compare-cap: compare-cap.go $(GOPACKAGE)
- GOPATH=$(realpath .) go build $<
+compare-cap: compare-cap.go $(CAPGOPACKAGE)
+ CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(realpath .) go build $<
-web: web.go $(GOPACKAGE)
- GOPATH=$(realpath .) go build $<
+web: web.go $(CAPGOPACKAGE)
+ CGO_LDFLAGS_ALLOW="$(CGO_LDFLAGS_ALLOW)" CGO_CFLAGS="$(CGO_CFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" GOPATH=$(realpath .) go build $<
clean:
GOPATH=$(realpath .) go clean -x -i libcap/cap 2> /dev/null || exit 0
+ GOPATH=$(realpath .) go clean -x -i libcap/psx 2> /dev/null || exit 0
rm -f *.o *.so mknames web compare-cap *~
- rm -f ../cap/*~ ../cap/names.go ../cap/syscalls.go
+ rm -f ../cap/*~ ../cap/names.go ../cap/syscalls*.go
+ rm -f ../psx/*~
rm -fr pkg src
diff --git a/go/syscalls.sh b/go/syscalls.sh
index 4966742..eeba450 100755
--- a/go/syscalls.sh
+++ b/go/syscalls.sh
@@ -1,27 +1,72 @@
#!/bin/bash
-cat <<EOF
+dir="$1"
+if [[ -z "$dir" ]]; then
+ echo need an argument directory
+ exit 1
+fi
+
+# This is something that we should revisit if golang adopts my
+# syscall.PosixSyscall patch. At that stage, we won't need cgo to
+# support a pure Go program. However, we will need a to use the cgo
+# version if the program being compiled actually needs cgo. That is,
+# we should have two permenant files that use +build lines to control
+# which one is built based on cgo or not.
+
+if [ -z "$(go doc syscall 2>/dev/null|grep PosixSyscall)" ]; then
+ rm -f "${dir}/syscalls_cgo.go"
+ cat > "${dir}/syscalls.go" <<EOF
+// +build linux
+
package cap
-import "syscall"
+import (
+ "libcap/psx"
+ "syscall"
+)
// callKernel variables overridable for testing purposes.
+// (Go build tree has no syscall.PosixSyscall support.)
+var callWKernel = psx.Syscall3
+var callWKernel6 = psx.Syscall6
+var callRKernel = syscall.RawSyscall
+var callRKernel6 = syscall.RawSyscall6
EOF
-if [ -n "$(go doc syscall 2>/dev/null|grep PosixSyscall)" ]; then
- cat <<EOF
-// (Go build tree contains PosixSyscall support.)
+ exit 0
+fi
+
+# pure Go support.
+cat > "${dir}/syscalls.go" <<EOF
+// +build linux,!cgo
+
+package cap
+
+import "syscall"
+
+// callKernel variables overridable for testing purposes.
+// (Go build tree contains syscall.PosixSyscall support.)
var callWKernel = syscall.PosixSyscall
var callWKernel6 = syscall.PosixSyscall6
var callRKernel = syscall.RawSyscall
var callRKernel6 = syscall.RawSyscall6
EOF
-else
- cat <<EOF
-// (Go build tree does not contain PosixSyscall support.)
-var callWKernel = syscall.RawSyscall
-var callWKernel6 = syscall.RawSyscall6
+
+cat > "${dir}/syscalls_cgo.go" <<EOF
+// +build linux,cgo
+
+package cap
+
+import (
+ "libcap/psx"
+ "syscall"
+)
+
+// callKernel variables overridable for testing purposes.
+// We use this version when we are cgo compiling because
+// we need to manage the native C pthreads too.
+var callWKernel = psx.Syscall3
+var callWKernel6 = psx.Syscall6
var callRKernel = syscall.RawSyscall
var callRKernel6 = syscall.RawSyscall6
EOF
-fi
diff --git a/go/web.go b/go/web.go
index 0d5a943..70a9668 100644
--- a/go/web.go
+++ b/go/web.go
@@ -1,15 +1,23 @@
// Progam web provides an example of a webserver using capabilities to
-// bind to a privileged port.
+// bind to a privileged port, and then drop all capabilities before
+// handling the first web request.
//
-// This program will not work reliably without the equivalent of
-// the Go runtime patch that adds a POSIX semantics wrappers around
-// the system calls that change kernel state. A patch for the Go
-// compiler/runtime to add this support is available here [2019-11-16]:
+// This program cannot work reliably as a pure Go application without
+// the equivalent of the Go runtime patch that adds a POSIX semantics
+// wrapper around the system calls that change kernel state. A patch
+// for the pure Go compiler/runtime to add this support is available
+// here [2019-11-16]:
//
// https://git.kernel.org/pub/scm/libs/libcap/libcap.git/tree/contrib/golang/go.patch
//
+// Until that patch, or something like it, is absorbed into the Go
+// runtime the only way to get capabilities to work reliably on the Go
+// runtime is to use something like libpsx to do capability setting
+// syscalls in C with POSIX semantics. As of this build of the Go
+// libcap/cap package, this is how things work.
+//
// To set this up, compile and empower this binary as follows (package
-// libcap/cap should be installed):
+// libcap/cap should be installed, as must libpsx.a):
//
// go build web.go
// sudo setcap cap_net_bind_service=p web