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]>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_vkms.c
index 5abd7f5ad2db..0d499917682d 100644
--- 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
-- 
2.51.0

Reply via email to