aboutsummaryrefslogtreecommitdiffstats
path: root/executor
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-08-28 16:33:32 +0200
committerDmitry Vyukov <dvyukov@google.com>2016-08-28 16:33:32 +0200
commit8278953eb4abb4fb147f6f06cd9bdcf1eff7e84d (patch)
tree171e6ee53a3ed08660df8ba7a6fbff5373fd1464 /executor
parent58b2762fed21612145a1e21051adf13d55a79d98 (diff)
csource: teach how to execute pseudo syz_ syscalls
Update #59
Diffstat (limited to 'executor')
-rw-r--r--executor/common.h113
-rw-r--r--executor/executor.cc109
2 files changed, 115 insertions, 107 deletions
diff --git a/executor/common.h b/executor/common.h
index 0c4613859..7d896373f 100644
--- a/executor/common.h
+++ b/executor/common.h
@@ -2,15 +2,19 @@
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// This file is shared between executor and csource package.
-
+#include <fcntl.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/types.h>
#include <unistd.h>
__thread int skip_segv;
@@ -41,3 +45,110 @@ static void install_segv_handler()
} \
__atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); \
}
+
+static uintptr_t syz_open_dev(uintptr_t a0, uintptr_t a1, uintptr_t a2)
+{
+ if (a0 == 0xc || a0 == 0xb) {
+ // syz_open_dev$char(dev const[0xc], major intptr, minor intptr) fd
+ // syz_open_dev$block(dev const[0xb], major intptr, minor intptr) fd
+ char buf[128];
+ sprintf(buf, "/dev/%s/%d:%d", a0 == 0xc ? "char" : "block", (uint8_t)a1, (uint8_t)a2);
+ return open(buf, O_RDWR, 0);
+ } else {
+ // syz_open_dev(dev strconst, id intptr, flags flags[open_flags]) fd
+ char buf[1024];
+ char* hash;
+ strncpy(buf, (char*)a0, sizeof(buf));
+ buf[sizeof(buf) - 1] = 0;
+ while ((hash = strchr(buf, '#'))) {
+ *hash = '0' + (char)(a1 % 10); // 10 devices should be enough for everyone.
+ a1 /= 10;
+ }
+ return open(buf, a2, 0);
+ }
+}
+
+static uintptr_t syz_open_pts(uintptr_t a0, uintptr_t a1)
+{
+ // syz_openpts(fd fd[tty], flags flags[open_flags]) fd[tty]
+ int ptyno = 0;
+ if (ioctl(a0, TIOCGPTN, &ptyno))
+ return -1;
+ char buf[128];
+ sprintf(buf, "/dev/pts/%d", ptyno);
+ return open(buf, a1, 0);
+}
+
+static uintptr_t syz_fuse_mount(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
+{
+ // syz_fuse_mount(target filename, mode flags[fuse_mode], uid uid, gid gid, maxread intptr, flags flags[mount_flags]) fd[fuse]
+ uint64_t target = a0;
+ uint64_t mode = a1;
+ uint64_t uid = a2;
+ uint64_t gid = a3;
+ uint64_t maxread = a4;
+ uint64_t flags = a5;
+
+ int fd = open("/dev/fuse", O_RDWR);
+ if (fd == -1)
+ return fd;
+ char buf[1024];
+ sprintf(buf, "fd=%d,user_id=%ld,group_id=%ld,rootmode=0%o", fd, (long)uid, (long)gid, (unsigned)mode & ~3u);
+ if (maxread != 0)
+ sprintf(buf + strlen(buf), ",max_read=%ld", (long)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.
+ return fd;
+}
+
+static uintptr_t syz_fuseblk_mount(uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7)
+{
+ // 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 = a0;
+ uint64_t blkdev = a1;
+ uint64_t mode = a2;
+ uint64_t uid = a3;
+ uint64_t gid = a4;
+ uint64_t maxread = a5;
+ uint64_t blksize = a6;
+ uint64_t flags = a7;
+
+ int fd = open("/dev/fuse", O_RDWR);
+ if (fd == -1)
+ return fd;
+ if (syscall(SYS_mknodat, AT_FDCWD, blkdev, S_IFBLK, makedev(7, 199)))
+ return fd;
+ char buf[256];
+ sprintf(buf, "fd=%d,user_id=%ld,group_id=%ld,rootmode=0%o", fd, (long)uid, (long)gid, (unsigned)mode & ~3u);
+ if (maxread != 0)
+ sprintf(buf + strlen(buf), ",max_read=%ld", (long)maxread);
+ if (blksize != 0)
+ sprintf(buf + strlen(buf), ",blksize=%ld", (long)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.
+ return fd;
+}
+
+static uintptr_t execute_syscall(int nr, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8)
+{
+ switch (nr) {
+ default:
+ return syscall(nr, a0, a1, a2, a3, a4, a5);
+ case __NR_syz_open_dev:
+ return syz_open_dev(a0, a1, a2);
+ case __NR_syz_open_pts:
+ return syz_open_pts(a0, a1);
+ case __NR_syz_fuse_mount:
+ return syz_fuse_mount(a0, a1, a2, a3, a4, a5);
+ case __NR_syz_fuseblk_mount:
+ return syz_fuseblk_mount(a0, a1, a2, a3, a4, a5, a6, a7);
+ }
+}
diff --git a/executor/executor.cc b/executor/executor.cc
index 9b336b2c6..972a80d24 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -33,9 +33,10 @@
#include <time.h>
#include <unistd.h>
-#include "common.h"
#include "syscalls.h"
+#include "common.h"
+
#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long long)
#define KCOV_INIT_TABLE _IOR('c', 2, unsigned long long)
#define KCOV_ENABLE _IO('c', 100)
@@ -656,111 +657,7 @@ void execute_call(thread_t* th)
debug(")\n");
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_open_dev: {
- const char* dev = (char*)th->args[0];
- if ((uintptr_t)dev == 0xc || (uintptr_t)dev == 0xb) {
- // syz_open_dev$char(dev const[0xc], major intptr, minor intptr) fd
- // syz_open_dev$block(dev const[0xb], major intptr, minor intptr) fd
- uint64_t major = th->args[1];
- uint64_t minor = th->args[2];
- uint64_t flags = O_RDWR;
- char buf[128];
- sprintf(buf, "/dev/%s/%d:%d", (uintptr_t)dev == 0xc ? "char" : "block", (uint8_t)major, (uint8_t)minor);
- debug("open(\"%s\", 0x%lx)\n", buf, flags);
- th->res = open(buf, flags, 0);
- } else {
-
- // syz_open_dev(dev strconst, id intptr, flags flags[open_flags]) fd
- uint64_t id = th->args[1];
- uint64_t flags = th->args[2];
- char buf[128];
- strncpy(buf, dev, sizeof(buf));
- buf[sizeof(buf) - 1] = 0;
- while (char* hash = strchr(buf, '#')) {
- *hash = '0' + (char)(id % 10); // 10 devices should be enough for everyone.
- id /= 10;
- }
- debug("syz_open_dev(\"%s\", 0x%lx, 0)\n", buf, flags);
- th->res = open(buf, flags, 0);
- }
- break;
- }
- case __NR_syz_open_pts: {
- // 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];
- sprintf(buf, "/dev/pts/%d", ptyno);
- th->res = open(buf, th->args[1], 0);
- } else {
- th->res = -1;
- }
- break;
- }
- 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=%ld,group_id=%ld,rootmode=0%o", fd, (long)uid, (long)gid, (unsigned)mode & ~3u);
- if (maxread != 0)
- sprintf(buf + strlen(buf), ",max_read=%ld", (long)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;
- break;
- }
- 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_mknodat, AT_FDCWD, blkdev, S_IFBLK, makedev(7, 199)) == 0) {
- char buf[256];
- sprintf(buf, "fd=%d,user_id=%ld,group_id=%ld,rootmode=0%o", fd, (long)uid, (long)gid, (unsigned)mode & ~3u);
- if (maxread != 0)
- sprintf(buf + strlen(buf), ",max_read=%ld", (long)maxread);
- if (blksize != 0)
- sprintf(buf + strlen(buf), ",blksize=%ld", (long)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;
- break;
- }
- }
+ th->res = execute_syscall(call->sys_nr, th->args[0], th->args[1], th->args[2], th->args[3], th->args[4], th->args[5], th->args[6], th->args[7], th->args[8]);
th->reserrno = errno;
th->cover_size = cover_read(th);