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)
PoC verification
Evidence pack
findings/poc/DF-4487 Β· 2 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | β | 2.0 KB | β raw | |
| verdict.json | β | 1.5 KB | view 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_testableInfo-severity hardening; not runtime-tested.
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.
No comments yet.