mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Fix panic when IPv4 address is used in sendmsg for IPv6 sockets
We do not rely on error for getsockopt options(which have boolean values) anymore. This will cause issue in sendmsg where we used to return error for IPV6_V6Only option. Fix the panic by returning error (for sockets other than TCP and UDP) if the address does not match the type(AF_INET/AF_INET6) of the socket. PiperOrigin-RevId: 347063838
This commit is contained in:
committed by
gVisor bot
parent
5bdc167d17
commit
d45420b152
@@ -227,6 +227,13 @@ func (e *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-c
|
||||
return 0, nil, tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
||||
if opts.To != nil {
|
||||
// Raw sockets do not support sending to a IPv4 address on a IPv6 endpoint.
|
||||
if e.TransportEndpointInfo.NetProto == header.IPv6ProtocolNumber && len(opts.To.Addr) != header.IPv6AddressSize {
|
||||
return 0, nil, tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
}
|
||||
|
||||
n, ch, err := e.write(p, opts)
|
||||
switch err {
|
||||
case nil:
|
||||
@@ -397,6 +404,11 @@ func (*endpoint) Disconnect() *tcpip.Error {
|
||||
|
||||
// Connect implements tcpip.Endpoint.Connect.
|
||||
func (e *endpoint) Connect(addr tcpip.FullAddress) *tcpip.Error {
|
||||
// Raw sockets do not support connecting to a IPv4 address on a IPv6 endpoint.
|
||||
if e.TransportEndpointInfo.NetProto == header.IPv6ProtocolNumber && len(addr.Addr) != header.IPv6AddressSize {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
|
||||
@@ -852,6 +852,51 @@ TEST(RawSocketTest, IPv6ProtoRaw) {
|
||||
SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
TEST(RawSocketTest, IPv6SendMsg) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
|
||||
|
||||
int sock;
|
||||
ASSERT_THAT(sock = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP),
|
||||
SyscallSucceeds());
|
||||
|
||||
char kBuf[] = "hello";
|
||||
struct iovec iov = {};
|
||||
iov.iov_base = static_cast<void*>(const_cast<char*>(kBuf));
|
||||
iov.iov_len = static_cast<size_t>(sizeof(kBuf));
|
||||
|
||||
struct sockaddr_storage addr = {};
|
||||
struct sockaddr_in* sin = reinterpret_cast<struct sockaddr_in*>(&addr);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
struct msghdr msg = {};
|
||||
msg.msg_name = static_cast<void*>(&addr);
|
||||
msg.msg_namelen = sizeof(sockaddr_in);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
ASSERT_THAT(sendmsg(sock, &msg, 0), SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
TEST_P(RawSocketTest, ConnectOnIPv6Socket) {
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_RAW)));
|
||||
|
||||
int sock;
|
||||
ASSERT_THAT(sock = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP),
|
||||
SyscallSucceeds());
|
||||
|
||||
struct sockaddr_storage addr = {};
|
||||
struct sockaddr_in* sin = reinterpret_cast<struct sockaddr_in*>(&addr);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
ASSERT_THAT(connect(sock, reinterpret_cast<struct sockaddr*>(&addr),
|
||||
sizeof(sockaddr_in6)),
|
||||
SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AllInetTests, RawSocketTest,
|
||||
::testing::Combine(::testing::Values(IPPROTO_TCP, IPPROTO_UDP),
|
||||
|
||||
Reference in New Issue
Block a user