acpi_thinkpad attach: kfreeenv(NULL) on the nosmbios path β panic("trying to free NULL pointer") when exactly one SMBIOS env var is unset
Summary
attach jumps to nosmbios when EITHER smbios env var returns NULL, then unconditionally kfreeenvs both pointers. kfreeenv has no NULL guard and DragonFly's _kfree panics on NULL. Inherited FreeBSD code that was harmless there (kfree(NULL) is a no-op on FreeBSD) but panics on DragonFly - a DF-specific divergence. Boot-time panic on ThinkPad firmware with a partial SMBIOS Type-1 table. NULL-guard fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4287 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.5 KB | β raw | |
| VERDICT.md | β | 2.5 KB | β raw | |
| fix.diff | β | 368 B | view raw | |
| manifest.json | β | 785 B | view raw | |
| verdict.json | β | 2.0 KB | view raw |
DF-4287 β acpi_thinkpad attach: kfreeenv(NULL) panics when exactly one SMBIOS env var is absent
What
acpi_thinkpad_attach() [sys/dev/acpica/acpi_thinkpad/acpi_thinkpad.c:607-624]:
maker = kgetenv("smbios.system.maker");
product = kgetenv("smbios.system.product");
if (maker == NULL || product == NULL)
goto nosmbios;
...
nosmbios:
kfreeenv(maker); /* acpi_thinkpad.c:623 */
kfreeenv(product); /* acpi_thinkpad.c:624 */
When exactly one of the two kenv variables is unset, the other
pointer is NULL and is passed to kfreeenv(), which forwards directly to
kfree() [sys/kern/kern_environment.c:332-336 β no NULL guard].
DragonFly's _kfree() panics on NULL:
sys/kern/kern_slaballoc.c:1404-1406 β if (ptr == NULL) panic("trying to
free NULL pointer"). (Note kenv_isdynamic is 1 on any loader-booted
system, so the kfreeenvβkfree path is live.)
Result: boot-time / driver-attach kernel panic on a ThinkPad whose firmware provides the IBM0068/LEN0068/LEN0268 ACPI device but a missing or malformed SMBIOS system-maker/product string (smbios(4) sets these only when an SMBIOS table with the corresponding structure exists).
Trigger
Hardware-gated boot path (ThinkPad + broken/partial SMBIOS table); no user interaction. Not reproducible on the audit guest (not a ThinkPad).
Fix
fix.diff β NULL-guard both kfreeenv calls. (A kernel-wide alternative β
making kfreeenv NULL-tolerant like FreeBSD's kfree(NULL) no-op β is noted
in the verdict but the minimal driver-local fix suffices.)
VERDICT β DF-4287
Status: inconclusive (source-certain; attach path cannot run on this guest) Impact: boot-time / attach-time kernel panic (panic("trying to free NULL pointer")) Confidence: certain
Proof chain
- acpi_thinkpad.c:607-610 β
kgetenv()returns NULL for an unset variable; if either is NULL the code jumps tonosmbioswithout distinguishing which one. - acpi_thinkpad.c:622-624 β
nosmbios: kfreeenv(maker); kfreeenv(product);β when exactly one is NULL, that kfreeenv call receives NULL. - sys/kern/kern_environment.c:332-336:
c void kfreeenv(char *env) { if (kenv_isdynamic) kfree(env, M_KENV); }no NULL check;kenv_isdynamicis set on loader (dynamic kenv) boots. - sys/kern/kern_slaballoc.c:1404-1406:
c if (ptr == NULL) panic("trying to free NULL pointer");β kernel panic.
Reachability
- Driver attaches only on ThinkPad ACPI HID IBM0068/LEN0068/LEN0268 [acpi_thinkpad.c:375, 448-456].
- Needs
smbios.system.makerXORsmbios.system.productmissing β both are populated by smbios(4) from the SMBIOS Type 1 structure; a table with a truncated/absent Type 1, or a string slot emptied, yields NULL from kgetenv. Corner-case firmware, hence Low. - This inherited FreeBSD code (acpi_ibm.c) was safe on FreeBSD because
FreeBSD's
free(NULL)/kfree(NULL)is a no-op; DragonFly's allocator panics β a DF-specific latent divergence.
Why not runtime-verified
The audit guest is not ThinkPad hardware (no IBM0068/LEN0068/LEN0268 ACPI node), so acpi_thinkpad_attach never executes there. The panic sequence (kgetenv NULL β kfreeenv β _kfree KKASSERT-free explicit panic) is source-certain. Module compiles cleanly on the guest (verified during this run).
Fix
fix.diff β NULL-guard the two kfreeenv calls (minimal, matches the
surrounding style). Kernel-wide hardening (kfreeenv tolerating NULL)
would also be reasonable but is out of scope for a single-driver fix.
Bottom line
Deterministic NULL-kfree panic chain on a corner-case ThinkPad firmware configuration; boot-time only; Low severity but zero-cost to fix.
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_testableNot testable: attach path requires IBM0068/LEN0068/LEN0268 ACPI hardware. The panic chain is explicit in source (_kfree panics on NULL by design); the fix is a two-line NULL guard.
source-level: fix.diff vs acpi_thinkpad.c:622-624
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md proof chain: acpi_thinkpad.c:607-624 -> kern_environment.c:332-336 -> kern_slaballoc.c:1404-1406
PoC changes
no seed; not runtime-testable (driver never attaches on this guest)
Verified recommended fix
NULL-guard the two kfreeenv() calls at the nosmbios label (fix.diff)
Verdict
acpi_thinkpad_attach() jumps to nosmbios when EITHER smbios.system.maker or product is NULL but unconditionally calls kfreeenv() on both; kfreeenv() forwards NULL straight to kfree() and DragonFly's _kfree() panics on NULL (kern_slaballoc.c:1405). Inherited FreeBSD code that was harmless there (FreeBSD kfree(NULL) is a no-op) but panics on DragonFly. Source-certain chain; requires ThinkPad ACPI hardware with corner-case SMBIOS env, absent from this guest.
No comments yet.