anatol/booster

udev race condition

Closed this issue · 1 comments

There is a race condition between reading udev events and closing udev reader. If we close udev reader in cleanup() while the udev goroutine tries to read events then the reader returns an error that panics inside bufio.fill():

panic: bufio: reader returned negative count from Read

goroutine 6 [running]:
bufio.(*Reader).fill(0xc000070f68)
	/usr/lib/go/src/bufio/bufio.go:103 +0x1dd
bufio.(*Reader).ReadSlice(0xc000070f68, 0x0, 0xc, 0x7f6718544c28, 0xc0003c42f0, 0x0, 0xab0fc0)
	/usr/lib/go/src/bufio/bufio.go:360 +0x3d
bufio.(*Reader).collectFragments(0xc000070f68, 0xc000070d00, 0x40d610, 0xc00006b440, 0x30, 0x30, 0x823120, 0xc00005c960, 0x60, 0x7f671854e308, ...)
	/usr/lib/go/src/bufio/bufio.go:435 +0x7a
bufio.(*Reader).ReadString(0xc000070f68, 0xc00005c900, 0x7, 0x0, 0xc00011a9d8, 0x0)
	/usr/lib/go/src/bufio/bufio.go:483 +0x4c
github.com/s-urbaniak/uevent.(*Decoder).next(...)
	/home/anatol/go/pkg/mod/github.com/s-urbaniak/uevent@v1.0.0/decoder.go:81
github.com/s-urbaniak/uevent.(*Decoder).Decode(0xc000070ed0, 0xc00006b3e0, 0x83cf0f, 0x7)
	/home/anatol/go/pkg/mod/github.com/s-urbaniak/uevent@v1.0.0/decoder.go:42 +0x75
main.udevListener()
	/mnt/cold/sources/golang/booster/init/main.go:454 +0x185
created by main.boost
	/mnt/cold/sources/golang/booster/init/main.go:782 +0x4bd
[    1.375818] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200
[    1.376737] CPU: 1 PID: 144 Comm: init Not tainted 5.10.14-arch1-1 #1
[    1.377591] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ArchLinux 1.14.0-1 04/01/2014
[    1.378961] Call Trace:
[    1.379355]  dump_stack+0x6b/0x83
[    1.379844]  panic+0x112/0x2e8
[    1.380304]  do_exit.cold+0x2c/0xb3
[    1.380854]  do_group_exit+0x33/0xa0
[    1.381288]  get_signal+0x13f/0x890
[    1.381690]  arch_do_signal+0x3d/0x740
[    1.382122]  exit_to_user_mode_prepare+0xb4/0x120
[    1.382653]  syscall_exit_to_user_mode+0x28/0x160
[    1.383185]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[    1.383761] RIP: 0033:0x4b3e4a
[    1.384161] Code: e8 db 16 fb ff 48 8b 7c 24 10 48 8b 74 24 18 48 8b 54 24 20 4c 8b 54 24 28 4c 8b 44 24 30 4c 8b 4c 24 38 48 8b 44 24 08 0f 05 <48> 3d 01 f0 ff ff 76 20 48 c7 44 24 40 ff ff ff ff 48 c7 44 24 48
[    1.386236] RSP: 002b:000000c00004dae8 EFLAGS: 00000212 ORIG_RAX: 0000000000000106
[    1.387080] RAX: 0000000000000000 RBX: 000000c00002e000 RCX: 00000000004b3e4a
[    1.387882] RDX: 000000c0006a05e8 RSI: 000000c000596200 RDI: ffffffffffffff9c
[    1.388675] RBP: 000000c00004db60 R08: 0000000000000000 R09: 0000000000000000
[    1.389477] R10: 0000000000000100 R11: 0000000000000212 R12: ffffffffffffffff
[    1.390273] R13: 0000000000000011 R14: 0000000000000010 R15: 0000000000000100
[    1.391149] Kernel Offset: 0xda00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[    1.392362] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200 ]---

A workaround for this problem is to use stapelberg's uevent fork that uses CloseOnExec flag for the udev reader fd s-urbaniak/uevent#1

In this case the reader is closed much later, at exec() time when no goroutines are active. Thus there is no race between reading uevent and closing its fd. There will be no panic().