In pvr2_hdw_create(), the error handling path under 'fail:' calls
flush_work(&hdw->workpoll) whenever hdw is non-NULL. However,
INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll) was placed near the
end of pvr2_hdw_create(), after multiple 'goto fail;' error paths
(such as v4l2_device_register() failure or kmalloc() failures for
control buffers).
If any of those earlier allocations or registrations fail, jumping to
'fail:' invokes flush_work(&hdw->workpoll) on an uninitialized
work_struct where work->func is still NULL, triggering WARN_ON(!work->func)
in __flush_work().
Move INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll) right after timer
and waitqueue initialization, before the first error path after hdw
allocation, ensuring workpoll is always initialized before flush_work()
can be called on it.
Fixes: 29a3006e5209 ("[media] pvrusb2: Remove deprecated create_singlethread_workqueue")
Reported-by: syzbot+b91abe6ef9924496daf8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b91abe6ef9924496daf8
Signed-off-by: zhangdaolong <dlzhangak@isoftstone.com>
---
drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 3c270ef00752..1fb93f4c8471 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2398,6 +2398,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->master_state = PVR2_STATE_DEAD;
init_waitqueue_head(&hdw->state_wait_data);
+ INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll);
hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
@@ -2567,8 +2568,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
} while (0);
mutex_unlock(&pvr2_unit_mtx);
- INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll);
-
if (hdw->unit_number == -1)
goto fail;
--
2.48.1