diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2015-11-19 17:16:36 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2015-11-19 17:16:36 +0100 |
| commit | 4784f4f6f50d7ddf958ddbb717bb2a0cb3e397a9 (patch) | |
| tree | e3f8006173e967ab1d3d0a1cc8f276a15d59074d /executor/executor.cc | |
| parent | 93f8cc38aa01d8ebfbfed4f111e7a0a48dc89cac (diff) | |
add fuse support
Diffstat (limited to 'executor/executor.cc')
| -rw-r--r-- | executor/executor.cc | 73 |
1 files changed, 66 insertions, 7 deletions
diff --git a/executor/executor.cc b/executor/executor.cc index c0cdf72f1..7f0e82ba9 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -33,7 +33,7 @@ const int kOutPipeFd = 6; const int kCoverFd = 5; const int kMaxInput = 1 << 20; const int kMaxOutput = 16 << 20; -const int kMaxArgs = 6; +const int kMaxArgs = 9; const int kMaxThreads = 16; const int kMaxCommands = 4 << 10; @@ -160,6 +160,7 @@ int main() fail("fork failed"); if (pid == 0) { setpgid(0, 0); + unshare(CLONE_NEWNS); if (flag_drop_privs) { // Pre-create one thread with root privileges for execution of special syscalls (e.g. mount). if (flag_threaded) @@ -167,9 +168,11 @@ int main() // TODO: 65534 is meant to be nobody if (setgroups(0, NULL)) fail("failed to setgroups"); - if (setresgid(65534, 65534, 65534)) + // glibc versions do not we want -- they force all threads to setuid. + // We want to preserve the thread above as root. + if (syscall(SYS_setresgid, 65534, 65534, 65534)) fail("failed to setresgid"); - if (setresuid(65534, 65534, 65534)) + if (syscall(SYS_setresuid, 65534, 65534, 65534)) fail("failed to setresuid"); } // Don't need that SIGCANCEL/SIGSETXID glibc stuff. @@ -336,7 +339,8 @@ thread_t* schedule_call(int n, int call_index, int call_num, uint64_t num_args, // Figure out whether we need root privs for this call. bool root = false; switch (syscalls[call_num].sys_nr) { - case __NR_syz_dri_open: + case __NR_syz_fuse_mount: + case __NR_syz_fuseblk_mount: root = true; } // Find a spare thread to execute the call. @@ -447,16 +451,16 @@ void execute_call(thread_t* th) } debug(")\n"); - if (kMaxArgs != 6) - fail("inconsistent number of arguments"); - cover_reset(th); switch (call->sys_nr) { default: { + if (th->num_args > 6) + fail("bad number of arguments"); th->res = syscall(call->sys_nr, th->args[0], th->args[1], th->args[2], th->args[3], th->args[4], th->args[5]); break; } case __NR_syz_openpts: { + // syz_openpts(fd fd[tty], flags flags[open_flags]) fd[tty] int ptyno = 0; if (ioctl(th->args[0], TIOCGPTN, &ptyno) == 0) { char buf[128]; @@ -468,10 +472,65 @@ void execute_call(thread_t* th) } } case __NR_syz_dri_open: { + // syz_dri_open(card_id intptr, flags flags[open_flags]) fd[dri] char buf[128]; sprintf(buf, "/dev/dri/card%lu", th->args[0]); th->res = open(buf, th->args[1], 0); } + case __NR_syz_fuse_mount: { + // syz_fuse_mount(target filename, mode flags[fuse_mode], uid uid, gid gid, maxread intptr, flags flags[mount_flags]) fd[fuse] + uint64_t target = th->args[0]; + uint64_t mode = th->args[1]; + uint64_t uid = th->args[2]; + uint64_t gid = th->args[3]; + uint64_t maxread = th->args[4]; + uint64_t flags = th->args[5]; + + int fd = open("/dev/fuse", O_RDWR); + if (fd != -1) { + char buf[256]; + sprintf(buf, "fd=%d,user_id=%lu,group_id=%lu,rootmode=0%o", fd, uid, gid, (unsigned)mode & ~3u); + if (maxread != 0) + sprintf(buf + strlen(buf), ",max_read=%lu", maxread); + if (mode & 1) + strcat(buf, ",default_permissions"); + if (mode & 2) + strcat(buf, ",allow_other"); + syscall(SYS_mount, "", target, "fuse", flags, buf); + // Ignore errors, maybe fuzzer can do something useful with fd alone. + } + th->res = fd; + } + case __NR_syz_fuseblk_mount: { + // syz_fuseblk_mount(target filename, blkdev filename, mode flags[fuse_mode], uid uid, gid gid, maxread intptr, blksize intptr, flags flags[mount_flags]) fd[fuse] + uint64_t target = th->args[0]; + uint64_t blkdev = th->args[1]; + uint64_t mode = th->args[2]; + uint64_t uid = th->args[3]; + uint64_t gid = th->args[4]; + uint64_t maxread = th->args[5]; + uint64_t blksize = th->args[6]; + uint64_t flags = th->args[7]; + + int fd = open("/dev/fuse", O_RDWR); + if (fd != -1) { + if (syscall(SYS_mknod, blkdev, S_IFBLK, makedev(7, 199)) == 0) { + char buf[256]; + sprintf(buf, "fd=%d,user_id=%lu,group_id=%lu,rootmode=0%o", fd, uid, gid, (unsigned)mode & ~3u); + if (maxread != 0) + sprintf(buf + strlen(buf), ",max_read=%lu", maxread); + if (blksize != 0) + sprintf(buf + strlen(buf), ",blksize=%lu", blksize); + if (mode & 1) + strcat(buf, ",default_permissions"); + if (mode & 2) + strcat(buf, ",allow_other"); + syscall(SYS_mount, blkdev, target, "fuseblk", flags, buf); + // Ignore errors, maybe fuzzer can do something useful with fd alone. + } + } + th->res = fd; + } } int errno0 = errno; th->cover_size = cover_read(th); |
