diff options
author | Andrei Vagin <avagin@google.com> | 2020-04-22 14:15:33 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-04-22 14:17:11 -0700 |
commit | 37f863f62813f76b05979494c1bc2fe102629321 (patch) | |
tree | 7f5beb725c201029369e78dd9f8225551224f465 /pkg | |
parent | c31641150d9ee0e4b9c7cf1210c4e89a030a6bd7 (diff) |
tcp: handle listen after shutdown properly
Right now, sentry panics in this case:
panic: close of nil channel
goroutine 67 [running]:
pkg/tcpip/transport/tcp/tcp.(*endpoint).listen(0xc0000ce000, 0x9, 0x0)
pkg/tcpip/transport/tcp/endpoint.go:2208 +0x170
pkg/tcpip/transport/tcp/tcp.(*endpoint).Listen(0xc0000ce000, 0x9, 0xc0003a1ad0)
pkg/tcpip/transport/tcp/endpoint.go:2179 +0x50
Fixes #2468
PiperOrigin-RevId: 307896725
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 43 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint_state.go | 5 |
2 files changed, 28 insertions, 20 deletions
diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 45f2aa78b..07d3e64c8 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -2158,8 +2158,6 @@ func (e *endpoint) shutdownLocked(flags tcpip.ShutdownFlags) *tcpip.Error { // // By not removing this endpoint from the demuxer mapping, we // ensure that any other bind to the same port fails, as on Linux. - // TODO(gvisor.dev/issue/2468): We need to enable applications to - // start listening on this endpoint again similar to Linux. e.rcvListMu.Lock() e.rcvClosed = true e.rcvListMu.Unlock() @@ -2188,26 +2186,31 @@ func (e *endpoint) listen(backlog int) *tcpip.Error { e.LockUser() defer e.UnlockUser() - // Allow the backlog to be adjusted if the endpoint is not shutting down. - // When the endpoint shuts down, it sets workerCleanup to true, and from - // that point onward, acceptedChan is the responsibility of the cleanup() - // method (and should not be touched anywhere else, including here). - if e.EndpointState() == StateListen && !e.workerCleanup { - // Adjust the size of the channel iff we can fix existing - // pending connections into the new one. + if e.EndpointState() == StateListen && !e.closed { e.acceptMu.Lock() defer e.acceptMu.Unlock() - if len(e.acceptedChan) > backlog { - return tcpip.ErrInvalidEndpointState - } - if cap(e.acceptedChan) == backlog { - return nil - } - origChan := e.acceptedChan - e.acceptedChan = make(chan *endpoint, backlog) - close(origChan) - for ep := range origChan { - e.acceptedChan <- ep + if e.acceptedChan == nil { + // listen is called after shutdown. + e.acceptedChan = make(chan *endpoint, backlog) + e.shutdownFlags = 0 + e.rcvListMu.Lock() + e.rcvClosed = false + e.rcvListMu.Unlock() + } else { + // Adjust the size of the channel iff we can fix + // existing pending connections into the new one. + if len(e.acceptedChan) > backlog { + return tcpip.ErrInvalidEndpointState + } + if cap(e.acceptedChan) == backlog { + return nil + } + origChan := e.acceptedChan + e.acceptedChan = make(chan *endpoint, backlog) + close(origChan) + for ep := range origChan { + e.acceptedChan <- ep + } } // Notify any blocked goroutines that they can attempt to diff --git a/pkg/tcpip/transport/tcp/endpoint_state.go b/pkg/tcpip/transport/tcp/endpoint_state.go index c3c692555..8b7562396 100644 --- a/pkg/tcpip/transport/tcp/endpoint_state.go +++ b/pkg/tcpip/transport/tcp/endpoint_state.go @@ -247,6 +247,11 @@ func (e *endpoint) Resume(s *stack.Stack) { if err := e.Listen(backlog); err != nil { panic("endpoint listening failed: " + err.String()) } + e.LockUser() + if e.shutdownFlags != 0 { + e.shutdownLocked(e.shutdownFlags) + } + e.UnlockUser() listenLoading.Done() tcpip.AsyncLoading.Done() }() |