NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/60487: netinet6: fragment accounting leak
>Number: 60487
>Category: kern
>Synopsis: netinet6: fragment accounting leak
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Jul 23 18:30:00 +0000 2026
>Originator: Taylor R Campbell
>Release: current, 11, 10, 9, ...
>Organization:
The NetBSDv6 Fragmentation, CPA
>Environment:
>Description:
When frag6_input enqueues a fragment for reassembly, it
increments a counter of the number of fragments in flight
systemwide and for this packet:
421 insert:
422 /*
423 * Stick new segment in its place.
424 */
425 frag6_enq(ip6af, af6->ip6af_up);
426 frag6_nfrags++;
427 q6->ip6q_nfrag++;
https://nxr.netbsd.org/xref/src/sys/netinet6/frag6.c?r=1.78#421
frag6_nfrags is used to reject an excess of fragments:
246 /*
247 * Enforce upper bound on number of fragments.
248 * If maxfrag is 0, never accept fragments.
249 * If maxfrag is -1, accept all fragments without limitation.
250 */
251 if (ip6_maxfrags < 0)
252 ;
253 else if (frag6_nfrags >= (u_int)ip6_maxfrags)
254 goto dropfrag;
https://nxr.netbsd.org/xref/src/sys/netinet6/frag6.c?r=1.78#246
And q6->ip6q_nfrag is used to count back down when the packet
reassembly is completed or aborted:
123 static void
124 frag6_dropfrag(struct ip6q *q6)
125 {
126 frag6_remque(q6);
127 frag6_nfrags -= q6->ip6q_nfrag;
128 kmem_intr_free(q6, sizeof(*q6));
129 frag6_nfragpackets--;
130 }
https://nxr.netbsd.org/xref/src/sys/netinet6/frag6.c?r=1.78#123
However, there is a path in fragment input where an existing
fragment is discarded -- and not deducted from q6->ip6q_nfrag
or frag6_nfrags:
346 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
347 IPV6_MAXPACKET) {
348 struct mbuf *merr = af6->ip6af_m;
349 struct ip6_hdr *ip6err;
350 int erroff = af6->ip6af_offset;
351
352 /* dequeue the fragment. */
353 frag6_deq(af6);
354 kmem_intr_free(af6, sizeof(struct ip6asfrag));
https://nxr.netbsd.org/xref/src/sys/netinet6/frag6.c?r=1.78#346
Taking this path can lead to fragments being spuriously dropped
while frag6_nfrags is high even though there aren't that many
fragments in flight.
The accounting doesn't go completely wrong, from what I can
tell: since the dropped fragment is still counted in
q6->ip6q_nfrag, it will be properly deducted from frag6_nfrags
when frag6_dropfrag finally runs.
>How-To-Repeat:
send ongoing carefully crafted fragments
>Fix:
--- src/sys/netinet6/frag6.c
+++ src/sys/netinet6/frag6.c
@@ -350,6 +348,8 @@
int erroff = af6->ip6af_offset;
/* dequeue the fragment. */
+ q6->ip6q_nfrag--;
+ frag6_nfrags--;
frag6_deq(af6);
kmem_intr_free(af6, sizeof(struct ip6asfrag));
Home |
Main Index |
Thread Index |
Old Index