drm_connector_register() error path leaves dangling connector->kdev β latent double-free on re-register; unchecked kzalloc in the sysfs stub
Summary
A late_register failure unwinds through drm_sysfs_connector_remove, which kfrees connector->kdev without NULLing it; any re-register early-returns on the stale non-NULL kdev yet marks the connector REGISTERED; the eventual unregister kfrees the dangling pointer (double free). Separately, drm_sysfs_connector_add dereferences an unchecked kzalloc result - NULL-deref panic under OOM at registration. No in-tree driver retries register after failure, so the double-free is a latent API hazard. NULL-after-kfree + check-alloc fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4195 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | β | 2.7 KB | β raw | |
| README.md | β | 572 B | β raw | |
| fix.diff | β | 871 B | view raw | |
| manifest.json | β | 814 B | view raw | |
| verdict.json | β | 2.5 KB | view raw |
DF-4195 evidence pack β drm_connector_register/unregister kdev lifecycle hazard
Latent double-free (re-register after failed register) + unchecked kzalloc NULL-deref in the DFBSD sysfs stub. Low severity, source-certain, reachability speculative (no in-tree retry path; OOM-gated).
Contents: VERDICT.md full narrative with path:line citations fix.diff NULL the kdev on remove; check kzalloc in add manifest.json / verdict.json
No runtime PoC: guest has no DRM device (see ../DF-4194/env.txt) and neither branch is reachable in-tree today. Status: untested.
DF-4195 β drm_connector_register/unregister kdev lifecycle hazard (dangling pointer, latent double-free)
sys/dev/drm/drm_connector.c β pass 2, Low, code-certain / reachability speculative.
The issue
On the error path of drm_connector_register() (sys/dev/drm/drm_connector.c:453-467),
a late_register (or, where compiled in, debugfs) failure unwinds through
drm_sysfs_connector_remove() (sys/dev/drm/drm_sysfs.c:48-55), which does
kfree(connector->kdev) without clearing connector->kdev, and leaves
registration_state == DRM_CONNECTOR_INITIALIZING (line 441 gates progress;
the REGISTERED assignment at line 461 is never reached).
Two consequences in the combined drm_connector.c + drm_sysfs.c lifecycle:
- Re-register leaves REGISTERED with a dangling kdev. If any driver ever
calls
drm_connector_register()again on such a connector, state is still INITIALIZING, so the function proceeds β butdrm_sysfs_connector_add()(drm_sysfs.c:37) early-returns on the stale non-NULLconnector->kdev("already added"), the connector is marked REGISTERED with a freed kdev, and the eventualdrm_connector_unregister()βdrm_sysfs_connector_remove()performskfree()on the already-freed pointer β double free. In-tree today no driver retries register on a failed connector (grep of alldrm_connector_register(call sites: drm_connector_register_all at device registration once; MST hotplug paths register each connector once after creation), so this is a latent API hazard, not a demonstrated in-tree trigger β hence Low / speculative reachability. - Unchecked kzalloc NULL-deref in the stub
drm_sysfs_connector_add()(drm_sysfs.c:41-44):connector->kdev = kzalloc(...); connector->kdev->kobj.name = kasprintf(...)dereferences the unchecked allocation β NULL-deref panic under kernel memory pressure (device registration / MST hotplug).
Fix
fix.diff: clear connector->kdev = NULL after kfree in
drm_sysfs_connector_remove(), and check the kzalloc result in
drm_sysfs_connector_add() (return -ENOMEM).
Verification
Not runtime-verified: the audit guest has no DRM device (env.txt in the DF-4194 pack), the re-register path has no in-tree caller, and the NULL-deref needs an OOM at registration. Recorded as Low with source-level certainty.
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_testablefix.diff (NULL kdev after kfree + check both allocations in add) removes both failure modes at the source; not kernel-build validated because the guest has no DRM hardware.
findings/poc/DF-4195/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (path:line walkthrough); fix.diff (kdev=NULL on remove + kzalloc/kasprintf checks); caller grep summarized in VERDICT.md; ../DF-4194/env.txt (no DRM on guest).
PoC changes
No seed PoC; no runtime PoC possible (no DRM device on guest; no in-tree re-register caller).
Verified recommended fix
In drm_sysfs_connector_remove() set connector->kdev = NULL after kfree; in drm_sysfs_connector_add() check the kzalloc/kasprintf results and return -ENOMEM.
Verdict
Code-certain lifecycle defect, reachability speculative. drm_connector_register()'s error unwind (sys/dev/drm/drm_connector.c:453-467) calls drm_sysfs_connector_remove(), which kfrees connector->kdev without NULLing it (sys/dev/drm/drm_sysfs.c:48-55) and leaves registration_state == INITIALIZING. A re-register would early-return on the stale non-NULL kdev (drm_sysfs.c:37) yet mark the connector REGISTERED, so the eventual unregister kfrees the dangling pointer (double free); separately drm_sysfs_connector_add() dereferences an unchecked kzalloc result (drm_sysfs.c:41-44) β NULL-deref panic under OOM at device registration/MST hotplug. Grep of every drm_connector_register() caller shows no in-tree retry after failure (register_all runs once; MST hotplug registers each connector once after creation), and the guest has no DRM device, so neither branch was exercised at runtime.
No comments yet.