aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorRobert Doebbelin <robert@quobyte.com>2016-03-07 03:50:56 -0500
committerMiklos Szeredi <miklos@szeredi.hu>2016-03-14 10:02:50 -0400
commit7cabc61e01a0a8b663bd2b4c982aa53048218734 (patch)
tree474f0a6e0cde183d19ccb0c9b14d2358e1944012 /fs/fuse/file.c
parentb562e44f507e863c6792946e4e1b1449fbbac85d (diff)
fuse: do not use iocb after it may have been freed
There's a race in fuse_direct_IO(), whereby is_sync_kiocb() is called on an iocb that could have been freed if async io has already completed. The fix in this case is simple and obvious: cache the result before starting io. It was discovered by KASan: kernel: ================================================================== kernel: BUG: KASan: use after free in fuse_direct_IO+0xb1a/0xcc0 at addr ffff88036c414390 Signed-off-by: Robert Doebbelin <robert@quobyte.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Fixes: bcba24ccdc82 ("fuse: enable asynchronous processing direct IO") Cc: <stable@vger.kernel.org> # 3.10+
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b03d253ece15..34a23df361ca 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2843,6 +2843,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
2843 loff_t i_size; 2843 loff_t i_size;
2844 size_t count = iov_iter_count(iter); 2844 size_t count = iov_iter_count(iter);
2845 struct fuse_io_priv *io; 2845 struct fuse_io_priv *io;
2846 bool is_sync = is_sync_kiocb(iocb);
2846 2847
2847 pos = offset; 2848 pos = offset;
2848 inode = file->f_mapping->host; 2849 inode = file->f_mapping->host;
@@ -2882,11 +2883,11 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
2882 * to wait on real async I/O requests, so we must submit this request 2883 * to wait on real async I/O requests, so we must submit this request
2883 * synchronously. 2884 * synchronously.
2884 */ 2885 */
2885 if (!is_sync_kiocb(iocb) && (offset + count > i_size) && 2886 if (!is_sync && (offset + count > i_size) &&
2886 iov_iter_rw(iter) == WRITE) 2887 iov_iter_rw(iter) == WRITE)
2887 io->async = false; 2888 io->async = false;
2888 2889
2889 if (io->async && is_sync_kiocb(iocb)) 2890 if (io->async && is_sync)
2890 io->done = &wait; 2891 io->done = &wait;
2891 2892
2892 if (iov_iter_rw(iter) == WRITE) { 2893 if (iov_iter_rw(iter) == WRITE) {
@@ -2900,7 +2901,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
2900 fuse_aio_complete(io, ret < 0 ? ret : 0, -1); 2901 fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
2901 2902
2902 /* we have a non-extending, async request, so return */ 2903 /* we have a non-extending, async request, so return */
2903 if (!is_sync_kiocb(iocb)) 2904 if (!is_sync)
2904 return -EIOCBQUEUED; 2905 return -EIOCBQUEUED;
2905 2906
2906 wait_for_completion(&wait); 2907 wait_for_completion(&wait);