From: Pavel Begunkov asml.silence@gmail.com
[ Upstream commit 437c23357d897f5b5b7d297c477da44b56654d46 ]
There might be many reasons why a user is resizing a ring, e.g. moving to huge pages or for some memory compaction using IORING_SETUP_NO_MMAP. Don't bypass resizing, the user will definitely be surprised seeing 0 while the rings weren't actually moved to a new place.
Signed-off-by: Pavel Begunkov asml.silence@gmail.com Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## BACKPORT RECOMMENDATION: **YES**
### DETAILED ANALYSIS
#### 1. Semantic Code Analysis Performed
**Tools Used:** - `mcp__semcode__find_function`: Located `io_register_resize_rings` function definition in `io_uring/register.c:401-585` - `mcp__semcode__find_callers`: Identified that the function is called by `__io_uring_register` - Git analysis: Traced the syscall path from user-space → `sys_io_uring_register` → `__io_uring_register` → `io_register_resize_rings` - Historical analysis: Determined the resize feature was introduced in kernel v6.13 (October 2024)
**Call Graph Analysis:** ``` user-space (io_uring_register syscall with IORING_REGISTER_RESIZE_RINGS opcode) └→ sys_io_uring_register (SYSCALL_DEFINE4) └→ __io_uring_register └→ io_register_resize_rings [BUG HERE] ```
#### 2. Nature of the Bug
**What Changed:** The commit removes 7 lines of code (io_uring/register.c:421-427) that implemented an optimization: ```c /* nothing to do, but copy params back */ if (p.sq_entries == ctx->sq_entries && p.cq_entries == ctx->cq_entries) { if (copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; // Returns success WITHOUT actually resizing } ```
**Why It's a Bug:** This optimization incorrectly assumes that if the ring size parameters match, there's nothing to do. However, users have legitimate reasons to resize with the same dimensions:
1. **Memory relocation to huge pages**: Using `IORING_SETUP_NO_MMAP` flag to move rings to huge page-backed memory for better TLB performance 2. **Memory compaction**: Consolidating memory allocations 3. **Memory region changes**: Moving rings to different physical memory locations
The kernel returns success (0) but silently doesn't perform the requested operation, breaking the user-space API contract.
#### 3. Impact Assessment
**Severity: Medium**
**Who is affected:** - Applications using `IORING_REGISTER_RESIZE_RINGS` (added in v6.13) - Specific scenario: Resizing to same dimensions for memory management purposes - Use cases: Performance-critical applications optimizing memory layout via huge pages
**User-space exposure:** - **Directly exposed via syscall**: Yes, through `io_uring_register(fd, IORING_REGISTER_RESIZE_RINGS, ...)` - **Exploitability**: Not a security issue, but causes silent functional failure - **Data corruption risk**: None, but causes application logic bugs when applications expect memory to be reallocated
#### 4. Backport Suitability Analysis
**Positive Indicators:** 1. ✅ **Bug fix, not a feature**: Removes broken optimization 2. ✅ **Small, contained change**: Only 7 lines removed, no new code added 3. ✅ **No architectural changes**: Doesn't modify data structures or APIs 4. ✅ **Low regression risk**: Removes code rather than adding complex logic 5. ✅ **Clear functional issue**: Kernel claims success but doesn't perform requested operation 6. ✅ **Affects real use cases**: Huge page optimization is documented in commit message as legitimate use case
**Context:** - Feature introduced: v6.13 (October 2024) - Bug exists: v6.13 through v6.17 - Fix landed: v6.18-rc2 - No explicit `Fixes:` or `Cc: stable` tags in the commit (oversight by author)
**Stable Tree Compliance:** - Bug fixes: ✅ YES - New features: ✅ NO - Security fixes: ✅ NO (but functional correctness issue) - Performance optimizations: ⚠️ Removes a broken optimization - Architectural changes: ✅ NO
#### 5. Dependencies and Prerequisites
The fix requires: - `IORING_REGISTER_RESIZE_RINGS` support (present in v6.13+) - No other dependencies identified
**Version compatibility:** This should be backported to stable kernels v6.13+
#### 6. Risk Assessment
**Regression risk: VERY LOW**
The change **removes** code rather than adding it: - The removed code was an optimization that caused incorrect behavior - Removing it makes the function always perform the full resize operation - All existing code paths after the removed check remain unchanged - The function already handles the case where source and destination sizes match (it copies entries correctly)
**Testing considerations:** - Test case: Call `IORING_REGISTER_RESIZE_RINGS` with same size + `IORING_SETUP_NO_MMAP` flag - Expected: Memory should be reallocated to new location - Current broken behavior: Returns 0 but doesn't reallocate
### CONCLUSION
**BACKPORT: YES to stable v6.13+ kernels**
This is a clear functional bug in a newly added feature. While it lacks explicit stable tree tags, it meets all criteria for backporting: - Fixes incorrect behavior exposed to user-space - Small, contained, low-risk change - Affects legitimate use cases (huge page optimization) - No dependencies or architectural complexity - Removes broken code rather than adding risky new logic
The absence of `Fixes:` or `Cc: stable` tags appears to be an oversight, not an indication that backporting is inappropriate. The commit message explicitly describes the bug and its user-space impact, making this a suitable candidate for stable tree inclusion.
io_uring/register.c | 7 ------- 1 file changed, 7 deletions(-)
diff --git a/io_uring/register.c b/io_uring/register.c index b1772a470bf6e..dacbe8596b5c2 100644 --- a/io_uring/register.c +++ b/io_uring/register.c @@ -426,13 +426,6 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg) if (unlikely(ret)) return ret;
- /* nothing to do, but copy params back */ - if (p.sq_entries == ctx->sq_entries && p.cq_entries == ctx->cq_entries) { - if (copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - return 0; - } - size = rings_size(p.flags, p.sq_entries, p.cq_entries, &sq_array_offset); if (size == SIZE_MAX)