[PATCH 1/2] fuse: do not use iocb after it may have been freed

From: Seth Forshee
Date: Fri Mar 11 2016 - 11:35:58 EST


From: Robert Doebbelin <robert@xxxxxxxxxxx>

Reading wrong data may cause the IO thread to starve waiting for completion.
The issue was introduced with commit 04b2fa9 and thus affects kernel >= 4.1. It
was discovered by KASan:

kernel: ==================================================================
kernel: BUG: KASan: use after free in fuse_direct_IO+0xb1a/0xcc0 at addr ffff88036c414390
kernel: Read of size 8 by task qemu-system-x86/2784
kernel: =============================================================================
kernel: BUG kmalloc-128 (Tainted: G I ): kasan: bad access detected
kernel: -----------------------------------------------------------------------------
kernel: Disabling lock debugging due to kernel taint
kernel: INFO: Slab 0xffffea000db10500 objects=32 used=26 fp=0xffff88036c414e80 flags=0x2ffff0000000080
kernel: INFO: Object 0xffff88036c414380 @offset=896 fp=0x (null)
kernel: Bytes b4 ffff88036c414370: 18 00 00 00 40 27 a3 1f 3b 56 00 00 00 00 00 00 ....@'..;V......
kernel: Object ffff88036c414380: 00 00 00 00 00 00 00 00 00 f0 75 35 00 00 00 00 ..........u5....
kernel: Object ffff88036c414390: 80 27 67 81 ff ff ff ff 00 00 00 00 00 00 00 00 .'g.............
kernel: Object ffff88036c4143a0: 05 00 00 00 00 00 00 00 80 82 44 ad 05 88 ff ff ..........D.....
kernel: Object ffff88036c4143b0: 00 00 00 00 00 00 00 00 10 e1 bc 56 49 56 00 00 ...........VIV..
kernel: Object ffff88036c4143c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: Object ffff88036c4143d0: 00 00 00 00 00 00 00 00 80 f6 85 6d 03 88 ff ff ...........m....
kernel: Object ffff88036c4143e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: Object ffff88036c4143f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: CPU: 0 PID: 2784 Comm: qemu-system-x86 Tainted: G B I 4.2.0-25-generic 0000030
kernel: Hardware name: IBM System x3550 M2 -[794654G]-/49Y6512 , BIOS -[D6E131CUS-1.05]- 11/25/2009
kernel: ffff88036c414380 00000000d939cde9 ffff8805adf0f7c8 ffffffff828cafee
kernel: 0000000000000080 ffff880373803680 ffff8805adf0f7f8 ffffffff81546759
kernel: ffff880373803680 ffffea000db10500 ffff88036c414380 ffff8805ad56d600
kernel: Call Trace:
kernel: [<ffffffff828cafee>] dump_stack+0x45/0x57
kernel: [<ffffffff81546759>] print_trailer+0xf9/0x150
kernel: [<ffffffff8154b9c8>] object_err+0x38/0x50
kernel: [<ffffffff8154e3d8>] kasan_report_error+0x1e8/0x3f0
kernel: [<ffffffff8154de94>] ? kasan_slab_free+0x44/0x50
kernel: [<ffffffff8154e791>] __asan_report_load8_noabort+0x61/0x70
kernel: [<ffffffff818d8bfa>] ? fuse_direct_IO+0xb1a/0xcc0
kernel: [<ffffffff818d8bfa>] fuse_direct_IO+0xb1a/0xcc0
kernel: [<ffffffff818d80e0>] ? fuse_direct_write_iter+0x1f0/0x1f0
kernel: [<ffffffff815d1d90>] ? SyS_pselect6+0x460/0x460
kernel: [<ffffffff8193528e>] ? cap_inode_need_killpriv+0x8e/0xb0
kernel: [<ffffffff8145eda6>] generic_file_direct_write+0x246/0x540
kernel: [<ffffffff815e1ced>] ? file_remove_privs+0xfd/0x270
kernel: [<ffffffff8145eb60>] ? generic_file_read_iter+0x1090/0x1090
kernel: [<ffffffff8159beaa>] ? __sb_start_write+0x10a/0x2d0
kernel: [<ffffffff8159bda0>] ? __sb_end_write+0xc0/0xc0
kernel: [<ffffffff818da16c>] fuse_file_write_iter+0x31c/0x780
kernel: [<ffffffff81a0e91d>] ? aa_file_perm+0x24d/0xa00
kernel: [<ffffffff81673aba>] aio_run_iocb+0x68a/0x870
kernel: [<ffffffff815cfa80>] ? poll_select_copy_remaining+0x3a0/0x3a0
kernel: [<ffffffff818d9e50>] ? fuse_perform_write+0xe80/0xe80
kernel: [<ffffffff81673430>] ? aio_complete+0xcb0/0xcb0
kernel: [<ffffffff8166f52a>] ? eventfd_ctx_read+0xda/0x6d0
kernel: [<ffffffff8166f450>] ? eventfd_write+0x6e0/0x6e0
kernel: [<ffffffff815cfa80>] ? poll_select_copy_remaining+0x3a0/0x3a0
kernel: [<ffffffff811d3280>] ? wake_up_q+0xe0/0xe0
kernel: [<ffffffff81652110>] ? __fsnotify_inode_delete+0x10/0x10
kernel: [<ffffffff815e872e>] ? __fget_light+0x7e/0x1f0
kernel: [<ffffffff8154de4d>] ? kasan_slab_alloc+0xd/0x10
kernel: [<ffffffff81676567>] do_io_submit+0x4a7/0xb40
kernel: [<ffffffff816760c0>] ? SyS_io_destroy+0x200/0x200
kernel: [<ffffffff81597fc0>] ? do_sendfile+0x1280/0x1280
kernel: [<ffffffff81676c10>] SyS_io_submit+0x10/0x20
kernel: [<ffffffff828dc632>] entry_SYSCALL_64_fastpath+0x16/0x75
kernel: Memory state around the buggy address:
kernel: ffff88036c414280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kernel: ffff88036c414300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
kernel: >ffff88036c414380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kernel: ^
kernel: ffff88036c414400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
kernel: ffff88036c414480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
kernel: ==================================================================
kernel: ==================================================================
kernel: BUG: KASan: use after free in fuse_direct_IO+0xb1a/0xcc0 at addr ffff88054c8ad210
kernel: Read of size 8 by task qemu-system-x86/2747
kernel: =============================================================================
kernel: BUG kmalloc-128 (Tainted: G B I ): kasan: bad access detected
kernel: -----------------------------------------------------------------------------
kernel: INFO: Slab 0xffffea0015322b40 objects=32 used=10 fp=0xffff88054c8ad200 flags=0x6ffff0000000080
kernel: INFO: Object 0xffff88054c8ad200 @offset=512 fp=0xffff88054c8ade00
kernel: Bytes b4 ffff88054c8ad1f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: Object ffff88054c8ad200: 00 de 8a 4c 05 88 ff ff 00 00 12 07 00 00 00 00 ...L............
kernel: Object ffff88054c8ad210: 80 27 67 81 ff ff ff ff 00 00 00 00 00 00 00 00 .'g.............
kernel: Object ffff88054c8ad220: 05 00 00 00 00 00 00 00 00 80 44 ad 05 88 ff ff ..........D.....
kernel: Object ffff88054c8ad230: 00 00 00 00 00 00 00 00 90 a3 6e 75 94 55 00 00 ..........nu.U..
kernel: Object ffff88054c8ad240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: Object ffff88054c8ad250: 00 00 00 00 00 00 00 00 00 ed 81 ae 05 88 ff ff ................
kernel: Object ffff88054c8ad260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: Object ffff88054c8ad270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
kernel: CPU: 3 PID: 2747 Comm: qemu-system-x86 Tainted: G B I 4.2.0-25-generic 0000030
kernel: Hardware name: IBM System x3550 M2 -[794654G]-/49Y6512 , BIOS -[D6E131CUS-1.05]- 11/25/2009
kernel: ffff88054c8ad200 000000005e8ba930 ffff880371aef7c8 ffffffff828cafee
kernel: 0000000000000080 ffff880373803680 ffff880371aef7f8 ffffffff81546759
kernel: ffff880373803680 ffffea0015322b40 ffff88054c8ad200 ffff8805aa4d1e00
kernel: Call Trace:
kernel: [<ffffffff828cafee>] dump_stack+0x45/0x57
kernel: [<ffffffff81546759>] print_trailer+0xf9/0x150
kernel: [<ffffffff8154b9c8>] object_err+0x38/0x50
kernel: [<ffffffff8154e3d8>] kasan_report_error+0x1e8/0x3f0
kernel: [<ffffffff8154de94>] ? kasan_slab_free+0x44/0x50
kernel: [<ffffffff8154e791>] __asan_report_load8_noabort+0x61/0x70
kernel: [<ffffffff818d8bfa>] ? fuse_direct_IO+0xb1a/0xcc0
kernel: [<ffffffff818d8bfa>] fuse_direct_IO+0xb1a/0xcc0
kernel: [<ffffffff818d80e0>] ? fuse_direct_write_iter+0x1f0/0x1f0
kernel: [<ffffffff8193528e>] ? cap_inode_need_killpriv+0x8e/0xb0
kernel: [<ffffffff8145eda6>] generic_file_direct_write+0x246/0x540
kernel: [<ffffffff815e1ced>] ? file_remove_privs+0xfd/0x270
kernel: [<ffffffff8145eb60>] ? generic_file_read_iter+0x1090/0x1090
kernel: [<ffffffff8159beaa>] ? __sb_start_write+0x10a/0x2d0
kernel: [<ffffffff8159bda0>] ? __sb_end_write+0xc0/0xc0
kernel: [<ffffffff818da16c>] fuse_file_write_iter+0x31c/0x780
kernel: [<ffffffff81673aba>] aio_run_iocb+0x68a/0x870
kernel: [<ffffffff815cfa80>] ? poll_select_copy_remaining+0x3a0/0x3a0
kernel: [<ffffffff818d9e50>] ? fuse_perform_write+0xe80/0xe80
kernel: [<ffffffff81673430>] ? aio_complete+0xcb0/0xcb0
kernel: [<ffffffff8120390d>] ? should_numa_migrate_memory+0xfd/0x410
kernel: [<ffffffff8153a963>] ? mpol_misplaced+0x393/0x520
kernel: [<ffffffff815e872e>] ? __fget_light+0x7e/0x1f0
kernel: [<ffffffff8154de4d>] ? kasan_slab_alloc+0xd/0x10
kernel: [<ffffffff81676567>] do_io_submit+0x4a7/0xb40
kernel: [<ffffffff816760c0>] ? SyS_io_destroy+0x200/0x200
kernel: [<ffffffff81597fc0>] ? do_sendfile+0x1280/0x1280
kernel: [<ffffffff81676c10>] SyS_io_submit+0x10/0x20
kernel: [<ffffffff828dc632>] entry_SYSCALL_64_fastpath+0x16/0x75
kernel: Memory state around the buggy address:
kernel: ffff88054c8ad100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kernel: ffff88054c8ad180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kernel: >ffff88054c8ad200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kernel: ^
kernel: ffff88054c8ad280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kernel: ffff88054c8ad300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fc
kernel: ==================================================================

