Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

io_uring/timeout: immediate timeout arg

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, snippet below will lead to UAF of 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 for timeout
or sqe->addr2 for timeout update requests will be interpreted as a time
value in nanosecods.

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();
}

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Pavel Begunkov and committed by
Jens Axboe
d8345a21 0e78aa18

+20 -5
+5
include/uapi/linux/io_uring.h
··· 343 343 344 344 /* 345 345 * sqe->timeout_flags 346 + * 347 + * IORING_TIMEOUT_IMMEDIATE_ARG: If set, sqe->addr stores the timeout 348 + * value in nanoseconds instead of 349 + * pointing to a timespec. 346 350 */ 347 351 #define IORING_TIMEOUT_ABS (1U << 0) 348 352 #define IORING_TIMEOUT_UPDATE (1U << 1) ··· 355 351 #define IORING_LINK_TIMEOUT_UPDATE (1U << 4) 356 352 #define IORING_TIMEOUT_ETIME_SUCCESS (1U << 5) 357 353 #define IORING_TIMEOUT_MULTISHOT (1U << 6) 354 + #define IORING_TIMEOUT_IMMEDIATE_ARG (1U << 7) 358 355 #define IORING_TIMEOUT_CLOCK_MASK (IORING_TIMEOUT_BOOTTIME | IORING_TIMEOUT_REALTIME) 359 356 #define IORING_TIMEOUT_UPDATE_MASK (IORING_TIMEOUT_UPDATE | IORING_LINK_TIMEOUT_UPDATE) 360 357 /*
+15 -5
io_uring/timeout.c
··· 35 35 bool ltimeout; 36 36 }; 37 37 38 - static int io_parse_user_time(ktime_t *time, u64 arg) 38 + static int io_parse_user_time(ktime_t *time, u64 arg, unsigned flags) 39 39 { 40 40 struct timespec64 ts; 41 + 42 + if (flags & IORING_TIMEOUT_IMMEDIATE_ARG) { 43 + *time = ns_to_ktime(arg); 44 + if (*time < 0) 45 + return -EINVAL; 46 + return 0; 47 + } 41 48 42 49 if (get_timespec64(&ts, u64_to_user_ptr(arg))) 43 50 return -EFAULT; ··· 482 475 return -EINVAL; 483 476 if (tr->flags & IORING_LINK_TIMEOUT_UPDATE) 484 477 tr->ltimeout = true; 485 - if (tr->flags & ~(IORING_TIMEOUT_UPDATE_MASK|IORING_TIMEOUT_ABS)) 478 + if (tr->flags & ~(IORING_TIMEOUT_UPDATE_MASK | 479 + IORING_TIMEOUT_ABS | 480 + IORING_TIMEOUT_IMMEDIATE_ARG)) 486 481 return -EINVAL; 487 - ret = io_parse_user_time(&tr->time, READ_ONCE(sqe->addr2)); 482 + ret = io_parse_user_time(&tr->time, READ_ONCE(sqe->addr2), tr->flags); 488 483 if (ret) 489 484 return ret; 490 485 } else if (tr->flags) { ··· 554 545 flags = READ_ONCE(sqe->timeout_flags); 555 546 if (flags & ~(IORING_TIMEOUT_ABS | IORING_TIMEOUT_CLOCK_MASK | 556 547 IORING_TIMEOUT_ETIME_SUCCESS | 557 - IORING_TIMEOUT_MULTISHOT)) 548 + IORING_TIMEOUT_MULTISHOT | 549 + IORING_TIMEOUT_IMMEDIATE_ARG)) 558 550 return -EINVAL; 559 551 /* more than one clock specified is invalid, obviously */ 560 552 if (hweight32(flags & IORING_TIMEOUT_CLOCK_MASK) > 1) ··· 584 574 data->req = req; 585 575 data->flags = flags; 586 576 587 - ret = io_parse_user_time(&data->time, READ_ONCE(sqe->addr)); 577 + ret = io_parse_user_time(&data->time, READ_ONCE(sqe->addr), flags); 588 578 if (ret) 589 579 return ret; 590 580