Commit e41255ce authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'io_uring-7.0-20260403' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull io_uring fixes from Jens Axboe:

 - A previous fix in this release covered the case of the rings being
   RCU protected during resize, but it missed a few spots. This covers
   the rest

 - Fix the cBPF filters when COW'ed, introduced in this merge window

 - Fix for an attempt to import a zero sized buffer

 - Fix for a missing clamp in importing bundle buffers

* tag 'io_uring-7.0-20260403' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux:
  io_uring/bpf_filters: retain COW'ed settings on parse failures
  io_uring: protect remaining lockless ctx->rings accesses with RCU
  io_uring/rsrc: reject zero-length fixed buffer import
  io_uring/net: fix slab-out-of-bounds read in io_bundle_nbufs()
parents c514f733 aa35dd6b
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -2015,7 +2015,7 @@ int io_submit_sqes(struct io_ring_ctx *ctx, unsigned int nr)
	if (ctx->flags & IORING_SETUP_SQ_REWIND)
		entries = ctx->sq_entries;
	else
		entries = io_sqring_entries(ctx);
		entries = __io_sqring_entries(ctx);

	entries = min(nr, entries);
	if (unlikely(!entries))
@@ -2250,7 +2250,9 @@ static __poll_t io_uring_poll(struct file *file, poll_table *wait)
	 */
	poll_wait(file, &ctx->poll_wq, wait);

	if (!io_sqring_full(ctx))
	rcu_read_lock();

	if (!__io_sqring_full(ctx))
		mask |= EPOLLOUT | EPOLLWRNORM;

	/*
@@ -2270,6 +2272,7 @@ static __poll_t io_uring_poll(struct file *file, poll_table *wait)
	if (__io_cqring_events_user(ctx) || io_has_work(ctx))
		mask |= EPOLLIN | EPOLLRDNORM;

	rcu_read_unlock();
	return mask;
}

+29 −5
Original line number Diff line number Diff line
@@ -142,16 +142,28 @@ struct io_wait_queue {
#endif
};

static inline struct io_rings *io_get_rings(struct io_ring_ctx *ctx)
{
	return rcu_dereference_check(ctx->rings_rcu,
			lockdep_is_held(&ctx->uring_lock) ||
			lockdep_is_held(&ctx->completion_lock));
}

static inline bool io_should_wake(struct io_wait_queue *iowq)
{
	struct io_ring_ctx *ctx = iowq->ctx;
	int dist = READ_ONCE(ctx->rings->cq.tail) - (int) iowq->cq_tail;
	struct io_rings *rings;
	int dist;

	guard(rcu)();
	rings = io_get_rings(ctx);

	/*
	 * Wake up if we have enough events, or if a timeout occurred since we
	 * started waiting. For timeouts, we always want to return to userspace,
	 * regardless of event count.
	 */
	dist = READ_ONCE(rings->cq.tail) - (int) iowq->cq_tail;
	return dist >= 0 || atomic_read(&ctx->cq_timeouts) != iowq->nr_timeouts;
}

@@ -431,9 +443,9 @@ static inline void io_cqring_wake(struct io_ring_ctx *ctx)
	__io_wq_wake(&ctx->cq_wait);
}

static inline bool io_sqring_full(struct io_ring_ctx *ctx)
static inline bool __io_sqring_full(struct io_ring_ctx *ctx)
{
	struct io_rings *r = ctx->rings;
	struct io_rings *r = io_get_rings(ctx);

	/*
	 * SQPOLL must use the actual sqring head, as using the cached_sq_head
@@ -445,9 +457,15 @@ static inline bool io_sqring_full(struct io_ring_ctx *ctx)
	return READ_ONCE(r->sq.tail) - READ_ONCE(r->sq.head) == ctx->sq_entries;
}

static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
static inline bool io_sqring_full(struct io_ring_ctx *ctx)
{
	struct io_rings *rings = ctx->rings;
	guard(rcu)();
	return __io_sqring_full(ctx);
}

static inline unsigned int __io_sqring_entries(struct io_ring_ctx *ctx)
{
	struct io_rings *rings = io_get_rings(ctx);
	unsigned int entries;

	/* make sure SQ entry isn't read before tail */
@@ -455,6 +473,12 @@ static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
	return min(entries, ctx->sq_entries);
}

static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)
{
	guard(rcu)();
	return __io_sqring_entries(ctx);
}

/*
 * Don't complete immediately but use deferred completion infrastructure.
 * Protected by ->uring_lock and can only be used either with
+4 −0
Original line number Diff line number Diff line
@@ -421,6 +421,8 @@ int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)

	sr->done_io = 0;
	sr->len = READ_ONCE(sqe->len);
	if (unlikely(sr->len < 0))
		return -EINVAL;
	sr->flags = READ_ONCE(sqe->ioprio);
	if (sr->flags & ~SENDMSG_FLAGS)
		return -EINVAL;
@@ -791,6 +793,8 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)

	sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr));
	sr->len = READ_ONCE(sqe->len);
	if (unlikely(sr->len < 0))
		return -EINVAL;
	sr->flags = READ_ONCE(sqe->ioprio);
	if (sr->flags & ~RECVMSG_FLAGS)
		return -EINVAL;
+9 −1
Original line number Diff line number Diff line
@@ -178,9 +178,17 @@ static __cold int io_register_restrictions(struct io_ring_ctx *ctx,
		return -EBUSY;

	ret = io_parse_restrictions(arg, nr_args, &ctx->restrictions);
	/* Reset all restrictions if an error happened */
	/*
	 * Reset all restrictions if an error happened, but retain any COW'ed
	 * settings.
	 */
	if (ret < 0) {
		struct io_bpf_filters *bpf = ctx->restrictions.bpf_filters;
		bool cowed = ctx->restrictions.bpf_filters_cow;

		memset(&ctx->restrictions, 0, sizeof(ctx->restrictions));
		ctx->restrictions.bpf_filters = bpf;
		ctx->restrictions.bpf_filters_cow = cowed;
		return ret;
	}
	if (ctx->restrictions.op_registered)
+4 −0
Original line number Diff line number Diff line
@@ -1061,6 +1061,10 @@ static int io_import_fixed(int ddir, struct iov_iter *iter,
		return ret;
	if (!(imu->dir & (1 << ddir)))
		return -EFAULT;
	if (unlikely(!len)) {
		iov_iter_bvec(iter, ddir, NULL, 0, 0);
		return 0;
	}

	offset = buf_addr - imu->ubuf;

Loading