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.

usb: gadget: f_hid: move list and spinlock inits from bind to alloc

There was an issue when you did the following:
- setup and bind an hid gadget
- open /dev/hidg0
- use the resulting fd in EPOLL_CTL_ADD
- unbind the UDC
- bind the UDC
- use the fd in EPOLL_CTL_DEL

When CONFIG_DEBUG_LIST was enabled, a list_del corruption was reported
within remove_wait_queue (via ep_remove_wait_queue). After some
debugging I found out that the queues, which f_hid registers via
poll_wait were the problem. These were initialized using
init_waitqueue_head inside hidg_bind. So effectively, the bind function
re-initialized the queues while there were still items in them.

The solution is to move the initialization from hidg_bind to hidg_alloc
to extend their lifetimes to the lifetime of the function instance.

Additionally, I found many other possibly problematic init calls in the
bind function, which I moved as well.

Signed-off-by: Michael Zimmermann <sigmaepsilon92@gmail.com>
Cc: stable <stable@kernel.org>
Link: https://patch.msgid.link/20260331184844.2388761-1-sigmaepsilon92@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Michael Zimmermann and committed by
Greg Kroah-Hartman
4e0a8825 5abbe6ec

+10 -9
+10 -9
drivers/usb/gadget/function/f_hid.c
··· 1262 1262 if (status) 1263 1263 goto fail; 1264 1264 1265 - spin_lock_init(&hidg->write_spinlock); 1266 1265 hidg->write_pending = 1; 1267 1266 hidg->req = NULL; 1268 - spin_lock_init(&hidg->read_spinlock); 1269 - spin_lock_init(&hidg->get_report_spinlock); 1270 - init_waitqueue_head(&hidg->write_queue); 1271 - init_waitqueue_head(&hidg->read_queue); 1272 - init_waitqueue_head(&hidg->get_queue); 1273 - init_waitqueue_head(&hidg->get_id_queue); 1274 - INIT_LIST_HEAD(&hidg->completed_out_req); 1275 - INIT_LIST_HEAD(&hidg->report_list); 1276 1267 1277 1268 INIT_WORK(&hidg->work, get_report_workqueue_handler); 1278 1269 hidg->workqueue = alloc_workqueue("report_work", ··· 1598 1607 opts = container_of(fi, struct f_hid_opts, func_inst); 1599 1608 1600 1609 mutex_lock(&opts->lock); 1610 + 1611 + spin_lock_init(&hidg->write_spinlock); 1612 + spin_lock_init(&hidg->read_spinlock); 1613 + spin_lock_init(&hidg->get_report_spinlock); 1614 + init_waitqueue_head(&hidg->write_queue); 1615 + init_waitqueue_head(&hidg->read_queue); 1616 + init_waitqueue_head(&hidg->get_queue); 1617 + init_waitqueue_head(&hidg->get_id_queue); 1618 + INIT_LIST_HEAD(&hidg->completed_out_req); 1619 + INIT_LIST_HEAD(&hidg->report_list); 1601 1620 1602 1621 device_initialize(&hidg->dev); 1603 1622 hidg->dev.release = hidg_release;