From 037bb2f45abada02fb50b563f3d37381f88de7f5 Mon Sep 17 00:00:00 2001 From: Bhasker Hariharan Date: Fri, 26 Feb 2021 20:14:34 -0800 Subject: Fix panic due to zero length writes in TCP. There is a short race where in Write an endpoint can transition from writable to non-writable state due to say an incoming RST during the time we release the endpoint lock and reacquire after copying the payload. In such a case if the write happens to be a zero sized write we end up trying to call sendData() even though nothing was queued. This can panic when trying to enable/disable TCP timers if the endpoint had already transitioned to a CLOSED/ERROR state due to the incoming RST as we cleanup timers when the protocol goroutine terminates. Sadly the race window is small enough that my attempts at reproducing the panic in a syscall test has not been successful. PiperOrigin-RevId: 359887905 --- pkg/tcpip/transport/tcp/endpoint.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'pkg/tcpip/transport/tcp') diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 8c5be0586..83ec99fa9 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -1586,7 +1586,9 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp return e.drainSendQueueLocked(), len(v), nil }() - if err != nil { + // Return if either we didn't queue anything or if an error occurred while + // attempting to queue data. + if n == 0 || err != nil { return 0, err } e.sendData(nextSeg) -- cgit v1.2.3