Re: [PATCH] io_uring/zcrx: don't clear master_ctx from the import path
Pavel Begunkov <[email protected]> Thu, 30 Jul 2026 20:16:07 +0100
| Newsgroups | org.kernel.vger.io-uring,org.kernel.vger.linux-kernel,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On 7/30/26 17:27, Woraphat Khiaodaeng wrote: > import_zcrx() attaches an existing ifq to another ring. It never calls > zcrx_set_ring_ctx() and so never takes the ->master_ctx reference, but > its error path still passes @ctx to zcrx_unregister(), which clears > ->master_ctx and drops its percpu_ref whenever ifq->master_ctx == ctx. > > That condition is reachable. A ring that registers an ifq with a > non-zero event type_mask gets ->master_ctx pointed at itself, and > nothing stops it from exporting that ifq with ZCRX_CTRL_EXPORT and > importing the resulting fd back into the same ring. Failing the import > after the refcount bumps -- an argument page mapped PROT_READ makes the > copy_to_user() in import_zcrx() return -EFAULT -- then clears the > ->master_ctx owned by the original registration, which is still live. > > Refcounts stay balanced and nothing is freed early, so there is no > splat. The ring silently stops receiving ZCRX_EVENT_ALLOC_FAIL and > ZCRX_EVENT_COPY: zcrx_send_notif() returns early on a NULL > ->master_ctx, and ->master_ctx is only ever set on a freshly allocated > ifq, so it cannot be restored without tearing the ring down. Yep, it effectively disables event CQEs. Reviewed-by: Pavel Begunkov <[email protected]> ...> diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c > index 76b9b0d54af9e..fea2b27272ec2 100644 > --- a/io_uring/zcrx.c > +++ b/io_uring/zcrx.c > @@ -808,7 +808,8 @@ static int import_zcrx(struct io_ring_ctx *ctx, > scoped_guard(mutex, &ctx->mmap_lock) > xa_erase(&ctx->zcrx_ctxs, id); > err: > - zcrx_unregister(ifq, ctx); > + /* the import path never took the ->master_ctx ref, don't drop it */ nit: I'd say "... it never set ->master_ctx ..." as it's about having a ctx and not references, but it's not worth of respinning. > + zcrx_unregister(ifq, NULL); > return ret; > } -- Pavel Begunkov