From 5181b54d45a7f7a1bd67396a8a9721ad512134fe Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 22 Jul 2019 11:15:52 +0200 Subject: [PATCH] executor: drop CAP_SYS_PTRACE with sandbox=none We only drop CAP_SYS_PTRACE for sandbox=namespace, but it can equally affect testing with sandbox=none. Drop it for sandbox=none, add a test. --- executor/common_linux.h | 42 ++++++++++++++++++++++++---------------- pkg/csource/generated.go | 34 ++++++++++++++++++++------------ sys/linux/test/caps | 5 +++++ sys/linux/test/vusb | 1 + 4 files changed, 53 insertions(+), 29 deletions(-) create mode 100644 sys/linux/test/caps diff --git a/executor/common_linux.h b/executor/common_linux.h index ff3126641fe0..682425a3dc4f 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -1976,6 +1976,29 @@ int wait_for_loop(int pid) } #endif +#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_NAMESPACE +#include + +static void drop_caps(void) +{ + // Drop CAP_SYS_PTRACE so that test processes can't attach to parent processes. + // Previously it lead to hangs because the loop process stopped due to SIGSTOP. + // Note that a process can always ptrace its direct children, which is enough for testing purposes. + struct __user_cap_header_struct cap_hdr = {}; + struct __user_cap_data_struct cap_data[2] = {}; + cap_hdr.version = _LINUX_CAPABILITY_VERSION_3; + cap_hdr.pid = getpid(); + if (syscall(SYS_capget, &cap_hdr, &cap_data)) + fail("capget failed"); + const int drop = (1 << CAP_SYS_PTRACE); + cap_data[0].effective &= ~drop; + cap_data[0].permitted &= ~drop; + cap_data[0].inheritable &= ~drop; + if (syscall(SYS_capset, &cap_hdr, &cap_data)) + fail("capset failed"); +} +#endif + #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE #include #include @@ -1997,6 +2020,7 @@ static int do_sandbox_none(void) setup_common(); sandbox_common(); + drop_caps(); #if SYZ_EXECUTOR || SYZ_ENABLE_NETDEV initialize_netdevices_init(); #endif @@ -2063,7 +2087,6 @@ static int do_sandbox_setuid(void) #endif #if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE -#include #include #include #include @@ -2151,22 +2174,7 @@ static int namespace_sandbox_proc(void* arg) fail("chroot failed"); if (chdir("/")) fail("chdir failed"); - - // Drop CAP_SYS_PTRACE so that test processes can't attach to parent processes. - // Previously it lead to hangs because the loop process stopped due to SIGSTOP. - // Note that a process can always ptrace its direct children, which is enough - // for testing purposes. - struct __user_cap_header_struct cap_hdr = {}; - struct __user_cap_data_struct cap_data[2] = {}; - cap_hdr.version = _LINUX_CAPABILITY_VERSION_3; - cap_hdr.pid = getpid(); - if (syscall(SYS_capget, &cap_hdr, &cap_data)) - fail("capget failed"); - cap_data[0].effective &= ~(1 << CAP_SYS_PTRACE); - cap_data[0].permitted &= ~(1 << CAP_SYS_PTRACE); - cap_data[0].inheritable &= ~(1 << CAP_SYS_PTRACE); - if (syscall(SYS_capset, &cap_hdr, &cap_data)) - fail("capset failed"); + drop_caps(); loop(); doexit(1); diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 1dc6bf4c6216..eb863e8e19b9 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -4430,6 +4430,26 @@ int wait_for_loop(int pid) } #endif +#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_NAMESPACE +#include + +static void drop_caps(void) +{ + struct __user_cap_header_struct cap_hdr = {}; + struct __user_cap_data_struct cap_data[2] = {}; + cap_hdr.version = _LINUX_CAPABILITY_VERSION_3; + cap_hdr.pid = getpid(); + if (syscall(SYS_capget, &cap_hdr, &cap_data)) + fail("capget failed"); + const int drop = (1 << CAP_SYS_PTRACE); + cap_data[0].effective &= ~drop; + cap_data[0].permitted &= ~drop; + cap_data[0].inheritable &= ~drop; + if (syscall(SYS_capset, &cap_hdr, &cap_data)) + fail("capset failed"); +} +#endif + #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE #include #include @@ -4445,6 +4465,7 @@ static int do_sandbox_none(void) setup_common(); sandbox_common(); + drop_caps(); #if SYZ_EXECUTOR || SYZ_ENABLE_NETDEV initialize_netdevices_init(); #endif @@ -4507,7 +4528,6 @@ static int do_sandbox_setuid(void) #endif #if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE -#include #include #include #include @@ -4585,17 +4605,7 @@ static int namespace_sandbox_proc(void* arg) fail("chroot failed"); if (chdir("/")) fail("chdir failed"); - struct __user_cap_header_struct cap_hdr = {}; - struct __user_cap_data_struct cap_data[2] = {}; - cap_hdr.version = _LINUX_CAPABILITY_VERSION_3; - cap_hdr.pid = getpid(); - if (syscall(SYS_capget, &cap_hdr, &cap_data)) - fail("capget failed"); - cap_data[0].effective &= ~(1 << CAP_SYS_PTRACE); - cap_data[0].permitted &= ~(1 << CAP_SYS_PTRACE); - cap_data[0].inheritable &= ~(1 << CAP_SYS_PTRACE); - if (syscall(SYS_capset, &cap_hdr, &cap_data)) - fail("capset failed"); + drop_caps(); loop(); doexit(1); diff --git a/sys/linux/test/caps b/sys/linux/test/caps new file mode 100644 index 000000000000..f3ef3a9e025c --- /dev/null +++ b/sys/linux/test/caps @@ -0,0 +1,5 @@ +# Ensure that test processes don't have capabilities to do dangerious things, +# see drop_caps function in executor for details. +# requires: -sandbox= + +ptrace(0x10, 0x1) # EPERM diff --git a/sys/linux/test/vusb b/sys/linux/test/vusb index 0593b4c83232..16c7780f2bc1 100644 --- a/sys/linux/test/vusb +++ b/sys/linux/test/vusb @@ -2,4 +2,5 @@ # Temporary disabled because deserialization fails (run go test ./pkg/csource). #syz_usb_connect(0x0, 0x24, &(0x7f0000000000)={0x12, 0x1, 0x0, 0x97, 0xff, 0x82, 0x8, 0x2058, 0x1005, 0xc19b, 0x0, 0x0, 0x0, 0x1, [{0x9, 0x2, 0x12, 0x1, 0x0, 0x0, 0x0, 0x0, [{0x9, 0x4, 0x8f, 0x0, 0x0, 0xbf, 0x57, 0x5a, 0x0, [], []}]}]}, 0x0) + getpid()