mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
[bind] Return EINVAL for under sized address
...and EAFNOSUPPORT for unexpected address family. To comply with Linux. Updates #6021, #6575. PiperOrigin-RevId: 396893590
This commit is contained in:
committed by
gVisor bot
parent
2d9883e4f1
commit
149ca00967
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user