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
This commit is contained in:
Brian Geffon
2018-06-19 14:12:52 -07:00
committed by Shentubot
parent 9db7cfad93
commit bda2a1ed35
+17 -7
View File
@@ -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.