summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNayana Bidari <nybidari@google.com>2020-12-11 13:29:05 -0800
committergVisor bot <gvisor-bot@google.com>2020-12-11 13:31:28 -0800
commitd45420b1528b8ad23e8f12fe81fb9cc148b83012 (patch)
tree35df2b3965fbe23b8772e49a4deae0ffb14ddd10
parent5bdc167d174515eb51ba1bb0f4b4d1e484e8996c (diff)
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
-rw-r--r--pkg/tcpip/transport/raw/endpoint.go12
-rw-r--r--test/syscalls/linux/raw_socket.cc45
2 files changed, 57 insertions, 0 deletions
diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go
index 90b032d85..d9a664c03 100644
--- a/pkg/tcpip/transport/raw/endpoint.go
+++ b/pkg/tcpip/transport/raw/endpoint.go
@@ -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()
diff --git a/test/syscalls/linux/raw_socket.cc b/test/syscalls/linux/raw_socket.cc
index 54709371c..c108c45df 100644
--- a/test/syscalls/linux/raw_socket.cc
+++ b/test/syscalls/linux/raw_socket.cc
@@ -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),