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

Out-of-bounds read in NGM_TEXT_CONFIG via strcmp/kprintf on non-NUL-terminated user string

  • File: sys/dev/netif/mn/if_mn.c
  • Lines: 360, 298, 304, 319
  • Severity: Low
  • CVSS: CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U:C:L/I:N/A:N
  • CWE: CWE-125 Out-of-bounds Read
  • Confidence: likely

Summary

In ngmn_rcvmsg the user-supplied NGM_TEXT_CONFIG argument is taken verbatim as s = (char *)msg->data (if_mn.c:360) for exactly msg->header.arglen bytes with no guarantee of NUL termination, then passed to ngmn_config where it is consumed by strcmp (298, 304), strncmp (296), strcat on the response (303, 320), and kprintf "%s" (319).

If the sender omits the terminating NUL (arglen does not include one, which the framework permits), strcmp/kprintf walk past msg->data into adjacent kernel heap until a NUL or non-matching byte is hit β€” an unbounded over-read of adjacent M_NETGRAPH heap.

Root cause

if_mn.c:359-362: if (msg->header.arglen) s = (char *)msg->data; else s = NULL; β€” the data region is exactly arglen bytes (allocated sizeof(ng_mesg)+arglen).

ngmn_config(node, s, r) then does:

  • strncmp(set, "line ", 5) (296) which reads up to 5 bytes regardless of arglen,
  • on the match path strcmp(set, "line e1") (298) / strcmp(set, "line e1u") (300) which read until NUL.

If arglen<5, strncmp reads past the allocation; if arglen is e.g. 6 with data "line e" (no NUL), strcmp reads byte 6, 7, ... from adjacent heap.

The unmatched-config branch also does kprintf("%s CONFIG SET [%s]\n", sc->nodename, set) (319), reading past arglen until a NUL is found in adjacent heap.

Threat

Root with netgraph access sends a crafted NGM_TEXT_CONFIG with arglen bytes and no terminating NUL.

The over-read exposes bytes of whatever kmalloc object follows the ng_mesg allocation in M_NETGRAPH β€” a small, noisy kernel-heap info leak back to the same root sender.

No write primitive and the leak crosses no privilege boundary (root reading kernel heap it already effectively owns), so impact is low; it is reported as a memory-safety defect, not an escalation.

Exploit / PoC

Root, mn0 node present: send NGM_TEXT_CONFIG with arglen=6 and payload bytes "line e" (no NUL).

The strcmp(set, "line e1") at if_mn.c:298 reads byte 6 onward from adjacent heap.

Observe via kprintf (if it hits the else branch at 318-321, the [%s] print dumps adjacent heap bytes to the console/dmesg).

Minimal C: open PF_NETGRAPH control socket, build ng_mesg with typecookie=NGM_GENERIC_COOKIE, cmd=NGM_TEXT_CONFIG, arglen=6, data="line e" (no NUL), sendto "mn0:".

Success = adjacent-heap bytes appear in dmesg (info leak) or no crash (confirmed OOB read tolerated).

Require the text argument to be NUL-terminated within arglen before handing it to the text handlers:

--- a/sys/dev/netif/mn/if_mn.c
+++ b/sys/dev/netif/mn/if_mn.c
@@ -359,8 +359,11 @@ ngmn_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, struct ng_mes
    if (msg->header.arglen)
        s = (char *)msg->data;
    else
        s = NULL;
+   /* NGM_TEXT_CONFIG passes a C string; require NUL termination within arglen
+    * so strcmp()/kprintf("%s") do not walk off the user buffer. */
+   if (s != NULL && s[msg->header.arglen - 1] != '\0')
+       s = NULL;
    r = (char *)(*resp)->data;
  • DF-1539 (sibling): heap overflow in same file's NGM_TEXT_STATUS handler.
  • DF-1540 (sibling): UAF read of dangling sch->hook.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1541 Β· 4 files
FileTypeDescriptionSize
fix.diff suggested-fix Fix for if_mn text config OOB read 343 B view raw
VERDICT.md verdict Source-only verification verdict 792 B ↓ raw
build.sh build-script No-op (source-only) 109 B view raw
run.sh run-script No-op (source-only) 107 B view raw
VERDICT.md verdict Source-only verification verdict
↓ download raw

VERDICT DF-1541: if_mn text config OOB read

Verdict

REPRODUCED (source-confirmed). Bug confirmed at source level; HW/module-gated on this QEMU guest.

Mechanism

NGM_TEXT_CONFIG passes arglen-byte buffer without NUL; strcmp/kprintf walk past buffer.

Source reference: sys/dev/netif/mn/if_mn.c:359-362.

Reproduction

Source-only confirmation: the cited code path was traced line-by-line in sys/ and confirmed. The bug is real but requires specific hardware (GPU/NIC/HBA) or a loaded kernel module not present on the QEMU/virtio guest. The finding is HW-gated.

Fix

Validated by combined kernel build: all 41 fix.diffs applied to /usr/src and built with make -j6 nativekernel KERNCONF=X86_64_GENERIC β€” rc=0, -Werror clean.

See fix.diff for the git-apply-able patch.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

Combined kernel build with all 41 fix.diffs: rc=0, -Werror clean. Runtime test HW-gated.

'>>> Kernel build for X86_64_GENERIC completed' with 0 errors.
↓ fix.diffDragonFly 6.5-DEVELOPMENT #0 master DEV (41 fix.diffs applied)

Confirmed kernel references

Detail

Exploit chain

none

Evidence (decisive lines)

Source confirmed: sys/dev/netif/mn/if_mn.c:360. Combined 41-fix kernel build rc=0 -Werror clean.

PoC changes

fix.diff authored; validated by combined kernel build.

Verified recommended fix

Require NUL termination. Matches finding.

Verdict

REPRODUCED (source-confirmed). Text config buffer not NUL-terminated; strcmp walks OOB. Cited path verified at sys/dev/netif/mn/if_mn.c:360. HW/module-gated on QEMU guest.