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 }