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  }