mirror of
https://github.com/torvalds/linux
synced 2026-07-22 10:10:47 +09:00
fuse-uring: make a fuse_req on SQE commit only findable after memcpy
Bad userspace might try to trick us and send commit SQEs request
unique / commit-id of requests that are not even send to
fuse-server (io_uring_cmd_done() not called) yet.
fuse_uring_commit_fetch() ends the fuse request when the ring entry
has a wrong state, but that could have caused a use-after-free
with the memcpy operations in fuse_uring_send_in_task().
In order to avoid such races the call of fuse_uring_add_to_pq()
is moved after the copy operations and just before completing
the io-uring request - malicious userspace cannot find the request
anymore until all prepration work in fuse-client/kernel is completed.
This also moves fuse_uring_add_to_pq() a bit up in the code to
avoid a forward declaration. Also not with a preparation commit,
to make it easier to back port to older kernels.
Reported-by: xlabai <xlabai@tencent.com>
Reported-by: Berkant Koc <me@berkoc.com>
Fixes: c090c8abae ("fuse: Add io-uring sqe commit and fetch support")
Cc: stable@kernel.org # 6.14
Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
committed by
Miklos Szeredi
parent
b70a3aca16
commit
1efd3d474f
@@ -717,6 +717,19 @@ static int fuse_uring_prepare_send(struct fuse_ring_ent *ent,
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Used to find the request on SQE commit */
|
||||
static void fuse_uring_add_to_pq(struct fuse_ring_ent *ent)
|
||||
{
|
||||
struct fuse_ring_queue *queue = ent->queue;
|
||||
struct fuse_pqueue *fpq = &queue->fpq;
|
||||
unsigned int hash;
|
||||
struct fuse_req *req = ent->fuse_req;
|
||||
|
||||
req->ring_entry = ent;
|
||||
hash = fuse_req_hash(req->in.h.unique);
|
||||
list_move_tail(&req->list, &fpq->processing[hash]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data to the ring buffer and send the request to userspace,
|
||||
* userspace will read it
|
||||
@@ -739,6 +752,7 @@ static int fuse_uring_send_next_to_ring(struct fuse_ring_ent *ent,
|
||||
ent->cmd = NULL;
|
||||
ent->state = FRRS_USERSPACE;
|
||||
list_move_tail(&ent->list, &queue->ent_in_userspace);
|
||||
fuse_uring_add_to_pq(ent);
|
||||
spin_unlock(&queue->lock);
|
||||
|
||||
io_uring_cmd_done(cmd, 0, issue_flags);
|
||||
@@ -756,19 +770,6 @@ static void fuse_uring_ent_avail(struct fuse_ring_ent *ent,
|
||||
ent->state = FRRS_AVAILABLE;
|
||||
}
|
||||
|
||||
/* Used to find the request on SQE commit */
|
||||
static void fuse_uring_add_to_pq(struct fuse_ring_ent *ent,
|
||||
struct fuse_req *req)
|
||||
{
|
||||
struct fuse_ring_queue *queue = ent->queue;
|
||||
struct fuse_pqueue *fpq = &queue->fpq;
|
||||
unsigned int hash;
|
||||
|
||||
req->ring_entry = ent;
|
||||
hash = fuse_req_hash(req->in.h.unique);
|
||||
list_move_tail(&req->list, &fpq->processing[hash]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign a fuse queue entry to the given entry
|
||||
*/
|
||||
@@ -786,10 +787,13 @@ static void fuse_uring_add_req_to_ring_ent(struct fuse_ring_ent *ent,
|
||||
}
|
||||
|
||||
clear_bit(FR_PENDING, &req->flags);
|
||||
|
||||
/* Until fuse_uring_add_to_pq() the req is not attached to any list */
|
||||
list_del_init(&req->list);
|
||||
|
||||
ent->fuse_req = req;
|
||||
ent->state = FRRS_FUSE_REQ;
|
||||
list_move_tail(&ent->list, &queue->ent_w_req_queue);
|
||||
fuse_uring_add_to_pq(ent, req);
|
||||
}
|
||||
|
||||
/* Fetch the next fuse request if available */
|
||||
@@ -1220,6 +1224,7 @@ static void fuse_uring_send(struct fuse_ring_ent *ent, struct io_uring_cmd *cmd,
|
||||
ent->state = FRRS_USERSPACE;
|
||||
list_move_tail(&ent->list, &queue->ent_in_userspace);
|
||||
ent->cmd = NULL;
|
||||
fuse_uring_add_to_pq(ent);
|
||||
spin_unlock(&queue->lock);
|
||||
|
||||
io_uring_cmd_done(cmd, ret, issue_flags);
|
||||
|
||||
Reference in New Issue
Block a user