device: make RoutineReadFromTUN keep encryption queue alive

RoutineReadFromTUN can trigger a call to SendStagedPackets.
SendStagedPackets attempts to protect against sending
on the encryption queue by checking peer.isRunning and device.isClosed.
However, those are subject to TOCTOU bugs.

If that happens, we get this:

goroutine 1254 [running]:
golang.zx2c4.com/wireguard/device.(*Peer).SendStagedPackets(0xc000798300)
        .../wireguard-go/device/send.go:321 +0x125
golang.zx2c4.com/wireguard/device.(*Device).RoutineReadFromTUN(0xc000014780)
        .../wireguard-go/device/send.go:271 +0x21c
created by golang.zx2c4.com/wireguard/device.NewDevice
        .../wireguard-go/device/device.go:315 +0x298

Fix this with a simple, big hammer: Keep the encryption queue
alive as long as it might be written to.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
Josh Bleecher Snyder 2021-02-09 09:53:00 -08:00
parent 30b96ba083
commit 4eab21a7b7
2 changed files with 3 additions and 1 deletions

View file

@ -311,7 +311,8 @@ func NewDevice(tunDevice tun.Device, logger *Logger) *Device {
go device.RoutineHandshake() go device.RoutineHandshake()
} }
device.state.stopping.Add(1) // read from TUN device.state.stopping.Add(1) // RoutineReadFromTUN
device.queue.encryption.wg.Add(1) // RoutineReadFromTUN
go device.RoutineReadFromTUN() go device.RoutineReadFromTUN()
go device.RoutineTUNEventReader() go device.RoutineTUNEventReader()

View file

@ -206,6 +206,7 @@ func (device *Device) RoutineReadFromTUN() {
defer func() { defer func() {
device.log.Verbosef("Routine: TUN reader - stopped") device.log.Verbosef("Routine: TUN reader - stopped")
device.state.stopping.Done() device.state.stopping.Done()
device.queue.encryption.wg.Done()
}() }()
device.log.Verbosef("Routine: TUN reader - started") device.log.Verbosef("Routine: TUN reader - started")