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

     1  // Copyright 2017 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 linux
     5  
     6  import (
     7  	"runtime"
     8  
     9  	"github.com/google/syzkaller/prog"
    10  	"github.com/google/syzkaller/sys/targets"
    11  )
    12  
    13  func InitTarget(target *prog.Target) {
    14  	arch := &arch{
    15  		unix:                        targets.MakeUnixNeutralizer(target),
    16  		clockGettimeSyscall:         target.SyscallMap["clock_gettime"],
    17  		MREMAP_MAYMOVE:              target.GetConst("MREMAP_MAYMOVE"),
    18  		MREMAP_FIXED:                target.GetConst("MREMAP_FIXED"),
    19  		SYSLOG_ACTION_CONSOLE_OFF:   target.GetConst("SYSLOG_ACTION_CONSOLE_OFF"),
    20  		SYSLOG_ACTION_CONSOLE_ON:    target.GetConst("SYSLOG_ACTION_CONSOLE_ON"),
    21  		SYSLOG_ACTION_CONSOLE_LEVEL: target.GetConst("SYSLOG_ACTION_CONSOLE_LEVEL"),
    22  		SYSLOG_ACTION_CLEAR:         target.GetConst("SYSLOG_ACTION_CLEAR"),
    23  		SYSLOG_ACTION_SIZE_UNREAD:   target.GetConst("SYSLOG_ACTION_SIZE_UNREAD"),
    24  		FIFREEZE:                    target.GetConst("FIFREEZE"),
    25  		FITHAW:                      target.GetConst("FITHAW"),
    26  		SNAPSHOT_FREEZE:             target.GetConst("SNAPSHOT_FREEZE"),
    27  		SNAPSHOT_POWER_OFF:          target.GetConst("SNAPSHOT_POWER_OFF"),
    28  		EXT4_IOC_SHUTDOWN:           target.GetConst("EXT4_IOC_SHUTDOWN"),
    29  		EXT4_IOC_RESIZE_FS:          target.GetConst("EXT4_IOC_RESIZE_FS"),
    30  		EXT4_IOC_MIGRATE:            target.GetConst("EXT4_IOC_MIGRATE"),
    31  		FAN_OPEN_PERM:               target.GetConst("FAN_OPEN_PERM"),
    32  		FAN_ACCESS_PERM:             target.GetConst("FAN_ACCESS_PERM"),
    33  		FAN_OPEN_EXEC_PERM:          target.GetConst("FAN_OPEN_EXEC_PERM"),
    34  		PTRACE_TRACEME:              target.GetConst("PTRACE_TRACEME"),
    35  		CLOCK_REALTIME:              target.GetConst("CLOCK_REALTIME"),
    36  		AF_NFC:                      target.GetConst("AF_NFC"),
    37  		AF_LLC:                      target.GetConst("AF_LLC"),
    38  		AF_BLUETOOTH:                target.GetConst("AF_BLUETOOTH"),
    39  		AF_X25:                      target.GetConst("AF_X25"),
    40  		AF_AX25:                     target.GetConst("AF_AX25"),
    41  		AF_NETROM:                   target.GetConst("AF_NETROM"),
    42  		AF_ROSE:                     target.GetConst("AF_ROSE"),
    43  		AF_IEEE802154:               target.GetConst("AF_IEEE802154"),
    44  		AF_NETLINK:                  target.GetConst("AF_NETLINK"),
    45  		SOCK_RAW:                    target.GetConst("SOCK_RAW"),
    46  		NETLINK_GENERIC:             target.GetConst("NETLINK_GENERIC"),
    47  		USB_MAJOR:                   target.GetConst("USB_MAJOR"),
    48  		TIOCSSERIAL:                 target.GetConst("TIOCSSERIAL"),
    49  		TIOCGSERIAL:                 target.GetConst("TIOCGSERIAL"),
    50  		// These are not present on all arches.
    51  		ARCH_SET_FS: target.ConstMap["ARCH_SET_FS"],
    52  		ARCH_SET_GS: target.ConstMap["ARCH_SET_GS"],
    53  	}
    54  
    55  	target.MakeDataMmap = targets.MakePosixMmap(target, true, true)
    56  	target.Neutralize = arch.neutralize
    57  	target.SpecialTypes = map[string]func(g *prog.Gen, typ prog.Type, dir prog.Dir, old prog.Arg) (
    58  		prog.Arg, []*prog.Call){
    59  		"timespec":                  arch.generateTimespec,
    60  		"timeval":                   arch.generateTimespec,
    61  		"sockaddr_alg":              arch.generateSockaddrAlg,
    62  		"alg_name":                  arch.generateAlgName,
    63  		"alg_aead_name":             arch.generateAlgAeadName,
    64  		"alg_hash_name":             arch.generateAlgHashName,
    65  		"alg_skcipher_name":         arch.generateAlgSkcipherhName,
    66  		"ipt_replace":               arch.generateIptables,
    67  		"ip6t_replace":              arch.generateIptables,
    68  		"arpt_replace":              arch.generateArptables,
    69  		"ebt_replace":               arch.generateEbtables,
    70  		"usb_device_descriptor":     arch.generateUsbDeviceDescriptor,
    71  		"usb_device_descriptor_hid": arch.generateUsbHidDeviceDescriptor,
    72  	}
    73  
    74  	target.AuxResources = map[string]bool{
    75  		"uid":       true,
    76  		"pid":       true,
    77  		"gid":       true,
    78  		"timespec":  true,
    79  		"timeval":   true,
    80  		"time_sec":  true,
    81  		"time_usec": true,
    82  		"time_nsec": true,
    83  	}
    84  
    85  	switch target.Arch {
    86  	case targets.AMD64:
    87  		target.SpecialPointers = []uint64{
    88  			0xffffffff81000000, // kernel text
    89  			0xffffffffff600000, // VSYSCALL_ADDR
    90  		}
    91  	case targets.RiscV64:
    92  		target.SpecialPointers = []uint64{
    93  			0xffffffe000000000, // PAGE_OFFSET
    94  			0xffffff0000000000, // somewhere in VMEMMAP range
    95  		}
    96  	case targets.I386, targets.ARM64, targets.ARM, targets.PPC64LE, targets.MIPS64LE, targets.S390x:
    97  	default:
    98  		panic("unknown arch")
    99  	}
   100  
   101  	target.SpecialFileLenghts = []int{
   102  		int(target.GetConst("PATH_MAX")),
   103  		int(target.GetConst("UNIX_PATH_MAX")),
   104  		int(target.GetConst("NAME_MAX")),
   105  		int(target.GetConst("BTRFS_INO_LOOKUP_PATH_MAX")),
   106  		int(target.GetConst("BTRFS_INO_LOOKUP_USER_PATH_MAX")),
   107  		int(target.GetConst("SMB_PATH_MAX")),
   108  		int(target.GetConst("XT_CGROUP_PATH_MAX")),
   109  		int(target.GetConst("XENSTORE_REL_PATH_MAX")),
   110  		1 << 16, // gVisor's MaxFilenameLen
   111  	}
   112  
   113  	if target.Arch == runtime.GOARCH {
   114  		KCOV_INIT_TRACE = uintptr(target.GetConst("KCOV_INIT_TRACE"))
   115  		KCOV_ENABLE = uintptr(target.GetConst("KCOV_ENABLE"))
   116  		KCOV_REMOTE_ENABLE = uintptr(target.GetConst("KCOV_REMOTE_ENABLE"))
   117  		KCOV_DISABLE = uintptr(target.GetConst("KCOV_DISABLE"))
   118  		KCOV_TRACE_PC = uintptr(target.GetConst("KCOV_TRACE_PC"))
   119  		KCOV_TRACE_CMP = uintptr(target.GetConst("KCOV_TRACE_CMP"))
   120  	}
   121  }
   122  
   123  var (
   124  	// This should not be here, but for now we expose this for syz-fuzzer.
   125  	KCOV_INIT_TRACE    uintptr
   126  	KCOV_ENABLE        uintptr
   127  	KCOV_REMOTE_ENABLE uintptr
   128  	KCOV_DISABLE       uintptr
   129  	KCOV_TRACE_PC      uintptr
   130  	KCOV_TRACE_CMP     uintptr
   131  )
   132  
   133  type arch struct {
   134  	unix *targets.UnixNeutralizer
   135  
   136  	clockGettimeSyscall *prog.Syscall
   137  
   138  	MREMAP_MAYMOVE              uint64
   139  	MREMAP_FIXED                uint64
   140  	SYSLOG_ACTION_CONSOLE_OFF   uint64
   141  	SYSLOG_ACTION_CONSOLE_ON    uint64
   142  	SYSLOG_ACTION_CONSOLE_LEVEL uint64
   143  	SYSLOG_ACTION_CLEAR         uint64
   144  	SYSLOG_ACTION_SIZE_UNREAD   uint64
   145  	FIFREEZE                    uint64
   146  	FITHAW                      uint64
   147  	SNAPSHOT_FREEZE             uint64
   148  	SNAPSHOT_POWER_OFF          uint64
   149  	EXT4_IOC_SHUTDOWN           uint64
   150  	EXT4_IOC_RESIZE_FS          uint64
   151  	EXT4_IOC_MIGRATE            uint64
   152  	FAN_OPEN_PERM               uint64
   153  	FAN_ACCESS_PERM             uint64
   154  	FAN_OPEN_EXEC_PERM          uint64
   155  	PTRACE_TRACEME              uint64
   156  	CLOCK_REALTIME              uint64
   157  	ARCH_SET_FS                 uint64
   158  	ARCH_SET_GS                 uint64
   159  	AF_NFC                      uint64
   160  	AF_LLC                      uint64
   161  	AF_BLUETOOTH                uint64
   162  	AF_X25                      uint64
   163  	AF_AX25                     uint64
   164  	AF_NETROM                   uint64
   165  	AF_ROSE                     uint64
   166  	AF_IEEE802154               uint64
   167  	AF_NETLINK                  uint64
   168  	SOCK_RAW                    uint64
   169  	NETLINK_GENERIC             uint64
   170  	USB_MAJOR                   uint64
   171  	TIOCSSERIAL                 uint64
   172  	TIOCGSERIAL                 uint64
   173  }
   174  
   175  func (arch *arch) neutralize(c *prog.Call, fixStructure bool) error {
   176  	err := arch.unix.Neutralize(c, fixStructure)
   177  	if err != nil {
   178  		return err
   179  	}
   180  	switch c.Meta.CallName {
   181  	case "mremap":
   182  		// Add MREMAP_FIXED flag, otherwise it produces non-deterministic results.
   183  		flags := c.Args[3].(*prog.ConstArg)
   184  		if flags.Val&arch.MREMAP_MAYMOVE != 0 {
   185  			flags.Val |= arch.MREMAP_FIXED
   186  		}
   187  	case "syslog":
   188  		cmd := c.Args[0].(*prog.ConstArg)
   189  		cmd.Val = uint64(uint32(cmd.Val))
   190  		// These disable console output, but we need it.
   191  		if cmd.Val == arch.SYSLOG_ACTION_CONSOLE_OFF ||
   192  			cmd.Val == arch.SYSLOG_ACTION_CONSOLE_ON ||
   193  			cmd.Val == arch.SYSLOG_ACTION_CONSOLE_LEVEL ||
   194  			cmd.Val == arch.SYSLOG_ACTION_CLEAR {
   195  			cmd.Val = arch.SYSLOG_ACTION_SIZE_UNREAD
   196  		}
   197  	case "ioctl":
   198  		arch.neutralizeIoctl(c)
   199  	case "fanotify_mark":
   200  		// FAN_*_PERM require the program to reply to open requests.
   201  		// If that does not happen, the program will hang in an unkillable state forever.
   202  		// See the following bug for details:
   203  		// https://groups.google.com/d/msg/syzkaller-bugs/pD-vbqJu6U0/kGH30p3lBgAJ
   204  		mask := c.Args[2].(*prog.ConstArg)
   205  		mask.Val &^= arch.FAN_OPEN_PERM | arch.FAN_ACCESS_PERM | arch.FAN_OPEN_EXEC_PERM
   206  	case "ptrace":
   207  		req := c.Args[0].(*prog.ConstArg)
   208  		// PTRACE_TRACEME leads to unkillable processes, see:
   209  		// https://groups.google.com/forum/#!topic/syzkaller/uGzwvhlCXAw
   210  		if uint64(uint32(req.Val)) == arch.PTRACE_TRACEME {
   211  			req.Val = ^uint64(0)
   212  		}
   213  	case "arch_prctl":
   214  		// fs holds address of tls, if a program messes it at least signal
   215  		// handling will break. This also allows a program to do writes
   216  		// at arbitrary addresses, which usually leads to machine outbreak.
   217  		cmd := c.Args[0].(*prog.ConstArg)
   218  		if uint64(uint32(cmd.Val)) == arch.ARCH_SET_FS {
   219  			cmd.Val = arch.ARCH_SET_GS
   220  		}
   221  	case "init_module":
   222  		// Kernel tries to vmalloc whatever we pass as size and it's not accounted against memcg.
   223  		// As the result it can lead to massive OOM kills of everything running on the machine.
   224  		// Strictly saying, the same applies to finit_module with a sparse file too,
   225  		// but there is no simple way to handle that.
   226  		sz := c.Args[1].(*prog.ConstArg)
   227  		sz.Val %= 1 << 20
   228  	case "syz_init_net_socket":
   229  		// Don't let it mess with arbitrary sockets in init namespace.
   230  		family := c.Args[0].(*prog.ConstArg)
   231  		switch uint64(uint32(family.Val)) {
   232  		case arch.AF_NFC, arch.AF_LLC, arch.AF_BLUETOOTH, arch.AF_IEEE802154,
   233  			arch.AF_X25, arch.AF_AX25, arch.AF_NETROM, arch.AF_ROSE:
   234  		case arch.AF_NETLINK:
   235  			c.Args[1].(*prog.ConstArg).Val = arch.SOCK_RAW
   236  			c.Args[2].(*prog.ConstArg).Val = arch.NETLINK_GENERIC
   237  		default:
   238  			family.Val = ^uint64(0)
   239  		}
   240  	case "syz_open_dev":
   241  		enforceIntArg(c.Args[0])
   242  		enforceIntArg(c.Args[1])
   243  		enforceIntArg(c.Args[2])
   244  	case "sched_setattr":
   245  		// Enabling a SCHED_FIFO or a SCHED_RR policy may lead to false positive stall-related crashes.
   246  		neutralizeSchedAttr(c.Args[1])
   247  	}
   248  
   249  	switch c.Meta.Name {
   250  	case "setsockopt$EBT_SO_SET_ENTRIES":
   251  		arch.neutralizeEbtables(c)
   252  	}
   253  	return nil
   254  }
   255  
   256  func neutralizeSchedAttr(a prog.Arg) {
   257  	switch attr := a.(type) {
   258  	case *prog.PointerArg:
   259  		if attr.Res == nil {
   260  			// If it's just a pointer to somewhere, still set it to NULL as there's a risk that
   261  			// it points to the valid memory and it can be interpreted as a sched_attr struct.
   262  			attr.Address = 0
   263  			return
   264  		}
   265  		groupArg, ok := attr.Res.(*prog.GroupArg)
   266  		if !ok || len(groupArg.Inner) == 0 {
   267  			return
   268  		}
   269  		if unionArg, ok := groupArg.Inner[0].(*prog.UnionArg); ok {
   270  			dataArg, ok := unionArg.Option.(*prog.DataArg)
   271  			if !ok {
   272  				return
   273  			}
   274  			if dataArg.Dir() == prog.DirOut {
   275  				return
   276  			}
   277  			// Clear the first 16 bytes to prevent overcoming the limitation by squashing the struct.
   278  			data := append([]byte{}, dataArg.Data()...)
   279  			for i := 0; i < 16 && i < len(data); i++ {
   280  				data[i] = 0
   281  			}
   282  			dataArg.SetData(data)
   283  		}
   284  
   285  		// Most likely it's the intended sched_attr structure.
   286  		if len(groupArg.Inner) > 1 {
   287  			policyField, ok := groupArg.Inner[1].(*prog.ConstArg)
   288  			if !ok {
   289  				return
   290  			}
   291  			const SCHED_FIFO = 0x1
   292  			const SCHED_RR = 0x2
   293  			if policyField.Val == SCHED_FIFO || policyField.Val == SCHED_RR {
   294  				policyField.Val = 0
   295  			}
   296  		}
   297  	case *prog.ConstArg:
   298  		attr.Val = 0
   299  	}
   300  }
   301  
   302  func enforceIntArg(a prog.Arg) {
   303  	arg, ok := a.(*prog.ConstArg)
   304  	if !ok {
   305  		return
   306  	}
   307  	switch typ := arg.Type().(type) {
   308  	case *prog.ConstType:
   309  		arg.Val = typ.Val
   310  	case *prog.IntType:
   311  		if typ.Kind == prog.IntRange && (arg.Val < typ.RangeBegin || arg.Val > typ.RangeEnd) {
   312  			arg.Val = typ.RangeBegin
   313  		}
   314  	}
   315  }
   316  
   317  func (arch *arch) neutralizeIoctl(c *prog.Call) {
   318  	cmd := c.Args[1].(*prog.ConstArg)
   319  	switch uint64(uint32(cmd.Val)) {
   320  	case arch.FIFREEZE:
   321  		// Freeze kills machine. Though, it is an interesting functions,
   322  		// so we need to test it somehow.
   323  		// TODO: not required if executor drops privileges.
   324  		// Fortunately, the value does not conflict with any other ioctl commands for now.
   325  		cmd.Val = arch.FITHAW
   326  	case arch.SNAPSHOT_FREEZE:
   327  		// SNAPSHOT_FREEZE freezes all processes and leaves the machine dead.
   328  		cmd.Val = arch.FITHAW
   329  	case arch.SNAPSHOT_POWER_OFF:
   330  		// SNAPSHOT_POWER_OFF shuts down the machine.
   331  		cmd.Val = arch.FITHAW
   332  	case arch.EXT4_IOC_SHUTDOWN:
   333  		// EXT4_IOC_SHUTDOWN on root fs effectively brings the machine down in weird ways.
   334  		// Fortunately, the value does not conflict with any other ioctl commands for now.
   335  		cmd.Val = arch.EXT4_IOC_MIGRATE
   336  	case arch.EXT4_IOC_RESIZE_FS:
   337  		// EXT4_IOC_RESIZE_FS on root fs can shrink it to 0 (or whatever is the minimum size)
   338  		// and then creation of new temp dirs for tests will fail.
   339  		// TODO: not necessary for sandbox=namespace as it tests in a tmpfs
   340  		// and/or if we mount tmpfs for sandbox=none (#971).
   341  		cmd.Val = arch.EXT4_IOC_MIGRATE
   342  	case arch.TIOCSSERIAL:
   343  		// TIOCSSERIAL can do nasty things under root, like causing writes to random memory
   344  		// pretty much like /dev/mem, but this is also working as intended.
   345  		// For details see:
   346  		// https://groups.google.com/g/syzkaller-bugs/c/1rVENJf9P4U/m/QtGpapRxAgAJ
   347  		// https://syzkaller.appspot.com/bug?extid=f4f1e871965064ae689e
   348  		// TODO: TIOCSSERIAL does some other things that are not dangerous
   349  		// and would be nice to test, if/when we can neutralize based on sandbox value
   350  		// we could prohibit it only under sandbox=none.
   351  		cmd.Val = arch.TIOCGSERIAL
   352  	}
   353  }
   354  
   355  func (arch *arch) generateTimespec(g *prog.Gen, typ0 prog.Type, dir prog.Dir, old prog.Arg) (
   356  	arg prog.Arg, calls []*prog.Call) {
   357  	typ := typ0.(*prog.StructType)
   358  	// We need to generate timespec/timeval that are either
   359  	// (1) definitely in the past, or
   360  	// (2) definitely in unreachable fututre, or
   361  	// (3) few ms ahead of now.
   362  	// Note: timespec/timeval can be absolute or relative to now.
   363  	// Note: executor has blocking syscall timeout of 45 ms,
   364  	// so we generate both 10ms and 60ms.
   365  	// TODO(dvyukov): this is now all outdated with tunable timeouts.
   366  	const (
   367  		timeout1 = uint64(10)
   368  		timeout2 = uint64(60)
   369  	)
   370  	usec := typ.Name() == "timeval"
   371  	switch {
   372  	case g.NOutOf(1, 4):
   373  		// Now for relative, past for absolute.
   374  		arg = prog.MakeGroupArg(typ, dir, []prog.Arg{
   375  			prog.MakeResultArg(typ.Fields[0].Type, dir, nil, 0),
   376  			prog.MakeResultArg(typ.Fields[1].Type, dir, nil, 0),
   377  		})
   378  	case g.NOutOf(1, 3):
   379  		// Few ms ahead for relative, past for absolute.
   380  		nsec := timeout1 * 1e6
   381  		if g.NOutOf(1, 2) {
   382  			nsec = timeout2 * 1e6
   383  		}
   384  		if usec {
   385  			nsec /= 1e3
   386  		}
   387  		arg = prog.MakeGroupArg(typ, dir, []prog.Arg{
   388  			prog.MakeResultArg(typ.Fields[0].Type, dir, nil, 0),
   389  			prog.MakeResultArg(typ.Fields[1].Type, dir, nil, nsec),
   390  		})
   391  	case g.NOutOf(1, 2):
   392  		// Unreachable fututre for both relative and absolute.
   393  		arg = prog.MakeGroupArg(typ, dir, []prog.Arg{
   394  			prog.MakeResultArg(typ.Fields[0].Type, dir, nil, 2e9),
   395  			prog.MakeResultArg(typ.Fields[1].Type, dir, nil, 0),
   396  		})
   397  	default:
   398  		// Few ms ahead for absolute.
   399  		meta := arch.clockGettimeSyscall
   400  		ptrArgType := meta.Args[1].Type.(*prog.PtrType)
   401  		argType := ptrArgType.Elem.(*prog.StructType)
   402  		tp := prog.MakeGroupArg(argType, prog.DirOut, []prog.Arg{
   403  			prog.MakeResultArg(argType.Fields[0].Type, prog.DirOut, nil, 0),
   404  			prog.MakeResultArg(argType.Fields[1].Type, prog.DirOut, nil, 0),
   405  		})
   406  		var tpaddr prog.Arg
   407  		tpaddr, calls = g.Alloc(ptrArgType, prog.DirIn, tp)
   408  		gettime := prog.MakeCall(meta, []prog.Arg{
   409  			prog.MakeConstArg(meta.Args[0].Type, prog.DirIn, arch.CLOCK_REALTIME),
   410  			tpaddr,
   411  		})
   412  		calls = append(calls, gettime)
   413  		sec := prog.MakeResultArg(typ.Fields[0].Type, dir, tp.Inner[0].(*prog.ResultArg), 0)
   414  		nsec := prog.MakeResultArg(typ.Fields[1].Type, dir, tp.Inner[1].(*prog.ResultArg), 0)
   415  		msec := timeout1
   416  		if g.NOutOf(1, 2) {
   417  			msec = timeout2
   418  		}
   419  		if usec {
   420  			nsec.OpDiv = 1e3
   421  			nsec.OpAdd = msec * 1e3
   422  		} else {
   423  			nsec.OpAdd = msec * 1e6
   424  		}
   425  		arg = prog.MakeGroupArg(typ, dir, []prog.Arg{sec, nsec})
   426  	}
   427  	return
   428  }