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 }