From ef34d6c9cbe190acb2c5853e5c44e67a720294bd Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 18 Jun 2016 14:46:41 +0100 Subject: [PATCH] drm: Protect drm_connector_register_all() under DRIVER_MODESET 0-day kbuilder found [ 1.360244] BUG: unable to handle kernel NULL pointer dereference at (null) [ 1.360972] IP: [] mutex_lock_nested+0x11f/0x2c3 [ 1.361512] *pde = 00000000 [ 1.361827] Oops: 0002 [#1] [ 1.362123] Modules linked in: [ 1.362451] CPU: 0 PID: 1 Comm: swapper Not tainted 4.7.0-rc2-00564-ge28cd4d #1 [ 1.363202] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Debian-1.8.2-1 04/01/2014 [ 1.364105] task: c03d0000 ti: d28da000 task.ti: d28da000 [ 1.364636] EIP: 0060:[] EFLAGS: 00210096 CPU: 0 [ 1.365215] EIP is at mutex_lock_nested+0x11f/0x2c3 [ 1.365703] EAX: 00000000 EBX: d39e8ae8 ECX: d39e8b14 EDX: c1361cf9 [ 1.366351] ESI: c03d0000 EDI: d28dbed0 EBP: d28dbeec ESP: d28dbec0 [ 1.367010] DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068 [ 1.367534] CR0: 80050033 CR2: 00000000 CR3: 019a9000 CR4: 00000690 [ 1.368152] Stack: [ 1.368356] d39e8b14 d39e8b24 c1361cf9 00200246 d39e8b14 00000000 11111111 d28dbed0 [ 1.369235] d39e8800 d39e8ae8 00000000 d28dbf08 c1361cf9 d28dbf0c c10b25be d39e8800 [ 1.370087] 00000000 00000000 d28dbf1c c135e37d fffffff4 ffffffff 00000000 d28dbf28 [ 1.371012] Call Trace: [ 1.371272] [] ? drm_connector_register_all+0x1a/0x92 [ 1.371847] [] drm_connector_register_all+0x1a/0x92 [ 1.372421] [] ? kstrdup+0x25/0x3a [ 1.372863] [] drm_dev_register+0x59/0x99 [ 1.373358] [] vgem_init+0x34/0x49 [ 1.373770] [] ? mipi_dsi_bus_init+0xf/0xf [ 1.374257] [] do_one_initcall+0x7c/0xfd [ 1.374754] [] ? parse_args+0x1fd/0x314 [ 1.375259] [] ? kernel_init_freeable+0xd0/0x179 [ 1.375837] [] kernel_init_freeable+0xec/0x179 [ 1.376371] [] kernel_init+0x8/0xcb [ 1.376806] [] ret_from_kernel_thread+0xe/0x30 [ 1.377322] [] ? rest_init+0x10e/0x10e [ 1.377754] Code: 89 fa e8 71 c5 b7 ff 8b 4e 04 89 fa 89 d8 e8 8e c6 b7 ff 8d 43 2c 89 45 d4 8b 43 30 8d 4b 2c 89 45 e8 89 7b 30 89 4d e4 8b 55 dc <89> 38 8d 43 3c 89 75 ec e8 c9 dd b7 ff eb 0c 31 c0 87 03 48 +75 [ 1.380442] EIP: [] mutex_lock_nested+0x11f/0x2c3 SS:ESP 0068:d28dbec0 [ 1.381174] CR2: 0000000000000000 when loading the non-modesetting vGEM module. To prevent use of the uninitialised dev->mode_config from drm_dev_register() we move the drm_connector_register_all() under a DRIVER_MODESET guard. Longer term, we probably want to initialise the embedded dev->mode_config automatically from drm_dev_init() for all DRIVER_MODESET drivers. v2: Also protect drm_dev_unregister. Fixes: e28cd4d0a223 ("drm: Automatically register/unregister all connectors") Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Emil Velikov Cc: dri-devel@lists.freedesktop.org Reviewed-by: Emil Velikov Testcase: igt/vgem_reload_basic Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1466257601-5656-1-git-send-email-chris@chris-wilson.co.uk --- drivers/gpu/drm/drm_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index f4cec6d6d948..0823aded93a9 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -705,7 +705,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto err_minors; } - drm_connector_register_all(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_connector_register_all(dev); ret = 0; goto out_unlock; @@ -737,7 +738,8 @@ void drm_dev_unregister(struct drm_device *dev) drm_lastclose(dev); - drm_connector_unregister_all(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_connector_unregister_all(dev); if (dev->driver->unload) dev->driver->unload(dev);