Diagnose currently sends the panic signal to generate a traceback for
additional context.
However, Diagnose is also called in otherwise successful scenarios
(vm.Instance.MonitorExecution -> vm.monitor.extractError). Triggering a
panic will make this successful scenario look like a failure.
We could simply suppress this panic, but 1) that means we never shutdown
cleanly (not important, but ugly), and 2) we're less likely to detect
delayed crashes since we kill the sandbox immediately (that's what
MonitorExecution is checking for).
Instead, switch from -panic-signal to -trace-signal, which simply logs a
traceback without exiting. This option was added to runsc in
24c1158b9c.
The other uses of Diagnose will always generate a report regardless of
an additional panic, so we're not losing any reports.
Without this check programs may end up panicing in places far away
from the real cause. E.g.
worker# ./syz-fuzzer -executor=./syz-executor -name=vm-0 -arch=amd64 -manager=10.128.0.101:21386 -sandbox=setuid -procs=2 -v=0 -cover=true -debug=false -test=false
2004/02/03 12:11:11 fuzzer started
2004/02/03 12:11:11 dialing manager at 10.128.0.101:21386
2004/02/03 12:11:12 syscalls: 1
2004/02/03 12:11:12 code coverage: enabled
2004/02/03 12:11:12 comparison tracing: support is not implemented in syzkaller
2004/02/03 12:11:12 setuid sandbox: support is not implemented in syzkaller
2004/02/03 12:11:12 namespace sandbox: support is not implemented in syzkaller
2004/02/03 12:11:12 Android sandbox: support is not implemented in syzkaller
2004/02/03 12:11:12 fault injection: support is not implemented in syzkaller
2004/02/03 12:11:12 leak checking: support is not implemented in syzkaller
2004/02/03 12:11:12 net packet injection: enabled
2004/02/03 12:11:12 net device setup: support is not implemented in syzkaller
panic: invalid argument to Intn
goroutine 27 [running]:
math/rand.(*Rand).Intn(0xc000dff530, 0x0, 0x40)
/usr/local/go/src/math/rand/rand.go:169 +0x9c
github.com/google/syzkaller/prog.(*ChoiceTable).Choose(0xc000d92ec0, 0xc000dff530, 0xffffffffffffffff, 0xc000dff650)
/syzkaller/gopath/src/github.com/google/syzkaller/prog/prio.go:241 +0x1a0
github.com/google/syzkaller/prog.(*randGen).generateCall(0xc000e145a0, 0xc000c2a200, 0xc000ce7f80, 0x2348f1940, 0xc000ce3440, 0xc000e6ee01)
/syzkaller/gopath/src/github.com/google/syzkaller/prog/rand.go:451 +0x69
github.com/google/syzkaller/prog.(*Target).Generate(0xc00007f1e0, 0x8f8680, 0xc000ce3440, 0x1e, 0xc000d92ec0, 0x0)
/syzkaller/gopath/src/github.com/google/syzkaller/prog/generation.go:19 +0x2b2
main.(*Proc).loop(0xc000d92f40)
/syzkaller/gopath/src/github.com/google/syzkaller/syz-fuzzer/proc.go:93 +0x2a1
created by main.main
/syzkaller/gopath/src/github.com/google/syzkaller/syz-fuzzer/fuzzer.go:236 +0xfe2
* Revert "Revert "executor: add setuid sandbox for openbsd""
The problem is the low file descriptor limit.
This reverts commit 4093e33b13.
* executor/executor make sure the file descriptor limit is sufficient
AUTO arguments can be used for:
- consts
- lens
- pointers
For const's and len's AUTO is replaced with the natural value,
addresses for AUTO pointers are allocated linearly.
This greatly simplifies writing test programs by hand
as most of the time we want these natural values.
Update tests to use AUTO.
Currently syz-runtest fails to start because -debug flag is defined
both in syz-runtest and ipcconfig.
But moving sandbox functions we prevent ipcconfig from being imported into syz-runtest.
Add bulk of checks for strict parsing mode.
Probably not complete, but we can extend then in future as needed.
Turns out we can't easily use it for serialized programs
as they omit default args and during deserialization it looks like missing args.
Over time we relaxed parsing to handle all kinds of invalid programs
(excessive/missing args, wrong types, etc).
This is useful when reading old programs from corpus.
But this is harmful for e.g. reading test inputs as they can become arbitrary outdated.
For runtests which creates additional problem of executing not
what is actually written in the test (or at least what author meant).
Add strict parsing mode that does not tolerate any errors.
For now it just checks excessive syscall arguments.
Move target and vars into parser and make all
parsing functions methods of the parser.
This reduces number of args that we need to pass around
and eases adding more state that needs to be passed around.
syz-cover generates coverage HTML report from raw coverage files.
Raw coverage files are text files with one PC in hex form per line, e.g.:
0xffffffff8398658d
0xffffffff839862fc
0xffffffff8398633f
Raw coverage files can be obtained either from /rawcover manager HTTP handler,
or from syz-execprog with -coverfile flag.
Usage:
syz-cover [-os=OS -arch=ARCH -kernel_src=. -kernel_obj=.] rawcover.file*
As suggested by Dmitry us a better description of the msg_flags
field, which is only used to provide information from the
kernel to the application for recvmsg() calls. This means that
the value provided is basically ignored.
golint suggests to comment all blank imports.
But actually we don't need whole sys, we can import only sys/linux.
Also rename target var to prevent name shadowing.
It's used only by 2 functions: genSockaddrNetlink and genIfrIfru.
Majority of functions just accept the straceType as argument,
which looks like a much more appropriate way to pass an argument to a function.
Amusingly, both functions already accept and use the straceType as argument.
This has number of advantages:
1. Tests are readable and writable.
The current checks [1] are neither.
2. Tests are much more compact.
3. Tests verify all aspects rather than just
1 aspect of the resulting program.
4. Tests are much less fragile.
5. Any diffs in the results will be more clearly visible.
[1]
switch a := p.Calls[1].Args[0].(type) {
case *prog.ResultArg:
if a.Res != p.Calls[0].Ret {
switch a := p.Calls[1].Args[0].(type) {
case *prog.ResultArg:
pipeSecondFd := p.Calls[0].Args[0].(*prog.PointerArg).Res.(*prog.GroupArg).Inner[1]
if a.Res != pipeSecondFd {
write := p.Calls[len(p.Calls)-2]
inotifyRmWatch := p.Calls[len(p.Calls)-1]
switch a := write.Args[0].Type().(type) {
case *prog.ResourceType:
if a.TypeName != "fd" {
t.Fatalf("expected first argument of write to have type fd, got: %s", a.TypeName)
}
default:
t.Fatalf("first argument of write is not resource type: %s", a.Name())
}
switch a := inotifyRmWatch.Args[1].(type) {
case *prog.ResultArg:
b := a.Type().(*prog.ResourceType)
if b.TypeName != "inotifydesc" {
t.Fatalf("expected second argument of inotify_rm_watch to have type inoitfydesc, got: %s", b.TypeName)
}
if a.Res != p.Calls[2].Ret {
t.Fatalf("inotify_rm_watch's second argument should match the result of inotify_add_watch.")
}
}
sockaddr, ok := a.(*prog.PointerArg).Res.(*prog.GroupArg)
if !ok {
t.Fatalf("%s", a.Type().Name())
}
ipv4Addr, ok := sockaddr.Inner[2].(*prog.UnionArg)
if !ok {
t.Fatalf("expected 3rd argument to be unionArg, got %s", sockaddr.Inner[2].Type().Name())
}
optName := ipv4Addr.Option.Type().FieldName()
if !strings.Contains(optName, "rand") {
t.Fatalf("expected ip option to be random opt, got: %s", optName)
}
ip, ok := ipv4Addr.Option.(*prog.ConstArg)
if !ok {
t.Fatalf("ipv4Addr option is not IntType")
}
if ip.Val != expectedIp {
t.Fatalf("parsed != expected, %d != %d", ip.Val, expectedIp)
}
There are 2 bugs:
1. We always allocate 1 page, even if use more.
2. VMA addresses are not aligned, so most mmap-like functions fail with EINVAL.
The added test currently panics with "unaligned vma address".