From 8278953eb4abb4fb147f6f06cd9bdcf1eff7e84d Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sun, 28 Aug 2016 16:33:32 +0200 Subject: csource: teach how to execute pseudo syz_ syscalls Update #59 --- executor/common.h | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) (limited to 'executor/common.h') 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 #include #include #include #include #include +#include #include #include +#include +#include #include +#include #include __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); + } +} -- cgit mrf-deployment