diff --git a/pkg/tcpip/header/BUILD b/pkg/tcpip/header/BUILD index 187aec597..6278dbcc9 100644 --- a/pkg/tcpip/header/BUILD +++ b/pkg/tcpip/header/BUILD @@ -7,6 +7,7 @@ go_library( srcs = [ "arp.go", "checksum.go", + "datagram.go", "eth.go", "gue.go", "icmpv4.go", diff --git a/pkg/tcpip/header/datagram.go b/pkg/tcpip/header/datagram.go new file mode 100644 index 000000000..7569091c5 --- /dev/null +++ b/pkg/tcpip/header/datagram.go @@ -0,0 +1,18 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package header + +// DatagramMaximumSize is the maximum supported size of a single datagram. +const DatagramMaximumSize = 0xffff // 65KB. diff --git a/pkg/tcpip/transport/icmp/endpoint.go b/pkg/tcpip/transport/icmp/endpoint.go index 8a4825cc3..b0de7d628 100644 --- a/pkg/tcpip/transport/icmp/endpoint.go +++ b/pkg/tcpip/transport/icmp/endpoint.go @@ -337,6 +337,11 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp } defer ctx.Release() + // Prevents giant buffer allocations. + if p.Len() > header.DatagramMaximumSize { + return 0, &tcpip.ErrMessageTooLong{} + } + v := bufferv2.NewView(p.Len()) defer v.Release() if _, err := io.CopyN(v, p, int64(p.Len())); err != nil { diff --git a/pkg/tcpip/transport/packet/endpoint.go b/pkg/tcpip/transport/packet/endpoint.go index f82e36517..3000d44b8 100644 --- a/pkg/tcpip/transport/packet/endpoint.go +++ b/pkg/tcpip/transport/packet/endpoint.go @@ -234,6 +234,11 @@ func (ep *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tc return 0, &tcpip.ErrInvalidOptionValue{} } + // Prevents giant buffer allocations. + if p.Len() > header.DatagramMaximumSize { + return 0, &tcpip.ErrMessageTooLong{} + } + var payload bufferv2.Buffer if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil { return 0, &tcpip.ErrBadBuffer{} diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index b4dac52b5..1192d7b1b 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -350,6 +350,11 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp return 0, &tcpip.ErrMessageTooLong{} } + // Prevents giant buffer allocations. + if p.Len() > header.DatagramMaximumSize { + return 0, &tcpip.ErrMessageTooLong{} + } + var payload bufferv2.Buffer defer payload.Release() if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil { diff --git a/test/syscalls/linux/ping_socket.cc b/test/syscalls/linux/ping_socket.cc index 2648ce074..bb8e3281b 100644 --- a/test/syscalls/linux/ping_socket.cc +++ b/test/syscalls/linux/ping_socket.cc @@ -81,6 +81,29 @@ TEST(PingSocket, ICMPPortExhaustion) { } } +TEST(PingSocket, PayloadTooLarge) { + PosixErrorOr result = + Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); + if (!result.ok()) { + int errno_value = result.error().errno_value(); + ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); + GTEST_SKIP() << "ping socket not supported"; + } + FileDescriptor& ping = result.ValueOrDie(); + + constexpr icmphdr kSendIcmp = { + .type = ICMP_ECHO, + }; + constexpr size_t kGiantSize = 1 << 21; // 2MB. + const sockaddr_in kAddr = { + .sin_family = AF_INET, + .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)}, + }; + ASSERT_THAT(sendto(ping.get(), &kSendIcmp, kGiantSize, 0, + reinterpret_cast(&kAddr), sizeof(kAddr)), + SyscallFailsWithErrno(EMSGSIZE)); +} + TEST(PingSocket, ReceiveTOS) { PosixErrorOr result = Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);