From: Chen Yufeng chenyufeng@iie.ac.cn
[ Upstream commit 153874010354d050f62f8ae25cbb960c17633dc5 ]
The variable tpgt in usbg_make_tpg() is defined as unsigned long and is assigned to tpgt->tport_tpgt, which is defined as u16. This may cause an integer overflow when tpgt is greater than USHRT_MAX (65535). I haven't tried to trigger it myself, but it is possible to trigger it by calling usbg_make_tpg() with a large value for tpgt.
I modified the type of tpgt to match tpgt->tport_tpgt and adjusted the relevant code accordingly.
This patch is similar to commit 59c816c1f24d ("vhost/scsi: potential memory corruption").
Signed-off-by: Chen Yufeng chenyufeng@iie.ac.cn Link: https://lore.kernel.org/r/20250415065857.1619-1-chenyufeng@iie.ac.cn Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org ---
Based on my comprehensive analysis, here's my decision:
**YES**
This commit should be backported to stable kernel trees for the following reasons:
## Analysis of the Integer Overflow Bug
**1. Clear Security/Correctness Issue:** The bug is a classic integer overflow vulnerability where a user- controlled value (`tpgt`) parsed from a string via `kstrtoul()` as an `unsigned long` gets truncated when assigned to a `u16` field (`tpg->tport_tpgt`).
In the original code at line 1690: ```c unsigned long tpgt; // Can hold values up to ULONG_MAX // ... kstrtoul(name + 5, 0, &tpgt) ... tpg->tport_tpgt = tpgt; // u16 field - truncation occurs! ```
If a user provides a value like `tpgt_70000`, the parsing succeeds (70000 < UINT_MAX), but when assigned to the 16-bit field, it becomes `70000 & 0xFFFF = 4464`, completely changing the intended value.
**2. Matches Stable Backport Criteria:** - **Important Bug Fix**: Yes - prevents integer overflow and data corruption - **Small, Contained Change**: Yes - only changes variable type and validation function - **No Architectural Changes**: Correct - simply fixes data type mismatch - **Minimal Regression Risk**: Very low risk - more restrictive validation - **Confined to Subsystem**: Yes - only affects USB gadget target mode
**3. Historical Precedent:** The fix directly references commit `59c816c1f24d` which was a nearly identical fix in `drivers/vhost/scsi.c` that was backported to stable trees. That commit fixed the exact same pattern: - `unsigned long tpgt` → `u16 tpgt` - `kstrtoul() || tpgt > UINT_MAX` → `kstrtou16()` - Assignment to `u16 tport_tpgt` field
**4. Real Impact:** While this requires privileged access to trigger (configfs manipulation), the integer overflow could lead to: - Unexpected behavior in target portal group handling - Potential confusion in multi-target setups - Data integrity issues in storage target configuration
**5. Code Quality:** The fix properly aligns the variable type with its intended use and makes the validation more precise by using `kstrtou16()` instead of the broader `kstrtoul()` check.
This fix exemplifies the type of integer overflow prevention that stable trees actively accept - targeted, low-risk corrections that prevent subtle but potentially serious bugs from affecting users.
drivers/usb/gadget/function/f_tcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 90fe33f9e0950..48d02c5ff8491 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1320,14 +1320,14 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn, struct usbg_tport *tport = container_of(wwn, struct usbg_tport, tport_wwn); struct usbg_tpg *tpg; - unsigned long tpgt; + u16 tpgt; int ret; struct f_tcm_opts *opts; unsigned i;
if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX) + if (kstrtou16(name + 5, 0, &tpgt)) return ERR_PTR(-EINVAL); ret = -ENODEV; mutex_lock(&tpg_instances_lock);