Skip to content

Commit a634dda

Browse files
committed
Merge tag 'io_uring-6.13-20250116' of git://git.kernel.dk/linux
Pull io_uring fixes from Jens Axboe: "One fix for the error handling in buffer cloning, and one fix for the ring resizing. Two minor followups for the latter as well. Both of these issues only affect 6.13, so not marked for stable" * tag 'io_uring-6.13-20250116' of git://git.kernel.dk/linux: io_uring/register: cache old SQ/CQ head reading for copies io_uring/register: document io_register_resize_rings() shared mem usage io_uring/register: use stable SQ/CQ ring data during resize io_uring/rsrc: fixup io_clone_buffers() error handling
2 parents f692a6c + 6f7a644 commit a634dda

File tree

2 files changed

+32
-30
lines changed

2 files changed

+32
-30
lines changed

io_uring/register.c

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,8 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
405405
{
406406
struct io_ring_ctx_rings o = { }, n = { }, *to_free = NULL;
407407
size_t size, sq_array_offset;
408+
unsigned i, tail, old_head;
408409
struct io_uring_params p;
409-
unsigned i, tail;
410410
void *ptr;
411411
int ret;
412412

@@ -449,10 +449,18 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
449449
if (IS_ERR(n.rings))
450450
return PTR_ERR(n.rings);
451451

452-
n.rings->sq_ring_mask = p.sq_entries - 1;
453-
n.rings->cq_ring_mask = p.cq_entries - 1;
454-
n.rings->sq_ring_entries = p.sq_entries;
455-
n.rings->cq_ring_entries = p.cq_entries;
452+
/*
453+
* At this point n.rings is shared with userspace, just like o.rings
454+
* is as well. While we don't expect userspace to modify it while
455+
* a resize is in progress, and it's most likely that userspace will
456+
* shoot itself in the foot if it does, we can't always assume good
457+
* intent... Use read/write once helpers from here on to indicate the
458+
* shared nature of it.
459+
*/
460+
WRITE_ONCE(n.rings->sq_ring_mask, p.sq_entries - 1);
461+
WRITE_ONCE(n.rings->cq_ring_mask, p.cq_entries - 1);
462+
WRITE_ONCE(n.rings->sq_ring_entries, p.sq_entries);
463+
WRITE_ONCE(n.rings->cq_ring_entries, p.cq_entries);
456464

457465
if (copy_to_user(arg, &p, sizeof(p))) {
458466
io_register_free_rings(&p, &n);
@@ -509,20 +517,22 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
509517
* rings can't hold what is already there, then fail the operation.
510518
*/
511519
n.sq_sqes = ptr;
512-
tail = o.rings->sq.tail;
513-
if (tail - o.rings->sq.head > p.sq_entries)
520+
tail = READ_ONCE(o.rings->sq.tail);
521+
old_head = READ_ONCE(o.rings->sq.head);
522+
if (tail - old_head > p.sq_entries)
514523
goto overflow;
515-
for (i = o.rings->sq.head; i < tail; i++) {
524+
for (i = old_head; i < tail; i++) {
516525
unsigned src_head = i & (ctx->sq_entries - 1);
517-
unsigned dst_head = i & n.rings->sq_ring_mask;
526+
unsigned dst_head = i & (p.sq_entries - 1);
518527

519528
n.sq_sqes[dst_head] = o.sq_sqes[src_head];
520529
}
521-
n.rings->sq.head = o.rings->sq.head;
522-
n.rings->sq.tail = o.rings->sq.tail;
530+
WRITE_ONCE(n.rings->sq.head, READ_ONCE(o.rings->sq.head));
531+
WRITE_ONCE(n.rings->sq.tail, READ_ONCE(o.rings->sq.tail));
523532

524-
tail = o.rings->cq.tail;
525-
if (tail - o.rings->cq.head > p.cq_entries) {
533+
tail = READ_ONCE(o.rings->cq.tail);
534+
old_head = READ_ONCE(o.rings->cq.head);
535+
if (tail - old_head > p.cq_entries) {
526536
overflow:
527537
/* restore old rings, and return -EOVERFLOW via cleanup path */
528538
ctx->rings = o.rings;
@@ -531,21 +541,21 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
531541
ret = -EOVERFLOW;
532542
goto out;
533543
}
534-
for (i = o.rings->cq.head; i < tail; i++) {
544+
for (i = old_head; i < tail; i++) {
535545
unsigned src_head = i & (ctx->cq_entries - 1);
536-
unsigned dst_head = i & n.rings->cq_ring_mask;
546+
unsigned dst_head = i & (p.cq_entries - 1);
537547

538548
n.rings->cqes[dst_head] = o.rings->cqes[src_head];
539549
}
540-
n.rings->cq.head = o.rings->cq.head;
541-
n.rings->cq.tail = o.rings->cq.tail;
550+
WRITE_ONCE(n.rings->cq.head, READ_ONCE(o.rings->cq.head));
551+
WRITE_ONCE(n.rings->cq.tail, READ_ONCE(o.rings->cq.tail));
542552
/* invalidate cached cqe refill */
543553
ctx->cqe_cached = ctx->cqe_sentinel = NULL;
544554

545-
n.rings->sq_dropped = o.rings->sq_dropped;
546-
n.rings->sq_flags = o.rings->sq_flags;
547-
n.rings->cq_flags = o.rings->cq_flags;
548-
n.rings->cq_overflow = o.rings->cq_overflow;
555+
WRITE_ONCE(n.rings->sq_dropped, READ_ONCE(o.rings->sq_dropped));
556+
WRITE_ONCE(n.rings->sq_flags, READ_ONCE(o.rings->sq_flags));
557+
WRITE_ONCE(n.rings->cq_flags, READ_ONCE(o.rings->cq_flags));
558+
WRITE_ONCE(n.rings->cq_overflow, READ_ONCE(o.rings->cq_overflow));
549559

550560
/* all done, store old pointers and assign new ones */
551561
if (!(ctx->flags & IORING_SETUP_NO_SQARRAY))

io_uring/rsrc.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
997997
dst_node = io_rsrc_node_alloc(ctx, IORING_RSRC_BUFFER);
998998
if (!dst_node) {
999999
ret = -ENOMEM;
1000-
goto out_put_free;
1000+
goto out_unlock;
10011001
}
10021002

10031003
refcount_inc(&src_node->buf->refs);
@@ -1033,14 +1033,6 @@ static int io_clone_buffers(struct io_ring_ctx *ctx, struct io_ring_ctx *src_ctx
10331033
mutex_lock(&src_ctx->uring_lock);
10341034
/* someone raced setting up buffers, dump ours */
10351035
ret = -EBUSY;
1036-
out_put_free:
1037-
i = data.nr;
1038-
while (i--) {
1039-
if (data.nodes[i]) {
1040-
io_buffer_unmap(src_ctx, data.nodes[i]);
1041-
kfree(data.nodes[i]);
1042-
}
1043-
}
10441036
out_unlock:
10451037
io_rsrc_data_free(ctx, &data);
10461038
mutex_unlock(&src_ctx->uring_lock);

0 commit comments

Comments
 (0)