fix(net): Bound the transport checksum by the network header's length - #1778
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
Included review availability: 4 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour. 📝 WalkthroughWalkthroughChangesChecksum payload bounds
Suggested reviewers: Merge Risk: ⚪ Minimal · up to The PR bounds transport checksum calculations to the network packet length so Ethernet padding is not included. No actionable merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
An ethernet frame shorter than 60 octets arrives padded, and that padding sat inside the slice we summed. TCP and ICMPv6 take their pseudo header length from the slice, so a bare 54-octet ACK left with a checksum off by the pad length. This is wrong even when the padding is zeroed, which is why UDP and ICMPv4 usually survived it and TCP did not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Daniel Noland <daniel@githedgehog.com>
0005119 to
f41630d
Compare
mvachhar
left a comment
There was a problem hiding this comment.
Do we want to have a fix for the serializer when there is a short payload or is that a separate PR?
|
Oh, and FYI, the commit message is just wrong. 802.3 includes the header in the frame and size, so the threshold is not a frame size of 60 bytes, but a frame size of 64 bytes. I didn't check its numbers on the IP packet size. Annoying. Fix if you want, I won't hold up the PR for it. |
The defect
Packet::newkept everything after the parsed headers as the payload, and nothing ever trimmed the buffer to the IPv4 total length / IPv6 payload length (TrimFromEndexisted but was never called).do_serializethen handed that whole slice to the checksum code, so ethernet padding was summed as if it were L4 payload.Ethernet pads frames out to 64 octets including the Ethernet header, so any IPv4 frame under that was affected:
header_len + payload.len()payload.len() + header_lenlengthfieldThe sharp edge is IPv4 TCP: a bare ACK, RST, FIN, or option-less SYN is 54 octets on the wire. Every one of those this dataplane forwarded left with a checksum the far end drops. Flows carrying TCP timestamps produce 66-octet frames and escaped.