Pull io_uring fixes from Jens Axboe: - Small series sanitizing the locking done for either modifying or reading a chain of requests - If the application has a pid namespace, ensure that the sqthread pid is correctly printed in fdinfo - Fix for a hashing issue in the io-wq thread pool, which could lead to a use-after-free - Kill dead argument from io_prep_rw_pi() - Fix for a missed validation of the CQ ring head, affecting CQE refill * tag 'io_uring-7.1-20260515' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: io_uring: validate user-controlled cq.head in io_cqe_cache_refill() io-wq: check that the predecessor is hashed in io_wq_remove_pending() io_uring/rw: drop unused attr_type_mask from io_prep_rw_pi() io_uring: hold uring_lock across io_kill_timeouts() in cancel path io_uring: defer linked-timeout chain splice out of hrtimer context io_uring: hold uring_lock when walking link chain in io_wq_free_work() io_uring/fdinfo: translate SqThread PID through caller's pid_ns
Unified · Split
| @@ -561,8 +561,8 @@ __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx, · 560 unmodified lines | |||
| 561 | ret |= io_waitid_remove_all(ctx, tctx, cancel_all); | 561 | ret |= io_waitid_remove_all(ctx, tctx, cancel_all); |
| 562 | ret |= io_futex_remove_all(ctx, tctx, cancel_all); | 562 | ret |= io_futex_remove_all(ctx, tctx, cancel_all); |
| 563 | ret |= io_uring_try_cancel_uring_cmd(ctx, tctx, cancel_all); | 563 | ret |= io_uring_try_cancel_uring_cmd(ctx, tctx, cancel_all); |
| 564 | mutex_unlock(&ctx->uring_lock); | ||
| 565 | ret |= io_kill_timeouts(ctx, tctx, cancel_all); | 564 | ret |= io_kill_timeouts(ctx, tctx, cancel_all); |
| 565 | mutex_unlock(&ctx->uring_lock); | ||
| 566 | if (tctx) | 566 | if (tctx) |
| 567 | ret |= io_run_task_work() > 0; | 567 | ret |= io_run_task_work() > 0; |
| 568 | else | 568 | else |
| @@ -190,8 +190,9 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) · 189 unmodified lines | |||
| 190 | get_task_struct(tsk); | 190 | get_task_struct(tsk); |
| 191 | rcu_read_unlock(); | 191 | rcu_read_unlock(); |
| 192 | usec = io_sq_cpu_usec(tsk); | 192 | usec = io_sq_cpu_usec(tsk); |
| 193 | sq_pid = task_pid_nr_ns(tsk, | ||
| 194 | proc_pid_ns(file_inode(m->file)->i_sb)); | ||
| 193 | put_task_struct(tsk); | 195 | put_task_struct(tsk); |
| 194 | sq_pid = sq->task_pid; | ||
| 195 | sq_cpu = sq->sq_cpu; | 196 | sq_cpu = sq->sq_cpu; |
| 196 | sq_total_time = usec; | 197 | sq_total_time = usec; |
| 197 | sq_work_time = sq->work_time; | 198 | sq_work_time = sq->work_time; |
| @@ -1124,7 +1124,8 @@ static inline void io_wq_remove_pending(struct io_wq *wq, · 1123 unmodified lines | |||
| 1124 | if (io_wq_is_hashed(work) && work == wq->hash_tail[hash]) { | 1124 | if (io_wq_is_hashed(work) && work == wq->hash_tail[hash]) { |
| 1125 | if (prev) | 1125 | if (prev) |
| 1126 | prev_work = container_of(prev, struct io_wq_work, list); | 1126 | prev_work = container_of(prev, struct io_wq_work, list); |
| 1127 | if (prev_work && io_get_work_hash(prev_work) == hash) | 1127 | if (prev_work && io_wq_is_hashed(prev_work) && |
| 1128 | io_get_work_hash(prev_work) == hash) | ||
| 1128 | wq->hash_tail[hash] = prev_work; | 1129 | wq->hash_tail[hash] = prev_work; |
| 1129 | else | 1130 | else |
| 1130 | wq->hash_tail[hash] = NULL; | 1131 | wq->hash_tail[hash] = NULL; |
| @@ -686,13 +686,27 @@ static struct io_overflow_cqe *io_alloc_ocqe(struct io_ring_ctx *ctx, · 685 unmodified lines | |||
| 686 | return ocqe; | 686 | return ocqe; |
| 687 | } | 687 | } |
| 688 | 688 | ||
| 689 | /* | ||
| 690 | * Compute queued CQEs for free-space calculation, clamped to cq_entries. | ||
| 691 | */ | ||
| 692 | static unsigned int io_cqring_queued(struct io_ring_ctx *ctx) | ||
| 693 | { | ||
| 694 | struct io_rings *rings = io_get_rings(ctx); | ||
| 695 | int diff; | ||
| 696 | |||
| 697 | diff = (int)(ctx->cached_cq_tail - READ_ONCE(rings->cq.head)); | ||
| 698 | if (diff >= 0) | ||
| 699 | return min((unsigned int)diff, ctx->cq_entries); | ||
| 700 | return 0; | ||
| 701 | } | ||
| 702 | |||
| 689 | /* | 703 | /* |
| 690 | * Fill an empty dummy CQE, in case alignment is off for posting a 32b CQE | 704 | * Fill an empty dummy CQE, in case alignment is off for posting a 32b CQE |
| 691 | * because the ring is a single 16b entry away from wrapping. | 705 | * because the ring is a single 16b entry away from wrapping. |
| 692 | */ | 706 | */ |
| 693 | static bool io_fill_nop_cqe(struct io_ring_ctx *ctx, unsigned int off) | 707 | static bool io_fill_nop_cqe(struct io_ring_ctx *ctx, unsigned int off) |
| 694 | { | 708 | { |
| 695 | if (__io_cqring_events(ctx) < ctx->cq_entries) { | 709 | if (io_cqring_queued(ctx) < ctx->cq_entries) { |
| 696 | struct io_uring_cqe *cqe = &ctx->rings->cqes[off]; | 710 | struct io_uring_cqe *cqe = &ctx->rings->cqes[off]; |
| 697 | 711 | ||
| 698 | cqe->user_data = 0; | 712 | cqe->user_data = 0; |
| @@ -713,7 +727,7 @@ bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32) · 14 unmodified lines | |||
| 713 | { | 727 | { |
| 714 | struct io_rings *rings = ctx->rings; | 728 | struct io_rings *rings = ctx->rings; |
| 715 | unsigned int off = ctx->cached_cq_tail & (ctx->cq_entries - 1); | 729 | unsigned int off = ctx->cached_cq_tail & (ctx->cq_entries - 1); |
| 716 | unsigned int free, queued, len; | 730 | unsigned int free, len; |
| 717 | 731 | ||
| 718 | /* | 732 | /* |
| 719 | * Posting into the CQ when there are pending overflowed CQEs may break | 733 | * Posting into the CQ when there are pending overflowed CQEs may break |
| @@ -733,9 +747,7 @@ bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32) · 13 unmodified lines | |||
| 733 | off = 0; | 747 | off = 0; |
| 734 | } | 748 | } |
| 735 | 749 | ||
| 736 | /* userspace may cheat modifying the tail, be safe and do min */ | 750 | free = ctx->cq_entries - io_cqring_queued(ctx); |
| 737 | queued = min(__io_cqring_events(ctx), ctx->cq_entries); | ||
| 738 | free = ctx->cq_entries - queued; | ||
| 739 | /* we need a contiguous range, limit based on the current array offset */ | 751 | /* we need a contiguous range, limit based on the current array offset */ |
| 740 | len = min(free, ctx->cq_entries - off); | 752 | len = min(free, ctx->cq_entries - off); |
| 741 | if (len < (cqe32 + 1)) | 753 | if (len < (cqe32 + 1)) |
| @@ -1452,8 +1464,13 @@ struct io_wq_work *io_wq_free_work(struct io_wq_work *work) · 710 unmodified lines | |||
| 1452 | struct io_kiocb *nxt = NULL; | 1464 | struct io_kiocb *nxt = NULL; |
| 1453 | 1465 | ||
| 1454 | if (req_ref_put_and_test_atomic(req)) { | 1466 | if (req_ref_put_and_test_atomic(req)) { |
| 1455 | if (req->flags & IO_REQ_LINK_FLAGS) | 1467 | if (req->flags & IO_REQ_LINK_FLAGS) { |
| 1468 | struct io_ring_ctx *ctx = req->ctx; | ||
| 1469 | |||
| 1470 | mutex_lock(&ctx->uring_lock); | ||
| 1456 | nxt = io_req_find_next(req); | 1471 | nxt = io_req_find_next(req); |
| 1472 | mutex_unlock(&ctx->uring_lock); | ||
| 1473 | } | ||
| 1457 | io_free_req(req); | 1474 | io_free_req(req); |
| 1458 | } | 1475 | } |
| 1459 | return nxt ? &nxt->work : NULL; | 1476 | return nxt ? &nxt->work : NULL; |
| @@ -230,7 +230,7 @@ static inline void io_meta_restore(struct io_async_rw *io, struct kiocb *kiocb) · 229 unmodified lines | |||
| 230 | } | 230 | } |
| 231 | 231 | ||
| 232 | static int io_prep_rw_pi(struct io_kiocb *req, struct io_rw *rw, int ddir, | 232 | static int io_prep_rw_pi(struct io_kiocb *req, struct io_rw *rw, int ddir, |
| 233 | u64 attr_ptr, u64 attr_type_mask) | 233 | u64 attr_ptr) |
| 234 | { | 234 | { |
| 235 | struct io_uring_attr_pi pi_attr; | 235 | struct io_uring_attr_pi pi_attr; |
| 236 | struct io_async_rw *io; | 236 | struct io_async_rw *io; |
| @@ -305,7 +305,7 @@ static int __io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe, · 68 unmodified lines | |||
| 305 | return -EINVAL; | 305 | return -EINVAL; |
| 306 | 306 | ||
| 307 | attr_ptr = READ_ONCE(sqe->attr_ptr); | 307 | attr_ptr = READ_ONCE(sqe->attr_ptr); |
| 308 | return io_prep_rw_pi(req, rw, ddir, attr_ptr, attr_type_mask); | 308 | return io_prep_rw_pi(req, rw, ddir, attr_ptr); |
| 309 | } | 309 | } |
| 310 | return 0; | 310 | return 0; |
| 311 | } | 311 | } |
| @@ -284,6 +284,10 @@ static struct io_kiocb *__io_disarm_linked_timeout(struct io_kiocb *req, · 283 unmodified lines | |||
| 284 | struct io_timeout *timeout = io_kiocb_to_cmd(link, struct io_timeout); | 284 | struct io_timeout *timeout = io_kiocb_to_cmd(link, struct io_timeout); |
| 285 | 285 | ||
| 286 | io_remove_next_linked(req); | 286 | io_remove_next_linked(req); |
| 287 | |||
| 288 | /* If this is NULL, then timer already claimed it and will complete it */ | ||
| 289 | if (!timeout->head) | ||
| 290 | return NULL; | ||
| 287 | timeout->head = NULL; | 291 | timeout->head = NULL; |
| 288 | if (hrtimer_try_to_cancel(&io->timer) != -1) { | 292 | if (hrtimer_try_to_cancel(&io->timer) != -1) { |
| 289 | list_del(&timeout->list); | 293 | list_del(&timeout->list); |
| @@ -367,6 +371,14 @@ static void io_req_task_link_timeout(struct io_tw_req tw_req, io_tw_token_t tw) · 77 unmodified lines | |||
| 367 | int ret; | 371 | int ret; |
| 368 | 372 | ||
| 369 | if (prev) { | 373 | if (prev) { |
| 374 | /* | ||
| 375 | * splice the linked timeout out of prev's chain if the regular | ||
| 376 | * completion path didn't already do it. | ||
| 377 | */ | ||
| 378 | if (prev->link == req) | ||
| 379 | prev->link = req->link; | ||
| 380 | req->link = NULL; | ||
| 381 | |||
| 370 | if (!tw.cancel) { | 382 | if (!tw.cancel) { |
| 371 | struct io_cancel_data cd = { | 383 | struct io_cancel_data cd = { |
| 372 | .ctx = req->ctx, | 384 | .ctx = req->ctx, |
| @@ -401,10 +413,10 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer) · 28 unmodified lines | |||
| 401 | 413 | ||
| 402 | /* | 414 | /* |
| 403 | * We don't expect the list to be empty, that will only happen if we | 415 | * We don't expect the list to be empty, that will only happen if we |
| 404 | * race with the completion of the linked work. | 416 | * race with the completion of the linked work. Splice of prev is |
| 417 | * done in io_req_task_link_timeout(), if needed. | ||
| 405 | */ | 418 | */ |
| 406 | if (prev) { | 419 | if (prev) { |
| 407 | io_remove_next_linked(prev); | ||
| 408 | if (!req_ref_inc_not_zero(prev)) | 420 | if (!req_ref_inc_not_zero(prev)) |
| 409 | prev = NULL; | 421 | prev = NULL; |
| 410 | } | 422 | } |