diff --git a/pkg/host/host_test.go b/pkg/host/host_test.go index 470a6e5e187..aa70209425c 100644 --- a/pkg/host/host_test.go +++ b/pkg/host/host_test.go @@ -31,15 +31,9 @@ func TestLog(t *testing.T) { for c, reason := range disabled { t.Logf("%v: %v", c.Name, reason) } - trans := target.TransitivelyEnabledCalls(supp) + _, disabled = target.TransitivelyEnabledCalls(supp) t.Logf("\n\ntransitively unsupported:") - for _, c := range target.Syscalls { - s, ok := trans[c] - if ok && !s { - t.Fatalf("map contains false value") - } - if !s && supp[c] { - t.Logf("%v", c.Name) - } + for c, reason := range disabled { + t.Logf("%v: %v", c.Name, reason) } } diff --git a/prog/decl_test.go b/prog/decl_test.go index 72a6435e80a..4539be2fb85 100644 --- a/prog/decl_test.go +++ b/prog/decl_test.go @@ -5,6 +5,7 @@ package prog import ( "runtime" + "strings" "testing" ) @@ -32,20 +33,26 @@ func TestTransitivelyEnabledCalls(t *testing.T) { for _, c := range target.Syscalls { calls[c] = true } - if trans := target.TransitivelyEnabledCalls(calls); len(calls) != len(trans) { - for c := range calls { - if !trans[c] { - t.Logf("disabled %v", c.Name) - } + if trans, disabled := target.TransitivelyEnabledCalls(calls); len(disabled) != 0 { + for c, reason := range disabled { + t.Logf("disabled %v: %v", c.Name, reason) } t.Fatalf("can't create some resource") + } else if len(trans) != len(calls) { + t.Fatalf("transitive syscalls are not full") + } else { + for c, ok := range trans { + if !ok { + t.Fatalf("syscalls %v is false in transitive map", c.Name) + } + } } delete(calls, target.SyscallMap["epoll_create"]) - if trans := target.TransitivelyEnabledCalls(calls); len(calls) != len(trans) { + if trans, disabled := target.TransitivelyEnabledCalls(calls); len(disabled) != 0 || len(trans) != len(calls) { t.Fatalf("still must be able to create epoll fd with epoll_create1") } delete(calls, target.SyscallMap["epoll_create1"]) - trans := target.TransitivelyEnabledCalls(calls) + trans, disabled := target.TransitivelyEnabledCalls(calls) if len(calls)-6 != len(trans) || trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_ADD"]] || trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_MOD"]] || @@ -55,6 +62,14 @@ func TestTransitivelyEnabledCalls(t *testing.T) { trans[target.SyscallMap["kcmp$KCMP_EPOLL_TFD"]] { t.Fatalf("epoll fd is not disabled") } + if len(disabled) != 6 { + t.Fatalf("disabled %v syscalls, want 6", len(disabled)) + } + for c, reason := range disabled { + if !strings.Contains(reason, "no syscalls can create resource fd_epoll, enable some syscalls that can create it [epoll_create epoll_create1]") { + t.Fatalf("%v: wrong disable reason: %v", c.Name, reason) + } + } } func TestClockGettime(t *testing.T) { @@ -69,8 +84,9 @@ func TestClockGettime(t *testing.T) { } // Removal of clock_gettime should disable all calls that accept timespec/timeval. delete(calls, target.SyscallMap["clock_gettime"]) - trans := target.TransitivelyEnabledCalls(calls) - if len(trans)+10 > len(calls) { - t.Fatalf("clock_gettime did not disable enough calls: before %v, after %v", len(calls), len(trans)) + trans, disabled := target.TransitivelyEnabledCalls(calls) + if len(trans)+10 > len(calls) || len(trans)+len(disabled) != len(calls) || len(trans) == 0 { + t.Fatalf("clock_gettime did not disable enough calls: before %v, after %v, disabled %v", + len(calls), len(trans), len(disabled)) } } diff --git a/prog/resources.go b/prog/resources.go index e6ef080cd1f..33c497d5ab4 100644 --- a/prog/resources.go +++ b/prog/resources.go @@ -85,8 +85,9 @@ func (c *Syscall) inputResources() []*ResourceType { return resources } -func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*Syscall]bool { +func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) (map[*Syscall]bool, map[*Syscall]string) { supported := make(map[*Syscall]bool) + disabled := make(map[*Syscall]string) for c := range enabled { supported[c] = true } @@ -106,7 +107,8 @@ func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*S n := len(supported) haveGettime := supported[target.SyscallMap["clock_gettime"]] for c := range supported { - canCreate := true + cantCreate := "" + var resourceCtors []*Syscall for _, res := range inputResources[c] { noctors := true for _, ctor := range ctors[res.Desc.Name] { @@ -116,26 +118,33 @@ func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*S } } if noctors { - canCreate = false + cantCreate = res.Desc.Name + resourceCtors = ctors[res.Desc.Name] break } } // We need to support structs as resources, // but for now we just special-case timespec/timeval. - if canCreate && !haveGettime { + if cantCreate == "" && !haveGettime { ForeachType(c, func(typ Type) { if a, ok := typ.(*StructType); ok && a.Dir() != DirOut && (a.Name() == "timespec" || a.Name() == "timeval") { - canCreate = false + cantCreate = a.Name() + resourceCtors = []*Syscall{target.SyscallMap["clock_gettime"]} } }) } - if !canCreate { + if cantCreate != "" { delete(supported, c) + var ctorNames []string + for _, ctor := range resourceCtors { + ctorNames = append(ctorNames, ctor.Name) + } + disabled[c] = fmt.Sprintf("no syscalls can create resource %v, enable some syscalls that can create it %v", cantCreate, ctorNames) } } if n == len(supported) { break } } - return supported + return supported, disabled } diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go index 1701f74915d..bff1db56536 100644 --- a/syz-fuzzer/fuzzer.go +++ b/syz-fuzzer/fuzzer.go @@ -404,12 +404,9 @@ func buildCallList(target *prog.Target, enabledCalls, sandbox string) map[*prog. } } - trans := target.TransitivelyEnabledCalls(calls) - for c := range calls { - if !trans[c] { - Logf(1, "transitively unsupported: %v", c.Name) - delete(calls, c) - } + calls, disabled := target.TransitivelyEnabledCalls(calls) + for c, reason := range disabled { + Logf(1, "transitively unsupported: %v: %v", c.Name, reason) } return calls } diff --git a/syz-fuzzer/testing.go b/syz-fuzzer/testing.go index 257d638550e..57906c40748 100644 --- a/syz-fuzzer/testing.go +++ b/syz-fuzzer/testing.go @@ -36,7 +36,7 @@ func testImage(hostAddr string, target *prog.Target, sandbox string) { if err != nil { Fatalf("failed to detect supported syscalls: %v", err) } - calls = target.TransitivelyEnabledCalls(calls) + calls, _ = target.TransitivelyEnabledCalls(calls) Logf(0, "enabled syscalls: %v", len(calls)) if calls[target.SyscallMap["syz_emit_ethernet"]] || calls[target.SyscallMap["syz_extract_tcp_res"]] { diff --git a/tools/syz-mutate/mutate.go b/tools/syz-mutate/mutate.go index 4cf3401bc5c..73957c2465f 100644 --- a/tools/syz-mutate/mutate.go +++ b/tools/syz-mutate/mutate.go @@ -45,12 +45,10 @@ func main() { for id := range syscallsIDs { syscalls[target.Syscalls[id]] = true } - trans := target.TransitivelyEnabledCalls(syscalls) - for c := range syscalls { - if !trans[c] { - fmt.Fprintf(os.Stderr, "disabling %v\n", c.Name) - delete(syscalls, c) - } + var disabled map[*prog.Syscall]string + syscalls, disabled = target.TransitivelyEnabledCalls(syscalls) + for c, reason := range disabled { + fmt.Fprintf(os.Stderr, "disabling %v: %v\n", c.Name, reason) } } seed := time.Now().UnixNano() diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go index 73073c39266..2736c2f6ffd 100644 --- a/tools/syz-stress/stress.go +++ b/tools/syz-stress/stress.go @@ -148,14 +148,11 @@ func buildCallList(target *prog.Target) map[*prog.Syscall]bool { } } for c, reason := range disabled { - Logf(0, "disabling unsupported syscall: %v: %v", c.Name, reason) + Logf(0, "unsupported syscall: %v: %v", c.Name, reason) } - trans := target.TransitivelyEnabledCalls(calls) - for c := range calls { - if !trans[c] { - Logf(0, "disabling transitively unsupported syscall: %v", c.Name) - delete(calls, c) - } + calls, disabled = target.TransitivelyEnabledCalls(calls) + for c, reason := range disabled { + Logf(0, "transitively unsupported: %v: %v", c.Name, reason) } return calls }