From c020e2de836ae2a89ab01c896238da48e69524ec Mon Sep 17 00:00:00 2001 From: Nicolas Lacasse Date: Sat, 18 Feb 2023 13:11:33 -0800 Subject: [PATCH] Move netstack's isTCP/UDP/ICMPSocket methods into socket package. They are useful across other socket implementations. PiperOrigin-RevId: 510699847 --- pkg/abi/linux/ip.go | 1 + pkg/sentry/socket/netstack/netstack.go | 36 ++++++++------------------ pkg/sentry/socket/socket.go | 36 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/pkg/abi/linux/ip.go b/pkg/abi/linux/ip.go index df94e150b..e8bfa1af6 100644 --- a/pkg/abi/linux/ip.go +++ b/pkg/abi/linux/ip.go @@ -32,6 +32,7 @@ const ( IPPROTO_GRE = 47 IPPROTO_ESP = 50 IPPROTO_AH = 51 + IPPROTO_ICMPV6 = 58 IPPROTO_MTP = 92 IPPROTO_BEETPH = 94 IPPROTO_ENCAP = 98 diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index a032e0215..06d1278b7 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -1055,7 +1055,7 @@ func getSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, family // This option is only viable for TCP endpoints. var v bool - if _, skType, skProto := s.Type(); isTCPSocket(skType, skProto) { + if socket.IsTCP(s) { v = tcp.EndpointState(ep.State()) == tcp.StateListen } vP := primitive.Int32(boolToInt32(v)) @@ -1074,8 +1074,7 @@ func getSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, family // getSockOptTCP implements GetSockOpt when level is SOL_TCP. func getSockOptTCP(t *kernel.Task, s socket.Socket, ep commonEndpoint, name, outLen int) (marshal.Marshallable, *syserr.Error) { - if _, skType, skProto := s.Type(); !isTCPSocket(skType, skProto) { - log.Warningf("SOL_TCP options are only supported on TCP sockets: skType, skProto = %v, %d", skType, skProto) + if !socket.IsTCP(s) { return nil, syserr.ErrUnknownProtocolOption } @@ -1975,8 +1974,7 @@ func setSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, name i // setSockOptTCP implements SetSockOpt when level is SOL_TCP. func setSockOptTCP(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int, optVal []byte) *syserr.Error { - if _, skType, skProto := s.Type(); !isTCPSocket(skType, skProto) { - log.Warningf("SOL_TCP options are only supported on TCP sockets: skType, skProto = %v, %d", skType, skProto) + if !socket.IsTCP(s) { return syserr.ErrUnknownProtocolOption } @@ -2144,7 +2142,7 @@ func setSockOptIPv6(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int return syserr.ErrUnknownProtocolOption } - family, skType, skProto := s.Type() + family, _, _ := s.Type() if family != linux.AF_INET6 { return syserr.ErrUnknownProtocolOption } @@ -2164,9 +2162,9 @@ func setSockOptIPv6(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int return syserr.ErrInvalidArgument } - if isTCPSocket(skType, skProto) && tcp.EndpointState(ep.State()) != tcp.StateInitial { + if socket.IsTCP(s) && tcp.EndpointState(ep.State()) != tcp.StateInitial { return syserr.ErrInvalidEndpointState - } else if isUDPSocket(skType, skProto) && transport.DatagramEndpointState(ep.State()) != transport.DatagramEndpointStateInitial { + } else if socket.IsUDP(s) && transport.DatagramEndpointState(ep.State()) != transport.DatagramEndpointStateInitial { return syserr.ErrInvalidEndpointState } @@ -2286,7 +2284,7 @@ func setSockOptIPv6(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int } // Only valid for raw IPv6 sockets. - if skType != linux.SOCK_RAW { + if !socket.IsRaw(s) { return syserr.ErrProtocolNotAvailable } @@ -3319,18 +3317,6 @@ func nicStateFlagsToLinux(f stack.NICStateFlags) uint32 { return rv } -func isTCPSocket(skType linux.SockType, skProto int) bool { - return skType == linux.SOCK_STREAM && (skProto == 0 || skProto == unix.IPPROTO_TCP) -} - -func isUDPSocket(skType linux.SockType, skProto int) bool { - return skType == linux.SOCK_DGRAM && (skProto == 0 || skProto == unix.IPPROTO_UDP) -} - -func isICMPSocket(skType linux.SockType, skProto int) bool { - return skType == linux.SOCK_DGRAM && (skProto == unix.IPPROTO_ICMP || skProto == unix.IPPROTO_ICMPV6) -} - // State implements socket.Socket.State. State translates the internal state // returned by netstack to values defined by Linux. func (s *sock) State() uint32 { @@ -3340,7 +3326,7 @@ func (s *sock) State() uint32 { } switch { - case isTCPSocket(s.skType, s.protocol): + case socket.IsTCP(s): // TCP socket. switch tcp.EndpointState(s.Endpoint.State()) { case tcp.StateEstablished: @@ -3369,7 +3355,7 @@ func (s *sock) State() uint32 { // Internal or unknown state. return 0 } - case isUDPSocket(s.skType, s.protocol): + case socket.IsUDP(s): // UDP socket. switch transport.DatagramEndpointState(s.Endpoint.State()) { case transport.DatagramEndpointStateInitial, transport.DatagramEndpointStateBound, transport.DatagramEndpointStateClosed: @@ -3379,9 +3365,9 @@ func (s *sock) State() uint32 { default: return 0 } - case isICMPSocket(s.skType, s.protocol): + case socket.IsICMP(s): // TODO(b/112063468): Export states for ICMP sockets. - case s.skType == linux.SOCK_RAW: + case socket.IsRaw(s): // TODO(b/112063468): Export states for raw sockets. default: // Unknown transport protocol, how did we make this socket? diff --git a/pkg/sentry/socket/socket.go b/pkg/sentry/socket/socket.go index ae4cb1d84..9c88df8ef 100644 --- a/pkg/sentry/socket/socket.go +++ b/pkg/sentry/socket/socket.go @@ -610,3 +610,39 @@ func AddressAndFamily(addr []byte) (tcpip.FullAddress, uint16, *syserr.Error) { return tcpip.FullAddress{}, 0, syserr.ErrAddressFamilyNotSupported } } + +// IsTCP returns true if the socket is a TCP socket. +func IsTCP(s Socket) bool { + fam, typ, proto := s.Type() + if fam != linux.AF_INET && fam != linux.AF_INET6 { + return false + } + return typ == linux.SOCK_STREAM && (proto == 0 || proto == linux.IPPROTO_TCP) +} + +// IsUDP returns true if the socket is a UDP socket. +func IsUDP(s Socket) bool { + fam, typ, proto := s.Type() + if fam != linux.AF_INET && fam != linux.AF_INET6 { + return false + } + return typ == linux.SOCK_DGRAM && (proto == 0 || proto == linux.IPPROTO_UDP) +} + +// IsICMP returns true if the socket is an ICMP socket. +func IsICMP(s Socket) bool { + fam, typ, proto := s.Type() + if fam != linux.AF_INET && fam != linux.AF_INET6 { + return false + } + return typ == linux.SOCK_DGRAM && (proto == linux.IPPROTO_ICMP || proto == linux.IPPROTO_ICMPV6) +} + +// IsRaw returns true if the socket is a raw socket. +func IsRaw(s Socket) bool { + fam, typ, _ := s.Type() + if fam != linux.AF_INET && fam != linux.AF_INET6 { + return false + } + return typ == linux.SOCK_RAW +}