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