From 582cdc752dd41ef1bc8009fcd460f2eccb6f73e9 Mon Sep 17 00:00:00 2001 From: Max Larsson Date: Fri, 18 Jul 2025 21:16:48 -0700 Subject: [PATCH 1/3] Fix panic in raw socket fragmentation when payload buffer exceeds packet size --- src/iface/packet.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/iface/packet.rs b/src/iface/packet.rs index 70e5a5ccf..287687ea9 100644 --- a/src/iface/packet.rs +++ b/src/iface/packet.rs @@ -130,7 +130,10 @@ impl<'p> Packet<'p> { } #[cfg(feature = "socket-raw")] - IpPayload::Raw(raw_packet) => payload.copy_from_slice(raw_packet), + IpPayload::Raw(raw_packet) => { + let len = raw_packet.len(); + payload[..len].copy_from_slice(raw_packet) + } #[cfg(any(feature = "socket-udp", feature = "socket-dns"))] IpPayload::Udp(udp_repr, inner_payload) => udp_repr.emit( &mut UdpPacket::new_unchecked(payload), From b6dbcff182bc0a2cc915bda84abef44c7fe31928 Mon Sep 17 00:00:00 2001 From: Max Larsson Date: Sat, 19 Jul 2025 20:27:23 -0700 Subject: [PATCH 2/3] Add tests for raw socket tx fragmentation --- src/iface/interface/tests/ipv4.rs | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/iface/interface/tests/ipv4.rs b/src/iface/interface/tests/ipv4.rs index 37685a7ba..113463081 100644 --- a/src/iface/interface/tests/ipv4.rs +++ b/src/iface/interface/tests/ipv4.rs @@ -1029,6 +1029,66 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) { ); } +#[rstest] +#[case(Medium::Ip)] +#[cfg(all(feature = "socket-raw", feature = "proto-ipv4-fragmentation", feature = "medium-ip"))] +#[case(Medium::Ethernet)] +#[cfg(all( + feature = "socket-raw", + feature = "proto-ipv4-fragmentation", + feature = "medium-ethernet" +))] +fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) { + let (mut iface, mut sockets, device) = setup(medium); + let mtu = device.capabilities().max_transmission_unit; + + let packets = 5; + let rx_buffer = + raw::PacketBuffer::new(vec![raw::PacketMetadata::EMPTY; packets], vec![0; mtu * packets]); + let tx_buffer = raw::PacketBuffer::new( + vec![raw::PacketMetadata::EMPTY; packets], + vec![0; mtu * packets], + ); + let socket = raw::Socket::new( + Some(IpVersion::Ipv4), + Some(IpProtocol::Udp), + rx_buffer, + tx_buffer, + ); + let _handle = sockets.add(socket); + + let tx_packet_sizes = vec![ + mtu * 3 / 4, // Smaller than MTU + mtu * 5 / 4, // Larger than MTU, requires fragmentation + mtu * 9 / 4, // Much larger, requires two fragments + ]; + for packet_size in tx_packet_sizes { + let payload_len = packet_size - IPV4_HEADER_LEN; + let payload = vec![0u8; payload_len]; + + let ip_repr = Ipv4Repr { + src_addr: Ipv4Address::new(192, 168, 1, 3), + dst_addr: Ipv4Address::BROADCAST, + next_header: IpProtocol::Unknown(92), + hop_limit: 64, + payload_len, + }; + let ip_payload = IpPayload::Raw(&payload); + let packet = Packet::new_ipv4(ip_repr, ip_payload); + + // This should not panic for any payload size + let result = iface.inner.dispatch_ip( + MockTxToken {}, + PacketMeta::default(), + packet, + &mut iface.fragmenter, + ); + + // All transmissions should succeed without panicking + assert!(result.is_ok(), "Failed for packet size: {} with error: {:?}", packet_size, result.err()); + } +} + #[rstest] #[case(Medium::Ip)] #[cfg(all(feature = "socket-udp", feature = "medium-ip"))] From 51c1bbf6e66cbea868ecc93e93624c6f2cbc3472 Mon Sep 17 00:00:00 2001 From: Max Larsson Date: Sat, 19 Jul 2025 20:41:10 -0700 Subject: [PATCH 3/3] Format code and catch unwind in for loop --- src/iface/interface/tests/ipv4.rs | 36 ++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/iface/interface/tests/ipv4.rs b/src/iface/interface/tests/ipv4.rs index 113463081..154419e8b 100644 --- a/src/iface/interface/tests/ipv4.rs +++ b/src/iface/interface/tests/ipv4.rs @@ -1031,7 +1031,11 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) { #[rstest] #[case(Medium::Ip)] -#[cfg(all(feature = "socket-raw", feature = "proto-ipv4-fragmentation", feature = "medium-ip"))] +#[cfg(all( + feature = "socket-raw", + feature = "proto-ipv4-fragmentation", + feature = "medium-ip" +))] #[case(Medium::Ethernet)] #[cfg(all( feature = "socket-raw", @@ -1039,12 +1043,16 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) { feature = "medium-ethernet" ))] fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) { + use std::panic::AssertUnwindSafe; + let (mut iface, mut sockets, device) = setup(medium); let mtu = device.capabilities().max_transmission_unit; let packets = 5; - let rx_buffer = - raw::PacketBuffer::new(vec![raw::PacketMetadata::EMPTY; packets], vec![0; mtu * packets]); + let rx_buffer = raw::PacketBuffer::new( + vec![raw::PacketMetadata::EMPTY; packets], + vec![0; mtu * packets], + ); let tx_buffer = raw::PacketBuffer::new( vec![raw::PacketMetadata::EMPTY; packets], vec![0; mtu * packets], @@ -1058,9 +1066,9 @@ fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) { let _handle = sockets.add(socket); let tx_packet_sizes = vec![ - mtu * 3 / 4, // Smaller than MTU - mtu * 5 / 4, // Larger than MTU, requires fragmentation - mtu * 9 / 4, // Much larger, requires two fragments + mtu * 3 / 4, // Smaller than MTU + mtu * 5 / 4, // Larger than MTU, requires fragmentation + mtu * 9 / 4, // Much larger, requires two fragments ]; for packet_size in tx_packet_sizes { let payload_len = packet_size - IPV4_HEADER_LEN; @@ -1077,15 +1085,17 @@ fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) { let packet = Packet::new_ipv4(ip_repr, ip_payload); // This should not panic for any payload size - let result = iface.inner.dispatch_ip( - MockTxToken {}, - PacketMeta::default(), - packet, - &mut iface.fragmenter, - ); + let result = std::panic::catch_unwind(AssertUnwindSafe(|| { + iface.inner.dispatch_ip( + MockTxToken {}, + PacketMeta::default(), + packet, + &mut iface.fragmenter, + ) + })); // All transmissions should succeed without panicking - assert!(result.is_ok(), "Failed for packet size: {} with error: {:?}", packet_size, result.err()); + assert!(result.is_ok(), "Failed for packet size: {}", packet_size,); } }