From: Alexandre Negrel alexandre@negrel.dev
[ Upstream commit fc5ff2500976cd2710a7acecffd12d95ee4f98fc ]
Allocate the overflowing CQE with GFP_NOWAIT instead of GFP_ATOMIC. This changes causes allocations to fail earlier in out-of-memory situations, rather than being deferred. Using GFP_ATOMIC allows a process to exceed memory limits.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220794 Signed-off-by: Alexandre Negrel alexandre@negrel.dev Link: https://lore.kernel.org/io-uring/20251229201933.515797-1-alexandre@negrel.de... Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## Analysis of io_uring GFP_NOWAIT Commit
### 1. COMMIT MESSAGE ANALYSIS
The commit message is clear and well-structured: - **Problem**: Using `GFP_ATOMIC` for overflow CQE allocations allows processes to exceed memory limits - **Solution**: Change to `GFP_NOWAIT` which fails earlier in OOM situations - **Bug Reference**: Links to kernel bugzilla (bug 220794) - indicates a real user-reported issue - **Proper sign-offs**: Author and maintainer (Jens Axboe) signatures present
The key insight is that `GFP_ATOMIC` can dip into emergency memory reserves, allowing allocations to succeed even when a process should be constrained by memory limits. This is a resource exhaustion / memory limit bypass issue.
### 2. CODE CHANGE ANALYSIS
The change is minimal - a single line: ```c - ocqe = io_alloc_ocqe(ctx, cqe, big_cqe, GFP_ATOMIC); + ocqe = io_alloc_ocqe(ctx, cqe, big_cqe, GFP_NOWAIT); ```
**Technical mechanism of the bug:** - `io_cqe_overflow_locked()` is called when the completion queue is full and entries must overflow - This function runs with `completion_lock` held, so it cannot sleep (ruling out `GFP_KERNEL`) - `GFP_ATOMIC` can access emergency memory reserves, bypassing memory limits - `GFP_NOWAIT` is also non-sleeping but respects memory limits by failing instead of dipping into reserves
**Why the fix works:** - Both flags are appropriate for the atomic context (holding spinlock) - `GFP_NOWAIT` is semantically correct: the allocation should fail gracefully under memory pressure rather than bypass system memory constraints
### 3. CLASSIFICATION
- **Bug fix**: Yes - fixes memory limit bypass - **Feature**: No - no new functionality added - **Security-relevant**: Yes - this could be exploited for resource exhaustion/DoS, particularly in containerized or multi-tenant environments with memory cgroups
### 4. SCOPE AND RISK ASSESSMENT
- **Lines changed**: 1 - **Files touched**: 1 (io_uring/io_uring.c) - **Complexity**: Trivial - **Function context**: `__cold` path - not in hot path, used only during overflow conditions
**Risk analysis:** - Allocation may fail more readily under memory pressure - but that's the *intended* behavior - If overflow allocation fails, the CQE won't be recorded - applications relying on completion notifications might be affected, but this is correct behavior when memory is exhausted - Very low risk of regression since this is the semantically correct change
### 5. USER IMPACT
- **Who is affected**: Users running io_uring workloads (databases, high-performance I/O applications) - **Severity of bug**: Medium-High - allows memory limit bypass which is particularly problematic in: - Container environments (Docker, Kubernetes) - Systems with memory cgroups - Multi-tenant systems - **Reported by users**: Yes - bugzilla link indicates real-world issue
### 6. STABILITY INDICATORS
- Accepted by Jens Axboe (io_uring maintainer) - Has proper Link: to mailing list discussion - Referenced bug report demonstrates real user impact - Simple, well-understood change
### 7. DEPENDENCY CHECK
- No dependencies on other commits - `io_alloc_ocqe()` and `io_cqe_overflow_locked()` exist in stable kernels - io_uring has been present since kernel 5.1
### CONCLUSION
**Meets stable criteria:** - ✅ Obviously correct - semantically appropriate GFP flag - ✅ Fixes a real bug - memory limit bypass (resource exhaustion) - ✅ Small and contained - single line change - ✅ No new features or APIs - ✅ Tested in mainline - ✅ Referenced bug report shows real user impact
**Risk vs Benefit:** - Risk: Minimal - well-understood change to allocation flags - Benefit: Fixes a memory limit bypass that could be used for DoS
This is an ideal stable backport candidate: a tiny, surgical fix addressing a real security-relevant bug (memory limit bypass) with minimal risk of regression.
**YES**
io_uring/io_uring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 60adab71ad2d..93b203205a16 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -897,7 +897,7 @@ static __cold bool io_cqe_overflow_locked(struct io_ring_ctx *ctx, { struct io_overflow_cqe *ocqe;
- ocqe = io_alloc_ocqe(ctx, cqe, big_cqe, GFP_ATOMIC); + ocqe = io_alloc_ocqe(ctx, cqe, big_cqe, GFP_NOWAIT); return io_cqring_add_overflow(ctx, ocqe); }