[PATCH RFC] usb: gadget: f_uac1, f_uac2: fix memory leak in rate attribute store

"syzbot" <[email protected]> Mon, 3 Aug 2026 12:01:41 +0000 (UTC)
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
A memory leak occurs in the `f_uac1_opts_##name##_store` and
`f_uac2_opts_##name##_store` functions, which are generated by the
`UAC1_RATE_ATTRIBUTE` and `UAC2_RATE_ATTRIBUTE` macros.

When setting the sampling rates via configfs (e.g., writing to `p_srate` or
`c_srate`), the input string is duplicated using `kstrdup()`. The
duplicated string is then parsed using `strsep()`, which modifies the
pointer to point to the next token. By the time the loop finishes, the
pointer is updated to `NULL` (or points to the middle of the string if an
error occurred). Consequently, `kfree()` is called with an invalid pointer,
and the original memory block allocated by `kstrdup()` is never freed,
causing a memory leak.

Fix this by preserving the original pointer returned by `kstrdup()` in a
separate variable `split_page_alloc` so that it can be correctly passed to
`kfree()`. Additionally, add a check to return `-ENOMEM` if `kstrdup()`
fails to allocate memory.

Kmemleak reports the following:

BUG: memory leak
unreferenced object 0xffff88818b6ecf00 (size 64):
  comm "syz.0.17", pid 6220, jiffies 4294944006
  hex dump (first 32 bytes):
    34 34 31 30 30 00 34 38 30 30 30 00 38 38 32 30  44100.48000.8820
    30 00 39 36 30 30 30 00 31 37 36 34 30 30 00 31  0.96000.176400.1
  backtrace (crc 6cdecf20):
    kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline]
    slab_post_alloc_hook mm/slub.c:4597 [inline]
    slab_alloc_node mm/slub.c:4917 [inline]
    __do_kmalloc_node mm/slub.c:5333 [inline]
    __kmalloc_node_track_caller_noprof+0x309/0x4e0 mm/slub.c:5471
    __kmemdup_nul mm/util.c:64 [inline]
    kstrdup+0x3e/0xc0 mm/util.c:84
    f_uac2_opts_p_srate_store+0xeb/0x1a0
    drivers/usb/gadget/function/f_uac2.c:2087
    flush_write_buffer fs/configfs/file.c:207 [inline]
    configfs_write_iter+0x115/0x170 fs/configfs/file.c:229
    new_sync_write fs/read_write.c:595 [inline]
    vfs_write+0x3a0/0x640 fs/read_write.c:687

Fixes: a7339e4f5788 ("usb: gadget: f_uac2: Support multiple sampling rates")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=87c10526d2cfa8d14ff6
Link: https://syzkaller.appspot.com/ai_job?id=4939b73c-7f4a-4a7b-8e48-7889ee6fc965
To: "Greg Kroah-Hartman" <[email protected]>
To: <[email protected]>
To: "Julian Scheel" <[email protected]>
Cc: "Christophe JAILLET" <[email protected]>
Cc: "Kees Cook" <[email protected]>
Cc: <[email protected]>

---
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 85c502e98..ba1a9f51c 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -1595,6 +1595,7 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item,	\
 {									\
 	struct f_uac1_opts *opts = to_f_uac1_opts(item);		\
 	char *split_page = NULL;					\
+	char *split_page_alloc = NULL;					\
 	int ret = -EINVAL;						\
 	char *token;							\
 	u32 num;							\
@@ -1608,7 +1609,12 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item,	\
 									\
 	i = 0;								\
 	memset(opts->name##s, 0x00, sizeof(opts->name##s));		\
-	split_page = kstrdup(page, GFP_KERNEL);				\
+	split_page_alloc = kstrdup(page, GFP_KERNEL);			\
+	if (!split_page_alloc) {					\
+		ret = -ENOMEM;						\
+		goto end;						\
+	}								\
+	split_page = split_page_alloc;					\
 	while ((token = strsep(&split_page, ",")) != NULL) {		\
 		ret = kstrtou32(token, 0, &num);			\
 		if (ret)						\
@@ -1619,7 +1625,7 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item,	\
 	};								\
 									\
 end:									\
-	kfree(split_page);						\
+	kfree(split_page_alloc);					\
 	mutex_unlock(&opts->lock);					\
 	return ret;							\
 }									\
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 897787d08..c92caa149 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -2013,6 +2013,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item,	\
 {									\
 	struct f_uac2_opts *opts = to_f_uac2_opts(item);		\
 	char *split_page = NULL;					\
+	char *split_page_alloc = NULL;					\
 	int ret = -EINVAL;						\
 	char *token;							\
 	u32 num;							\
@@ -2026,7 +2027,12 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item,	\
 									\
 	i = 0;								\
 	memset(opts->name##s, 0x00, sizeof(opts->name##s));		\
-	split_page = kstrdup(page, GFP_KERNEL);				\
+	split_page_alloc = kstrdup(page, GFP_KERNEL);			\
+	if (!split_page_alloc) {					\
+		ret = -ENOMEM;						\
+		goto end;						\
+	}								\
+	split_page = split_page_alloc;					\
 	while ((token = strsep(&split_page, ",")) != NULL) {		\
 		ret = kstrtou32(token, 0, &num);			\
 		if (ret)						\
@@ -2037,7 +2043,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item,	\
 	};								\
 									\
 end:									\
-	kfree(split_page);						\
+	kfree(split_page_alloc);					\
 	mutex_unlock(&opts->lock);					\
 	return ret;							\
 }									\


base-commit: 075b74841bd0065a3bda3440873c747938e69b68
-- 
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).

See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at [email protected].