From bda2a1ed3503699b8cb814bb3cc7ad0b9694155b Mon Sep 17 00:00:00 2001 From: Brian Geffon Date: Tue, 19 Jun 2018 14:11:58 -0700 Subject: Rpcinet is racy around shutdown flags. Correct a data race in rpcinet where a shutdown and recvmsg can race around shutown flags. PiperOrigin-RevId: 201238366 Change-Id: I5eb06df4a2b4eba331eeb5de19076213081d581f --- pkg/sentry/socket/rpcinet/socket.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'pkg/sentry/socket') diff --git a/pkg/sentry/socket/rpcinet/socket.go b/pkg/sentry/socket/rpcinet/socket.go index f641f25df..207123d6f 100644 --- a/pkg/sentry/socket/rpcinet/socket.go +++ b/pkg/sentry/socket/rpcinet/socket.go @@ -15,6 +15,7 @@ package rpcinet import ( + "sync/atomic" "syscall" "gvisor.googlesource.com/gvisor/pkg/abi/linux" @@ -57,7 +58,7 @@ type socketOperations struct { // shState is the state of the connection with respect to shutdown. Because // we're mixing non-blocking semantics on the other side we have to adapt for // some strange differences between blocking and non-blocking sockets. - shState tcpip.ShutdownFlags + shState int32 } // Verify that we actually implement socket.Socket. @@ -105,26 +106,35 @@ func translateIOSyscallError(err error) error { // setShutdownFlags will set the shutdown flag so we can handle blocking reads // after a read shutdown. func (s *socketOperations) setShutdownFlags(how int) { + var f tcpip.ShutdownFlags switch how { case linux.SHUT_RD: - s.shState |= tcpip.ShutdownRead + f = tcpip.ShutdownRead case linux.SHUT_WR: - s.shState |= tcpip.ShutdownWrite + f = tcpip.ShutdownWrite case linux.SHUT_RDWR: - s.shState |= tcpip.ShutdownWrite | tcpip.ShutdownRead + f = tcpip.ShutdownWrite | tcpip.ShutdownRead + } + + // Atomically update the flags. + for { + old := atomic.LoadInt32(&s.shState) + if atomic.CompareAndSwapInt32(&s.shState, old, old|int32(f)) { + break + } } } func (s *socketOperations) resetShutdownFlags() { - s.shState = 0 + atomic.StoreInt32(&s.shState, 0) } func (s *socketOperations) isShutRdSet() bool { - return s.shState&tcpip.ShutdownRead != 0 + return atomic.LoadInt32(&s.shState)&int32(tcpip.ShutdownRead) != 0 } func (s *socketOperations) isShutWrSet() bool { - return s.shState&tcpip.ShutdownWrite != 0 + return atomic.LoadInt32(&s.shState)&int32(tcpip.ShutdownWrite) != 0 } // Release implements fs.FileOperations.Release. -- cgit v1.2.3