diff options
author | Eric Wong <normalperson@yhbt.net> | 2013-02-04 08:04:44 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2013-02-04 09:22:23 -0500 |
commit | 6a4e922c3db06f7da27e072729e047185c2fba66 (patch) | |
tree | 26d92e82ab982b25b3f115e52a9bf9956003889b /fs/fuse | |
parent | 23c153e54197171f30b889d9654929d74b6599d5 (diff) |
fuse: avoid out-of-scope stack access
The all pointers within fuse_req must point to valid memory once
fuse_force_forget() returns.
This bug appeared in "fuse: implement NFS-like readdirplus support"
and was never in any official Linux release.
I tested the fuse_force_forget() code path by injecting to fake -ENOMEM and
verified the FORGET operation was called properly in userspace.
Signed-off-by: Eric Wong <normalperson@yhbt.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dev.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index cbae09e5a491..e9bdec0b16d9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -440,9 +440,8 @@ __acquires(fc->lock) | |||
440 | } | 440 | } |
441 | } | 441 | } |
442 | 442 | ||
443 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | 443 | static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) |
444 | { | 444 | { |
445 | req->isreply = 1; | ||
446 | spin_lock(&fc->lock); | 445 | spin_lock(&fc->lock); |
447 | if (!fc->connected) | 446 | if (!fc->connected) |
448 | req->out.h.error = -ENOTCONN; | 447 | req->out.h.error = -ENOTCONN; |
@@ -459,6 +458,12 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | |||
459 | } | 458 | } |
460 | spin_unlock(&fc->lock); | 459 | spin_unlock(&fc->lock); |
461 | } | 460 | } |
461 | |||
462 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) | ||
463 | { | ||
464 | req->isreply = 1; | ||
465 | __fuse_request_send(fc, req); | ||
466 | } | ||
462 | EXPORT_SYMBOL_GPL(fuse_request_send); | 467 | EXPORT_SYMBOL_GPL(fuse_request_send); |
463 | 468 | ||
464 | static void fuse_request_send_nowait_locked(struct fuse_conn *fc, | 469 | static void fuse_request_send_nowait_locked(struct fuse_conn *fc, |
@@ -541,7 +546,9 @@ void fuse_force_forget(struct file *file, u64 nodeid) | |||
541 | req->in.args[0].size = sizeof(inarg); | 546 | req->in.args[0].size = sizeof(inarg); |
542 | req->in.args[0].value = &inarg; | 547 | req->in.args[0].value = &inarg; |
543 | req->isreply = 0; | 548 | req->isreply = 0; |
544 | fuse_request_send_nowait(fc, req); | 549 | __fuse_request_send(fc, req); |
550 | /* ignore errors */ | ||
551 | fuse_put_request(fc, req); | ||
545 | } | 552 | } |
546 | 553 | ||
547 | /* | 554 | /* |