github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/prog/rand.go (about)

     1  // Copyright 2015/2016 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  	"bytes"
     8  	"fmt"
     9  	"math"
    10  	"math/rand"
    11  	"path/filepath"
    12  	"sort"
    13  	"strings"
    14  
    15  	"github.com/google/syzkaller/pkg/ifuzz"
    16  )
    17  
    18  const (
    19  	// "Recommended" number of calls in programs that we try to aim at during fuzzing.
    20  	RecommendedCalls = 30
    21  	// "Recommended" max number of calls in programs.
    22  	// If we receive longer programs from hub/corpus we discard them.
    23  	MaxCalls = 40
    24  	// "Recommended" number of calls in KFuzzTest mode. These targets test the behavior
    25  	// of internal kernel functions rather than system behavior, and for this reason
    26  	// it is more sensible to generate a smaller number of calls instead of long chains.
    27  	RecommendedCallsKFuzzTest = 5
    28  )
    29  
    30  type randGen struct {
    31  	*rand.Rand
    32  	target                *Target
    33  	inGenerateResource    bool
    34  	patchConditionalDepth int
    35  	genKFuzzTest          bool
    36  	recDepth              map[string]int
    37  }
    38  
    39  func newRand(target *Target, rs rand.Source) *randGen {
    40  	return &randGen{
    41  		Rand:     rand.New(rs),
    42  		target:   target,
    43  		recDepth: make(map[string]int),
    44  	}
    45  }
    46  
    47  func (r *randGen) rand(n int) uint64 {
    48  	return uint64(r.Intn(n))
    49  }
    50  
    51  func (r *randGen) randRange(begin, end uint64) uint64 {
    52  	return begin + uint64(r.Intn(int(end-begin+1)))
    53  }
    54  
    55  func (r *randGen) bin() bool {
    56  	return r.Intn(2) == 0
    57  }
    58  
    59  func (r *randGen) oneOf(n int) bool {
    60  	return r.Intn(n) == 0
    61  }
    62  
    63  func (r *randGen) rand64() uint64 {
    64  	v := uint64(r.Int63())
    65  	if r.bin() {
    66  		v |= 1 << 63
    67  	}
    68  	return v
    69  }
    70  
    71  var (
    72  	// Some potentially interesting integers.
    73  	specialInts = []uint64{
    74  		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    75  		64, 127, 128, 129, 255, 256, 257, 511, 512,
    76  		1023, 1024, 1025, 2047, 2048, 4095, 4096,
    77  		(1 << 15) - 1, (1 << 15), (1 << 15) + 1,
    78  		(1 << 16) - 1, (1 << 16), (1 << 16) + 1,
    79  		(1 << 31) - 1, (1 << 31), (1 << 31) + 1,
    80  		(1 << 32) - 1, (1 << 32), (1 << 32) + 1,
    81  		(1 << 63) - 1, (1 << 63), (1 << 63) + 1,
    82  		(1 << 64) - 1,
    83  	}
    84  	// The indexes (exclusive) for the maximum specialInts values that fit in 1, 2, ... 8 bytes.
    85  	specialIntIndex [9]int
    86  )
    87  
    88  func init() {
    89  	sort.Slice(specialInts, func(i, j int) bool {
    90  		return specialInts[i] < specialInts[j]
    91  	})
    92  	for i := range specialIntIndex {
    93  		bitSize := uint64(8 * i)
    94  		specialIntIndex[i] = sort.Search(len(specialInts), func(i int) bool {
    95  			return specialInts[i]>>bitSize != 0
    96  		})
    97  	}
    98  }
    99  
   100  func (r *randGen) randInt64() uint64 {
   101  	return r.randInt(64)
   102  }
   103  
   104  func (r *randGen) randInt(bits uint64) uint64 {
   105  	v := r.rand64()
   106  	switch {
   107  	case r.nOutOf(100, 182):
   108  		v %= 10
   109  	case bits >= 8 && r.nOutOf(50, 82):
   110  		v = specialInts[r.Intn(specialIntIndex[bits/8])]
   111  	case r.nOutOf(10, 32):
   112  		v %= 256
   113  	case r.nOutOf(10, 22):
   114  		v %= 4 << 10
   115  	case r.nOutOf(10, 12):
   116  		v %= 64 << 10
   117  	default:
   118  		v %= 1 << 31
   119  	}
   120  	switch {
   121  	case r.nOutOf(100, 107):
   122  	case r.nOutOf(5, 7):
   123  		v = uint64(-int64(v))
   124  	default:
   125  		v <<= uint(r.Intn(int(bits)))
   126  	}
   127  	return truncateToBitSize(v, bits)
   128  }
   129  
   130  func truncateToBitSize(v, bitSize uint64) uint64 {
   131  	if bitSize == 0 || bitSize > 64 {
   132  		panic(fmt.Sprintf("invalid bitSize value: %d", bitSize))
   133  	}
   134  	return v & uint64(1<<bitSize-1)
   135  }
   136  
   137  func (r *randGen) randRangeInt(begin, end, bitSize, align uint64) uint64 {
   138  	if r.oneOf(100) {
   139  		return r.randInt(bitSize)
   140  	}
   141  	if align != 0 {
   142  		if begin == 0 && int64(end) == -1 {
   143  			// Special [0:-1] range for all possible values.
   144  			end = uint64(1<<bitSize - 1)
   145  		}
   146  		endAlign := (end - begin) / align
   147  		return begin + r.randRangeInt(0, endAlign, bitSize, 0)*align
   148  	}
   149  	return begin + (r.Uint64() % (end - begin + 1))
   150  }
   151  
   152  // biasedRand returns a random int in range [0..n),
   153  // probability of n-1 is k times higher than probability of 0.
   154  func (r *randGen) biasedRand(n, k int) int {
   155  	nf, kf := float64(n), float64(k)
   156  	rf := nf * (kf/2 + 1) * r.Float64()
   157  	bf := (-1 + math.Sqrt(1+2*kf*rf/nf)) * nf / kf
   158  	return int(bf)
   159  }
   160  
   161  const maxArrayLen = 10
   162  
   163  func (r *randGen) randArrayLen() uint64 {
   164  	// biasedRand produces: 10, 9, ..., 1, 0,
   165  	// we want: 1, 2, ..., 9, 10, 0
   166  	return uint64(maxArrayLen-r.biasedRand(maxArrayLen+1, 10)+1) % (maxArrayLen + 1)
   167  }
   168  
   169  func (r *randGen) randBufLen() (n uint64) {
   170  	switch {
   171  	case r.nOutOf(50, 56):
   172  		n = r.rand(256)
   173  	case r.nOutOf(5, 6):
   174  		n = 4 << 10
   175  	}
   176  	return
   177  }
   178  
   179  func (r *randGen) randPageCount() (n uint64) {
   180  	switch {
   181  	case r.nOutOf(100, 106):
   182  		n = r.rand(4) + 1
   183  	case r.nOutOf(5, 6):
   184  		n = r.rand(20) + 1
   185  	default:
   186  		n = (r.rand(3) + 1) * r.target.NumPages / 4
   187  	}
   188  	return
   189  }
   190  
   191  // Change a flag value or generate a new one.
   192  // If you are changing this function, run TestFlags and examine effect of results.
   193  func (r *randGen) flags(vv []uint64, bitmask bool, oldVal uint64) uint64 {
   194  	// Get these simpler cases out of the way first.
   195  	// Once in a while we want to return completely random values,
   196  	// or 0 which is frequently special.
   197  	if r.oneOf(100) {
   198  		return r.rand64()
   199  	}
   200  	if r.oneOf(50) {
   201  		return 0
   202  	}
   203  	if !bitmask && oldVal != 0 && r.oneOf(100) {
   204  		// Slightly increment/decrement the old value.
   205  		// This is especially important during mutation when len(vv) == 1,
   206  		// otherwise in that case we produce almost no randomness
   207  		// (the value is always mutated to 0).
   208  		inc := uint64(1)
   209  		if r.bin() {
   210  			inc = ^uint64(0)
   211  		}
   212  		v := oldVal + inc
   213  		for r.bin() {
   214  			v += inc
   215  		}
   216  		return v
   217  	}
   218  	if len(vv) == 1 {
   219  		// This usually means that value or 0,
   220  		// at least that's our best (and only) bet.
   221  		if r.bin() {
   222  			return 0
   223  		}
   224  		return vv[0]
   225  	}
   226  	if !bitmask && !r.oneOf(10) {
   227  		// Enumeration, so just choose one of the values.
   228  		return vv[r.rand(len(vv))]
   229  	}
   230  	if r.oneOf(len(vv) + 4) {
   231  		return 0
   232  	}
   233  	// Flip rand bits. Do this for non-bitmask sometimes
   234  	// because we may have detected bitmask incorrectly for complex cases
   235  	// (e.g. part of the vlaue is bitmask and another is not).
   236  	v := oldVal
   237  	if v != 0 && r.oneOf(10) {
   238  		v = 0 // Ignore the old value sometimes.
   239  	}
   240  	// We don't want to return 0 here, because we already given 0
   241  	// fixed probability above (otherwise we get 0 too frequently).
   242  	// Note: this loop can hang if all values are equal to 0. We don't generate such flags in the compiler now,
   243  	// but it used to hang occasionally, so we keep the try < 10 logic b/c we don't have a local check for values.
   244  	for try := 0; try < 10 && (v == 0 || r.nOutOf(2, 3)); try++ {
   245  		flag := vv[r.rand(len(vv))]
   246  		if r.oneOf(20) {
   247  			// Try choosing adjacent bit values in case we forgot
   248  			// to add all relevant flags to the descriptions.
   249  			if r.bin() {
   250  				flag >>= 1
   251  			} else {
   252  				flag <<= 1
   253  			}
   254  		}
   255  		v ^= flag
   256  	}
   257  	return v
   258  }
   259  
   260  func (r *randGen) filename(s *state, typ *BufferType) string {
   261  	fn := r.filenameImpl(s)
   262  	if fn != "" && fn[len(fn)-1] == 0 {
   263  		panic(fmt.Sprintf("zero-terminated filename: %q", fn))
   264  	}
   265  	if escapingFilename(fn) {
   266  		panic(fmt.Sprintf("sandbox escaping file name %q, s.files are %v", fn, s.files))
   267  	}
   268  	if !typ.Varlen() {
   269  		size := typ.Size()
   270  		if uint64(len(fn)) < size {
   271  			fn += string(make([]byte, size-uint64(len(fn))))
   272  		}
   273  		fn = fn[:size]
   274  	} else if !typ.NoZ {
   275  		fn += "\x00"
   276  	}
   277  	return fn
   278  }
   279  
   280  func escapingFilename(file string) bool {
   281  	file = filepath.Clean(file)
   282  	return len(file) >= 1 && file[0] == '/' ||
   283  		len(file) >= 2 && file[0] == '.' && file[1] == '.'
   284  }
   285  
   286  var specialFiles = []string{"", "."}
   287  
   288  const specialFileLenPad = "a"
   289  
   290  func (r *randGen) filenameImpl(s *state) string {
   291  	if r.oneOf(100) {
   292  		return specialFiles[r.Intn(len(specialFiles))]
   293  	}
   294  	if len(s.files) == 0 || r.oneOf(10) {
   295  		// Generate a new name.
   296  		dir := "."
   297  		if r.oneOf(2) && len(s.files) != 0 {
   298  			dir = r.randFromMap(s.files)
   299  			if dir != "" && dir[len(dir)-1] == 0 {
   300  				dir = dir[:len(dir)-1]
   301  			}
   302  			if r.oneOf(10) && filepath.Clean(dir)[0] != '.' {
   303  				dir += "/.."
   304  			}
   305  		}
   306  		for i := 0; ; i++ {
   307  			f := fmt.Sprintf("%v/file%v", dir, i)
   308  			if r.oneOf(100) {
   309  				// Make file name very long using target.SpecialFileLenghts consts.
   310  				// Add/subtract some small const to account for our file name prefix
   311  				// and potential kernel off-by-one's.
   312  				fileLen := r.randFilenameLength()
   313  				if add := fileLen - len(f); add > 0 {
   314  					f += strings.Repeat(specialFileLenPad, add)
   315  				}
   316  			}
   317  			if !s.files[f] {
   318  				return f
   319  			}
   320  		}
   321  	}
   322  	return r.randFromMap(s.files)
   323  }
   324  
   325  func (r *randGen) randFilenameLength() int {
   326  	off := r.biasedRand(10, 5)
   327  	if r.bin() {
   328  		off = -off
   329  	}
   330  	lens := r.target.SpecialFileLenghts
   331  	return max(lens[r.Intn(len(lens))]+off, 0)
   332  }
   333  
   334  func (r *randGen) randFromMap(m map[string]bool) string {
   335  	files := make([]string, 0, len(m))
   336  	for f := range m {
   337  		files = append(files, f)
   338  	}
   339  	sort.Strings(files)
   340  	return files[r.Intn(len(files))]
   341  }
   342  
   343  func (r *randGen) randString(s *state, t *BufferType) []byte {
   344  	if len(t.Values) != 0 {
   345  		return []byte(t.Values[r.Intn(len(t.Values))])
   346  	}
   347  	if len(s.strings) != 0 && r.bin() {
   348  		// Return an existing string.
   349  		// TODO(dvyukov): make s.strings indexed by string SubKind.
   350  		return []byte(r.randFromMap(s.strings))
   351  	}
   352  	punct := []byte{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '+', '\\',
   353  		'/', ':', '.', ',', '-', '\'', '[', ']', '{', '}'}
   354  	buf := new(bytes.Buffer)
   355  	for r.nOutOf(3, 4) {
   356  		if r.nOutOf(10, 11) {
   357  			buf.Write([]byte{punct[r.Intn(len(punct))]})
   358  		} else {
   359  			buf.Write([]byte{byte(r.Intn(256))})
   360  		}
   361  	}
   362  	// We always null-terminate strings that are inputs to KFuzzTest calls to
   363  	// avoid false-positive buffer overflow reports.
   364  	if r.oneOf(100) == t.NoZ || r.genKFuzzTest {
   365  		buf.Write([]byte{0})
   366  	}
   367  	return buf.Bytes()
   368  }
   369  
   370  func (r *randGen) allocAddr(s *state, typ Type, dir Dir, size uint64, data Arg) *PointerArg {
   371  	return MakePointerArg(typ, dir, s.ma.alloc(r, size, data.Type().Alignment()), data)
   372  }
   373  
   374  func (r *randGen) allocVMA(s *state, typ Type, dir Dir, numPages uint64) *PointerArg {
   375  	page := s.va.alloc(r, numPages)
   376  	return MakeVmaPointerArg(typ, dir, page*r.target.PageSize, numPages*r.target.PageSize)
   377  }
   378  
   379  func (r *randGen) pruneRecursion(name string) (bool, func()) {
   380  	if r.recDepth[name] >= 2 {
   381  		return false, nil
   382  	}
   383  	r.recDepth[name]++
   384  	return true, func() {
   385  		r.recDepth[name]--
   386  		if r.recDepth[name] == 0 {
   387  			delete(r.recDepth, name)
   388  		}
   389  	}
   390  }
   391  
   392  func (r *randGen) createResource(s *state, res *ResourceType, dir Dir) (Arg, []*Call) {
   393  	if !r.inGenerateResource {
   394  		panic("inGenerateResource is not set")
   395  	}
   396  	kind := res.Desc.Name
   397  	// Find calls that produce the necessary resources.
   398  	ctors := r.enabledCtors(s, kind)
   399  	// We may have no resources, but still be in createResource due to ANYRES.
   400  	if len(r.target.resourceMap) != 0 && r.oneOf(1000) {
   401  		// Spoof resource subkind.
   402  		var all []string
   403  		for kind1 := range r.target.resourceMap {
   404  			if r.target.isCompatibleResource(res.Desc.Kind[0], kind1) {
   405  				all = append(all, kind1)
   406  			}
   407  		}
   408  		if len(all) == 0 {
   409  			panic(fmt.Sprintf("got no spoof resources for %v in %v/%v",
   410  				kind, r.target.OS, r.target.Arch))
   411  		}
   412  		sort.Strings(all)
   413  		kind1 := all[r.Intn(len(all))]
   414  		ctors1 := r.enabledCtors(s, kind1)
   415  		if len(ctors1) != 0 {
   416  			// Don't use the resource for which we don't have any ctors.
   417  			// It's fine per-se because below we just return nil in such case.
   418  			// But in TestCreateResource tests we want to ensure that we don't fail
   419  			// to create non-optional resources, and if we spoof a non-optional
   420  			// resource with ctors with a optional resource w/o ctors, then that check will fail.
   421  			kind, ctors = kind1, ctors1
   422  		}
   423  	}
   424  	if len(ctors) == 0 {
   425  		// We may not have any constructors for optional input resources because we don't disable
   426  		// syscalls based on optional inputs resources w/o ctors in TransitivelyEnabledCalls.
   427  		return nil, nil
   428  	}
   429  	// Now we have a set of candidate calls that can create the necessary resource.
   430  	// Generate one of them.
   431  	var meta *Syscall
   432  	// Prefer precise constructors.
   433  	var precise []*Syscall
   434  	for _, info := range ctors {
   435  		if info.Precise {
   436  			precise = append(precise, info.Call)
   437  		}
   438  	}
   439  	if len(precise) > 0 {
   440  		// If the argument is optional, it's not guaranteed that there'd be a
   441  		// precise constructor.
   442  		meta = precise[r.Intn(len(precise))]
   443  	}
   444  	if meta == nil || r.oneOf(3) {
   445  		// Sometimes just take a random one.
   446  		meta = ctors[r.Intn(len(ctors))].Call
   447  	}
   448  
   449  	calls := r.generateParticularCall(s, meta)
   450  	s1 := newState(r.target, s.ct, nil)
   451  	s1.analyze(calls[len(calls)-1])
   452  	// Now see if we have what we want.
   453  	var allres []*ResultArg
   454  	for kind1, res1 := range s1.resources {
   455  		if r.target.isCompatibleResource(kind, kind1) {
   456  			allres = append(allres, res1...)
   457  		}
   458  	}
   459  	sort.SliceStable(allres, func(i, j int) bool {
   460  		return allres[i].Type().Name() < allres[j].Type().Name()
   461  	})
   462  	if len(allres) == 0 {
   463  		panic(fmt.Sprintf("failed to create a resource %v (%v) with %v",
   464  			res.Desc.Kind[0], kind, meta.Name))
   465  	}
   466  	arg := MakeResultArg(res, dir, allres[r.Intn(len(allres))], 0)
   467  	return arg, calls
   468  }
   469  
   470  func (r *randGen) enabledCtors(s *state, kind string) []ResourceCtor {
   471  	var ret []ResourceCtor
   472  	for _, info := range r.target.resourceCtors[kind] {
   473  		if s.ct.Generatable(info.Call.ID) {
   474  			ret = append(ret, info)
   475  		}
   476  	}
   477  	return ret
   478  }
   479  
   480  func (r *randGen) generateText(kind TextKind) []byte {
   481  	switch kind {
   482  	case TextTarget:
   483  		if cfg := createTargetIfuzzConfig(r.target); cfg != nil {
   484  			return ifuzz.Generate(cfg, r.Rand)
   485  		}
   486  		text := make([]byte, 50)
   487  		for i := range text {
   488  			text[i] = byte(r.Intn(256))
   489  		}
   490  		return text
   491  	default:
   492  		cfg := createIfuzzConfig(kind)
   493  		return ifuzz.Generate(cfg, r.Rand)
   494  	}
   495  }
   496  
   497  func (r *randGen) mutateText(kind TextKind, text []byte) []byte {
   498  	switch kind {
   499  	case TextTarget:
   500  		if cfg := createTargetIfuzzConfig(r.target); cfg != nil {
   501  			return ifuzz.Mutate(cfg, r.Rand, text)
   502  		}
   503  		return mutateData(r, text, 40, 60)
   504  	default:
   505  		cfg := createIfuzzConfig(kind)
   506  		return ifuzz.Mutate(cfg, r.Rand, text)
   507  	}
   508  }
   509  
   510  func createTargetIfuzzConfig(target *Target) *ifuzz.Config {
   511  	cfg := &ifuzz.Config{
   512  		Len:  10,
   513  		Priv: false,
   514  		Exec: true,
   515  		MemRegions: []ifuzz.MemRegion{
   516  			{Start: target.DataOffset, Size: target.NumPages * target.PageSize},
   517  		},
   518  	}
   519  	for _, p := range target.SpecialPointers {
   520  		cfg.MemRegions = append(cfg.MemRegions, ifuzz.MemRegion{
   521  			Start: p & ^target.PageSize, Size: p & ^target.PageSize + target.PageSize,
   522  		})
   523  	}
   524  	switch target.Arch {
   525  	case "amd64":
   526  		cfg.Mode = ifuzz.ModeLong64
   527  		cfg.Arch = ifuzz.ArchX86
   528  	case "386":
   529  		cfg.Mode = ifuzz.ModeProt32
   530  		cfg.Arch = ifuzz.ArchX86
   531  	case "ppc64":
   532  		cfg.Mode = ifuzz.ModeLong64
   533  		cfg.Arch = ifuzz.ArchPowerPC
   534  	case "arm64":
   535  		cfg.Mode = ifuzz.ModeLong64
   536  		cfg.Arch = ifuzz.ArchArm64
   537  	default:
   538  		return nil
   539  	}
   540  	return cfg
   541  }
   542  
   543  func createIfuzzConfig(kind TextKind) *ifuzz.Config {
   544  	cfg := &ifuzz.Config{
   545  		Len:  10,
   546  		Priv: true,
   547  		Exec: true,
   548  		MemRegions: []ifuzz.MemRegion{
   549  			{Start: 0 << 12, Size: 1 << 12},
   550  			{Start: 1 << 12, Size: 1 << 12},
   551  			{Start: 2 << 12, Size: 1 << 12},
   552  			{Start: 3 << 12, Size: 1 << 12},
   553  			{Start: 4 << 12, Size: 1 << 12},
   554  			{Start: 5 << 12, Size: 1 << 12},
   555  			{Start: 6 << 12, Size: 1 << 12},
   556  			{Start: 7 << 12, Size: 1 << 12},
   557  			{Start: 8 << 12, Size: 1 << 12},
   558  			{Start: 9 << 12, Size: 1 << 12},
   559  			{Start: 0xfec00000, Size: 0x100}, // ioapic
   560  		},
   561  	}
   562  	switch kind {
   563  	case TextX86Real:
   564  		cfg.Mode = ifuzz.ModeReal16
   565  		cfg.Arch = ifuzz.ArchX86
   566  	case TextX86bit16:
   567  		cfg.Mode = ifuzz.ModeProt16
   568  		cfg.Arch = ifuzz.ArchX86
   569  	case TextX86bit32:
   570  		cfg.Mode = ifuzz.ModeProt32
   571  		cfg.Arch = ifuzz.ArchX86
   572  	case TextX86bit64:
   573  		cfg.Mode = ifuzz.ModeLong64
   574  		cfg.Arch = ifuzz.ArchX86
   575  	case TextPpc64:
   576  		cfg.Mode = ifuzz.ModeLong64
   577  		cfg.Arch = ifuzz.ArchPowerPC
   578  	case TextArm64:
   579  		cfg.Mode = ifuzz.ModeLong64
   580  		cfg.Arch = ifuzz.ArchArm64
   581  	default:
   582  		panic(fmt.Sprintf("unknown text kind: %v", kind))
   583  	}
   584  	return cfg
   585  }
   586  
   587  // nOutOf returns true n out of outOf times.
   588  func (r *randGen) nOutOf(n, outOf int) bool {
   589  	if n <= 0 || n >= outOf {
   590  		panic("bad probability")
   591  	}
   592  	v := r.Intn(outOf)
   593  	return v < n
   594  }
   595  
   596  func (r *randGen) generateCall(s *state, p *Prog, insertionPoint int) []*Call {
   597  	biasCall := -1
   598  	if insertionPoint > 0 {
   599  		// Choosing the base call is based on the insertion point of the new calls sequence.
   600  		insertionCall := p.Calls[r.Intn(insertionPoint)].Meta
   601  		if !insertionCall.Attrs.NoGenerate {
   602  			// We must be careful not to bias towards a non-generatable call.
   603  			biasCall = insertionCall.ID
   604  		}
   605  	}
   606  	idx := s.ct.choose(r.Rand, biasCall)
   607  	meta := r.target.Syscalls[idx]
   608  	return r.generateParticularCall(s, meta)
   609  }
   610  
   611  func (r *randGen) generateParticularCall(s *state, meta *Syscall) (calls []*Call) {
   612  	if meta.Attrs.Disabled {
   613  		panic(fmt.Sprintf("generating disabled call %v", meta.Name))
   614  	}
   615  	if meta.Attrs.NoGenerate {
   616  		panic(fmt.Sprintf("generating no_generate call: %v", meta.Name))
   617  	}
   618  	c := MakeCall(meta, nil)
   619  	// KFuzzTest calls restrict mutation and generation. Since calls to
   620  	// generateParticularCall can be recursive, we save the previous value, and
   621  	// set it true.
   622  	if c.Meta.Attrs.KFuzzTest {
   623  		tmp := r.genKFuzzTest
   624  		r.genKFuzzTest = true
   625  		defer func() {
   626  			r.genKFuzzTest = tmp
   627  		}()
   628  	}
   629  	c.Args, calls = r.generateArgs(s, meta.Args, DirIn)
   630  	moreCalls, _ := r.patchConditionalFields(c, s)
   631  	r.target.assignSizesCall(c)
   632  	return append(append(calls, moreCalls...), c)
   633  }
   634  
   635  // GenerateAllSyzProg generates a program that contains all pseudo syz_ calls for testing.
   636  func (target *Target) GenerateAllSyzProg(rs rand.Source) *Prog {
   637  	p := &Prog{
   638  		Target: target,
   639  	}
   640  	r := newRand(target, rs)
   641  	s := newState(target, target.DefaultChoiceTable(), nil)
   642  	for _, meta := range target.PseudoSyscalls() {
   643  		calls := r.generateParticularCall(s, meta)
   644  		for _, c := range calls {
   645  			s.analyze(c)
   646  			p.Calls = append(p.Calls, c)
   647  		}
   648  	}
   649  	if err := p.validate(); err != nil {
   650  		panic(err)
   651  	}
   652  	return p
   653  }
   654  
   655  // PseudoSyscalls selects one *Syscall for each pseudosyscall.
   656  func (target *Target) PseudoSyscalls() []*Syscall {
   657  	handled := make(map[string]bool)
   658  	var ret []*Syscall
   659  	for _, meta := range target.Syscalls {
   660  		if !strings.HasPrefix(meta.CallName, "syz_") ||
   661  			handled[meta.CallName] ||
   662  			meta.Attrs.Disabled ||
   663  			meta.Attrs.NoGenerate {
   664  			continue
   665  		}
   666  		ret = append(ret, meta)
   667  		handled[meta.CallName] = true
   668  	}
   669  	return ret
   670  }
   671  
   672  // GenSampleProg generates a single sample program for the call.
   673  func (target *Target) GenSampleProg(meta *Syscall, rs rand.Source, ct *ChoiceTable) *Prog {
   674  	r := newRand(target, rs)
   675  	s := newState(target, ct, nil)
   676  	p := &Prog{
   677  		Target: target,
   678  	}
   679  	for _, c := range r.generateParticularCall(s, meta) {
   680  		s.analyze(c)
   681  		p.Calls = append(p.Calls, c)
   682  	}
   683  	if err := p.validate(); err != nil {
   684  		panic(err)
   685  	}
   686  	return p
   687  }
   688  
   689  // DataMmapProg creates program that maps data segment.
   690  // Also used for testing as the simplest program.
   691  func (target *Target) DataMmapProg() *Prog {
   692  	return &Prog{
   693  		Target:   target,
   694  		Calls:    target.MakeDataMmap(),
   695  		isUnsafe: true,
   696  	}
   697  }
   698  
   699  func (r *randGen) generateArgs(s *state, fields []Field, dir Dir) ([]Arg, []*Call) {
   700  	var calls []*Call
   701  	args := make([]Arg, len(fields))
   702  
   703  	// Generate all args. Size args have the default value 0 for now.
   704  	for i, field := range fields {
   705  		arg, calls1 := r.generateArg(s, field.Type, field.Dir(dir))
   706  		if arg == nil {
   707  			panic(fmt.Sprintf("generated arg is nil for field '%v', fields: %+v", field.Type.Name(), fields))
   708  		}
   709  		args[i] = arg
   710  		calls = append(calls, calls1...)
   711  	}
   712  
   713  	return args, calls
   714  }
   715  
   716  func (r *randGen) generateArg(s *state, typ Type, dir Dir) (arg Arg, calls []*Call) {
   717  	return r.generateArgImpl(s, typ, dir, false)
   718  }
   719  
   720  func (r *randGen) generateArgImpl(s *state, typ Type, dir Dir, ignoreSpecial bool) (arg Arg, calls []*Call) {
   721  	if dir == DirOut {
   722  		// No need to generate something interesting for output scalar arguments.
   723  		// But we still need to generate the argument itself so that it can be referenced
   724  		// in subsequent calls. For the same reason we do generate pointer/array/struct
   725  		// output arguments (their elements can be referenced in subsequent calls).
   726  		switch typ.(type) {
   727  		case *IntType, *FlagsType, *ConstType, *ProcType, *VmaType, *ResourceType:
   728  			return typ.DefaultArg(dir), nil
   729  		}
   730  	}
   731  
   732  	if typ.Optional() && r.oneOf(5) {
   733  		if res, ok := typ.(*ResourceType); ok {
   734  			v := res.Desc.Values[r.Intn(len(res.Desc.Values))]
   735  			return MakeResultArg(typ, dir, nil, v), nil
   736  		}
   737  		return typ.DefaultArg(dir), nil
   738  	}
   739  
   740  	if !ignoreSpecial && dir != DirOut {
   741  		switch typ.(type) {
   742  		case *StructType, *UnionType:
   743  			if gen := r.target.SpecialTypes[typ.Name()]; gen != nil {
   744  				return gen(&Gen{r, s}, typ, dir, nil)
   745  			}
   746  		}
   747  	}
   748  
   749  	return typ.generate(r, s, dir)
   750  }
   751  
   752  func (a *ResourceType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   753  	canRecurse := false
   754  	if !r.inGenerateResource {
   755  		// Don't allow recursion for resourceCentric/createResource.
   756  		// That can lead to generation of huge programs and may be very slow
   757  		// (esp. if we are generating some failing attempts in createResource already).
   758  		r.inGenerateResource = true
   759  		defer func() { r.inGenerateResource = false }()
   760  		canRecurse = true
   761  	}
   762  	if canRecurse && r.nOutOf(8, 10) ||
   763  		!canRecurse && r.nOutOf(19, 20) {
   764  		arg = r.existingResource(s, a, dir)
   765  		if arg != nil {
   766  			return
   767  		}
   768  	}
   769  	if canRecurse {
   770  		if r.oneOf(4) {
   771  			arg, calls = r.resourceCentric(s, a, dir)
   772  			if arg != nil {
   773  				return
   774  			}
   775  		}
   776  		if r.nOutOf(4, 5) {
   777  			// If we could not reuse a resource, let's prefer resource creation over
   778  			// random int substitution.
   779  			arg, calls = r.createResource(s, a, dir)
   780  			if arg != nil {
   781  				return
   782  			}
   783  		}
   784  	}
   785  	special := a.SpecialValues()
   786  	arg = MakeResultArg(a, dir, nil, special[r.Intn(len(special))])
   787  	return
   788  }
   789  
   790  func (a *BufferType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   791  	switch a.Kind {
   792  	case BufferBlobRand, BufferBlobRange:
   793  		sz := r.randBufLen()
   794  		if a.Kind == BufferBlobRange {
   795  			sz = r.randRange(a.RangeBegin, a.RangeEnd)
   796  		}
   797  		if dir == DirOut {
   798  			return MakeOutDataArg(a, dir, sz), nil
   799  		}
   800  		data := make([]byte, sz)
   801  		for i := range data {
   802  			data[i] = byte(r.Intn(256))
   803  		}
   804  		return MakeDataArg(a, dir, data), nil
   805  	case BufferString:
   806  		data := r.randString(s, a)
   807  		if dir == DirOut {
   808  			return MakeOutDataArg(a, dir, uint64(len(data))), nil
   809  		}
   810  		return MakeDataArg(a, dir, data), nil
   811  	case BufferFilename:
   812  		if dir == DirOut {
   813  			var sz uint64
   814  			switch {
   815  			case !a.Varlen():
   816  				sz = a.Size()
   817  			case r.nOutOf(1, 3):
   818  				sz = r.rand(100)
   819  			default:
   820  				sz = uint64(r.randFilenameLength())
   821  			}
   822  			return MakeOutDataArg(a, dir, sz), nil
   823  		}
   824  		return MakeDataArg(a, dir, []byte(r.filename(s, a))), nil
   825  	case BufferGlob:
   826  		return MakeDataArg(a, dir, r.randString(s, a)), nil
   827  	case BufferText:
   828  		if dir == DirOut {
   829  			return MakeOutDataArg(a, dir, uint64(r.Intn(100))), nil
   830  		}
   831  		return MakeDataArg(a, dir, r.generateText(a.Text)), nil
   832  	case BufferCompressed:
   833  		panic(fmt.Sprintf("can't generate compressed type %v", a))
   834  	default:
   835  		panic("unknown buffer kind")
   836  	}
   837  }
   838  
   839  func (a *VmaType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   840  	npages := r.randPageCount()
   841  	if a.RangeBegin != 0 || a.RangeEnd != 0 {
   842  		npages = a.RangeBegin + uint64(r.Intn(int(a.RangeEnd-a.RangeBegin+1)))
   843  	}
   844  	return r.allocVMA(s, a, dir, npages), nil
   845  }
   846  
   847  func (a *FlagsType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   848  	return MakeConstArg(a, dir, r.flags(a.Vals, a.BitMask, 0)), nil
   849  }
   850  
   851  func (a *ConstType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   852  	return MakeConstArg(a, dir, a.Val), nil
   853  }
   854  
   855  func (a *IntType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   856  	bits := a.TypeBitSize()
   857  	v := r.randInt(bits)
   858  	switch a.Kind {
   859  	case IntRange:
   860  		v = r.randRangeInt(a.RangeBegin, a.RangeEnd, bits, a.Align)
   861  	}
   862  	return MakeConstArg(a, dir, v), nil
   863  }
   864  
   865  func (a *ProcType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   866  	return MakeConstArg(a, dir, r.rand(int(a.ValuesPerProc))), nil
   867  }
   868  
   869  func (a *ArrayType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   870  	// Allow infinite recursion for arrays.
   871  	switch a.Elem.(type) {
   872  	case *StructType, *ArrayType, *UnionType:
   873  		ok, release := r.pruneRecursion(a.Elem.Name())
   874  		if !ok {
   875  			return MakeGroupArg(a, dir, nil), nil
   876  		}
   877  		defer release()
   878  	}
   879  	var count uint64
   880  	switch a.Kind {
   881  	case ArrayRandLen:
   882  		count = r.randArrayLen()
   883  	case ArrayRangeLen:
   884  		count = r.randRange(a.RangeBegin, a.RangeEnd)
   885  	}
   886  	// The resource we are trying to generate may be in the array elements, so create at least 1.
   887  	if r.inGenerateResource && count == 0 {
   888  		count = 1
   889  	}
   890  	var inner []Arg
   891  	for i := uint64(0); i < count; i++ {
   892  		arg1, calls1 := r.generateArg(s, a.Elem, dir)
   893  		inner = append(inner, arg1)
   894  		calls = append(calls, calls1...)
   895  	}
   896  	return MakeGroupArg(a, dir, inner), calls
   897  }
   898  
   899  func (a *StructType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   900  	args, calls := r.generateArgs(s, a.Fields, dir)
   901  	group := MakeGroupArg(a, dir, args)
   902  	return group, calls
   903  }
   904  
   905  func (a *UnionType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   906  	if a.isConditional() {
   907  		// Conditions may reference other fields that may not have already
   908  		// been generated. We'll fill them in later.
   909  		return a.DefaultArg(dir), nil
   910  	}
   911  	index := r.Intn(len(a.Fields))
   912  	optType, optDir := a.Fields[index].Type, a.Fields[index].Dir(dir)
   913  	opt, calls := r.generateArg(s, optType, optDir)
   914  	return MakeUnionArg(a, dir, opt, index), calls
   915  }
   916  
   917  func (a *PtrType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   918  	// Allow infinite recursion for optional pointers.
   919  	if a.Optional() {
   920  		switch a.Elem.(type) {
   921  		case *StructType, *ArrayType, *UnionType:
   922  			ok, release := r.pruneRecursion(a.Elem.Name())
   923  			if !ok {
   924  				return MakeSpecialPointerArg(a, dir, 0), nil
   925  			}
   926  			defer release()
   927  		}
   928  	}
   929  	// The resource we are trying to generate may be in the pointer,
   930  	// so don't try to create an empty special pointer during resource generation.
   931  	if !r.inGenerateResource && r.oneOf(1000) {
   932  		index := r.rand(len(r.target.SpecialPointers))
   933  		return MakeSpecialPointerArg(a, dir, index), nil
   934  	}
   935  	inner, calls := r.generateArg(s, a.Elem, a.ElemDir)
   936  	arg = r.allocAddr(s, a, dir, inner.Size(), inner)
   937  	return arg, calls
   938  }
   939  
   940  func (a *LenType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   941  	// Updated later in assignSizesCall.
   942  	return MakeConstArg(a, dir, 0), nil
   943  }
   944  
   945  func (a *CsumType) generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call) {
   946  	// Filled at runtime by executor.
   947  	return MakeConstArg(a, dir, 0), nil
   948  }
   949  
   950  func (r *randGen) existingResource(s *state, res *ResourceType, dir Dir) Arg {
   951  	alltypes := make([][]*ResultArg, 0, len(s.resources))
   952  	for _, res1 := range s.resources {
   953  		alltypes = append(alltypes, res1)
   954  	}
   955  	sort.Slice(alltypes, func(i, j int) bool {
   956  		return alltypes[i][0].Type().Name() < alltypes[j][0].Type().Name()
   957  	})
   958  	var allres []*ResultArg
   959  	for _, res1 := range alltypes {
   960  		name1 := res1[0].Type().Name()
   961  		if r.target.isCompatibleResource(res.Desc.Name, name1) ||
   962  			r.oneOf(50) && r.target.isCompatibleResource(res.Desc.Kind[0], name1) {
   963  			allres = append(allres, res1...)
   964  		}
   965  	}
   966  	if len(allres) == 0 {
   967  		return nil
   968  	}
   969  	return MakeResultArg(res, dir, allres[r.Intn(len(allres))], 0)
   970  }
   971  
   972  // Finds a compatible resource with the type `t` and the calls that initialize that resource.
   973  func (r *randGen) resourceCentric(s *state, t *ResourceType, dir Dir) (arg Arg, calls []*Call) {
   974  	var p *Prog
   975  	var resource *ResultArg
   976  	for _, idx := range r.Perm(len(s.corpus)) {
   977  		corpusProg := s.corpus[idx]
   978  		resources := getCompatibleResources(corpusProg, t.TypeName, r)
   979  		if len(resources) == 0 {
   980  			continue
   981  		}
   982  		argMap := make(map[*ResultArg]*ResultArg)
   983  		p = corpusProg.cloneWithMap(argMap)
   984  		resource = argMap[resources[r.Intn(len(resources))]]
   985  		break
   986  	}
   987  
   988  	// No compatible resource was found.
   989  	if resource == nil {
   990  		return nil, nil
   991  	}
   992  
   993  	// Set that stores the resources that appear in the same calls with the selected resource.
   994  	relatedRes := map[*ResultArg]bool{resource: true}
   995  
   996  	// Remove unrelated calls from the program.
   997  	for idx := len(p.Calls) - 1; idx >= 0; idx-- {
   998  		includeCall := false
   999  		var newResources []*ResultArg
  1000  		ForeachArg(p.Calls[idx], func(arg Arg, _ *ArgCtx) {
  1001  			if a, ok := arg.(*ResultArg); ok {
  1002  				if a.Res != nil && !relatedRes[a.Res] {
  1003  					newResources = append(newResources, a.Res)
  1004  				}
  1005  				if relatedRes[a] || relatedRes[a.Res] {
  1006  					includeCall = true
  1007  				}
  1008  			}
  1009  		})
  1010  		if !includeCall {
  1011  			p.RemoveCall(idx)
  1012  		} else {
  1013  			for _, res := range newResources {
  1014  				relatedRes[res] = true
  1015  			}
  1016  		}
  1017  	}
  1018  
  1019  	// Selects a biased random length of the returned calls (more calls could offer more
  1020  	// interesting programs). The values returned (n = len(calls): n, n-1, ..., 2.
  1021  	biasedLen := 2 + r.biasedRand(len(calls)-1, 10)
  1022  
  1023  	// Removes the references that are not used anymore.
  1024  	for i := biasedLen; i < len(calls); i++ {
  1025  		p.RemoveCall(i)
  1026  	}
  1027  
  1028  	return MakeResultArg(t, dir, resource, 0), p.Calls
  1029  }
  1030  
  1031  func getCompatibleResources(p *Prog, resourceType string, r *randGen) (resources []*ResultArg) {
  1032  	for _, c := range p.Calls {
  1033  		ForeachArg(c, func(arg Arg, _ *ArgCtx) {
  1034  			// Collect only initialized resources (the ones that are already used in other calls).
  1035  			a, ok := arg.(*ResultArg)
  1036  			if !ok || len(a.uses) == 0 || a.Dir() != DirOut {
  1037  				return
  1038  			}
  1039  			if !r.target.isCompatibleResource(resourceType, a.Type().Name()) {
  1040  				return
  1041  			}
  1042  			resources = append(resources, a)
  1043  		})
  1044  	}
  1045  	return resources
  1046  }