DragonFlyBSD Kernel Audit
← dashboard
DF-0036

%n format specifier enabled in kernel printf engine with zero in-tree consumers

Field Value
ID DF-0036
Status new
Severity Info
CVSS 3.1 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N
CWE CWE-134 Use of Externally-Controlled Format String
File sys/kern/subr_prf.c
Lines 688-701
Area kern
Confidence certain
Discovered 2026-06-29
Reported pending

Summary

kvcprintf implements %n (write the character-count-so-far to a caller- supplied pointer obtained via va_arg) at :688-701. A tree-wide search finds zero in-tree consumers of %n. Its presence means any format-string vulnerability in any kernel caller (kprintf/kvprintf/ksprintf/uprintf/ panic — all route through kvcprintf) is amplified from an info-leak/read into an arbitrary kernel-memory write primitive (the attacker controls the target pointer via va_arg and the written value via padding).

Root cause

sys/kern/subr_prf.c:688-701 — the 'n' case writes retval to *va_arg(ap, T *) for various integer-pointer types T.

Threat model & preconditions

  • Attacker position: no direct exploit — requires a separate format-string vulnerability in a caller (kprintf(user_controlled_string) where the string contains %n). Not independently reachable.
  • Privileges gained or impact: none directly. Defense-in-depth: removing %n eliminates the read→write amplification for any future format-string bug at zero functional cost (nothing uses it).
  • Confidence: certain (the specifier is present and unused).

Make %n a no-op that still consumes its pointer argument (preserving va_list alignment for any remaining conversions):

--- a/sys/kern/subr_prf.c
+++ b/sys/kern/subr_prf.c
@@ -688
-       case 'n':
-           if (cflag)
-               *(__va_arg(ap, char *)) = retval;
-           ... (all the pointer writes) ...
-           else
-               *(__va_arg(ap, int *)) = retval;
+       case 'n':
+           /* %n is a no-op: no in-tree consumers, and its availability
+            * converts any format-string bug into an arbitrary kernel
+            * write. Consume the pointer to keep va_list alignment. */
+           (void)__va_arg(ap, void *);
            break;

References

Timeline

  • 2026-06-29 Discovered during automated file-by-file audit of sys/kern/subr_prf.c.
  • pending Reported to DragonFlyBSD security contact.