diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-08-28 16:33:32 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2016-08-28 16:33:32 +0200 |
| commit | 8278953eb4abb4fb147f6f06cd9bdcf1eff7e84d (patch) | |
| tree | 171e6ee53a3ed08660df8ba7a6fbff5373fd1464 /csource | |
| parent | 58b2762fed21612145a1e21051adf13d55a79d98 (diff) | |
csource: teach how to execute pseudo syz_ syscalls
Update #59
Diffstat (limited to 'csource')
| -rw-r--r-- | csource/common.go | 148 | ||||
| -rw-r--r-- | csource/csource.go | 30 |
2 files changed, 165 insertions, 13 deletions
diff --git a/csource/common.go b/csource/common.go new file mode 100644 index 000000000..46dfca8ce --- /dev/null +++ b/csource/common.go @@ -0,0 +1,148 @@ +// AUTOGENERATED FROM executor/common.h +package csource + +var commonHeader = ` + +#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; +__thread jmp_buf segv_env; + +static void segv_handler(int sig, siginfo_t* info, void* uctx) +{ + if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED)) + _longjmp(segv_env, 1); + exit(sig); +} + +static void install_segv_handler() +{ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = segv_handler; + sa.sa_flags = SA_NODEFER | SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); +} + +#define NONFAILING(...) \ + { \ + __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); \ + if (_setjmp(segv_env) == 0) { \ + __VA_ARGS__; \ + } \ + __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) { + 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 { + 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); + a1 /= 10; + } + return open(buf, a2, 0); + } +} + +static uintptr_t syz_open_pts(uintptr_t a0, uintptr_t a1) +{ + 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) +{ + 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); + 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) +{ + 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); + 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/csource/csource.go b/csource/csource.go index 214483c5d..28be9e22a 100644 --- a/csource/csource.go +++ b/csource/csource.go @@ -1,7 +1,7 @@ // Copyright 2015 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. -//go:generate bash -c "echo -e '// AUTOGENERATED FROM executor/common.h\npackage csource\nvar commonHeader = `' > common.go; cat ../executor/common.h | grep -v // >> common.go; echo '`' >> common.go" +//go:generate bash -c "echo -e '// AUTOGENERATED FROM executor/common.h\npackage csource\nvar commonHeader = `' > common.go; cat ../executor/common.h | egrep -v '^[ ]*//' | sed 's#[ ]*//.*##g' >> common.go; echo '`' >> common.go" package csource @@ -27,23 +27,27 @@ func Write(p *prog.Prog, opts Options) []byte { exec := p.SerializeForExec() w := new(bytes.Buffer) - fmt.Fprint(w, "// autogenerated by syzkaller (http://github.com/google/syzkaller)\n") - fmt.Fprint(w, commonHeader) - fmt.Fprint(w, "\n") + fmt.Fprint(w, "// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n") - handled := make(map[string]bool) + handled := make(map[string]int) for _, c := range p.Calls { - name := c.Meta.CallName - if handled[name] { - continue + handled[c.Meta.CallName] = c.Meta.NR + } + for _, c := range sys.Calls { + if strings.HasPrefix(c.CallName, "syz_") { + handled[c.CallName] = c.NR } - handled[name] = true - fmt.Fprintf(w, "#ifndef SYS_%v\n", name) - fmt.Fprintf(w, "#define SYS_%v %v\n", name, c.Meta.NR) + } + for name, nr := range handled { + fmt.Fprintf(w, "#ifndef __NR_%v\n", name) + fmt.Fprintf(w, "#define __NR_%v %v\n", name, nr) fmt.Fprintf(w, "#endif\n") } fmt.Fprintf(w, "\n") + fmt.Fprint(w, commonHeader) + fmt.Fprint(w, "\n") + calls, nvar := generateCalls(exec) fmt.Fprintf(w, "long r[%v];\n", nvar) @@ -166,7 +170,7 @@ loop: // Normal syscall. newCall() meta := sys.Calls[instr] - fmt.Fprintf(w, "\tr[%v] = syscall(SYS_%v", n, meta.CallName) + fmt.Fprintf(w, "\tr[%v] = execute_syscall(__NR_%v", n, meta.CallName) nargs := read() for i := uintptr(0); i < nargs; i++ { typ := read() @@ -181,7 +185,7 @@ loop: panic("unknown arg type") } } - for i := nargs; i < 6; i++ { + for i := nargs; i < 9; i++ { fmt.Fprintf(w, ", 0") } fmt.Fprintf(w, ");\n") |
