drm/vc4: NULL deref in vc4_hvs_unbind()/vc4_v3d_unbind() - component unbind reads master drvdata after vc4_drm_unbind() cleared it
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Anfängerfreundlichkeit
- 78/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Aktiv
- Tech-Stack
- c, linux, raspberry-pi
- Bereich
- computer-graphics, embedded-iot, operating-systems
Rechercherichtung
Start with the unbind callbacks in drivers/gpu/drm/vc4/vc4_hvs.c and vc4_v3d.c, then read vc4_component_unbind_all in vc4_drv.c and the component teardown order in drivers/base/component.c. Build the vc4 driver and verify that removing a DSI panel completes without an Oops, leaves the module removable, and permits a normal reboot.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Describe the bug
vc4_hvs_unbind() and vc4_v3d_unbind() read the DRM device from dev_get_drvdata(master), but vc4_drm_unbind() has already set that to NULL by the time the component unbind callbacks run. The result is a NULL pointer dereference whenever the vc4 component chain is torn down.
Mainline uses the void *data argument the component framework passes in, which is still valid at that point. The rpi tree does not, and appears to have diverged accidentally — vc4_v3d_unbind() is at the same line number in both trees and differs only in that one expression.
The practical consequence is worse than a single oops: after it fires, systemctl reboot hangs in DRM teardown and the machine has to be power-cycled physically.
Steps to reproduce
On a CM4 with a DSI panel, remove the panel driver module:
# systemctl stop <whatever holds the display>
# rmmod <dsi_panel_driver>
Segmentation fault
The panel driver here is an out-of-tree ST7701 driver, but nothing about it is special — its remove() only calls mipi_dsi_detach() and drm_panel_remove(). Any DSI panel driver being removed will reach the same path.
Actual behaviour
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000638
Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP
CPU: 2 UID: 0 PID: 6578 Comm: rmmod Tainted: G C O 6.12.25+rpt-rpi-v8 #1
Hardware name: Raspberry Pi Compute Module 4 Rev 1.1 (DT)
pc : vc4_hvs_unbind+0x20/0x160 [vc4]
lr : component_unbind+0x40/0x70
x20: 0000000000000000
Call trace:
vc4_hvs_unbind+0x20/0x160 [vc4]
component_unbind+0x40/0x70
component_unbind_all+0xd0/0xe8
vc4_component_unbind_all+0x20/0x38 [vc4]
devm_action_release+0x1c/0x30
release_nodes+0x70/0x100
devres_release_group+0xd4/0x158
component_del+0xb8/0x170
vc4_dsi_host_detach+0x30/0x58 [vc4]
mipi_dsi_detach+0x40/0x68
<panel>_dsi_remove+0x20/0x40 [<panel driver>]
mipi_dsi_drv_remove+0x28/0x40
device_remove+0x78/0x90
device_release_driver_internal+0x1dc/0x238
driver_detach+0x58/0xa8
bus_remove_driver+0x74/0xd0
driver_unregister+0x38/0x70
mipi_dsi_driver_unregister+0x18/0x30
<panel>_dsi_driver_exit+0x18/0x890 [<panel driver>]
__arm64_sys_delete_module+0x1a8/0x298
Code: 910003fd a90153f3 f90013f5 f9403c34 (f9431e95)
Afterwards: card1 is gone, the DSI connector is gone, the module is stuck at refcount -1, and reinserting it fails with EBUSY.
Then systemctl reboot never completes. The journal stops at
kernel: Console: switching to colour dummy device 80x25
with no service stops, no unmounts and no Reached target Shutdown. The machine drops off the network at that point and only removing mains power recovers it.
Root cause
vc4_drm_unbind() clears the master's drvdata (drivers/gpu/drm/vc4/vc4_drv.c):
static void vc4_drm_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
drm_dev_unplug(drm);
drm_atomic_helper_shutdown(drm);
dev_set_drvdata(dev, NULL); /* cleared here */
}
drivers/base/component.c runs the master unbind before releasing the devres group that drives the component unbinds:
adev->ops->unbind(adev->parent); /* vc4_drm_unbind, nulls drvdata */
devres_release_group(adev->parent, adev); /* -> vc4_component_unbind_all */
and component_unbind() passes the master data through to each component:
component->ops->unbind(component->dev, adev->parent, data);
vc4 supplies a perfectly good pointer for that (vc4_drv.c):
static void vc4_component_unbind_all(void *ptr)
{
struct vc4_dev *vc4 = ptr;
component_unbind_all(vc4->dev, &vc4->base); /* master_data = the drm_device */
}
but the two unbind callbacks ignore it and re-read the drvdata that was just nulled. Because struct vc4_dev has struct drm_device base as its first member, to_vc4_dev(NULL) is exactly NULL rather than a small offset, so the very next member access faults. 0x638 is offsetof(struct vc4_dev, hvs), and the Code: bytes decode to exactly that:
f9403c34 ldr x20, [x1, #120] ; x1 = master, +120 = struct device.driver_data
f9431e95 ldr x21, [x20, #1592] ; 1592 = 0x638, faults with x20 == NULL
Only these two callbacks are affected. vc4_crtc, vc4_hdmi, vc4_txp, vc4_dpi and vc4_vec do not use dev_get_drvdata(master) in their unbind. The bind callbacks are fine and should not change — drvdata is valid during bind, and mainline reads it there too.
Suggested fix
Match mainline:
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ static void vc4_hvs_unbind(struct device *dev, struct device *master,
void *data)
{
- struct drm_device *drm = dev_get_drvdata(master);
+ struct drm_device *drm = data;
struct vc4_dev *vc4 = to_vc4_dev(drm);
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
void *data)
{
- struct drm_device *drm = dev_get_drvdata(master);
+ struct drm_device *drm = data;
struct vc4_dev *vc4 = to_vc4_dev(drm);
Verification
Tested on the affected hardware.
The vc4 driver was built out of tree against the installed headers from commit 3dd2c2c507c2 (SUBLEVEL = 25, matching the Debian 1:6.12.25-1+rpt1 (2025-04-30) build stamp in /proc/version). Unpatched, that build reproduces the shipped module exactly — vc4_hvs_unbind disassembles opcode-for-opcode identically to the distributed vc4.ko, so the only variable in what follows is the two-line change.
With the patch applied, vc4_hvs_unbind becomes mov x20, x2 / ldr x21, [x2, #1592] — reading the data argument — and vc4_v3d_unbind starts mov x0, x2.
Booted on that module, then the same rmmod:
| shipped | patched | |
|---|---|---|
rmmod output |
Segmentation fault |
(silent) |
| Oopses | 1 | 0 |
| Module afterwards | stuck at refcount -1 |
fully removed |
insmod afterwards |
EBUSY |
— |
systemctl is-system-running |
wedged, reboot hangs, power cycle required | running, reboot completes normally |
The teardown also completes properly rather than merely not crashing — the panel receives its disable and unprepare DSI commands, which never happened before because the crash came first. A subsequent systemctl reboot unmounted everything and reached reboot.target cleanly.
Environment
- Raspberry Pi Compute Module 4 Rev 1.1
6.12.25+rpt-rpi-v8, Debian package1:6.12.25-1+rpt1raspi-firmware 1:1.20250430-1- DSI0, single DSI panel,
vc4-kms-v3d
- Vorherrschende Sprache
- C
- Sterne
- 13.3k
- Forks
- 5.5k
- Ø Merge
- 3 T. 20 Std.
- Gemergte PRs (30 T.)
- 27
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus raspberrypi/linux
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 63/100
raspberrypi/linux#7718 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
raspberrypi/linux#7415 · 2 Kommentare · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag
-
rp1-cfe doesn't forward V4L2_EVENT_SOURCE_CHANGE event from csi-2 sensor driver to userspace appOffen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
raspberrypi/linux#7399 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 82/100
raspberrypi/linux#7357 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
raspberrypi/linux#7054 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in raspberrypi/linux
Ähnliche Issues
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
Maintainer antworten meist innerhalb von 1 Tag
-
SPIDevice selects an active-high device as soon as it is createdEvtl. vergeben @mikeysklar hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 73/100
adafruit/circuitpython#11869 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 78/100
gnif/LookingGlass#1352 ·
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 75/100
Maintainer antworten meist innerhalb von 1 Tag
-
bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
kovidgoyal/kitty#10862 ·
Maintainer antworten meist innerhalb von 1 Tag