usb: gadget: f_fs: do not set cancel function on synchronous {read,write}

Message ID 1432723291-1831-1-git-send-email-rui.silva@linaro.org
State Accepted
Commit 4088acf1e845aba35f30fb91dee10649edbd0e84
Headers show

Commit Message

Rui Miguel Silva May 27, 2015, 10:41 a.m.
do not try to set cancel function in synchronous operations in
ffs_epfile_{read,write}_iter.

With, 70e60d917 gadget/function/f_fs.c: switch to ->{read,write}_iter()
if CONFIG_AIO is disable there is no problem as kiocb_set_cancel_fn
is a nop, with this option enabled it will try to use ctx that is not
allocated for synchronous operations. And for that will dereference a
null at the set cancel function in any synchronous read/write.

A simplified trace of the callstack (for the write case):
BUG: unable to handle kernel NULL pointer dereference at 00000000000000e8
IP: [<ffffffff810f6510>] kiocb_set_cancel_fn+0x20/0x50

Call Trace:
[<ffffffffa0022a40>] ffs_name_dev+0x4980/0x4c1d [usb_f_fs]
[<ffffffff8107f550>] ? perf_event_fork+0x10/0x20
[<ffffffff81033432>] ? copy_process.part.65+0xbe2/0x1580
[<ffffffff810bba2b>] new_sync_write+0x7b/0xb0
[<ffffffff810bc01d>] vfs_write+0xad/0x1d0
[<ffffffff810bc705>] SyS_write+0x45/0xc0
[<ffffffff81034221>] ? SyS_clone+0x11/0x20
[<ffffffff813ee8bc>] ? stub_clone+0x6c/0x90
[<ffffffff813ee5f0>] system_call_fastpath+0x12/0x17

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
changes v1 -> v2:
 * Requested by Felipe Balbi:
   - add a more complete log message
   - include Al Viro in cc.

 drivers/usb/gadget/function/f_fs.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

Patch

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 6bdb570..fa538fa 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -925,7 +925,8 @@  static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
 
 	kiocb->private = p;
 
-	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+	if (p->aio)
+		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
 	res = ffs_epfile_io(kiocb->ki_filp, p);
 	if (res == -EIOCBQUEUED)
@@ -969,7 +970,8 @@  static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
 
 	kiocb->private = p;
 
-	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
+	if (p->aio)
+		kiocb_set_cancel_fn(kiocb, ffs_aio_cancel);
 
 	res = ffs_epfile_io(kiocb->ki_filp, p);
 	if (res == -EIOCBQUEUED)