gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/seccomp/seccomp_fuzz_helpers.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package seccomp 16 17 // This file contains helpers to generate fuzz tests for seccomp rules. 18 // It contains the `InterestingValues` implementations for all matchers, 19 // and a helper function to generate test cases based on `RuleSet`s. 20 21 import ( 22 "sort" 23 24 "gvisor.dev/gvisor/pkg/abi/linux" 25 ) 26 27 // UsefulTestCases returns a best-effort list of test cases that may be 28 // useful in fuzzing this set of rules. 29 func (sr SyscallRules) UsefulTestCases() []linux.SeccompData { 30 var testCases []linux.SeccompData 31 for sysno, r := range sr.rules { 32 33 // valueMatchers maps argument indexes to value matchers 34 // seen for that argument index. 35 // valueMatchersRepr tracks the `Repr()` of those 36 // `ValueMatcher`s in order to avoid inserting duplicates. 37 valueMatchers := make(map[int][]ValueMatcher) 38 valueMatchersRepr := make(map[int]map[string]struct{}) 39 40 // Find all unique `ValueMatcher`s for each argument. 41 var processRule func(SyscallRule) SyscallRule 42 processRule = func(r SyscallRule) SyscallRule { 43 r.Recurse(processRule) 44 pa, isPerArg := r.(PerArg) 45 if !isPerArg { 46 return r 47 } 48 for argNum, arg := range pa { 49 if arg == nil { 50 arg = AnyValue{} 51 } 52 valueMatchersReprMap, ok := valueMatchersRepr[argNum] 53 if !ok { 54 valueMatchersReprMap = make(map[string]struct{}) 55 valueMatchersRepr[argNum] = valueMatchersReprMap 56 } 57 repr := arg.Repr() 58 if _, seen := valueMatchersReprMap[repr]; seen { 59 continue 60 } 61 valueMatchersReprMap[repr] = struct{}{} 62 valueMatchers[argNum] = append(valueMatchers[argNum], arg) 63 } 64 return r 65 } 66 processRule(r) 67 68 // Now compute the combination of all interesting values for them. 69 sysnoCases := []linux.SeccompData{{ 70 Nr: int32(sysno), 71 Arch: LINUX_AUDIT_ARCH, 72 }} 73 for argNum, vms := range valueMatchers { 74 // Deduplicate interesting values across value matchers. 75 interestingValuesMap := make(map[uint64]struct{}) 76 interestingValuesMap[0] = struct{}{} // The zero value is always interesting. 77 for _, vm := range vms { 78 for _, interestingValue := range vm.InterestingValues() { 79 interestingValuesMap[interestingValue] = struct{}{} 80 } 81 } 82 83 // Convert to sorted slice of integers. 84 interestingValues := make([]uint64, 0, len(interestingValuesMap)) 85 for interestingValue := range interestingValuesMap { 86 interestingValues = append(interestingValues, interestingValue) 87 } 88 sort.Slice(interestingValues, func(i, j int) bool { 89 return interestingValues[i] < interestingValues[j] 90 }) 91 92 // Generate test cases. 93 newSysnoCases := make([]linux.SeccompData, 0, len(sysnoCases)*len(interestingValues)) 94 for _, sysnoCase := range sysnoCases { 95 for _, interestingValue := range interestingValues { 96 if argNum == RuleIP { 97 sysnoCase.InstructionPointer = interestingValue 98 } else { 99 sysnoCase.Args[argNum] = interestingValue 100 } 101 newSysnoCases = append(newSysnoCases, sysnoCase) 102 } 103 } 104 sysnoCases = newSysnoCases 105 } 106 testCases = append(testCases, sysnoCases...) 107 } 108 return testCases 109 } 110 111 // InterestingValues implements `halfValueMatcher.InterestingValues`. 112 func (halfAnyValue) InterestingValues() []uint32 { 113 return []uint32{0} 114 } 115 116 // InterestingValues implements `halfValueMatcher.InterestingValues`. 117 func (heq halfEqualTo) InterestingValues() []uint32 { 118 return []uint32{uint32(heq), uint32(heq + 1)} 119 } 120 121 // InterestingValues implements `halfValueMatcher.InterestingValues`. 122 func (hns halfNotSet) InterestingValues() []uint32 { 123 return []uint32{uint32(hns), uint32(hns + 1)} 124 } 125 126 // InterestingValues implements `halfValueMatcher.InterestingValues`. 127 func (hmeq halfMaskedEqual) InterestingValues() []uint32 { 128 return []uint32{uint32(hmeq.mask), uint32(hmeq.mask + 1)} 129 } 130 131 // InterestingValues implements `halfValueMatcher.InterestingValues`. 132 func (sm splitMatcher) InterestingValues() []uint64 { 133 interestingHigh := sm.highMatcher.InterestingValues() 134 interestingLow := sm.lowMatcher.InterestingValues() 135 interesting := make([]uint64, 0, len(interestingHigh)*len(interestingLow)) 136 for _, high := range interestingHigh { 137 for _, low := range interestingLow { 138 interesting = append(interesting, (uint64(high)<<32)|uint64(low)) 139 } 140 } 141 return interesting 142 } 143 144 // InterestingValues implements `halfValueMatcher.InterestingValues`. 145 func (av AnyValue) InterestingValues() []uint64 { 146 return []uint64{0} 147 } 148 149 // InterestingValues implements `halfValueMatcher.InterestingValues`. 150 func (eq EqualTo) InterestingValues() []uint64 { 151 return eq.split().InterestingValues() 152 } 153 154 // InterestingValues implements `halfValueMatcher.InterestingValues`. 155 func (ne NotEqual) InterestingValues() []uint64 { 156 return EqualTo(ne).InterestingValues() 157 } 158 159 // InterestingValues implements `halfValueMatcher.InterestingValues`. 160 func (gt GreaterThan) InterestingValues() []uint64 { 161 return []uint64{ 162 uint64(high32Bits(uintptr(gt))+1) << 32, 163 uint64(high32Bits(uintptr(gt))-1) << 32, 164 uint64(high32Bits(uintptr(gt))) << 32, 165 (uint64(high32Bits(uintptr(gt))) << 32) + uint64(low32Bits(uintptr(gt))), 166 (uint64(high32Bits(uintptr(gt))) << 32) + uint64(low32Bits(uintptr(gt))) + 1, 167 (uint64(high32Bits(uintptr(gt))) << 32) + uint64(low32Bits(uintptr(gt))) - 1, 168 } 169 } 170 171 // InterestingValues implements `halfValueMatcher.InterestingValues`. 172 func (ge GreaterThanOrEqual) InterestingValues() []uint64 { 173 return GreaterThan(ge).InterestingValues() 174 } 175 176 // InterestingValues implements `halfValueMatcher.InterestingValues`. 177 func (lt LessThan) InterestingValues() []uint64 { 178 return GreaterThan(lt).InterestingValues() 179 } 180 181 // InterestingValues implements `halfValueMatcher.InterestingValues`. 182 func (le LessThanOrEqual) InterestingValues() []uint64 { 183 return GreaterThan(le).InterestingValues() 184 } 185 186 // InterestingValues implements `halfValueMatcher.InterestingValues`. 187 func (nnfd NonNegativeFD) InterestingValues() []uint64 { 188 return nnfd.split().InterestingValues() 189 } 190 191 // InterestingValues implements `halfValueMatcher.InterestingValues`. 192 func (me maskedEqual) InterestingValues() []uint64 { 193 return me.split().InterestingValues() 194 }