> From: Stephen Hemminger [mailto:[email protected]] > Sent: Friday, 19 June 2026 19.01 > > On Fri, 19 Jun 2026 15:12:21 +0200 > Morten Brørup <[email protected]> wrote: > > > > + /* > > > + * Overlap with an existing fragment. Per RFC 8200 section > > > 4.5 > > > + * (and RFC 5722) the datagram must be discarded; the same > > > is > > > + * applied to IPv4. Free all collected fragments, drop this > > > one, > > > + * and invalidate the entry. > > > + */ > > > + if (ofs < fp->frags[i].ofs + fp->frags[i].len && > > > + fp->frags[i].ofs < ofs + len) { > > > > This only catches fragments that are smaller than existing fragments, > i.e. fit within one of the existing fragments. > > It should be: > > if ((ofs >= fp->frags[i].ofs && > > ofs < fp->frags[i].ofs + fp->frags[i].len) || > > (ofs + len >= fp->frags[i].ofs && > > ofs + len < fp->frags[i].ofs + fp->frags[i].len)) { > > > > > + ip_frag_free(fp, dr); > > The code here is comparing an incoming fragment N against existing > fragment E, > using half-open ranges [start, end). > > The test in the patch is symmetric in N and E. > ofs < e.ofs + e.len && e.ofs < ofs + len > > The one you propose tests that either endpoint of N lands inside E. > > Take a fixed stored fragment E = [200, 400) and run several incoming > fragments through both. > N0 = ofs, N1 = ofs+len. > > N inside E: N = [250, 300) > > E: |=========| (200..400) > N: |===| (250..300) > > Patch: 250 < 400 && 200 < 300 → T && T → overlap. > Proposed: (250≥200 && 250<400) → T → overlap. > Both agree. > > N encloses E: N = [100, 500) > > E: |=========| (200..400) > N: |=============| (100..500) > > Patch: 100 < 400 && 200 < 500 → T && T → overlap. > Proposed: (100≥200 && …) → F, (500≥200 && 500<400) → T && F → F, so F > || F → no overlap, MISSED. > > This is the case the new version version drops. Neither endpoint of N > (100 or 500) sits inside [200,400), > because N straddles E completely, so new version endpoint-in-E check > fails even though the ranges clearly overlap. > Patch version catches it because the interval test doesn't care which > range is larger. > > N partial on the left: N = [100, 300) > > E: |=========| (200..400) > N: |======| (100..300) > > Patch: 100 < 400 && 200 < 300 → T → overlap. > Proposed: (300≥200 && 300<400) → T → overlap. > Agree. > > N partial on the right: N = [300, 500) — symmetric to the above, both > catch it. > > So on the four genuine-overlap geometries, your suggestion catches all > four and his misses the enclosing one. > That is not right since the enclosing overlap is a legitimate attack > shape (a big fragment overwriting a smaller stored one). > > There is another issue. > The >= on the exclusive end produces a false positive on fragments that > merely abut, which is the normal case. > Take E already stored as [1400, 2800) and an in-order-but-late fragment > N = [0, 1400) arriving after it (ordinary out-of-order delivery): > > N: |======| (0..1400) > E: |======| (1400..2800) > > These share no bytes; byte 1400 belongs only to E. > Patch: 0 < 2800 && 1400 < 1400 → T && F → no overlap, correct. > Proposed: (1400≥1400 && 1400<2800) → T && T → overlap, wrong. > This test would discard a perfectly valid datagram whenever a left- > abutting fragment arrives after its neighbor. > Adjacent fragments abutting is what fragmentation produces by design, > so this would fire constantly under reordering. > > Bottom line: the patch was correct as far as I can tell.
Thank you for the detailed explanation, Stephen. Agreed, and sorry about the noise. :-)

