[PATCH RFC] usb: gadget: f_uac1, f_uac2: fix memory leak and invalid free
"syzbot" <[email protected]> Fri, 31 Jul 2026 08:42:04 +0000 (UTC)
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
In the UAC1_RATE_ATTRIBUTE and UAC2_RATE_ATTRIBUTE macros, the store
functions duplicate the input string using kstrdup(). The duplicated string
is then parsed using strsep(), which modifies the pointer to point to the
next token.
When the loop finishes successfully, the pointer becomes NULL, and calling
kfree() on it does nothing, resulting in a memory leak. If an error occurs
during parsing (e.g., kstrtou32() fails), the pointer is advanced to the
middle of the allocated block. Calling kfree() on this modified pointer
leads to an invalid free.
BUG: memory leak
unreferenced object 0xffff8881a08a76c0 (size 64):
comm "syz.0.18", pid 6226, jiffies 4294944138
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 9bbd8bc9):
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_c_srate_store+0xeb/0x1a0
drivers/usb/gadget/function/f_uac2.c:2091
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
To fix this, use a separate pointer to keep track of the original memory
block returned by kstrdup() so it can be correctly passed to kfree().
Additionally, add a check for kstrdup() failure and return -ENOMEM instead
of relying on strsep() to handle the NULL pointer and returning -EINVAL.
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=ebd045a6645cfb713c95
Link: https://syzkaller.appspot.com/ai_job?id=cd9711f3-2259-4827-9de9-96cca016901b
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..05684d9f3 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -1594,6 +1594,7 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
struct f_uac1_opts *opts = to_f_uac1_opts(item); \
+ char *page_alloc = NULL; \
char *split_page = NULL; \
int ret = -EINVAL; \
char *token; \
@@ -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); \
+ page_alloc = kstrdup(page, GFP_KERNEL); \
+ if (!page_alloc) { \
+ ret = -ENOMEM; \
+ goto end; \
+ } \
+ split_page = 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(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..201a38815 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -2012,6 +2012,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
struct f_uac2_opts *opts = to_f_uac2_opts(item); \
+ char *page_alloc = NULL; \
char *split_page = NULL; \
int ret = -EINVAL; \
char *token; \
@@ -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); \
+ page_alloc = kstrdup(page, GFP_KERNEL); \
+ if (!page_alloc) { \
+ ret = -ENOMEM; \
+ goto end; \
+ } \
+ split_page = 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(page_alloc); \
mutex_unlock(&opts->lock); \
return ret; \
} \
base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
--
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].