Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/gud: fix NULL crtc dereference on display disable

gud_plane_atomic_update() currently handles both crtc state and
framebuffer updates - the complexity has led to a few accidental
NULL pointer dereferences.

Commit dc2d5ddb193e ("drm/gud: fix NULL fb and crtc dereferences
on USB disconnect") [1] fixed an earlier dereference but planes
can also be disabled in non-hotplug paths (e.g. display disables
via the desktop environment). The drm_dev_enter() call would not
cause an early return in those and subsequently oops on
dereferencing crtc:

BUG: kernel NULL pointer dereference, address: 00000000000005c8
CPU: 6 UID: 1000 PID: 3473 Comm: kwin_wayland Not tainted 6.18.2-200.vanilla.gud.fc42.x86_64 #1 PREEMPT(lazy)
RIP: 0010:gud_plane_atomic_update+0x148/0x470 [gud]
<TASK>
drm_atomic_helper_commit_planes+0x28e/0x310
drm_atomic_helper_commit_tail+0x2a/0x70
commit_tail+0xf1/0x150
drm_atomic_helper_commit+0x13c/0x180
drm_atomic_commit+0xb1/0xe0
info ? __pfx___drm_printfn_info+0x10/0x10
drm_mode_atomic_ioctl+0x70f/0x7c0
? __pfx_drm_mode_atomic_ioctl+0x10/0x10
drm_ioctl_kernel+0xae/0x100
drm_ioctl+0x2a8/0x550
? __pfx_drm_mode_atomic_ioctl+0x10/0x10
__x64_sys_ioctl+0x97/0xe0
do_syscall_64+0x7e/0x7f0
? __ct_user_enter+0x56/0xd0
? do_syscall_64+0x158/0x7f0
? __ct_user_enter+0x56/0xd0
? do_syscall_64+0x158/0x7f0
entry_SYSCALL_64_after_hwframe+0x76/0x7e

Split out crtc handling from gud_plane_atomic_update() into
atomic_enable() and atomic_disable() functions to delegate
crtc state transitioning work to the DRM helpers.

To preserve the gud state commit sequence [2], switch to
the runtime PM version of drm_atomic_helper_commit_tail() which
ensures that crtcs are enabled (hence sending the
GUD_REQ_SET_CONTROLLER_ENABLE and GUD_REQ_SET_DISPLAY_ENABLE
requests) before a framebuffer update is sent.

[1] https://lore.kernel.org/all/20251231055039.44266-1-me@shenghaoyang.info/
[2] https://github.com/notro/gud/wiki/GUD-Protocol#display-state

Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/r/202601142159.0v8ilfVs-lkp@intel.com/
Fixes: 73cfd166e045 ("drm/gud: Replace simple display pipe with DRM atomic helpers")
Cc: <stable@vger.kernel.org> # 6.19.x
Cc: <stable@vger.kernel.org> # 6.18.x
Signed-off-by: Shenghao Yang <me@shenghaoyang.info>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Ruben Wauters <rubenru09@aol.com>
Signed-off-by: Ruben Wauters <rubenru09@aol.com>
Link: https://patch.msgid.link/20260222054551.80864-1-me@shenghaoyang.info

authored by

Shenghao Yang and committed by
Ruben Wauters
7149be78 46d8a07b

+48 -19
+8 -1
drivers/gpu/drm/gud/gud_drv.c
··· 339 339 } 340 340 341 341 static const struct drm_crtc_helper_funcs gud_crtc_helper_funcs = { 342 - .atomic_check = drm_crtc_helper_atomic_check 342 + .atomic_check = drm_crtc_helper_atomic_check, 343 + .atomic_enable = gud_crtc_atomic_enable, 344 + .atomic_disable = gud_crtc_atomic_disable, 343 345 }; 344 346 345 347 static const struct drm_crtc_funcs gud_crtc_funcs = { ··· 364 362 .disable_plane = drm_atomic_helper_disable_plane, 365 363 .destroy = drm_plane_cleanup, 366 364 DRM_GEM_SHADOW_PLANE_FUNCS, 365 + }; 366 + 367 + static const struct drm_mode_config_helper_funcs gud_mode_config_helpers = { 368 + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, 367 369 }; 368 370 369 371 static const struct drm_mode_config_funcs gud_mode_config_funcs = { ··· 505 499 drm->mode_config.min_height = le32_to_cpu(desc.min_height); 506 500 drm->mode_config.max_height = le32_to_cpu(desc.max_height); 507 501 drm->mode_config.funcs = &gud_mode_config_funcs; 502 + drm->mode_config.helper_private = &gud_mode_config_helpers; 508 503 509 504 /* Format init */ 510 505 formats_dev = devm_kmalloc(dev, GUD_FORMATS_MAX_NUM, GFP_KERNEL);
+4
drivers/gpu/drm/gud/gud_internal.h
··· 62 62 63 63 void gud_clear_damage(struct gud_device *gdrm); 64 64 void gud_flush_work(struct work_struct *work); 65 + void gud_crtc_atomic_enable(struct drm_crtc *crtc, 66 + struct drm_atomic_state *state); 67 + void gud_crtc_atomic_disable(struct drm_crtc *crtc, 68 + struct drm_atomic_state *state); 65 69 int gud_plane_atomic_check(struct drm_plane *plane, 66 70 struct drm_atomic_state *state); 67 71 void gud_plane_atomic_update(struct drm_plane *plane,
+36 -18
drivers/gpu/drm/gud/gud_pipe.c
··· 580 580 return ret; 581 581 } 582 582 583 + void gud_crtc_atomic_enable(struct drm_crtc *crtc, 584 + struct drm_atomic_state *state) 585 + { 586 + struct drm_device *drm = crtc->dev; 587 + struct gud_device *gdrm = to_gud_device(drm); 588 + int idx; 589 + 590 + if (!drm_dev_enter(drm, &idx)) 591 + return; 592 + 593 + gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 1); 594 + gud_usb_set(gdrm, GUD_REQ_SET_STATE_COMMIT, 0, NULL, 0); 595 + gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, 1); 596 + 597 + drm_dev_exit(idx); 598 + } 599 + 600 + void gud_crtc_atomic_disable(struct drm_crtc *crtc, 601 + struct drm_atomic_state *state) 602 + { 603 + struct drm_device *drm = crtc->dev; 604 + struct gud_device *gdrm = to_gud_device(drm); 605 + int idx; 606 + 607 + if (!drm_dev_enter(drm, &idx)) 608 + return; 609 + 610 + gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, 0); 611 + gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0); 612 + 613 + drm_dev_exit(idx); 614 + } 615 + 583 616 void gud_plane_atomic_update(struct drm_plane *plane, 584 617 struct drm_atomic_state *atomic_state) 585 618 { ··· 640 607 mutex_unlock(&gdrm->damage_lock); 641 608 } 642 609 643 - if (!drm_dev_enter(drm, &idx)) 610 + if (!crtc || !drm_dev_enter(drm, &idx)) 644 611 return; 645 - 646 - if (!old_state->fb) 647 - gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 1); 648 - 649 - if (fb && (crtc->state->mode_changed || crtc->state->connectors_changed)) 650 - gud_usb_set(gdrm, GUD_REQ_SET_STATE_COMMIT, 0, NULL, 0); 651 - 652 - if (crtc->state->active_changed) 653 - gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, crtc->state->active); 654 - 655 - if (!fb) 656 - goto ctrl_disable; 657 612 658 613 ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); 659 614 if (ret) 660 - goto ctrl_disable; 615 + goto out; 661 616 662 617 drm_atomic_helper_damage_iter_init(&iter, old_state, new_state); 663 618 drm_atomic_for_each_plane_damage(&iter, &damage) ··· 653 632 654 633 drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); 655 634 656 - ctrl_disable: 657 - if (!crtc->state->enable) 658 - gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0); 659 - 635 + out: 660 636 drm_dev_exit(idx); 661 637 }