public inbox for io-uring@vger.kernel.org
 help / color / mirror / Atom feed
From: Pavel Begunkov <asml.silence@gmail.com>
To: io-uring@vger.kernel.org
Cc: asml.silence@gmail.com, axboe@kernel.dk, Keith Busch <kbusch@kernel.org>
Subject: [PATCH v2 2/2] io_uring/timeout: immediate timeout arg
Date: Wed, 25 Feb 2026 10:35:58 +0000	[thread overview]
Message-ID: <6151302f1dc01d1c4e3176da50ab4224947b709f.1772015321.git.asml.silence@gmail.com> (raw)
In-Reply-To: <cover.1772015321.git.asml.silence@gmail.com>

One the things the user has always keep in mind is that any user
pointers they put into an SQE is not going to be read by the kernel
until submission happens, and the user has to ensure the pointee
stays alive until then. For example, this snippet:

void prep_timeout(struct io_uring_sqe *sqe) {
	struct __kernel_timespec ts = {...};
	prep_timeout(sqe, &ts);
}

void submit() {
	sqe = get_sqe();
	prep_timeout(sqe);
	io_uring_submit();
}

would lead to UAF for the on stack variable 'ts'. Instead of passing
the timeout value as a pointer allow to store it immediately in the SQE.
The user has to set a new flag called IORING_TIMEOUT_IMMEDIATE_ARG,
in which case sqe->addr will be interpreted as the timeout value in ns.
It only works with relative timeouts and rejected if set together with
IORING_TIMEOUT_ABS out of concerns of not having enough range in u64 to
represent a good long term API.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 include/uapi/linux/io_uring.h |  5 +++++
 io_uring/timeout.c            | 28 +++++++++++++++++++++++-----
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 6750c383a2ab..8f4de786e6e9 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -340,6 +340,10 @@ enum io_uring_op {
 
 /*
  * sqe->timeout_flags
+ *
+ * IORING_TIMEOUT_IMMEDIATE_ARG:	If set, sqe->addr stores the timeout
+ *					value in nanoseconds instead of
+ *					pointing to a timespec.
  */
 #define IORING_TIMEOUT_ABS		(1U << 0)
 #define IORING_TIMEOUT_UPDATE		(1U << 1)
@@ -348,6 +352,7 @@ enum io_uring_op {
 #define IORING_LINK_TIMEOUT_UPDATE	(1U << 4)
 #define IORING_TIMEOUT_ETIME_SUCCESS	(1U << 5)
 #define IORING_TIMEOUT_MULTISHOT	(1U << 6)
+#define IORING_TIMEOUT_IMMEDIATE_ARG	(1U << 7)
 #define IORING_TIMEOUT_CLOCK_MASK	(IORING_TIMEOUT_BOOTTIME | IORING_TIMEOUT_REALTIME)
 #define IORING_TIMEOUT_UPDATE_MASK	(IORING_TIMEOUT_UPDATE | IORING_LINK_TIMEOUT_UPDATE)
 /*
diff --git a/io_uring/timeout.c b/io_uring/timeout.c
index cb61d4862fc6..a0d1db98d1fc 100644
--- a/io_uring/timeout.c
+++ b/io_uring/timeout.c
@@ -446,6 +446,7 @@ static int io_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
 int io_timeout_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
 	struct io_timeout_rem *tr = io_kiocb_to_cmd(req, struct io_timeout_rem);
+	__u64 arg;
 
 	if (unlikely(req->flags & (REQ_F_FIXED_FILE | REQ_F_BUFFER_SELECT)))
 		return -EINVAL;
@@ -460,10 +461,20 @@ int io_timeout_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 			return -EINVAL;
 		if (tr->flags & IORING_LINK_TIMEOUT_UPDATE)
 			tr->ltimeout = true;
-		if (tr->flags & ~(IORING_TIMEOUT_UPDATE_MASK|IORING_TIMEOUT_ABS))
+		if (tr->flags & ~(IORING_TIMEOUT_UPDATE_MASK |
+				  IORING_TIMEOUT_ABS |
+				  IORING_TIMEOUT_IMMEDIATE_ARG))
 			return -EINVAL;
-		if (get_timespec64(&tr->ts, u64_to_user_ptr(READ_ONCE(sqe->addr2))))
+
+		arg = READ_ONCE(sqe->addr2);
+		if (tr->flags & IORING_TIMEOUT_IMMEDIATE_ARG) {
+			if (tr->flags & IORING_TIMEOUT_ABS)
+				return -EINVAL;
+			tr->ts = ns_to_timespec64(arg);
+		} else if (get_timespec64(&tr->ts, u64_to_user_ptr(arg))) {
 			return -EFAULT;
+		}
+
 		if (tr->ts.tv_sec < 0 || tr->ts.tv_nsec < 0)
 			return -EINVAL;
 	} else if (tr->flags) {
@@ -518,8 +529,8 @@ static int __io_timeout_prep(struct io_kiocb *req,
 {
 	struct io_timeout *timeout = io_kiocb_to_cmd(req, struct io_timeout);
 	struct io_timeout_data *data;
-	unsigned flags;
 	u32 off = READ_ONCE(sqe->off);
+	unsigned flags;
 
 	if (sqe->buf_index || sqe->len != 1 || sqe->splice_fd_in)
 		return -EINVAL;
@@ -528,7 +539,8 @@ static int __io_timeout_prep(struct io_kiocb *req,
 	flags = READ_ONCE(sqe->timeout_flags);
 	if (flags & ~(IORING_TIMEOUT_ABS | IORING_TIMEOUT_CLOCK_MASK |
 		      IORING_TIMEOUT_ETIME_SUCCESS |
-		      IORING_TIMEOUT_MULTISHOT))
+		      IORING_TIMEOUT_MULTISHOT |
+		      IORING_TIMEOUT_IMMEDIATE_ARG))
 		return -EINVAL;
 	/* more than one clock specified is invalid, obviously */
 	if (hweight32(flags & IORING_TIMEOUT_CLOCK_MASK) > 1)
@@ -557,8 +569,14 @@ static int __io_timeout_prep(struct io_kiocb *req,
 	data->req = req;
 	data->flags = flags;
 
-	if (get_timespec64(&data->ts, u64_to_user_ptr(READ_ONCE(sqe->addr))))
+	if (flags & IORING_TIMEOUT_IMMEDIATE_ARG) {
+		if (flags & IORING_TIMEOUT_ABS)
+			return -EINVAL;
+		data->ts = ns_to_timespec64(READ_ONCE(sqe->addr));
+	} else if (get_timespec64(&data->ts,
+				  u64_to_user_ptr(READ_ONCE(sqe->addr)))) {
 		return -EFAULT;
+	}
 
 	if (data->ts.tv_sec < 0 || data->ts.tv_nsec < 0)
 		return -EINVAL;
-- 
2.53.0


  parent reply	other threads:[~2026-02-25 10:36 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-25 10:35 [PATCH v2 0/2] timeout immediate arg Pavel Begunkov
2026-02-25 10:35 ` [PATCH v2 1/2] io_uring/timeout: READ_ONCE sqe->addr Pavel Begunkov
2026-02-25 10:35 ` Pavel Begunkov [this message]
2026-02-25 15:36 ` (subset) [PATCH v2 0/2] timeout immediate arg Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6151302f1dc01d1c4e3176da50ab4224947b709f.1772015321.git.asml.silence@gmail.com \
    --to=asml.silence@gmail.com \
    --cc=axboe@kernel.dk \
    --cc=io-uring@vger.kernel.org \
    --cc=kbusch@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox