[PATCH] usb: gadget: f_midi: hold transmit_lock while freeing IN requests

Hyeontae Lee <[email protected]>
Newsgroups org.kernel.vger.linux-usb,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
f_midi_disable() drains in_req_fifo and frees the requests without taking
transmit_lock.  f_midi_transmit() holds that lock across the whole of
f_midi_do_transmit(), which peeks a request off the fifo without removing
it and then keeps using it.  kfifo_peek() does not advance the read index,
so the drain frees exactly the request the transmit path is still using.

No hostile host is needed: __composite_disconnect() calls f->disable() as
well, so a bus reset or a cable pull while a MIDI client is writing is
enough.

  BUG: KASAN: slab-use-after-free in f_midi_in_work+0x126c/0x18c0
  Read of size 4 at addr ffff888104818e20 by task kworker/2:2H/164
  Freed by task 158:
   kfree+0x121/0x380
   f_midi_disable+0x20e/0x430
   reset_config+0x9d/0x200
   __composite_disconnect+0xa7/0x140

Take the lock around the drain, the way hidg_disable() does.

Fixes: e1e3d7ec5da3 ("usb: gadget: f_midi: pre-allocate IN requests")
Cc: [email protected]
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Hyeontae Lee <[email protected]>
---
 drivers/usb/gadget/function/f_midi.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index fba8cf787d6c1..9e67b3c74296f 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -420,6 +420,7 @@ static void f_midi_disable(struct usb_function *f)
 	struct f_midi *midi = func_to_midi(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 	struct usb_request *req = NULL;
+	unsigned long flags;
 
 	DBG(cdev, "disable\n");
 
@@ -431,8 +432,10 @@ static void f_midi_disable(struct usb_function *f)
 	usb_ep_disable(midi->out_ep);
 
 	/* release IN requests */
+	spin_lock_irqsave(&midi->transmit_lock, flags);
 	while (kfifo_get(&midi->in_req_fifo, &req))
 		free_ep_req(midi->in_ep, req);
+	spin_unlock_irqrestore(&midi->transmit_lock, flags);
 
 	f_midi_drop_out_substreams(midi);
 }
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.