github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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 TestTransitivelyEnabledAutoCalls(t *testing.T) { 107 t.Parallel() 108 target, err := GetTarget("linux", "amd64") 109 if err != nil { 110 t.Fatal(err) 111 } 112 calls := make(map[*Syscall]bool) 113 for _, c := range target.Syscalls { 114 if c.Attrs.Automatic || c.Attrs.AutomaticHelper { 115 calls[c] = true 116 } 117 } 118 _, disabled := target.TransitivelyEnabledCalls(calls) 119 for c, reason := range disabled { 120 t.Errorf("disabled call %v: %v", c.Name, reason) 121 } 122 } 123 124 func TestGetInputResources(t *testing.T) { 125 expectedRequiredResources := map[string]bool{ 126 "required_res1": false, 127 "required_res2": false, 128 } 129 130 t.Parallel() 131 target, err := GetTarget("test", "64") 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 resources := target.getInputResources(target.SyscallMap["test$optional_res"]) 137 for _, resource := range resources { 138 if _, ok := expectedRequiredResources[resource.Name]; ok { 139 expectedRequiredResources[resource.Name] = true 140 } else { 141 t.Fatalf(" unexpected %v", resource.Name) 142 } 143 } 144 for expectedRes, found := range expectedRequiredResources { 145 if !found { 146 t.Fatalf(" missing %v", expectedRes) 147 } 148 } 149 } 150 151 func TestClockGettime(t *testing.T) { 152 t.Parallel() 153 target, err := GetTarget("linux", "amd64") 154 if err != nil { 155 t.Fatal(err) 156 } 157 calls := make(map[*Syscall]bool) 158 for _, c := range target.Syscalls { 159 calls[c] = true 160 } 161 // Removal of clock_gettime should disable all calls that accept timespec/timeval. 162 delete(calls, target.SyscallMap["clock_gettime"]) 163 trans, disabled := target.TransitivelyEnabledCalls(calls) 164 if len(trans)+10 > len(calls) || len(trans)+len(disabled) != len(calls) || len(trans) == 0 { 165 t.Fatalf("clock_gettime did not disable enough calls: before %v, after %v, disabled %v", 166 len(calls), len(trans), len(disabled)) 167 } 168 } 169 170 func TestCreateResourceRotation(t *testing.T) { 171 target, rs, _ := initTest(t) 172 allCalls := make(map[*Syscall]bool) 173 for _, call := range target.Syscalls { 174 allCalls[call] = true 175 } 176 rotator := MakeRotator(target, allCalls, rand.New(rs)) 177 testCreateResource(t, target, rotator.Select(), rs) 178 } 179 180 func TestCreateResourceHalf(t *testing.T) { 181 target, rs, _ := initTest(t) 182 r := rand.New(rs) 183 var halfCalls map[*Syscall]bool 184 for len(halfCalls) == 0 { 185 halfCalls = make(map[*Syscall]bool) 186 for _, call := range target.Syscalls { 187 if r.Intn(10) == 0 { 188 halfCalls[call] = true 189 } 190 } 191 halfCalls, _ = target.TransitivelyEnabledCalls(halfCalls) 192 } 193 testCreateResource(t, target, halfCalls, rs) 194 } 195 196 func testCreateResource(t *testing.T, target *Target, calls map[*Syscall]bool, rs rand.Source) { 197 r := newRand(target, rs) 198 r.inGenerateResource = true 199 ct := target.BuildChoiceTable(nil, calls) 200 for call := range calls { 201 if call.Attrs.Disabled { 202 continue 203 } 204 t.Logf("testing call %v", call.Name) 205 ForeachCallType(call, func(typ Type, ctx *TypeCtx) { 206 if res, ok := typ.(*ResourceType); ok && ctx.Dir != DirOut { 207 s := newState(target, ct, nil) 208 arg, calls := r.createResource(s, res, DirIn) 209 if arg == nil && !ctx.Optional { 210 t.Fatalf("failed to create resource %v", res.Name()) 211 } 212 if arg != nil && len(calls) == 0 { 213 t.Fatalf("created resource %v, but got no calls", res.Name()) 214 } 215 } 216 }) 217 } 218 } 219 220 func TestPreferPreciseResources(t *testing.T) { 221 target, rs, _ := initRandomTargetTest(t, "test", "64") 222 r := newRand(target, rs) 223 counts := map[string]int{} 224 for i := 0; i < 2000; i++ { 225 s := newState(target, target.DefaultChoiceTable(), nil) 226 calls := r.generateParticularCall(s, 227 target.SyscallMap["test$consume_subtype_of_common"]) 228 for _, call := range calls { 229 if call.Meta.Name == "test$consume_subtype_of_common" { 230 continue 231 } 232 counts[call.Meta.Name]++ 233 } 234 } 235 assert.Greater(t, counts["test$produce_common"], 70) 236 assert.Greater(t, counts["test$also_produce_common"], 70) 237 assert.Greater(t, counts["test$produce_subtype_of_common"], 1000) 238 }