Skip to content

Commit

Permalink
executor: linux: chroot into tmpfs with sandbox=none
Browse files Browse the repository at this point in the history
To prevent the executor from accidentally making the whole root file system
immutable (which breaks fuzzing), modify sandbox=none to create a tmpfs mount
and chroot into it before executing programs in a process.

According to `syz-manager -mode=smoke-test`, the number of enabled syscalls on
x86 doesn't change with this patch.

Fixes google#4939, google#2933, google#971.
  • Loading branch information
ramosian-glider authored and dvyukov committed Jul 2, 2024
1 parent dc6047a commit 3160a12
Showing 1 changed file with 63 additions and 50 deletions.
113 changes: 63 additions & 50 deletions executor/common_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -3863,7 +3863,7 @@ static void setup_cgroups_test()
}
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NAMESPACE
#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_NAMESPACE
static void initialize_cgroups()
{
#if SYZ_EXECUTOR
Expand Down Expand Up @@ -3892,6 +3892,66 @@ static void initialize_cgroups()
#endif
#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_NAMESPACE
// Mount tmpfs and chroot into it in sandbox=none and sandbox=namespace.
// This is to prevent persistent changes to the root file system (e.g. setting attributes) that may
// hinder fuzzing.
// See https://github.com/google/syzkaller/issues/4939 for more details.
static void sandbox_common_mount_tmpfs(void)
{
if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed");
if (mount("", "./syz-tmp", "tmpfs", 0, NULL))
fail("mount(tmpfs) failed");
if (mkdir("./syz-tmp/newroot", 0777))
fail("mkdir failed");
if (mkdir("./syz-tmp/newroot/dev", 0700))
fail("mkdir failed");
unsigned bind_mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
if (mount("/dev", "./syz-tmp/newroot/dev", NULL, bind_mount_flags, NULL))
fail("mount(dev) failed");
if (mkdir("./syz-tmp/newroot/proc", 0700))
fail("mkdir failed");
if (mount(NULL, "./syz-tmp/newroot/proc", "proc", 0, NULL))
fail("mount(proc) failed");
if (mkdir("./syz-tmp/newroot/selinux", 0700))
fail("mkdir failed");
// selinux mount used to be at /selinux, but then moved to /sys/fs/selinux.
const char* selinux_path = "./syz-tmp/newroot/selinux";
if (mount("/selinux", selinux_path, NULL, bind_mount_flags, NULL)) {
if (errno != ENOENT)
fail("mount(/selinux) failed");
if (mount("/sys/fs/selinux", selinux_path, NULL, bind_mount_flags, NULL) && errno != ENOENT)
fail("mount(/sys/fs/selinux) failed");
}
if (mkdir("./syz-tmp/newroot/sys", 0700))
fail("mkdir failed");
if (mount("/sys", "./syz-tmp/newroot/sys", 0, bind_mount_flags, NULL))
fail("mount(sysfs) failed");
#if SYZ_EXECUTOR || SYZ_CGROUPS
initialize_cgroups();
#endif
if (mkdir("./syz-tmp/pivot", 0777))
fail("mkdir failed");
if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) {
debug("pivot_root failed\n");
if (chdir("./syz-tmp"))
fail("chdir failed");
} else {
debug("pivot_root OK\n");
if (chdir("/"))
fail("chdir failed");
if (umount2("./pivot", MNT_DETACH))
fail("umount failed");
}
if (chroot("./newroot"))
fail("chroot failed");
if (chdir("/"))
fail("chdir failed");
}

#endif

#if SYZ_EXECUTOR || SYZ_SANDBOX_NONE || SYZ_SANDBOX_SETUID || SYZ_SANDBOX_NAMESPACE || SYZ_SANDBOX_ANDROID
#include <errno.h>
#include <sys/mount.h>
Expand Down Expand Up @@ -4104,6 +4164,7 @@ static int do_sandbox_none(void)
#if SYZ_EXECUTOR || SYZ_WIFI
initialize_wifi_devices();
#endif
sandbox_common_mount_tmpfs();
setup_binderfs();
loop();
doexit(1);
Expand Down Expand Up @@ -4217,55 +4278,7 @@ static int namespace_sandbox_proc(void* arg)
initialize_wifi_devices();
#endif

if (mkdir("./syz-tmp", 0777))
fail("mkdir(syz-tmp) failed");
if (mount("", "./syz-tmp", "tmpfs", 0, NULL))
fail("mount(tmpfs) failed");
if (mkdir("./syz-tmp/newroot", 0777))
fail("mkdir failed");
if (mkdir("./syz-tmp/newroot/dev", 0700))
fail("mkdir failed");
unsigned bind_mount_flags = MS_BIND | MS_REC | MS_PRIVATE;
if (mount("/dev", "./syz-tmp/newroot/dev", NULL, bind_mount_flags, NULL))
fail("mount(dev) failed");
if (mkdir("./syz-tmp/newroot/proc", 0700))
fail("mkdir failed");
if (mount(NULL, "./syz-tmp/newroot/proc", "proc", 0, NULL))
fail("mount(proc) failed");
if (mkdir("./syz-tmp/newroot/selinux", 0700))
fail("mkdir failed");
// selinux mount used to be at /selinux, but then moved to /sys/fs/selinux.
const char* selinux_path = "./syz-tmp/newroot/selinux";
if (mount("/selinux", selinux_path, NULL, bind_mount_flags, NULL)) {
if (errno != ENOENT)
fail("mount(/selinux) failed");
if (mount("/sys/fs/selinux", selinux_path, NULL, bind_mount_flags, NULL) && errno != ENOENT)
fail("mount(/sys/fs/selinux) failed");
}
if (mkdir("./syz-tmp/newroot/sys", 0700))
fail("mkdir failed");
if (mount("/sys", "./syz-tmp/newroot/sys", 0, bind_mount_flags, NULL))
fail("mount(sysfs) failed");
#if SYZ_EXECUTOR || SYZ_CGROUPS
initialize_cgroups();
#endif
if (mkdir("./syz-tmp/pivot", 0777))
fail("mkdir failed");
if (syscall(SYS_pivot_root, "./syz-tmp", "./syz-tmp/pivot")) {
debug("pivot_root failed\n");
if (chdir("./syz-tmp"))
fail("chdir failed");
} else {
debug("pivot_root OK\n");
if (chdir("/"))
fail("chdir failed");
if (umount2("./pivot", MNT_DETACH))
fail("umount failed");
}
if (chroot("./newroot"))
fail("chroot failed");
if (chdir("/"))
fail("chdir failed");
sandbox_common_mount_tmpfs();
setup_binderfs();
drop_caps();

Expand Down

0 comments on commit 3160a12

Please sign in to comment.