Fixes: bcba24ccdc82 ("fuse: enable asynchronous processing direct IO")
Cc: stable@xxxxxxxxxxxxxxx # 3.10+
Signed-off-by: Robert Doebbelin <robert@xxxxxxxxxxx>
---
fs/fuse/file.c | 7 ++++---
1 file 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)
loff_t i_size;
size_t count = iov_iter_count(iter);
struct fuse_io_priv *io;
+ bool is_sync = is_sync_kiocb(iocb);

pos = offset;
inode = file->f_mapping->host;
@@ -2882,11 +2883,11 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
* to wait on real async I/O requests, so we must submit this request
* synchronously.
*/
- if (!is_sync_kiocb(iocb) && (offset + count > i_size) &&
+ if (!is_sync && (offset + count > i_size) &&
iov_iter_rw(iter) == WRITE)
io->async = false;

- if (io->async && is_sync_kiocb(iocb))
+ if (io->async && is_sync)
io->done = &wait;

if (iov_iter_rw(iter) == WRITE) {
@@ -2900,7 +2901,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
fuse_aio_complete(io, ret < 0 ? ret : 0, -1);

/* we have a non-extending, async request, so return */
- if (!is_sync_kiocb(iocb))
+ if (!is_sync)
return -EIOCBQUEUED;

wait_for_completion(&wait);
--
1.9.1