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

Unvalidated descriptor-field reads in the UVC entity/CS parsers: OOB reads up to 253 bytes past malformed descriptors

Summary

Four device-field reads before/without bLength validation: XU bControlSize at 22+bNrInPins (unbounded, up to 253B past a 24B descriptor and past the cdesc when last), IT offset-14 pre-read, VC bIfaceList[0] 1-byte over, COLORFORMAT offset-3. All values traced to rejection compares/bounded indexes - no disclosure path today (hardening; the XU traversal is one refactor from one). Guards compiled in the DF-5306 fix-validation build.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5307 Β· 5 files
FileTypeDescriptionSize
README.md β€” 2.3 KB ↓ raw
VERDICT.md β€” 2.1 KB ↓ raw
fix.diff β€” 2.9 KB view raw
manifest.json β€” 852 B view raw
verdict.json β€” 2.2 KB view raw

DF-5307 β€” unvalidated descriptor-field reads in uvc_drv_parse_standard_ctrl()/uvc_drv_parse_data(): OOB reads up to 253 bytes past malformed descriptors

Where (all in sys/bus/u4b/uvc/uvc_drv.c)

  1. Extension Unit (largest) β€” uvc_drv.c:2332-2334: c src_ids_num = xu_desc->bLength >= 22 ? xu_desc->bNrInPins : 0; ctrls_mask_size = xu_desc->bLength >= 24 ? *(&xu_desc->bControlSize + src_ids_num) : 0; bNrInPins (offset 21, up to 255) is not bounded by bLength; the bControlSize byte is read at offset 22 + bNrInPins, i.e. up to offset 277 of a descriptor whose bLength may be as small as 24 β€” up to 253 bytes past the descriptor end, past the end of the kmalloc()ed cdesc buffer when the XU descriptor is last. The value read is used for validation only (bLength < ctrls_mask_size + src_ids_num + 24 β†’ EINVAL), so no disclosure β€” but the kernel reads heap memory it must not read (and the traversal *(&field + n) is exactly the anti-pattern).
  2. Input Terminal β€” uvc_drv.c:2209: bControlSize is read from offset 14 (memcpy(&ctrls_mask_size, it_desc + 14, 1)) before the bLength < 15 + ctrls_mask_size check at 2212; a camera-terminal descriptor with bLength 8..14 gives a 1..7-byte over-read.
  3. VC header β€” uvc_drv.c:2109-2124: with bLength == 12 and vsnum == 1, bIfaceList[0] is read at offset 12 β€” one byte past the descriptor. (Same site as the DF-5306 acceptance bug; fixed together.)
  4. VS_COLORFORMAT β€” uvc_drv.c:1843-1845: cld->bColorPris is read at offset 3 with no bLength >= 4 check.

All four are read-only primitives with values consumed internally (no path to userspace found), hence Low. Same class as DF-2350/DF-5305 but distinct sites; the XU over-read is by far the largest reach.

Fix

fix.diff (shared with DF-5305/DF-5306, applies with git apply -p0): guards each read with the appropriate bLength check and clamps src_ids_num to bLength - 23. The VC-header guard was compiled and exercised during the DF-5306 fix validation; the other guards are compiled but not separately triggered (Low severity β€” not QEMU-verified in this run; status untested).

Files

fix.diff   covers all four sites
VERDICT.md
↓ download raw

DF-5307 VERDICT

Status: untested (Low severity, read-only primitives β€” Phase V not mandated), confidence: certain in the code defect, speculative in any impact beyond the OOB read itself.

Analysis

Four sites in the descriptor parsers read device-supplied fields without first proving the descriptor is long enough to contain them (see README.md for exact path:line and mechanics):

  • XU bControlSize at 22 + bNrInPins with bNrInPins unbounded by bLength β€” up to 253 bytes past the descriptor (uvc_drv.c:2332-2334);
  • IT bControlSize at offset 14 before validation (uvc_drv.c:2209);
  • VC header bIfaceList[0] at offset 12 when bLength == 12 (uvc_drv.c:2109-2124);
  • VS_COLORFORMAT bColorPris at offset 3 (uvc_drv.c:1843-1845).

Each over-read stays inside the cdesc allocation unless the descriptor sits at the end of the blob, in which case it is a kernel heap OOB read. I traced every consumer of the four values: they feed either a comparison that rejects the descriptor (XU, IT, VC) or a colorspace table index bounded by nitems() (COLORFORMAT) β€” no value reaches userspace, so this is hardening/defense-in-depth (CWE-125 read) with no demonstrated disclosure. The XU traversal is additionally fragile: any future code change that uses ctrls_mask_size from the over-read before validation would turn it into a heap-info leak.

Why untested

The QEMU harness built for DF-5305/DF-5306 exercises the parse paths but was not extended to trigger these specific malformed shapes; Low severity places them below the Phase V mandate. The fix.diff guards were compiled during the DF-5306 fix validation (the VC-header guard is on the exercised path); the XU/IT/COLORFORMAT guards are compile-checked only.

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

fix.diff guards present for all four sites; the VC-header guard was compiled and exercised via the DF-5306 fix-validation run; XU/IT/COLORFORMAT guards compile-checked only, not behaviorally verified.

fix.diff; DF-5306/fix.log (exercises the shared VC-header guard path)
↓ fix.diffper-fix-DF-5307

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (full path:line analysis of all four sites and value consumers), fix.diff (guards for every site)

PoC changes

no PoC built for this finding (Low; see verdict)

Verified recommended fix

Validate bLength before each field read and clamp XU bNrInPins to bLength-23 (included in fix.diff, shared with DF-5305/DF-5306).

Verdict

Static-analysis finding, certain at the code level: four descriptor-field reads happen before (or without) bLength validation, the largest being the Extension Unit bControlSize read at offset 22+bNrInPins with bNrInPins unbounded (up to 253 bytes past a 24-byte descriptor, and past the cdesc allocation when the descriptor is last). All four values were traced to rejection comparisons or a bounded table index - no userspace disclosure path exists today, so impact is a kernel OOB read / hardening defect (Low). Not QEMU-verified: Low severity falls below the Phase V mandate; the fix.diff guards for the shared VC-header site were compiled and exercised during the DF-5306 fix validation, the rest are compile-checked.