Skip to content

Commit 3e8cb8b

Browse files
author
Miklos Szeredi
committed
fuse: fix stack use after return
Normal, synchronous requests will have their args allocated on the stack. After the FR_FINISHED bit is set by receiving the reply from the userspace fuse server, the originating task may return and reuse the stack frame, resulting in an Oops if the args structure is dereferenced. Fix by setting a flag in the request itself upon initializing, indicating whether it has an asynchronous ->end() callback. Reported-by: Kyle Sanderson <kyle.leet@gmail.com> Reported-by: Michael Stapelberg <michael+lkml@stapelberg.ch> Fixes: 2b319d1 ("fuse: don't dereference req->args on finished request") Cc: <stable@vger.kernel.org> # v5.4 Tested-by: Michael Stapelberg <michael+lkml@stapelberg.ch> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent bb6d3fb commit 3e8cb8b

2 files changed

Lines changed: 5 additions & 3 deletions

File tree

fs/fuse/dev.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,10 @@ static void flush_bg_queue(struct fuse_conn *fc)
276276
void fuse_request_end(struct fuse_conn *fc, struct fuse_req *req)
277277
{
278278
struct fuse_iqueue *fiq = &fc->iq;
279-
bool async;
280279

281280
if (test_and_set_bit(FR_FINISHED, &req->flags))
282281
goto put_request;
283282

284-
async = req->args->end;
285283
/*
286284
* test_and_set_bit() implies smp_mb() between bit
287285
* changing and below intr_entry check. Pairs with
@@ -324,7 +322,7 @@ void fuse_request_end(struct fuse_conn *fc, struct fuse_req *req)
324322
wake_up(&req->waitq);
325323
}
326324

327-
if (async)
325+
if (test_bit(FR_ASYNC, &req->flags))
328326
req->args->end(fc, req->args, req->out.h.error);
329327
put_request:
330328
fuse_put_request(fc, req);
@@ -471,6 +469,8 @@ static void fuse_args_to_req(struct fuse_req *req, struct fuse_args *args)
471469
req->in.h.opcode = args->opcode;
472470
req->in.h.nodeid = args->nodeid;
473471
req->args = args;
472+
if (args->end)
473+
__set_bit(FR_ASYNC, &req->flags);
474474
}
475475

476476
ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)

fs/fuse/fuse_i.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ struct fuse_io_priv {
301301
* FR_SENT: request is in userspace, waiting for an answer
302302
* FR_FINISHED: request is finished
303303
* FR_PRIVATE: request is on private list
304+
* FR_ASYNC: request is asynchronous
304305
*/
305306
enum fuse_req_flag {
306307
FR_ISREPLY,
@@ -314,6 +315,7 @@ enum fuse_req_flag {
314315
FR_SENT,
315316
FR_FINISHED,
316317
FR_PRIVATE,
318+
FR_ASYNC,
317319
};
318320

319321
/**

0 commit comments

Comments
 (0)