vlv_dsi_init !fixed_mode error path kfrees a registered drm_connector without drm_connector_cleanup β dangling entry on mode_config.connector_list and in the mode-object IDR
Summary
The !fixed_mode branch jumps to err AFTER drm_connector_init registered the connector in the mode-object IDR and on the global connector list. The err label runs encoder_cleanup + kfrees but never connector_cleanup - leaving a dangling pointer on the global list and a live stale id in the IDR. Post-trigger, unprivileged GETRESOURCES/GETCONNECTOR walk/resolve the freed connector (UAF), and drm_mode_config_cleanup at unload does connector_put on freed memory (guaranteed unload crash). Trigger is a drm_mode_duplicate OOM during attach. Dedicated err_connector label with connector_cleanup fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4206 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.8 KB | β raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| verdict.json | β | 2.7 KB | view raw | |
| fix.diff | β | 728 B | view raw | |
| manifest.json | β | 916 B | view raw |
DF-4206 β vlv_dsi_init !fixed_mode error path kfrees a registered connector β dangling entry in mode_config list/IDR
File: sys/dev/drm/i915/vlv_dsi.c (pass 2)
Severity: Low | Confidence: certain | CWE-416 (use after free) with CWE-401 (leak of connector->name / probed modes)
Build / Run
No build or run: Phase V skipped per contract (Low severity β the trigger is a drm_mode_duplicate allocation failure, i.e. kernel OOM at exactly this point in DSI init; the audit guest has no Intel GPU). The defect is provable from source.
The bug (path:line)
Execution order in vlv_dsi_init():
- vlv_dsi.c:1839
drm_connector_init(dev, connector, ...)β registers the connector in the mode-object IDR (__drm_mode_object_add, drm_connector.c:208) and links it intodev->mode_config.connector_list(drm_connector.c:258). - vlv_dsi.c:1842
drm_connector_helper_add. - vlv_dsi.c:1848
intel_connector_attach_encoder. - vlv_dsi.c:1851
intel_dsi_vbt_get_modes()β duplicatesvbt.lfp_lvds_vbt_mode(non-NULL is guaranteed on this path becauseintel_dsi_vbt_init()already dereferenced it, intel_dsi_vbt.c:544) and adds it as PREFERRED. - vlv_dsi.c:1852-1857 loop picks the PREFERRED mode into
fixed_modevia a seconddrm_mode_duplicate. - vlv_dsi.c:1860-1863 β if
fixed_mode == NULL(either duplicate failed: kernel OOM),goto err. - err label vlv_dsi.c:1875-1878:
drm_encoder_cleanup(&intel_encoder->base); kfree(intel_dsi); kfree(intel_connector);βdrm_connector_cleanup()is never called.
Consequences after step 7 (i915 driver init continues β a failed output does not abort the driver):
dev->mode_config.connector_liststill contains&connector->headwhich now points into freed memory (connectoris embedded in the freedintel_connector). Every walker dereferences freed memory:DRM_IOCTL_MODE_GETRESOURCES(unprivileged) builds the connector id list from that list;DRM_IOCTL_MODE_GETCONNECTORwith the stale id resolves viadrm_mode_object_find()β the IDR still holds the freed connector's id (onlydrm_connector_cleanupβdrm_mode_object_unregisterremoves it, drm_connector.c:405) β returns the freed pointer β UAF read/write;drm_mode_config_cleanup()at unload doesdrm_connector_put()on each list entry β refcount write to freed memory β UAF write, guaranteed crash on unload.connector->name(kasprintf, drm_connector.c:236-239) and any probed modes leak ( drm_connector_cleanup would have freed both, drm_connector.c:392-396,406).
Trigger
drm_mode_duplicate β drm_mode_create β kzalloc failure: i.e. kernel
memory exhaustion during DSI connector init (step 4 or step 5). All other
goto err sites (:1811 host init, :1818 vbt init) are before
drm_connector_init and are correctly handled.
Distinct from known findings
- DF-1446 covers the leak of
dsi_hosts[port](host + mipi_dsi_device) on the sameerr:label and on encoder teardown. This finding is a different object class (the drm_connector) and a different impact (use-after-free of globally-linked state vs. a pure allocation leak).
Fix
Dedicated err_connector label calling drm_connector_cleanup(connector)
before the encoder cleanup β see fix.diff. drm_connector_cleanup
(drm_connector.c:375-422) removes probed modes, unregisters the IDR object,
frees the name, and list_dels from connector_list, so the dangling state
is fully unwound.
Threat model / impact ceiling
Trigger is OOM-gated (not attacker-chosen timing without memory-pressure influence). After the trigger, ordinary unprivileged DRM ioctls walk/use the freed connector β a genuine UAF surface β but the object is a small driver-owned struct; practical exploitation is constrained. Treated as Low.
DF-4206 VERDICT
Status: untested (Phase V skipped β Low severity, OOM-gated trigger, no Intel GPU on the audit guest). Bug existence: certain, proven from source.
Reproduced?
Not on the guest: the QEMU audit VM has no Intel GPU (i915 never attaches,
vlv_dsi_init unreachable), and the trigger requires a kzalloc failure
inside drm_mode_duplicate during DSI connector init on real hardware.
Source-level trace is complete and unambiguous (below), so bug existence is
rated certain; runtime impact untested.
The chain, with citations
- Registration:
drm_connector_initputs the connector in the mode-object IDR (drm_connector.c:208__drm_mode_object_add) and ondev->mode_config.connector_list(drm_connector.c:258list_add_tail). - Faulting flow: vlv_dsi.c:1839 (init) β :1848 (attach encoder) β :1851
(
intel_dsi_vbt_get_modes, adds PREFERRED mode) β :1852-1857 (second duplicate intofixed_mode) β :1860-1863goto errwhen the duplicate fails β :1875-1878kfree(intel_dsi); kfree(intel_connector)with nodrm_connector_cleanup. - Post-free use (unprivileged): MODE_GETRESOURCES walks connector_list;
MODE_GETCONNECTOR resolves the stale IDR id (
drm_mode_object_find);drm_mode_config_cleanupat unload doesdrm_connector_puton the freed entry (refcount write to freed memory). - Secondary leaks on the same path:
connector->name(drm_connector.c:236) and probed modes (drm_connector.c:392-396 would have freed them).
Impact ceiling
Use-after-free of a driver-owned intel_connector reachable through plain
DRM ioctls after the OOM-gated trigger fires during attach; guaranteed
crash at driver unload (drm_connector_put on freed memory). No escalation
chain developed: the trigger cannot be scheduled by an unprivileged user,
and the freed object is small driver state. Low severity.
Fix validation
Not performed on the guest (no hardware). By inspection, the
err_connector label calling drm_connector_cleanup(connector) exactly
undoes steps taken after :1839: IDR unregister (:405), name free (:406),
probed-modes free (:392-393), list_del (:409) β leaving the earlier err
sites (:1811, :1818) untouched and correct.
Relationship to DF-1446
DF-1446 (same label) is the dsi_hosts host/device leak β a CWE-401 resource leak. DF-4206 is the connector lifetime defect β CWE-416. Different object, different impact, complementary fix (fix.diff adds a label; DF-1446's fix adds dsi_hosts frees).
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_testableNo kernel-build fix validation performed: Low-severity OOM-gated finding, guest lacks Intel GPU; fix.diff is a two-hunk label addition whose correctness is checkable by inspection against drm_connector_cleanup (drm_connector.c:375-422).
fix.diff (err_connector label + rerouted goto); not built or applied to sys/.
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md and VERDICT.md in this pack; decisive lines: vlv_dsi.c:1839 (drm_connector_init), :1848 (attach), :1851-1857 (mode dup), :1860-1863 (goto err), :1875-1878 (kfree without cleanup); drm_connector.c:208 (IDR add), :258 (list_add_tail), :375-422 (what cleanup should have done).
PoC changes
No PoC authored: trigger is a kzalloc failure inside drm_mode_duplicate during DSI init on real hardware; audit guest has no Intel GPU. Static proof of path only.
Verified recommended fix
Add an err_connector label calling drm_connector_cleanup(connector) before the existing err cleanup, and route the !fixed_mode branch to it (fix.diff).
Verdict
Bug existence certain from source trace: when the PREFERRED-mode drm_mode_duplicate fails (kernel OOM) after drm_connector_init already registered the connector (drm_connector.c:208 IDR, :258 connector_list), vlv_dsi_init jumps to err (vlv_dsi.c:1860-1863 -> :1875-1878) and kfrees intel_connector without drm_connector_cleanup, leaving a dangling pointer on dev->mode_config.connector_list and a live id in the mode-object IDR. Post-trigger, unprivileged MODE_GETRESOURCES/MODE_GETCONNECTOR and drm_mode_config_cleanup at unload walk/put the freed connector (UAF read/write; guaranteed unload crash). Not verified on the guest: no Intel GPU on the audit VM and the trigger is OOM-gated, so Phase V is skipped per contract (Low severity). Distinct from DF-1446 (dsi_hosts leak on the same label - different object class and impact).
No comments yet.