github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/resources_test.go (about) 1 // Copyright 2015 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package prog 5 6 import ( 7 "math/rand" 8 "strings" 9 "testing" 10 11 "github.com/google/syzkaller/pkg/testutil" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestResourceCtors(t *testing.T) { 16 if testing.Short() && testutil.RaceEnabled { 17 t.Skip("too slow") 18 } 19 testEachTarget(t, func(t *testing.T, target *Target) { 20 for _, res := range target.Resources { 21 if len(target.calcResourceCtors(res, true)) == 0 && !strings.HasPrefix(res.Name, "ANY") && 22 res.Name != "disabled_resource" { 23 t.Errorf("resource %v can't be created", res.Name) 24 } 25 } 26 }) 27 } 28 29 func TestTransitivelyEnabledCalls(t *testing.T) { 30 testEachTarget(t, func(t *testing.T, target *Target) { 31 calls := make(map[*Syscall]bool) 32 for _, c := range target.Syscalls { 33 if c.Attrs.Disabled { 34 continue 35 } 36 calls[c] = true 37 } 38 enabled, disabled := target.TransitivelyEnabledCalls(calls) 39 for c, ok := range enabled { 40 if !ok { 41 t.Fatalf("syscalls %v is false in enabled map", c.Name) 42 } 43 } 44 if target.OS == "test" { 45 for c := range enabled { 46 if c.CallName == "unsupported" { 47 t.Errorf("call %v is not disabled", c.Name) 48 } 49 } 50 for c, reason := range disabled { 51 if c.CallName != "unsupported" { 52 t.Errorf("call %v is disabled: %v", c.Name, reason) 53 } 54 } 55 } else { 56 if len(enabled) != len(calls) { 57 t.Errorf("some calls are disabled: %v/%v", len(enabled), len(calls)) 58 } 59 for c, reason := range disabled { 60 t.Errorf("disabled %v: %v", c.Name, reason) 61 } 62 } 63 }) 64 } 65 66 func TestTransitivelyEnabledCallsLinux(t *testing.T) { 67 t.Parallel() 68 target, err := GetTarget("linux", "amd64") 69 if err != nil { 70 t.Fatal(err) 71 } 72 calls := make(map[*Syscall]bool) 73 for _, c := range target.Syscalls { 74 if c.Attrs.Disabled { 75 continue 76 } 77 calls[c] = true 78 } 79 delete(calls, target.SyscallMap["epoll_create"]) 80 if trans, disabled := target.TransitivelyEnabledCalls(calls); len(disabled) != 0 || len(trans) != len(calls) { 81 t.Fatalf("still must be able to create epoll fd with epoll_create1") 82 } 83 delete(calls, target.SyscallMap["epoll_create1"]) 84 trans, disabled := target.TransitivelyEnabledCalls(calls) 85 if len(calls)-8 != len(trans) || 86 trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_ADD"]] || 87 trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_MOD"]] || 88 trans[target.SyscallMap["epoll_ctl$EPOLL_CTL_DEL"]] || 89 trans[target.SyscallMap["epoll_wait"]] || 90 trans[target.SyscallMap["epoll_pwait"]] || 91 trans[target.SyscallMap["epoll_pwait2"]] || 92 trans[target.SyscallMap["kcmp$KCMP_EPOLL_TFD"]] || 93 trans[target.SyscallMap["syz_io_uring_submit$IORING_OP_EPOLL_CTL"]] { 94 t.Fatalf("epoll fd is not disabled") 95 } 96 if len(disabled) != 8 { 97 t.Fatalf("disabled %v syscalls, want 8", len(disabled)) 98 } 99 for c, reason := range disabled { 100 if !strings.Contains(reason, "fd_epoll [epoll_create epoll_create1]") { 101 t.Fatalf("%v: wrong disable reason: %v", c.Name, reason) 102 } 103 } 104 } 105 106 func TestGetInputResources(t *testing.T) { 107 expectedRequiredResources := map[string]bool{ 108 "required_res1": false, 109 "required_res2": false, 110 } 111 112 t.Parallel() 113 target, err := GetTarget("test", "64") 114 if err != nil { 115 t.Fatal(err) 116 } 117 118 resources := target.getInputResources(target.SyscallMap["test$optional_res"]) 119 for _, resource := range resources { 120 if _, ok := expectedRequiredResources[resource.Name]; ok { 121 expectedRequiredResources[resource.Name] = true 122 } else { 123 t.Fatalf(" unexpected %v", resource.Name) 124 } 125 } 126 for expectedRes, found := range expectedRequiredResources { 127 if !found { 128 t.Fatalf(" missing %v", expectedRes) 129 } 130 } 131 } 132 133 func TestClockGettime(t *testing.T) { 134 t.Parallel() 135 target, err := GetTarget("linux", "amd64") 136 if err != nil { 137 t.Fatal(err) 138 } 139 calls := make(map[*Syscall]bool) 140 for _, c := range target.Syscalls { 141 calls[c] = true 142 } 143 // Removal of clock_gettime should disable all calls that accept timespec/timeval. 144 delete(calls, target.SyscallMap["clock_gettime"]) 145 trans, disabled := target.TransitivelyEnabledCalls(calls) 146 if len(trans)+10 > len(calls) || len(trans)+len(disabled) != len(calls) || len(trans) == 0 { 147 t.Fatalf("clock_gettime did not disable enough calls: before %v, after %v, disabled %v", 148 len(calls), len(trans), len(disabled)) 149 } 150 } 151 152 func TestCreateResourceRotation(t *testing.T) { 153 target, rs, _ := initTest(t) 154 allCalls := make(map[*Syscall]bool) 155 for _, call := range target.Syscalls { 156 allCalls[call] = true 157 } 158 rotator := MakeRotator(target, allCalls, rand.New(rs)) 159 testCreateResource(t, target, rotator.Select(), rs) 160 } 161 162 func TestCreateResourceHalf(t *testing.T) { 163 target, rs, _ := initTest(t) 164 r := rand.New(rs) 165 var halfCalls map[*Syscall]bool 166 for len(halfCalls) == 0 { 167 halfCalls = make(map[*Syscall]bool) 168 for _, call := range target.Syscalls { 169 if r.Intn(10) == 0 { 170 halfCalls[call] = true 171 } 172 } 173 halfCalls, _ = target.TransitivelyEnabledCalls(halfCalls) 174 } 175 testCreateResource(t, target, halfCalls, rs) 176 } 177 178 func testCreateResource(t *testing.T, target *Target, calls map[*Syscall]bool, rs rand.Source) { 179 r := newRand(target, rs) 180 r.inGenerateResource = true 181 ct := target.BuildChoiceTable(nil, calls) 182 for call := range calls { 183 if call.Attrs.Disabled { 184 continue 185 } 186 t.Logf("testing call %v", call.Name) 187 ForeachCallType(call, func(typ Type, ctx *TypeCtx) { 188 if res, ok := typ.(*ResourceType); ok && ctx.Dir != DirOut { 189 s := newState(target, ct, nil) 190 arg, calls := r.createResource(s, res, DirIn) 191 if arg == nil && !ctx.Optional { 192 t.Fatalf("failed to create resource %v", res.Name()) 193 } 194 if arg != nil && len(calls) == 0 { 195 t.Fatalf("created resource %v, but got no calls", res.Name()) 196 } 197 } 198 }) 199 } 200 } 201 202 func TestPreferPreciseResources(t *testing.T) { 203 target, rs, _ := initRandomTargetTest(t, "test", "64") 204 r := newRand(target, rs) 205 counts := map[string]int{} 206 for i := 0; i < 2000; i++ { 207 s := newState(target, target.DefaultChoiceTable(), nil) 208 calls := r.generateParticularCall(s, 209 target.SyscallMap["test$consume_subtype_of_common"]) 210 for _, call := range calls { 211 if call.Meta.Name == "test$consume_subtype_of_common" { 212 continue 213 } 214 counts[call.Meta.Name]++ 215 } 216 } 217 assert.Greater(t, counts["test$produce_common"], 70) 218 assert.Greater(t, counts["test$also_produce_common"], 70) 219 assert.Greater(t, counts["test$produce_subtype_of_common"], 1000) 220 }