[PATCH 7.1 414/438] drm/vmwgfx: avoid destroy_workqueue(NULL) on vkms init failure
Greg Kroah-Hartman <[email protected]>
| Newsgroups | dev.linux.lists.patches,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
7.1-stable review patch. If anyone has any objections, please let me know. ------------------ From: Zack Rusin <[email protected]> commit 05eaa887e7b4f40fba425f8a1d7a5a8a043092a6 upstream. Two paths through vmw_vkms_init() can leave vmw->crc_workq NULL while still leaving the rest of the driver in a state that calls vmw_vkms_cleanup() at module unload: 1. vmw_host_get_guestinfo(GUESTINFO_VBLANK, ...) failing or returning an oversized buffer -- the common case on hosts without a VBLANK guestinfo entry -- early-returned before the workqueue allocation. 2. alloc_ordered_workqueue() returning NULL on memory pressure. vmw_vkms_cleanup() then calls destroy_workqueue(NULL), which dereferences wq->name and panics. Fix the first case by removing the early return: vmw->vkms_enabled is already false on the rpci-failure path so no work will ever be queued, and allocating the workqueue unconditionally keeps the control flow simple. Fix the second case by guarding the cleanup with a NULL check, since alloc_ordered_workqueue() can still fail under low memory. Fixes: 7b0062036c3b ("drm/vmwgfx: Implement virtual crc generation") Cc: [email protected] Assisted-by: Claude:claude-opus-4.7 Signed-off-by: Zack Rusin <[email protected]> Reviewed-by: Ian Forbes <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> --- drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) --- a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c @@ -214,14 +214,14 @@ vmw_vkms_init(struct vmw_private *vmw) vmw->vkms_enabled = false; ret = vmw_host_get_guestinfo(GUESTINFO_VBLANK, buffer, &buf_len); - if (ret || buf_len > max_buf_len) - return; - buffer[buf_len] = '\0'; + if (!ret && buf_len <= max_buf_len) { + buffer[buf_len] = '\0'; - ret = kstrtobool(buffer, &vmw->vkms_enabled); - if (!ret && vmw->vkms_enabled) { - ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS); - vmw->vkms_enabled = (ret == 0); + ret = kstrtobool(buffer, &vmw->vkms_enabled); + if (!ret && vmw->vkms_enabled) { + ret = drm_vblank_init(&vmw->drm, VMWGFX_NUM_DISPLAY_UNITS); + vmw->vkms_enabled = (ret == 0); + } } vmw->crc_workq = alloc_ordered_workqueue("vmwgfx_crc_generator", 0); @@ -236,7 +236,8 @@ vmw_vkms_init(struct vmw_private *vmw) void vmw_vkms_cleanup(struct vmw_private *vmw) { - destroy_workqueue(vmw->crc_workq); + if (vmw->crc_workq) + destroy_workqueue(vmw->crc_workq); } bool