@@ -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 ) {
526536overflow :
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 ))
0 commit comments