β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-0626

frag6_nfragpackets counter leak on queue allocation failure permanently reduces reassembly capacity

Field Value
ID DF-0626
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
CWE CWE-404 Improper Resource Shutdown or Release
File sys/netinet6/frag6.c
Lines 267, 270-271
Area netinet6 (IPv6 fragment reassembly queue accounting)
Confidence certain
Discovered 2026-07-02
Reported pending

Summary

When a new fragment creates a reassembly queue, frag6_nfragpackets is incremented at line 267 before the kmalloc at line 268. If kmalloc fails (returns NULL at line 270), the code jumps to dropfrag (line 271) without decrementing frag6_nfragpackets. This leaves a phantom count that permanently inflates the global packet counter, reducing the effective maximum number of concurrent reassembly queues by one for the lifetime of the system.

Root cause

At sys/netinet6/frag6.c:263-271:

263:    if (ip6_maxfragpackets < 0)
264:        ;
265:    else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
266:        goto dropfrag;
267:    frag6_nfragpackets++;                                    /* incremented BEFORE kmalloc */
268:    q6 = (struct ip6q *)kmalloc(sizeof(struct ip6q), M_FTABLE,
269:        M_NOWAIT | M_ZERO);
270:    if (q6 == NULL)
271:        goto dropfrag;                                   /* jump WITHOUT decrementing */

The dropfrag label (frag6.c:535) does m_freem(m) and returns IPPROTO_DONE β€” but never executes frag6_nfragpackets--. The label has no knowledge of whether frag6_nfragpackets was incremented. Once inflated to == ip6_maxfragpackets, the check at line 265 (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) blocks all future new-flow reassembly until existing queues drain (TTL expiry or completion), at which point the count drops below the limit again but remains permanently +1 above the true count.

Threat model & preconditions

  • Attacker position: unauthenticated remote β€” can trigger M_NOWAIT kmalloc failure by flooding the target with IPv6 fragments to create memory pressure (exhausting mbufs/clusters).
  • Impact: each failure leaks one phantom count into frag6_nfragpackets. However, because the limit check at line 265 uses >= and the leak can produce at most ONE phantom before the check blocks further increments, the practical impact is negligible: the effective queue capacity is reduced from nmbclusters/4 (typically 1024+) to nmbclusters/4 - 1. The phantom persists until reboot.
  • This is a resource-accounting correctness defect with marginal DoS amplification, not a memory-safety violation.

Move the frag6_nfragpackets increment to after the kmalloc success check, so the counter only reflects successfully allocated queue entries:

--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -264,11 +264,11 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
        else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
            goto dropfrag;
-       frag6_nfragpackets++;
        q6 = (struct ip6q *)kmalloc(sizeof(struct ip6q), M_FTABLE,
            M_NOWAIT | M_ZERO);
        if (q6 == NULL)
            goto dropfrag;
+       frag6_nfragpackets++;

        frag6_insque(q6, &ip6q);

This is safe because frag6_input is serialized on netisr0 (IPv6 hashcheck forces all IPv6 input to CPU 0), so there is no race window between the limit check and the increment.

References

Timeline

  • 2026-07-02 Discovered during automated DragonFlyBSD kernel security audit.
  • 2026-07-02 Reported to DragonFlyBSD security contact (pending).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0626 Β· 5 files
FileTypeDescriptionSize
fix.diff suggested-fix Move the increment to after a successful kmalloc. 425 B view raw
VERDICT.md verdict source-confirmation + fix 1.0 KB ↓ raw
../_batch_low/fix_build.log build-log combined 80-fix kernel build (rc=0, -Werror) 5.6 MB ↓ download
../_batch_low/combined_all.patch suggested-fix all 80 fixes batched 20.0 KB view raw
../_batch_low/env.txt environment guest uname + kern.version 247 B view raw
VERDICT.md verdict source-confirmation + fix
↓ download raw

DF-0626 β€” Low-severity source-confirmation

Verdict: REPRODUCED

Impact: dos Confidence: likely

Kernel ref: sys/netinet6/frag6.c:267

Mechanism / why

Source-confirmed: frag6_input does frag6_nfragpackets++ before the kmalloc; on M_NOWAIT failure it goto dropfrag without decrementing -> counter leak eventually blocks all fragments. netinet6 (GENERIC).

Move the increment to after a successful kmalloc.

Phase 8 (combined build)

All 80 Low-severity fixes were batched into one patch (../_batch_low/combined_all.patch) and applied to the in-guest /usr/src. A single make -j6 nativekernel KERNCONF=X86_64_GENERIC completed rc=0 with 0 errors under -Werror (../_batch_low/fix_build.log). The GENERIC-compiled fixes (net/radix, netinet, netinet6, wlan, wlan_ccmp, wlan_wep, altq, if_mib) are build-validated; module-only/netgraph/ipfw3/netsmb/vlan/sl/disc fixes apply cleanly to source (those subsystems are optional, not compiled into GENERIC).

A standalone git apply-able fix.diff is in this folder.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

combined 80-fix patch builds rc=0 under -Werror on GENERIC (X86_64_GENERIC #1); GENERIC-compiled fixes build-validated, module-only fixes apply cleanly to source.

baseline 6.5-DEVELOPMENT #0 (Jul 2) -> patched build #1 (Jul 23) rc=0 -Werror, 0 errors
↓ fix.diffDragonFly 6.5-DEVELOPMENT #1: Thu Jul 23 06:52:07 UTC 2026

Confirmed kernel references

Detail

Exploit chain

none (Low-severity dos; source-only confirmation)

Evidence (decisive lines)

DF-0626 [REPRODUCED] - sys/netinet6/frag6.c:267

PoC changes

fix.diff present in findings/poc/DF-0626/; batched into ../_batch_low/combined_all.patch

Verified recommended fix

Move the increment to after a successful kmalloc.

Verdict

Source-confirmed: frag6_input does frag6_nfragpackets++ before the kmalloc; on M_NOWAIT failure it goto dropfrag without decrementing -> counter leak eventually blocks all fragments. netinet6 (GENERIC).