io_uring/bpf-ops: clear bpf_ctx while submitting SQEs

bpf_io_uring_submit_sqes() calls io_submit_sqes() from inside the loop
program, with current->bpf_ctx set, and requests issued inline run with
it set too. The socket code uses has_current_bpf_ctx() to recognize
calls from bpf_setsockopt() and friends, where the caller holds the
socket lock and has already been vetted, and skips both.

So a SOCKET_URING_OP_SETSOCKOPT from the SQ passes sockopt_capable()
without the capability, and runs without lock_sock(). A task with no
capability can set SO_MARK, IP_TRANSPARENT or TCP_REPAIR, and two
threads changing IP_OPTIONS on one socket, one through the ring, double
free in no time. SOCK_DESTROY via IORING_OP_SENDMSG ends up in
tcp_abort() without the lock the same way.

Clear the run context around io_submit_sqes(). The SQEs come from
userspace and must be issued like those of any other ring. They still
run inside the program's RCU tasks trace read section, so a request
that sleeps there holds up that grace period, but other request types
do that already.

Fixes: 890819248a ("io_uring/bpf-ops: add kfunc helpers")
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Chris Mason 2026-10-21 08:24:13 +00:00 committed by Jens Axboe
parent 51bab09b7c
commit 8543a39f03

View File

@ -17,8 +17,22 @@ __bpf_kfunc_start_defs();
__bpf_kfunc int bpf_io_uring_submit_sqes(struct iou_ctx *loop_ctx, u32 nr)
{
struct io_ring_ctx *ctx = io_loop_demangle_ctx(loop_ctx);
struct bpf_run_ctx *old_run_ctx;
int ret;
return io_submit_sqes(ctx, nr);
/*
* The requests come from the SQ, which user space can write, so they
* are issued for the task and not for the BPF program. Hide the run
* context of the program from them. The users of has_current_bpf_ctx(),
* such as sockopt_lock_sock() and sockopt_capable(), take a context for
* a call from a BPF helper, whose caller holds the socket lock already
* and needs no capability.
*/
old_run_ctx = bpf_set_run_ctx(NULL);
ret = io_submit_sqes(ctx, nr);
bpf_reset_run_ctx(old_run_ctx);
return ret;
}
__bpf_kfunc