github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/sys/targets/common.go (about)

     1  // Copyright 2018 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 targets
     5  
     6  import (
     7  	"github.com/google/syzkaller/prog"
     8  )
     9  
    10  // MakePosixMmap creates a "normal" posix mmap call that maps the target data range.
    11  // If exec is set, the mapping is mapped as PROT_EXEC.
    12  // If contain is set, the mapping is surrounded by PROT_NONE pages.
    13  // These flags should be in sync with what executor.
    14  func MakePosixMmap(target *prog.Target, exec, contain bool) func() []*prog.Call {
    15  	meta := target.SyscallMap["mmap"]
    16  	protRW := target.GetConst("PROT_READ") | target.GetConst("PROT_WRITE")
    17  	if exec {
    18  		protRW |= target.GetConst("PROT_EXEC")
    19  	}
    20  	flags := target.GetConst("MAP_ANONYMOUS") | target.GetConst("MAP_PRIVATE") | target.GetConst("MAP_FIXED")
    21  	size := target.NumPages * target.PageSize
    22  	const invalidFD = ^uint64(0)
    23  	makeMmap := func(addr, size, prot uint64) *prog.Call {
    24  		call := prog.MakeCall(meta, []prog.Arg{
    25  			prog.MakeVmaPointerArg(meta.Args[0].Type, prog.DirIn, addr, size),
    26  			prog.MakeConstArg(meta.Args[1].Type, prog.DirIn, size),
    27  			prog.MakeConstArg(meta.Args[2].Type, prog.DirIn, prot),
    28  			prog.MakeConstArg(meta.Args[3].Type, prog.DirIn, flags),
    29  			prog.MakeResultArg(meta.Args[4].Type, prog.DirIn, nil, invalidFD),
    30  		})
    31  		i := len(call.Args)
    32  		// Some targets have a padding argument between fd and offset.
    33  		if len(meta.Args) > 6 {
    34  			call.Args = append(call.Args, prog.MakeConstArg(meta.Args[i].Type, prog.DirIn, 0))
    35  			i++
    36  		}
    37  		call.Args = append(call.Args, prog.MakeConstArg(meta.Args[i].Type, prog.DirIn, 0))
    38  		return call
    39  	}
    40  	return func() []*prog.Call {
    41  		if contain {
    42  			return []*prog.Call{
    43  				makeMmap(^target.PageSize+1, target.PageSize, 0),
    44  				makeMmap(0, size, protRW),
    45  				makeMmap(size, target.PageSize, 0),
    46  			}
    47  		}
    48  		return []*prog.Call{makeMmap(0, size, protRW)}
    49  	}
    50  }
    51  
    52  func MakeSyzMmap(target *prog.Target) func() []*prog.Call {
    53  	meta := target.SyscallMap["syz_mmap"]
    54  	size := target.NumPages * target.PageSize
    55  	return func() []*prog.Call {
    56  		return []*prog.Call{
    57  			prog.MakeCall(meta, []prog.Arg{
    58  				prog.MakeVmaPointerArg(meta.Args[0].Type, prog.DirIn, 0, size),
    59  				prog.MakeConstArg(meta.Args[1].Type, prog.DirIn, size),
    60  			}),
    61  		}
    62  	}
    63  }
    64  
    65  type UnixNeutralizer struct {
    66  	MAP_FIXED uint64
    67  	S_IFREG   uint64
    68  	S_IFCHR   uint64
    69  	S_IFBLK   uint64
    70  	S_IFIFO   uint64
    71  	S_IFSOCK  uint64
    72  }
    73  
    74  func MakeUnixNeutralizer(target *prog.Target) *UnixNeutralizer {
    75  	return &UnixNeutralizer{
    76  		MAP_FIXED: target.GetConst("MAP_FIXED"),
    77  		S_IFREG:   target.GetConst("S_IFREG"),
    78  		S_IFCHR:   target.GetConst("S_IFCHR"),
    79  		S_IFBLK:   target.GetConst("S_IFBLK"),
    80  		S_IFIFO:   target.GetConst("S_IFIFO"),
    81  		S_IFSOCK:  target.GetConst("S_IFSOCK"),
    82  	}
    83  }
    84  
    85  func (arch *UnixNeutralizer) Neutralize(c *prog.Call, fixStructure bool) error {
    86  	switch c.Meta.CallName {
    87  	case "mmap":
    88  		if c.Meta.Name == "mmap$bifrost" {
    89  			// Mali bifrost mmap doesn't support MAP_FIXED.
    90  			return nil
    91  		}
    92  		// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
    93  		c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
    94  	case "mknod", "mknodat", "compat_50_mknod":
    95  		pos := 1
    96  		if c.Meta.CallName == "mknodat" {
    97  			pos = 2
    98  		}
    99  		switch c.Args[pos+1].Type().(type) {
   100  		case *prog.ProcType, *prog.ResourceType:
   101  			return nil
   102  		}
   103  		mode := c.Args[pos].(*prog.ConstArg)
   104  		dev := c.Args[pos+1].(*prog.ConstArg)
   105  		dev.Val = uint64(uint32(dev.Val))
   106  		// Char and block devices read/write io ports, kernel memory and do other nasty things.
   107  		// TODO: not required if executor drops privileges.
   108  		mask := arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK
   109  		switch mode.Val & mask {
   110  		case arch.S_IFREG, arch.S_IFIFO, arch.S_IFSOCK:
   111  		case arch.S_IFBLK:
   112  			if dev.Val>>8 == 7 {
   113  				break // loop
   114  			}
   115  			mode.Val &^= arch.S_IFBLK
   116  			mode.Val |= arch.S_IFREG
   117  		case arch.S_IFCHR:
   118  			if dev.Val == 0x103 {
   119  				break // /dev/null
   120  			}
   121  			mode.Val &^= arch.S_IFCHR
   122  			mode.Val |= arch.S_IFREG
   123  		}
   124  	case "exit", "exit_group":
   125  		code := c.Args[0].(*prog.ConstArg)
   126  		// This code is reserved by executor.
   127  		if code.Val%128 == 67 {
   128  			code.Val = 1
   129  		}
   130  	}
   131  	return nil
   132  }