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

acpi_video_vo_init kmalloc without M_ZERO leaves vo_sysctl_tree uninitialized when the global video sysctl node is absent

Summary

vo_sysctl_tree is assigned only inside 'if (acpi_video_sysctl_tree != NULL)' but read unconditionally by SYSCTL_CHILDREN in five SYSCTL_ADD_PROC calls and re-checked in vo_destroy - when the node ADD failed (OOM) or MOD_UNLOAD NULLed the global while outputs exist, a garbage heap value is used as sysctl_oid*. OOM/boot-order-gated crash. M_ZERO fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4487 Β· 2 files
FileTypeDescriptionSize
VERDICT.md β€” 2.0 KB ↓ raw
verdict.json β€” 1.5 KB view raw
VERDICT.md
↓ download raw

DF-4487 β€” uninitialized vo_sysctl_tree when the global video sysctl tree is absent

Root cause (code-certain; trigger requires SYSCTL_ADD_NODE failure / OOM at attach): - sys/dev/acpica/acpi_video/acpi_video.c:513 β€” vo = kmalloc(sizeof(*vo), M_ACPIVIDEO, M_NOWAIT); β€” NOT zeroed (no M_ZERO). - :514-522 initialize the scalar fields, but vo->vo_sysctl_tree is NOT in that list. - :535-539 vo->vo_sysctl_tree is assigned ONLY inside if (acpi_video_sysctl_tree != NULL). - :540 if (vo->vo_sysctl_tree != NULL) β€” reads the uninitialized field. When acpi_video_sysctl_tree is NULL (SYSCTL_ADD_NODE failed at attach under memory pressure, acpi_video.c:254-259) or MOD_UNLOAD set it to NULL (:204-205) while outputs still exist, the garbage heap value is treated as a struct sysctl_oid *: - SYSCTL_ADD_PROC(..., SYSCTL_CHILDREN(vo->vo_sysctl_tree), ...) Γ—5 (:541-572) β€” dereferences the garbage pointer (arbitrary kernel memory read/crash). - acpi_video_vo_destroy() (:623-626) re-checks the same garbage field and may run sysctl_ctx_free() on the wrong condition.

Why "untested": reproducing requires forcing SYSCTL_ADD_NODE failure (kernel memory exhaustion at first attach) β€” not deterministic on the audit guest. The uninitialized-read itself is evident from the code (kmalloc without M_ZERO + conditionally-assigned field + unconditional read).

Fix: use M_NOWAIT | M_ZERO in the kmalloc (or explicitly set vo->vo_sysctl_tree = NULL; in the :514-522 init block).

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.

(No fix.diff for this item: documented recommendation only - see Fix above.)

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Info-severity hardening; not runtime-tested.

per-fix-DF-4487

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (code path)

Verified recommended fix

kmalloc(..., M_NOWAIT | M_ZERO) in acpi_video_vo_init (or explicitly init vo_sysctl_tree = NULL)

Verdict

vo is kmalloc'd without M_ZERO (acpi_video.c:513) and vo_sysctl_tree is only assigned inside 'if (acpi_video_sysctl_tree != NULL)' (:535-539); when the global node failed to be created (SYSCTL_ADD_NODE failure/OOM at attach, or MOD_UNLOAD NULLing it, :204-205) the unconditional read at :540 uses an uninitialized heap value as struct sysctl_oid* and passes it to SYSCTL_CHILDREN in five SYSCTL_ADD_PROC calls -> garbage-pointer dereference. OOM-gated, Info severity.