summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGhanan Gowripalan <ghanan@google.com>2021-09-15 12:18:00 -0700
committergVisor bot <gvisor-bot@google.com>2021-09-15 12:20:51 -0700
commit149ca009678edc580de9f0b1d54f551d376742cb (patch)
tree648e02a87b55617196e68474aa4a07b49d586c0f
parent2d9883e4f1355677f986fc9a387fb70b6e438611 (diff)
[bind] Return EINVAL for under sized address
...and EAFNOSUPPORT for unexpected address family. To comply with Linux. Updates #6021, #6575. PiperOrigin-RevId: 396893590
-rw-r--r--pkg/sentry/socket/netstack/netstack.go50
-rw-r--r--test/syscalls/linux/ping_socket.cc10
-rw-r--r--test/syscalls/linux/udp_socket.cc8
3 files changed, 44 insertions, 24 deletions
diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go
index 8cf2f29e4..f79bda922 100644
--- a/pkg/sentry/socket/netstack/netstack.go
+++ b/pkg/sentry/socket/netstack/netstack.go
@@ -419,6 +419,27 @@ func bytesToIPAddress(addr []byte) tcpip.Address {
return tcpip.Address(addr)
}
+// minSockAddrLen returns the minimum length in bytes of a socket address for
+// the socket's family.
+func (s *socketOpsCommon) minSockAddrLen() int {
+ const addressFamilySize = 2
+
+ switch s.family {
+ case linux.AF_UNIX:
+ return addressFamilySize
+ case linux.AF_INET:
+ return sockAddrInetSize
+ case linux.AF_INET6:
+ return sockAddrInet6Size
+ case linux.AF_PACKET:
+ return sockAddrLinkSize
+ case linux.AF_UNSPEC:
+ return addressFamilySize
+ default:
+ panic(fmt.Sprintf("s.family unrecognized = %d", s.family))
+ }
+}
+
func (s *socketOpsCommon) isPacketBased() bool {
return s.skType == linux.SOCK_DGRAM || s.skType == linux.SOCK_SEQPACKET || s.skType == linux.SOCK_RDM || s.skType == linux.SOCK_RAW
}
@@ -545,16 +566,21 @@ func (s *socketOpsCommon) Readiness(mask waiter.EventMask) waiter.EventMask {
return s.Endpoint.Readiness(mask)
}
-func (s *socketOpsCommon) checkFamily(family uint16, exact bool) *syserr.Error {
+// checkFamily returns true iff the specified address family may be used with
+// the socket.
+//
+// If exact is true, then the specified address family must be an exact match
+// with the socket's family.
+func (s *socketOpsCommon) checkFamily(family uint16, exact bool) bool {
if family == uint16(s.family) {
- return nil
+ return true
}
if !exact && family == linux.AF_INET && s.family == linux.AF_INET6 {
if !s.Endpoint.SocketOptions().GetV6Only() {
- return nil
+ return true
}
}
- return syserr.ErrInvalidArgument
+ return false
}
// mapFamily maps the AF_INET ANY address to the IPv4-mapped IPv6 ANY if the
@@ -587,8 +613,8 @@ func (s *socketOpsCommon) Connect(t *kernel.Task, sockaddr []byte, blocking bool
return syserr.TranslateNetstackError(err)
}
- if err := s.checkFamily(family, false /* exact */); err != nil {
- return err
+ if !s.checkFamily(family, false /* exact */) {
+ return syserr.ErrInvalidArgument
}
addr = s.mapFamily(addr, family)
@@ -655,14 +681,18 @@ func (s *socketOpsCommon) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error {
Addr: tcpip.Address(a.HardwareAddr[:header.EthernetAddressSize]),
}
} else {
+ if s.minSockAddrLen() > len(sockaddr) {
+ return syserr.ErrInvalidArgument
+ }
+
var err *syserr.Error
addr, family, err = socket.AddressAndFamily(sockaddr)
if err != nil {
return err
}
- if err = s.checkFamily(family, true /* exact */); err != nil {
- return err
+ if !s.checkFamily(family, true /* exact */) {
+ return syserr.ErrAddressFamilyNotSupported
}
addr = s.mapFamily(addr, family)
@@ -2872,8 +2902,8 @@ func (s *socketOpsCommon) SendMsg(t *kernel.Task, src usermem.IOSequence, to []b
if err != nil {
return 0, err
}
- if err := s.checkFamily(family, false /* exact */); err != nil {
- return 0, err
+ if !s.checkFamily(family, false /* exact */) {
+ return 0, syserr.ErrInvalidArgument
}
addrBuf = s.mapFamily(addrBuf, family)
diff --git a/test/syscalls/linux/ping_socket.cc b/test/syscalls/linux/ping_socket.cc
index 7ec1938bf..684983a4c 100644
--- a/test/syscalls/linux/ping_socket.cc
+++ b/test/syscalls/linux/ping_socket.cc
@@ -155,43 +155,33 @@ std::vector<std::tuple<SocketKind, BindTestCase>> ICMPTestCases() {
.bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"),
.want = EADDRNOTAVAIL,
},
- // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the test
- // cases below once ICMP sockets return EAFNOSUPPORT when binding to
- // IPv6 addresses.
{
.bind_to = V6Any(),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
{
.bind_to = V6Loopback(),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
{
.bind_to = V6Multicast(),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
{
.bind_to = V6MulticastInterfaceLocalAllNodes(),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
{
.bind_to = V6MulticastLinkLocalAllNodes(),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
{
.bind_to = V6MulticastLinkLocalAllRouters(),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
{
.bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"),
.want = EAFNOSUPPORT,
- .want_gvisor = EINVAL,
},
});
}
diff --git a/test/syscalls/linux/udp_socket.cc b/test/syscalls/linux/udp_socket.cc
index b9af5cbdd..0c0a16074 100644
--- a/test/syscalls/linux/udp_socket.cc
+++ b/test/syscalls/linux/udp_socket.cc
@@ -643,12 +643,12 @@ TEST_P(UdpSocketTest, DisconnectAfterBindToUnspecAndConnect) {
sockaddr_storage unspec = {.ss_family = AF_UNSPEC};
int bind_res = bind(sock_.get(), AsSockAddr(&unspec), sizeof(unspec));
- if (IsRunningOnGvisor() && !IsRunningWithHostinet()) {
- // TODO(https://gvisor.dev/issue/6575): Match Linux's behaviour.
- ASSERT_THAT(bind_res, SyscallFailsWithErrno(EINVAL));
- } else if (GetFamily() == AF_INET) {
+ if ((!IsRunningOnGvisor() || IsRunningWithHostinet()) &&
+ GetFamily() == AF_INET) {
// Linux allows this for undocumented compatibility reasons:
// https://github.com/torvalds/linux/commit/29c486df6a208432b370bd4be99ae1369ede28d8.
+ //
+ // TODO(https://gvisor.dev/issue/6575): Match Linux's behaviour.
ASSERT_THAT(bind_res, SyscallSucceeds());
} else {
ASSERT_THAT(bind_res, SyscallFailsWithErrno(EAFNOSUPPORT));