[PATCH] usb: gadget: uac1/uac2: reject more than UAC_MAX_RATES sample rates
From: Haofeng Li
Date: Wed Aug 26 2026 - 09:43:43 EST
The UAC1_RATE_ATTRIBUTE / UAC2_RATE_ATTRIBUTE configfs store loops parse
a comma-separated sample-rate list with
while ((token = strsep(&split_page, ",")) != NULL) {
...
opts->name##s[i++] = num;
}
without checking the running index against UAC_MAX_RATES (10). The
storing arrays (c_srates / p_srates in struct f_uac1_opts /
struct f_uac2_opts) have exactly UAC_MAX_RATES entries, so an 11th
token already writes past the array, and feeding more tokens (the
configfs write limit is 4096 bytes, i.e. up to ~2000 rates) walks past
the whole opts object into the surrounding kernel heap.
Attack chain (no USB host/device involved; the caller only needs
configfs write access to the gadget function, e.g. for the kernel to
issue the echo):
echo 1,1,1,1,1,1,1,1,1,1,2,... > .../functions/uac1.NAME/c_srate
-> f_uac1_opts_c_srate_store()
-> opts->c_srates[i++] = num for i = 10, 11, ... (unbounded)
-> out-of-bounds heap write (index into a 10-element int array)
Reproduced on kernel 7.2.0+ (KASAN + UBSAN + slub_debug=Z). An
1801-token write to uac1/c_srate yields
BUG: KASAN: slab-out-of-bounds in f_uac1_opts_c_srate_store
Write of size 4 ... f_uac1_opts_c_srate_store -> configfs_write_iter
and the exact array boundary is caught for the three remaining
attributes with 11 tokens:
UBSAN: array-index-out-of-bounds ... index 10 is out of range for
type 'int [10]'
in f_uac1_opts_p_srate_store / f_uac2_opts_c_srate_store /
f_uac2_opts_p_srate_store
plus: the 1800+ token variant plows through several slab objects, and
the kfree() of the duplicated token buffer afterwards enters a
pathological spin under slub_debug=Z, demonstrating live corruption of
the downstream heap.
Signed-off-by: Haofeng Li <lihaofeng@xxxxxxxxxx>
Assisted-by: opencode:deepseek-v4-flash-free
---
drivers/usb/gadget/function/f_uac1.c | 4 ++++
drivers/usb/gadget/function/f_uac2.c | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 85c502e98f57..de34891163ef 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -1614,6 +1614,10 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
if (ret) \
goto end; \
\
+ if (i >= UAC_MAX_RATES) { \
+ ret = -E2BIG; \
+ goto end; \
+ } \
opts->name##s[i++] = num; \
ret = len; \
}; \
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 897787d0803c..02fb27daf04a 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -2032,6 +2032,10 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
if (ret) \
goto end; \
\
+ if (i >= UAC_MAX_RATES) { \
+ ret = -E2BIG; \
+ goto end; \
+ } \
opts->name##s[i++] = num; \
ret = len; \
}; \
--
2.25.1