aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
Diffstat (limited to 'executor')
-rw-r--r--executor/common_linux.h98
-rw-r--r--executor/syscalls_linux.h10
2 files changed, 84 insertions, 24 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h
index 3ad7d374f..e61a42902 100644
--- a/executor/common_linux.h
+++ b/executor/common_linux.h
@@ -263,6 +263,7 @@ static void execute_command(const char* format, ...)
}
static int tunfd = -1;
+static int tun_frags_enabled;
// We just need this to be large enough to hold headers that we parse (ethernet/ip/tcp).
// Rest of the packet (if any) will be silently truncated which is fine.
@@ -281,6 +282,13 @@ static int tunfd = -1;
#define LOCAL_IPV6 "fe80::%02hxaa"
#define REMOTE_IPV6 "fe80::%02hxbb"
+#ifndef IFF_NAPI
+#define IFF_NAPI 0x0010
+#endif
+#ifndef IFF_NAPI_FRAGS
+#define IFF_NAPI_FRAGS 0x0020
+#endif
+
static void initialize_tun(uint64_t pid)
{
if (pid >= MAX_PIDS)
@@ -297,9 +305,19 @@ static void initialize_tun(uint64_t pid)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
- fail("tun: ioctl(TUNSETIFF) failed");
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
+ // IFF_NAPI_FRAGS requires root, so try without it.
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
+ fail("tun: ioctl(TUNSETIFF) failed");
+ }
+ // If IFF_NAPI_FRAGS is not supported it will be silently dropped,
+ // so query the effective flags.
+ if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
+ fail("tun: ioctl(TUNGETIFF) failed");
+ tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
+ debug("tun_frags_enabled=%d\n", tun_frags_enabled);
char local_mac[ADDR_MAX_LEN];
snprintf_check(local_mac, sizeof(local_mac), LOCAL_MAC, id);
@@ -345,7 +363,10 @@ static int read_tun(char* data, int size)
if (rv < 0) {
if (errno == EAGAIN)
return -1;
- fail("tun: read failed with %d, errno: %d", rv, errno);
+ // Tun sometimes returns this, unclear if it's a kernel bug or not.
+ if (errno == EBADFD)
+ return -1;
+ fail("tun: read failed with %d", rv);
}
return rv;
}
@@ -366,17 +387,60 @@ static void debug_dump_data(const char* data, int length)
#endif
#if defined(SYZ_EXECUTOR) || (defined(__NR_syz_emit_ethernet) && defined(SYZ_TUN_ENABLE))
-static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1)
-{
- // syz_emit_ethernet(len len[packet], packet ptr[in, eth_packet])
+#define MAX_FRAGS 4
+struct vnet_fragmentation {
+ uint32_t full;
+ uint32_t count;
+ uint32_t frags[MAX_FRAGS];
+};
+static uintptr_t syz_emit_ethernet(uintptr_t a0, uintptr_t a1, uintptr_t a2)
+{
+ // syz_emit_ethernet(len len[packet], packet ptr[in, eth_packet], frags ptr[in, vnet_fragmentation, opt])
+ // vnet_fragmentation {
+ // full int32[0:1]
+ // count len[frags, int32]
+ // frags array[int32[0:4096], 1:4]
+ // }
if (tunfd < 0)
return (uintptr_t)-1;
- int64_t length = a0;
+ uint32_t length = a0;
char* data = (char*)a1;
debug_dump_data(data, length);
- return write(tunfd, data, length);
+
+ struct vnet_fragmentation* frags = (struct vnet_fragmentation*)a2;
+ struct iovec vecs[MAX_FRAGS + 1];
+ uint32_t nfrags = 0;
+ if (!tun_frags_enabled || frags == NULL) {
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = length;
+ nfrags++;
+ } else {
+ bool full = true;
+ uint32_t i, count = 0;
+ NONFAILING(full = frags->full);
+ NONFAILING(count = frags->count);
+ if (count > MAX_FRAGS)
+ count = MAX_FRAGS;
+ for (i = 0; i < count && length != 0; i++) {
+ uint32_t size = 0;
+ NONFAILING(size = frags->frags[i]);
+ if (size > length)
+ size = length;
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = size;
+ nfrags++;
+ data += size;
+ length -= size;
+ }
+ if (length != 0 && (full || nfrags == 0)) {
+ vecs[nfrags].iov_base = data;
+ vecs[nfrags].iov_len = length;
+ nfrags++;
+ }
+ }
+ return writev(tunfd, vecs, nfrags);
}
#endif
@@ -685,8 +749,6 @@ static bool write_file(const char* file, const char* what, ...)
#if defined(SYZ_EXECUTOR) || defined(SYZ_SANDBOX_NAMESPACE)
static int real_uid;
static int real_gid;
-static int epid;
-static bool etun;
__attribute__((aligned(64 << 10))) static char sandbox_stack[1 << 20];
static int namespace_sandbox_proc(void* arg)
@@ -700,12 +762,6 @@ static int namespace_sandbox_proc(void* arg)
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid))
fail("write of /proc/self/gid_map failed");
-#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
- // For sandbox namespace we setup tun after initializing uid mapping,
- // otherwise ip commands fail.
- setup_tun(epid, etun);
-#endif
-
if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed");
if (mount("", "./syz-tmp", "tmpfs", 0, NULL))
@@ -759,10 +815,14 @@ static int namespace_sandbox_proc(void* arg)
static int do_sandbox_namespace(int executor_pid, bool enable_tun)
{
+#if defined(SYZ_EXECUTOR) || defined(SYZ_TUN_ENABLE)
+ // For sandbox namespace we setup tun before dropping privs,
+ // because IFF_NAPI_FRAGS requires root.
+ setup_tun(executor_pid, enable_tun);
+#endif
+
real_uid = getuid();
real_gid = getgid();
- epid = executor_pid;
- etun = enable_tun;
mprotect(sandbox_stack, 4096, PROT_NONE); // to catch stack underflows
return clone(namespace_sandbox_proc, &sandbox_stack[sizeof(sandbox_stack) - 64],
CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWUTS | CLONE_NEWNET, NULL);
diff --git a/executor/syscalls_linux.h b/executor/syscalls_linux.h
index b30807290..2f5842e1c 100644
--- a/executor/syscalls_linux.h
+++ b/executor/syscalls_linux.h
@@ -2,7 +2,7 @@
#if defined(__i386__) || 0
#define GOARCH "386"
-#define SYZ_REVISION "7b2f1949d48094cf3369932d0743db166049457b"
+#define SYZ_REVISION "20782fd14495c17a4a404316929c89e9d66373d6"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@@ -1501,7 +1501,7 @@ call_t syscalls[] = {
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
-#define SYZ_REVISION "8349df62e623f9c8d8bfaefcc8ba3febf463ce92"
+#define SYZ_REVISION "c1ab3550b8fbe92662ee054df76419327b5b72a7"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@@ -3061,7 +3061,7 @@ call_t syscalls[] = {
#if defined(__arm__) || 0
#define GOARCH "arm"
-#define SYZ_REVISION "02567c0623e18214f0be8d059aad68c263064645"
+#define SYZ_REVISION "48d11406b51cb3dad2399863375cfc24d4892473"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@@ -4574,7 +4574,7 @@ call_t syscalls[] = {
#if defined(__aarch64__) || 0
#define GOARCH "arm64"
-#define SYZ_REVISION "0709fe60bdd20ea30d937d14615a40269fadb2b8"
+#define SYZ_REVISION "65746b600515d1f1026ed56961d3450e70d65878"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@@ -6062,7 +6062,7 @@ call_t syscalls[] = {
#if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0
#define GOARCH "ppc64le"
-#define SYZ_REVISION "8bfb8686625fa3398eb8d1a5d66834dec0d3fa06"
+#define SYZ_REVISION "5e9d29319478130f5d8b9238e869d979870e5cb3"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002