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

UAC2.0 Feature Unit descriptor accepted too short causing OOB read of bmaControls[0]

Summary

uaudio20_mixer_verify_desc only requires bLength>=6 for UAC2 Feature Unit (sizeof(*u.fu)=5 +1=6) but uaudio20_mixer_add_feature unconditionally reads UGETDW(d->bmaControls[0]) a 4-byte field at offset 5 requiring bLength>=9. Malicious USB audio device presenting UAC2.0 Audio Control interface with Feature Unit bLength 6-8 passes verification stored in node tree triggers 1-3 byte OOB read. If malformed FU is last descriptor in config descriptor read crosses end of kmalloc buffer into adjacent kernel heap. Contrast EFFECT case uses +4 correctly. Attacker: malicious USB audio device automatic enumeration on plug-in. Impact: small heap OOB read panic at page boundary or indirect info leak.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2333 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict gate analysis + too-short FU descriptor trace 3.2 KB ↓ raw
fix.diff suggested-fix require bLength >= sizeof(fu)+4+1 in verifier 362 B view raw
build.sh build-script documents HW gate 153 B view raw
run.sh run-script prints gate proof 290 B view raw
env.txt environment guest env 1.1 KB view raw
usb_gate.txt gate-proof usbconfig empty, no /dev/ugen*/uaudio* 375 B view raw
VERDICT.md verdict gate analysis + too-short FU descriptor trace
↓ download raw

DF-2333 β€” UAC2.0 Feature Unit descriptor accepted too short (uaudio.c)

Verdict: NOT REPRODUCED (HW-gated); REAL BUG IN SOURCE (defense-in-depth fix warranted)

Hardware gate (why the PoC cannot run on this guest)

uaudio attaches only to a USB audio device plugged into the bus. The audit QEMU/KVM guest has USB host controllers loaded (ehci.ko, xhci.ko) but no USB device of any kind attached:

$ usbconfig list                  # No device match or lack of permissions.
$ ls /dev/ugen* /dev/uaudio*      # No such file or directory
$ ls /dev/usb*                    # only /dev/usbctl (operator-readable; maxx not in operator)
$ ifconfig -l                     # vtnet0 lo0  (no usb wlan)

With no USB audio device the uaudio driver never probes/attaches, so its descriptor-parsing path (uaudio20_mixer_verify_desc / uaudio20_mixer_add_feature) is never executed. The unprivileged maxx user cannot plug a USB device into the QEMU guest, and even if a controller could be made to enumerate, maxx is not in the operator group and cannot open /dev/usbctl for device control. The bug requires a malicious physical USB audio device.

Source trace β€” the bug is REAL (sys/bus/u4b/audio/uaudio.c)

struct usb_audio20_feature_unit (uaudioreg.h:690-698):

struct usb_audio20_feature_unit {
    uByte  bLength; uByte bDescriptorType; uByte bDescriptorSubtype;
    uByte  bUnitId; uByte bSourceId;
    uDWord bmaControls[0];   /* flexible array; each entry is 4 bytes */
    /* uByte iFeature; */
} __packed;                  /* sizeof == 5 */

Verification (uaudio.c:4000-4002):

case UDESCSUB_AC_FEATURE:
    len += sizeof(*u.fu) + 1;   /* requires bLength >= 5 + 1 = 6 only */
    break;

Contrast UDESCSUB_AC_EFFECT (uaudio.c:4004-4005) which correctly adds sizeof(*u.ef) + 4.

Consumer (uaudio.c:3563, inside uaudio20_mixer_add_feature):

if (UGETDW(d->bmaControls[0]) == 0)   /* reads 4 bytes at offset 5: needs bLength >= 9 */
    return;
...
mmask = UGETDW(d->bmaControls[0]);     /* uaudio.c:3569 */

bmaControls[0] lives at offset 5 and is 4 bytes wide, so a well-formed Feature Unit needs bLength >= 9. The verifier only demands bLength >= 6. A malicious USB audio device presenting a UAC2 Feature Unit with bLength in 6..8 passes verification, is stored in the mixer node tree, and then uaudio20_mixer_add_feature performs a 1-3 byte OOB read at offset 5 of the descriptor. If the truncated FU is the last descriptor in the config descriptor, the read crosses the end of the kmalloc'd config buffer into adjacent kernel heap β†’ small heap OOB read / panic at a page boundary / latent info leak.

Trigger: malicious USB audio device, automatic enumeration on plug-in. No privilege, no user interaction.

Exploit chain status

Not pursuable β€” primitive (small OOB read) behind absent USB audio hardware (valid Phase-6 hard blocker: dead path at runtime on this guest). Read-only-ish bug; no escalation.

PoC changes

None. No USB audio device on guest; verified by source trace only.

Require bLength >= sizeof(*u.fu) + 4 + 1 (room for bmaControls[0] + the trailing iFeature byte). See fix.diff (supersedes finding proposal by clamping to the actual first-control-field requirement).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

not_testable: PoC cannot run on this guest (HW-gated, no target device). fix.diff validated by git apply --check (clean) + line-accurate source trace confirming it closes the cited path.

git apply --check findings/poc/DF-2333/fix.diff -> OK (clean apply). No runtime test possible (HW-gated).
↓ fix.diffn/a (no target HW/device on this guest)

Confirmed kernel references

Detail

Exploit chain

none β€” valid hard blocker (driver/device path dead at runtime on this guest: no target HW / no attached device). No unprivileged->root path.

Evidence (decisive lines)

usbconfig list -> No device match or lack of permissions.; pciconf -l -> no target controller HW; ifconfig -l -> vtnet0 lo0; kldstat -> kernel/ehci/xhci only; ls /dev/<target> -> No such file or directory; id maxx -> uid=1001 groups=1001 (not operator). Source confirmed at cited lines.

PoC changes

Created findings/poc/DF-2333/{VERDICT.md,fix.diff,build.sh,run.sh,env.txt,gate_proof.txt,manifest.json}. No PoC source (HW-gated).

Verified recommended fix

verifier requires sizeof(*u.fu)+4+1 (room for bmaControls[0]+iFeature). Full git-apply-able diff in findings/poc/DF-2333/fix.diff (git apply --check OK).

Verdict

NOT REPRODUCED (HW-gated). The bug is REAL in source (traced line-by-line). uaudio UAC2.0 Feature Unit descriptor accepted too short (1-3 byte OOB read); no USB audio device. Gate confirmed via usbconfig list (No device match / no /dev/ugen*), pciconf -l (no target controller HW), ifconfig (vtnet0 lo0 only), kldstat (no target module), and ls /dev (no target nodes). maxx (uid 1001, not in operator) cannot reach any /dev/usbctl write path.