diff options
| author | Aleksandr Nogikh <nogikh@google.com> | 2021-10-26 15:15:11 +0000 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2021-10-29 10:10:32 +0200 |
| commit | c40503e1fa86f3027e003118aaf91646a82f2b5d (patch) | |
| tree | da694c2add8430574310be74ea8566d11990f50a | |
| parent | 2353a3ec6e28d26c020ea7176d16d8fafb772e24 (diff) | |
all: add binderfs fuzzing support
Create one instance of binderfs per process and add descriptions to
enable syzkaller to create binderfs mounts and binder devices itself.
Keep descriptions compatible with the legacy mode (when devices are
created at boot time).
| -rw-r--r-- | executor/common_linux.h | 38 | ||||
| -rw-r--r-- | pkg/csource/generated.go | 28 | ||||
| -rw-r--r-- | sys/linux/dev_binder.txt | 10 | ||||
| -rw-r--r-- | sys/linux/dev_binderfs.txt | 40 | ||||
| -rw-r--r-- | sys/linux/dev_binderfs.txt.const | 10 | ||||
| -rw-r--r-- | sys/linux/test/binder | 4 |
6 files changed, 123 insertions, 7 deletions
diff --git a/executor/common_linux.h b/executor/common_linux.h index b4303de1e..6875c88a0 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -3630,6 +3630,8 @@ static void initialize_cgroups() #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID #include <errno.h> #include <sys/mount.h> +#include <sys/stat.h> +#include <unistd.h> static void setup_common() { @@ -3638,6 +3640,31 @@ static void setup_common() } } +static void setup_binderfs() +{ + // NOTE: this function must be called after chroot. + // Bind an instance of binderfs specific just to this executor - it will + // only be visible in its mount namespace and will help isolate binder + // devices during fuzzing. + // These commands will just silently fail if binderfs is not supported. + // Ideally it should have been added as a separate feature (with lots of + // minor changes throughout the code base), but it seems to be an overkill + // for just 2 simple lines of code. + if (mkdir("/dev/binderfs", 0777)) { + debug("mkdir(/dev/binderfs) failed: %d\n", errno); + } + + if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) { + debug("mount of binder at /dev/binderfs failed: %d\n", errno); + } +#if !SYZ_EXECUTOR && !SYZ_USE_TMP_DIR + // Do a local symlink right away. + if (symlink("/dev/binderfs", "./binderfs")) { + debug("symlink(/dev/binderfs, ./binderfs) failed: %d\n", errno); + } +#endif +} + #include <sched.h> #include <sys/prctl.h> #include <sys/resource.h> @@ -3809,6 +3836,7 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR || SYZ_WIFI initialize_wifi_devices(); #endif + setup_binderfs(); loop(); doexit(1); } @@ -3852,6 +3880,7 @@ static int do_sandbox_setuid(void) #if SYZ_EXECUTOR || SYZ_WIFI initialize_wifi_devices(); #endif + setup_binderfs(); const int nobody = 65534; if (setgroups(0, NULL)) @@ -3967,6 +3996,7 @@ static int namespace_sandbox_proc(void* arg) fail("chroot failed"); if (chdir("/")) fail("chdir failed"); + setup_binderfs(); drop_caps(); loop(); @@ -4147,6 +4177,7 @@ static int do_sandbox_android(void) setfilecon(".", SELINUX_LABEL_APP_DATA_FILE); setcon(SELINUX_CONTEXT_UNTRUSTED_APP); + setup_binderfs(); loop(); doexit(1); } @@ -4430,6 +4461,7 @@ static void reset_loop() #if SYZ_EXECUTOR || SYZ_REPEAT #include <sys/prctl.h> +#include <unistd.h> #define SYZ_HAVE_SETUP_TEST 1 static void setup_test() @@ -4446,6 +4478,12 @@ static void setup_test() // isolate consequently executing programs. flush_tun(); #endif +#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR + // Add a binderfs symlink to the tmp folder. + if (symlink("/dev/binderfs", "./binderfs")) { + debug("symlink(/dev/binderfs, ./binderfs) failed: %d", errno); + } +#endif } #endif diff --git a/pkg/csource/generated.go b/pkg/csource/generated.go index 44b6a1297..8b8fadc5c 100644 --- a/pkg/csource/generated.go +++ b/pkg/csource/generated.go @@ -8251,6 +8251,8 @@ static void initialize_cgroups() #if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID #include <errno.h> #include <sys/mount.h> +#include <sys/stat.h> +#include <unistd.h> static void setup_common() { @@ -8259,6 +8261,22 @@ static void setup_common() } } +static void setup_binderfs() +{ + if (mkdir("/dev/binderfs", 0777)) { + debug("mkdir(/dev/binderfs) failed: %d\n", errno); + } + + if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) { + debug("mount of binder at /dev/binderfs failed: %d\n", errno); + } +#if !SYZ_EXECUTOR && !SYZ_USE_TMP_DIR + if (symlink("/dev/binderfs", "./binderfs")) { + debug("symlink(/dev/binderfs, ./binderfs) failed: %d\n", errno); + } +#endif +} + #include <sched.h> #include <sys/prctl.h> #include <sys/resource.h> @@ -8406,6 +8424,7 @@ static int do_sandbox_none(void) #if SYZ_EXECUTOR || SYZ_WIFI initialize_wifi_devices(); #endif + setup_binderfs(); loop(); doexit(1); } @@ -8449,6 +8468,7 @@ static int do_sandbox_setuid(void) #if SYZ_EXECUTOR || SYZ_WIFI initialize_wifi_devices(); #endif + setup_binderfs(); const int nobody = 65534; if (setgroups(0, NULL)) @@ -8549,6 +8569,7 @@ static int namespace_sandbox_proc(void* arg) fail("chroot failed"); if (chdir("/")) fail("chdir failed"); + setup_binderfs(); drop_caps(); loop(); @@ -9217,6 +9238,7 @@ static int do_sandbox_android(void) setfilecon(".", SELINUX_LABEL_APP_DATA_FILE); setcon(SELINUX_CONTEXT_UNTRUSTED_APP); + setup_binderfs(); loop(); doexit(1); } @@ -9477,6 +9499,7 @@ static void reset_loop() #if SYZ_EXECUTOR || SYZ_REPEAT #include <sys/prctl.h> +#include <unistd.h> #define SYZ_HAVE_SETUP_TEST 1 static void setup_test() @@ -9490,6 +9513,11 @@ static void setup_test() #if SYZ_EXECUTOR || SYZ_NET_INJECTION flush_tun(); #endif +#if SYZ_EXECUTOR || SYZ_USE_TMP_DIR + if (symlink("/dev/binderfs", "./binderfs")) { + debug("symlink(/dev/binderfs, ./binderfs) failed: %d", errno); + } +#endif } #endif diff --git a/sys/linux/dev_binder.txt b/sys/linux/dev_binder.txt index b7b50f655..1fcfa6a95 100644 --- a/sys/linux/dev_binder.txt +++ b/sys/linux/dev_binder.txt @@ -1,10 +1,10 @@ # Copyright 2017 syzkaller project authors. All rights reserved. # Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. -# Description uses binder device per test process, they are expected to be configured with -# CONFIG_ANDROID_BINDER_DEVICES="binder0,...,binder31". -# "binder,hwbinder,vndbinder" is also supported; this is the kconfig default and -# it's what's used on real Android devices (the main user of binder). +# These descriptions rely on binderfs being enabled and creating at least binder0 +# and binder1 devices right after a mount. +# "binder,hwbinder,vndbinder" devices are also supported; this is the kconfig default +# and it's what's used on real Android devices (the main user of binder). # Description assumes CONFIG_ANDROID_BINDER_IPC_32BIT is not set. include <linux/android/binder.h> @@ -19,8 +19,8 @@ type binder_handle int32[0:3] # It seems that cookies are only checked for inequality and non-matching cookies only cover error paths. type binder_cookie const[0, int64] -syz_open_dev$binderN(dev ptr[in, string["/dev/binder#"]], id proc[0, 1], flags flags[binder_open_flags]) fd_binder openat$binder(fd const[AT_FDCWD], file ptr[in, string["/dev/binder"]], flags flags[binder_open_flags], mode const[0]) fd_binder +openat$binderfs(fd const[AT_FDCWD], file ptr[in, string[binderfs_devpath]], flags flags[binder_open_flags], mode const[0]) fd_binder openat$hwbinder(fd const[AT_FDCWD], file ptr[in, string["/dev/hwbinder"]], flags flags[binder_open_flags], mode const[0]) fd_binder openat$vndbinder(fd const[AT_FDCWD], file ptr[in, string["/dev/vndbinder"]], flags flags[binder_open_flags], mode const[0]) fd_binder diff --git a/sys/linux/dev_binderfs.txt b/sys/linux/dev_binderfs.txt new file mode 100644 index 000000000..f2dff258a --- /dev/null +++ b/sys/linux/dev_binderfs.txt @@ -0,0 +1,40 @@ +# Copyright 2021 syzkaller project authors. All rights reserved. +# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +include <linux/fcntl.h> +include <linux/unistd.h> +include <linux/android/binderfs.h> + +# ./binderfs will be mounted by syz-executor, but let's also see how a single process +# operates with multiple ones. +binderfs_mountpoint = "./binderfs", "./binderfs2" + +# Control paths. +binderfs_ctrlpath = "./binderfs/binder-control", "./binderfs2/binder-control" + +# Device names. +binderfs_devname = "binder0", "binder1", "custom0", "custom1" + +# Unfortunately, syzlang does not currently favor string concatenation for open (and related) syscalls. So we concatenate it manually. +binderfs_devpath = "./binderfs/binder0", "./binderfs/binder1", "./binderfs/custom0", "./binderfs/custom1", "./binderfs2/binder0", "./binderfs2/binder1", "./binderfs2/custom0", "./binderfs2/custom1" + +mkdirat$binderfs(fd const[AT_FDCWD], path ptr[in, string[binderfs_mountpoint]], mode const[0x1ff]) +mount$binderfs(src ptr[in, string["binder"]], dst ptr[in, string[binderfs_mountpoint]], type ptr[in, string["binder"]], flags flags[mount_flags], opts ptr[in, fs_options[binderfs_options]]) +unlinkat$binderfs_device(fd const[AT_FDCWD], path ptr[in, string[binderfs_devpath]]) + +binderfs_options [ + max fs_opt_oct["max", int32] + stats stringnoz["stats=global"] +] [varlen] + +define BINDERFS_NAME_LEN BINDERFS_MAX_NAME + 1 + +binderfs_device { + name string[binderfs_devname, BINDERFS_NAME_LEN] (in) + major int32 (out) + minor int32 (out) +} + +resource fd_binderfs_ctrl[fd] +openat$binderfs_ctrl(fd const[AT_FDCWD], file ptr[in, string[binderfs_ctrlpath]], flags flags[binder_open_flags], mode const[0]) fd_binderfs_ctrl +ioctl$BINDER_CTL_ADD(fd fd_binderfs_ctrl, cmd const[BINDER_CTL_ADD], arg ptr[inout, binderfs_device]) diff --git a/sys/linux/dev_binderfs.txt.const b/sys/linux/dev_binderfs.txt.const new file mode 100644 index 000000000..f21650a03 --- /dev/null +++ b/sys/linux/dev_binderfs.txt.const @@ -0,0 +1,10 @@ +# Code generated by syz-sysgen. DO NOT EDIT. +arches = 386, amd64, arm, arm64, mips64le, ppc64le, riscv64, s390x +AT_FDCWD = 18446744073709551516 +BINDERFS_NAME_LEN = 256 +BINDER_CTL_ADD = 3238552065 +__NR_ioctl = 54, amd64:16, arm64:riscv64:29, mips64le:5015 +__NR_mkdirat = 34, 386:296, amd64:258, arm:323, mips64le:5248, ppc64le:287, s390x:289 +__NR_mount = 21, amd64:165, arm64:riscv64:40, mips64le:5160 +__NR_openat = 56, 386:295, amd64:257, arm:322, mips64le:5247, ppc64le:286, s390x:288 +__NR_unlinkat = 35, 386:301, amd64:263, arm:328, mips64le:5253, ppc64le:292, s390x:294 diff --git a/sys/linux/test/binder b/sys/linux/test/binder index 8805d2deb..0c4445595 100644 --- a/sys/linux/test/binder +++ b/sys/linux/test/binder @@ -1,6 +1,6 @@ -r0 = syz_open_dev$binderN(&AUTO='/dev/binder#\x00', 0x0, 0x2) +r0 = openat$binderfs(0xffffffffffffff9c, &(0x7f00000000c0)='./binderfs/binder0\x00', 0x0, 0x0) ioctl$BINDER_SET_CONTEXT_MGR_EXT(r0, AUTO, &AUTO={AUTO, 0x100, 0x0, 0x0}) mmap$binder(&(0x7f00000a0000), 0x2000, 0x1, 0x11, r0, 0x0) -r1 = syz_open_dev$binderN(&AUTO='/dev/binder#\x00', 0x0, 0x2) +r1 = openat$binderfs(0xffffffffffffff9c, &(0x7f00000000c0)='./binderfs/binder1\x00', 0x0, 0x0) mmap$binder(&(0x7f00000c0000), 0x2000, 0x1, 0x11, r1, 0x0) ioctl$BINDER_WRITE_READ(r1, AUTO, &AUTO={AUTO, AUTO, &AUTO=[@transaction_sg={AUTO, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, AUTO, AUTO, &AUTO={@flat=@binder={AUTO, 0x0, 0x0, 0x0}, @fd={AUTO, AUTO, r0, AUTO, 0x0}, @ptr={AUTO, 0x0, &AUTO=""/10, AUTO, 0x0, 0x0}}, &AUTO={AUTO, AUTO, AUTO}}, 0x10}], AUTO, AUTO, &AUTO}) |
