Message ID | 1653989775-14267-3-git-send-email-quic_linyyuan@quicinc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | usb: f_fs: safe operation in ffs_epfile_io() | expand |
On Tue, May 31, 2022 at 05:36:15PM +0800, Linyu Yuan wrote: > In ffs_epfile_io(), when read/write data in blocking mode, it will wait > the completion in interruptible mode, if task receive a signal, it will > terminate the wait, at same time, if function unbind occurs, > ffs_func_unbind() will kfree all eps, ffs_epfile_io() still try to > dequeue request by dereferencing ep which may become invalid. > > Fix it by add ep spinlock and will not dereference ep if it is not valid. > > Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com> Reviewed-by: John Keeping <john@metanate.com> > --- > drivers/usb/gadget/function/f_fs.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c > index dcba835..b6c9b44 100644 > --- a/drivers/usb/gadget/function/f_fs.c > +++ b/drivers/usb/gadget/function/f_fs.c > @@ -1077,6 +1077,11 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) > spin_unlock_irq(&epfile->ffs->eps_lock); > > if (wait_for_completion_interruptible(&io_data->done)) { > + spin_lock_irq(&epfile->ffs->eps_lock); > + if (epfile->ep != ep) { > + ret = -ESHUTDOWN; > + goto error_lock; > + } > /* > * To avoid race condition with ffs_epfile_io_complete, > * dequeue the request first then check > @@ -1084,6 +1089,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) > * condition with req->complete callback. > */ > usb_ep_dequeue(ep->ep, req); > + spin_unlock_irq(&epfile->ffs->eps_lock); > wait_for_completion(&io_data->done); > interrupted = true; > } > -- > 2.7.4 >
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index dcba835..b6c9b44 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1077,6 +1077,11 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); if (wait_for_completion_interruptible(&io_data->done)) { + spin_lock_irq(&epfile->ffs->eps_lock); + if (epfile->ep != ep) { + ret = -ESHUTDOWN; + goto error_lock; + } /* * To avoid race condition with ffs_epfile_io_complete, * dequeue the request first then check @@ -1084,6 +1089,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) * condition with req->complete callback. */ usb_ep_dequeue(ep->ep, req); + spin_unlock_irq(&epfile->ffs->eps_lock); wait_for_completion(&io_data->done); interrupted = true; }
In ffs_epfile_io(), when read/write data in blocking mode, it will wait the completion in interruptible mode, if task receive a signal, it will terminate the wait, at same time, if function unbind occurs, ffs_func_unbind() will kfree all eps, ffs_epfile_io() still try to dequeue request by dereferencing ep which may become invalid. Fix it by add ep spinlock and will not dereference ep if it is not valid. Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com> --- drivers/usb/gadget/function/f_fs.c | 6 ++++++ 1 file changed, 6 insertions(+)