If a copy into the userspace ring buffer fails, a request will be
terminated and fuse_uring_req_end() will set ent->fuse_req to NULL but
it will leave the entry on ent_w_req_queue in FRRS_FUSE_REQ state. This
can lead to a NULL deref if the request expiration logic scans
ent_w_req_queue in the window before the entry is moved off it.
Fix this by taking the entry off ent_w_req_queue and changing its state
from FRRS_FUSE_REQ to FRRS_INVALID before terminating the request.
Fixes: 4fea593e625c ("fuse: optimize over-io-uring request expiration check")
Cc: stable@kernel.org
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
int err;
err = fuse_uring_copy_to_ring(ent, req);
- if (!err)
+ if (!err) {
set_bit(FR_SENT, &req->flags);
- else
+ } else {
+ /*
+ * Copying the request failed. Remove the entry from the
+ * ent_w_req_queue list and terminate the request
+ */
+ spin_lock(&ent->queue->lock);
+ list_del_init(&ent->list);
+ ent->state = FRRS_INVALID;
+ spin_unlock(&ent->queue->lock);
+
fuse_uring_req_end(ent, req, err);
+ }
return err;
}