From ef6bb95608c44a117f7ef90f625dbe2d9b548f66 Mon Sep 17 00:00:00 2001 From: clydebarrow <2366188+clydebarrow@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:52:47 +1100 Subject: [PATCH] [udp] Drop datagrams longer than the receive buffer A read cuts a datagram longer than the buffer to fit, so a 600 byte datagram arrived as a valid looking 508 byte packet. The buffer is now one byte longer, and a read that fills it is dropped. The split packet test also checks the bytes joined in the copy buffer. Co-Authored-By: Claude Opus 5.5 --- esphome/components/udp/udp_component.cpp | 7 ++++++- tests/components/udp/udp_packet_interface.cpp | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/esphome/components/udp/udp_component.cpp b/esphome/components/udp/udp_component.cpp index 535fdd62f29..61c171a26ee 100644 --- a/esphome/components/udp/udp_component.cpp +++ b/esphome/components/udp/udp_component.cpp @@ -209,7 +209,8 @@ void UDPComponent::loop() { this->disable_loop(); return; } - std::array buf; + // One byte more than the largest packet, as a read cuts a longer datagram to fit and so cannot report it + std::array buf; for (;;) { if (!this->listen_socket_->ready()) break; @@ -217,6 +218,10 @@ void UDPComponent::loop() { if (len <= 0) break; size_t packet_len = static_cast(len); + if (packet_len > MAX_PACKET_SIZE) { + ESP_LOGV(TAG, "Packet longer than %zu bytes dropped", MAX_PACKET_SIZE); + continue; + } ESP_LOGV(TAG, "Received packet of length %zu", packet_len); this->packet_listeners_.call(std::span(buf.data(), packet_len)); } diff --git a/tests/components/udp/udp_packet_interface.cpp b/tests/components/udp/udp_packet_interface.cpp index 6eccbfacd6d..50a62e02f73 100644 --- a/tests/components/udp/udp_packet_interface.cpp +++ b/tests/components/udp/udp_packet_interface.cpp @@ -56,6 +56,9 @@ TEST_F(UdpPacketInterfaceTest, SendsContiguousAndSplitPackets) { uint8_t header = 0; PacketBuffer body(packet); EXPECT_TRUE(this->link_.send_to_interface(PacketBuffer(&header, 1, &body, nullptr, 0), {})); + // A packet split across buffers is joined in the copy buffer before it is sent + const auto *storage = this->link_.tx_buffer_storage; + EXPECT_EQ(Packet(storage, storage + 5), (Packet{0, 1, 2, 3, 4})); } TEST_F(UdpPacketInterfaceTest, OversizedPacketNotSent) {