aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--sandbox/container.go2
-rw-r--r--sandbox/init.go17
-rw-r--r--sandbox/syscall.go12
-rw-r--r--test/test.py7
4 files changed, 30 insertions, 8 deletions
diff --git a/sandbox/container.go b/sandbox/container.go
index 70929bb1..f2595c38 100644
--- a/sandbox/container.go
+++ b/sandbox/container.go
@@ -165,7 +165,7 @@ func (p *Container) Start() error {
syscall.CLONE_NEWNS,
// remain privileged for setup
- AmbientCaps: []uintptr{CAP_SYS_ADMIN},
+ AmbientCaps: []uintptr{CAP_SYS_ADMIN, CAP_SETPCAP},
UseCgroupFD: p.Cgroup != nil,
}
diff --git a/sandbox/init.go b/sandbox/init.go
index 11167679..437eb7aa 100644
--- a/sandbox/init.go
+++ b/sandbox/init.go
@@ -108,6 +108,9 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
}
}
+ // cache sysctl before pivot_root
+ LastCap()
+
/*
set up mount points from intermediate root
*/
@@ -217,15 +220,21 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
load seccomp filter
*/
- if _, _, err := syscall.Syscall(PR_SET_NO_NEW_PRIVS, 1, 0, 0); err != 0 {
- log.Fatalf("prctl(PR_SET_NO_NEW_PRIVS): %v", err)
+ if _, _, errno := syscall.Syscall(PR_SET_NO_NEW_PRIVS, 1, 0, 0); errno != 0 {
+ log.Fatalf("prctl(PR_SET_NO_NEW_PRIVS): %v", errno)
+ }
+ if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0); errno != 0 {
+ log.Fatalf("cannot clear the ambient capability set: %v", errno)
+ }
+ for i := uintptr(0); i <= LastCap(); i++ {
+ if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_CAPBSET_DROP, i, 0); errno != 0 {
+ log.Fatalf("cannot drop capability: %v", errno)
+ }
}
if err := seccomp.Load(params.Flags.seccomp(params.Seccomp)); err != nil {
log.Fatalf("cannot load syscall filter: %v", err)
}
- /* at this point CAP_SYS_ADMIN can be dropped, however it is kept for now as it does not increase attack surface */
-
/*
pass through extra files
*/
diff --git a/sandbox/syscall.go b/sandbox/syscall.go
index d477dbc0..a92fa173 100644
--- a/sandbox/syscall.go
+++ b/sandbox/syscall.go
@@ -3,9 +3,15 @@ package sandbox
import "syscall"
const (
- O_PATH = 0x200000
+ O_PATH = 0x200000
+
PR_SET_NO_NEW_PRIVS = 0x26
- CAP_SYS_ADMIN = 0x15
+
+ PR_CAP_AMBIENT = 47
+ PR_CAP_AMBIENT_CLEAR_ALL = 4
+
+ CAP_SYS_ADMIN = 0x15
+ CAP_SETPCAP = 8
)
const (
@@ -15,7 +21,7 @@ const (
func SetDumpable(dumpable uintptr) error {
// linux/sched/coredump.h
- if _, _, errno := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_DUMPABLE, dumpable, 0); errno != 0 {
+ if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_SET_DUMPABLE, dumpable, 0); errno != 0 {
return errno
}
diff --git a/test/test.py b/test/test.py
index 1b3bef0f..9288bb87 100644
--- a/test/test.py
+++ b/test/test.py
@@ -99,6 +99,13 @@ print(denyOutputVerbose)
# Fail direct fsu call:
print(machine.fail("sudo -u alice -i fsu"))
+# Verify capabilities/securebits in user namespace:
+print(machine.succeed("sudo -u alice -i fortify run capsh --has-no-new-privs"))
+print(machine.fail("sudo -u alice -i fortify run capsh --has-a=CAP_SYS_ADMIN"))
+print(machine.fail("sudo -u alice -i fortify run capsh --has-b=CAP_SYS_ADMIN"))
+print(machine.fail("sudo -u alice -i fortify run capsh --has-p=CAP_SYS_ADMIN"))
+print(machine.fail("sudo -u alice -i fortify run umount -R /dev"))
+
# Verify PrintBaseError behaviour:
if denyOutput != "fsu: uid 1001 is not in the fsurc file\n":
raise Exception(f"unexpected deny output:\n{denyOutput}")