Linux USB
 help / color / mirror / Atom feed
* [PATCH] usb: gadget: midi2: copy configfs strings for live functions
@ 2026-11-06 15:59 Yingjie Wang
  2026-11-06 16:09 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Yingjie Wang @ 2026-11-06 15:59 UTC (permalink / raw)
  To: linux-usb@vger.kernel.org
  Cc: Neill Kapron, Greg Kroah-Hartman, Takashi Iwai,
	linux-kernel@vger.kernel.org

f_midi2_alloc() shallow-copies the card, endpoint, and block string
pointers from configfs.  Dynamic ep.* and block.* groups may be removed
after the function has been allocated.  Their release callbacks then free
strings still used by live USB string descriptors and UMP discovery
replies.

Copy the optional strings while opts->lock is held, so configfs release
cannot free the source strings during the copy.  Free the private copies
with the live function and build the USB string table from those copies.

Fixes: 29ee7a4dddd5 ("usb: gadget: midi2: Add configfs support")

Tested:
  x86_64 KASAN dummy_hcd: the base kernel reports two slab-use-after-free
  errors after removing a dynamic block and endpoint; the fixed kernel
  completes the same descriptor requests without a KASAN report.
  x86_64 and arm64 MIDI2 function object builds with W=1.
Signed-off-by: Yingjie Wang <x-professor@outlook.com>
---
 drivers/usb/gadget/function/f_midi2.c | 57 +++++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c
index d693de427641..c02d6f11be14 100644
--- a/drivers/usb/gadget/function/f_midi2.c
+++ b/drivers/usb/gadget/function/f_midi2.c
@@ -171,6 +171,31 @@ static const char *ump_fb_name(const struct f_midi2_block_info *info)
 	return info->name ? info->name : "MIDI 2.0 Gadget I/O";
 }
 
+static int f_midi2_copy_string(const char **dst, const char *src)
+{
+	*dst = NULL;
+	if (!src)
+		return 0;
+
+	*dst = kstrdup(src, GFP_KERNEL);
+	return *dst ? 0 : -ENOMEM;
+}
+
+static void f_midi2_free_strings(struct f_midi2 *midi2)
+{
+	int i, blk;
+
+	kfree(midi2->info.iface_name);
+	for (i = 0; i < midi2->num_eps; i++) {
+		struct f_midi2_ep *ep = &midi2->midi2_eps[i];
+
+		kfree(ep->info.ep_name);
+		kfree(ep->info.product_id);
+		for (blk = 0; blk < ep->num_blks; blk++)
+			kfree(ep->blks[blk].info.name);
+	}
+}
+
 /*
  * USB Descriptor Definitions
  */
@@ -2701,6 +2726,7 @@ static void do_f_midi2_free(struct f_midi2 *midi2, struct f_midi2_opts *opts)
 	--opts->refcnt;
 	mutex_unlock(&opts->lock);
 	kfree(midi2->string_defs);
+	f_midi2_free_strings(midi2);
 	kfree(midi2);
 }
 
@@ -2811,7 +2837,7 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
 	struct f_midi2_opts *opts;
 	struct f_midi2_ep *ep;
 	struct f_midi2_block *bp;
-	int i, num_eps, blk;
+	int i, num_eps, blk, ret;
 
 	midi2 = kzalloc_obj(*midi2);
 	if (!midi2)
@@ -2826,7 +2852,6 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
 		return ERR_PTR(num_eps);
 	}
 	++opts->refcnt;
-	mutex_unlock(&opts->lock);
 
 	spin_lock_init(&midi2->queue_lock);
 
@@ -2841,19 +2866,38 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
 
 	midi2->info = opts->info;
 	midi2->num_eps = num_eps;
+	ret = f_midi2_copy_string(&midi2->info.iface_name,
+				  opts->info.iface_name);
+	if (ret)
+		goto err_unlock;
 
 	for (i = 0; i < num_eps; i++) {
 		ep = &midi2->midi2_eps[i];
 		ep->info = opts->eps[i]->info;
+		ep->info.ep_name = NULL;
+		ep->info.product_id = NULL;
+		ret = f_midi2_copy_string(&ep->info.ep_name,
+					  opts->eps[i]->info.ep_name);
+		if (ret)
+			goto err_unlock;
+		ret = f_midi2_copy_string(&ep->info.product_id,
+					  opts->eps[i]->info.product_id);
+		if (ret)
+			goto err_unlock;
 		ep->card = midi2;
 		for (blk = 0; blk < SNDRV_UMP_MAX_BLOCKS &&
 			     opts->eps[i]->blks[blk]; blk++) {
 			bp = &ep->blks[blk];
 			ep->num_blks++;
 			bp->info = opts->eps[i]->blks[blk]->info;
+			ret = f_midi2_copy_string(&bp->info.name,
+						  opts->eps[i]->blks[blk]->info.name);
+			if (ret)
+				goto err_unlock;
 			bp->gtb_id = ++midi2->total_blocks;
 		}
 	}
+	mutex_unlock(&opts->lock);
 
 	midi2->string_defs = kzalloc_objs(*midi2->string_defs,
 					  midi2->total_blocks + 1);
@@ -2862,8 +2906,8 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	if (opts->info.iface_name && *opts->info.iface_name)
-		midi2->string_defs[STR_IFACE].s = opts->info.iface_name;
+	if (midi2->info.iface_name && *midi2->info.iface_name)
+		midi2->string_defs[STR_IFACE].s = midi2->info.iface_name;
 	else
 		midi2->string_defs[STR_IFACE].s = ump_ep_name(&midi2->midi2_eps[0]);
 
@@ -2885,6 +2929,11 @@ static struct usb_function *f_midi2_alloc(struct usb_function_instance *fi)
 	}
 
 	return &midi2->func;
+
+err_unlock:
+	mutex_unlock(&opts->lock);
+	do_f_midi2_free(midi2, opts);
+	return ERR_PTR(ret);
 }
 
 DECLARE_USB_FUNCTION_INIT(midi2, f_midi2_alloc_inst, f_midi2_alloc);

base-commit: 3149e8b3237f58d4dd440fc64c45c93404c4b064
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-06 16:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-06 15:59 [PATCH] usb: gadget: midi2: copy configfs strings for live functions Yingjie Wang
2026-11-06 16:09 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox