aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource/linux_common.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-03-05 12:07:59 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-03-05 12:10:27 +0100
commit42467f5b7bf4eef20f78f796fc6eb10401784d86 (patch)
tree6dd3caddad413b777f407abdcd1969b15cb40a84 /pkg/csource/linux_common.go
parente91c118db99874bef7e2cd657505aa4bafbbb6fa (diff)
sys/linux: add syz_init_net_socket syscall
The new pseudo syscall allows opening sockets that can only be created in init net namespace (BLUETOOTH, NFC, LLC). Use it to open these sockets. Unfortunately this only works with sandbox none at the moment. The problem is that setns of a network namespace requires CAP_SYS_ADMIN in the target namespace, and we've lost all privs in the init namespace during creation of a user namespace.
Diffstat (limited to 'pkg/csource/linux_common.go')
-rw-r--r--pkg/csource/linux_common.go52
1 files changed, 48 insertions, 4 deletions
diff --git a/pkg/csource/linux_common.go b/pkg/csource/linux_common.go
index 5b630e4fe..ee92f9fe5 100644
--- a/pkg/csource/linux_common.go
+++ b/pkg/csource/linux_common.go
@@ -113,11 +113,19 @@ var commonHeaderLinux = `
#include <sys/ioctl.h>
#include <sys/stat.h>
#endif
+#if defined(SYZ_EXECUTOR) || defined(__NR_syz_init_net_socket)
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
defined(SYZ_USE_TMP_DIR) || defined(SYZ_HANDLE_SEGV) || defined(SYZ_TUN_ENABLE) || \
defined(SYZ_SANDBOX_NAMESPACE) || defined(SYZ_SANDBOX_SETUID) || \
- defined(SYZ_SANDBOX_NONE) || defined(SYZ_FAULT_INJECTION) || defined(__NR_syz_kvm_setup_cpu)
+ defined(SYZ_SANDBOX_NONE) || defined(SYZ_FAULT_INJECTION) || \
+ defined(__NR_syz_kvm_setup_cpu) || defined(__NR_syz_init_net_socket)
__attribute__((noreturn)) static void doexit(int status)
{
volatile unsigned i;
@@ -193,9 +201,10 @@ const int kRetryStatus = 69;
const int kErrorStatus = 68;
#endif
-#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
- defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \
- defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(__NR_syz_kvm_setup_cpu)
+#if defined(SYZ_EXECUTOR) || (defined(SYZ_REPEAT) && defined(SYZ_WAIT_REPEAT)) || \
+ defined(SYZ_USE_TMP_DIR) || defined(SYZ_TUN_ENABLE) || defined(SYZ_SANDBOX_NAMESPACE) || \
+ defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(__NR_syz_kvm_setup_cpu) || \
+ defined(__NR_syz_init_net_socket)
NORETURN PRINTF static void fail(const char* msg, ...)
{
int e = errno;
@@ -797,6 +806,32 @@ static uintptr_t syz_fuseblk_mount(uintptr_t a0, uintptr_t a1, uintptr_t a2, uin
}
#endif
+#if defined(SYZ_EXECUTOR) || defined(__NR_syz_init_net_socket)
+#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NONE) || defined(SYZ_SANDBOX_SETUID) || defined(SYZ_SANDBOX_NAMESPACE)
+const int kInitNetNsFd = 253;
+static uintptr_t syz_init_net_socket(uintptr_t domain, uintptr_t type, uintptr_t proto)
+{
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ return netns;
+ if (setns(kInitNetNsFd, 0))
+ return -1;
+ int sock = syscall(__NR_socket, domain, type, proto);
+ int err = errno;
+ if (setns(netns, 0))
+ fail("setns(netns) failed");
+ close(netns);
+ errno = err;
+ return sock;
+}
+#else
+static uintptr_t syz_init_net_socket(uintptr_t domain, uintptr_t type, uintptr_t proto)
+{
+ return syscall(__NR_socket, domain, type, proto);
+}
+#endif
+#endif
+
#if defined(SYZ_EXECUTOR) || defined(__NR_syz_kvm_setup_cpu)
#if defined(__x86_64__)
@@ -1771,6 +1806,15 @@ static void sandbox_common()
setpgrp();
setsid();
+#if defined(SYZ_EXECUTOR) || defined(__NR_syz_init_net_socket)
+ int netns = open("/proc/self/ns/net", O_RDONLY);
+ if (netns == -1)
+ fail("open(/proc/self/ns/net) failed");
+ if (dup2(netns, kInitNetNsFd) < 0)
+ fail("dup2(netns, kInitNetNsFd) failed");
+ close(netns);
+#endif
+
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = 128 << 20;
setrlimit(RLIMIT_AS, &rlim);