Skip to content

Commit 8ff7cb9

Browse files
authored
Merge pull request #1077 from maxslarsson/fix-raw-socket-fragmentation
Fix panic in raw socket fragmentation when payload buffer exceeds packet size
2 parents 2fa85f6 + 51c1bbf commit 8ff7cb9

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

src/iface/interface/tests/ipv4.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,76 @@ fn test_raw_socket_with_udp_socket(#[case] medium: Medium) {
10651065
);
10661066
}
10671067

1068+
#[rstest]
1069+
#[case(Medium::Ip)]
1070+
#[cfg(all(
1071+
feature = "socket-raw",
1072+
feature = "proto-ipv4-fragmentation",
1073+
feature = "medium-ip"
1074+
))]
1075+
#[case(Medium::Ethernet)]
1076+
#[cfg(all(
1077+
feature = "socket-raw",
1078+
feature = "proto-ipv4-fragmentation",
1079+
feature = "medium-ethernet"
1080+
))]
1081+
fn test_raw_socket_tx_fragmentation(#[case] medium: Medium) {
1082+
use std::panic::AssertUnwindSafe;
1083+
1084+
let (mut iface, mut sockets, device) = setup(medium);
1085+
let mtu = device.capabilities().max_transmission_unit;
1086+
1087+
let packets = 5;
1088+
let rx_buffer = raw::PacketBuffer::new(
1089+
vec![raw::PacketMetadata::EMPTY; packets],
1090+
vec![0; mtu * packets],
1091+
);
1092+
let tx_buffer = raw::PacketBuffer::new(
1093+
vec![raw::PacketMetadata::EMPTY; packets],
1094+
vec![0; mtu * packets],
1095+
);
1096+
let socket = raw::Socket::new(
1097+
Some(IpVersion::Ipv4),
1098+
Some(IpProtocol::Udp),
1099+
rx_buffer,
1100+
tx_buffer,
1101+
);
1102+
let _handle = sockets.add(socket);
1103+
1104+
let tx_packet_sizes = vec![
1105+
mtu * 3 / 4, // Smaller than MTU
1106+
mtu * 5 / 4, // Larger than MTU, requires fragmentation
1107+
mtu * 9 / 4, // Much larger, requires two fragments
1108+
];
1109+
for packet_size in tx_packet_sizes {
1110+
let payload_len = packet_size - IPV4_HEADER_LEN;
1111+
let payload = vec![0u8; payload_len];
1112+
1113+
let ip_repr = Ipv4Repr {
1114+
src_addr: Ipv4Address::new(192, 168, 1, 3),
1115+
dst_addr: Ipv4Address::BROADCAST,
1116+
next_header: IpProtocol::Unknown(92),
1117+
hop_limit: 64,
1118+
payload_len,
1119+
};
1120+
let ip_payload = IpPayload::Raw(&payload);
1121+
let packet = Packet::new_ipv4(ip_repr, ip_payload);
1122+
1123+
// This should not panic for any payload size
1124+
let result = std::panic::catch_unwind(AssertUnwindSafe(|| {
1125+
iface.inner.dispatch_ip(
1126+
MockTxToken {},
1127+
PacketMeta::default(),
1128+
packet,
1129+
&mut iface.fragmenter,
1130+
)
1131+
}));
1132+
1133+
// All transmissions should succeed without panicking
1134+
assert!(result.is_ok(), "Failed for packet size: {}", packet_size,);
1135+
}
1136+
}
1137+
10681138
#[rstest]
10691139
#[case(Medium::Ip)]
10701140
#[cfg(all(feature = "socket-udp", feature = "medium-ip"))]

src/iface/packet.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,10 @@ impl<'p> Packet<'p> {
130130
}
131131

132132
#[cfg(feature = "socket-raw")]
133-
IpPayload::Raw(raw_packet) => payload.copy_from_slice(raw_packet),
133+
IpPayload::Raw(raw_packet) => {
134+
let len = raw_packet.len();
135+
payload[..len].copy_from_slice(raw_packet)
136+
}
134137
#[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
135138
IpPayload::Udp(udp_repr, inner_payload) => udp_repr.emit(
136139
&mut UdpPacket::new_unchecked(payload),

0 commit comments

Comments
 (0)