提交 fb1f16d7 编写于 作者: L Linyu Yuan 提交者: Greg Kroah-Hartman

usb: gadget: f_fs: change ep->status safe in ffs_epfile_io()

If a task read/write data in blocking mode, it will wait the completion
in ffs_epfile_io(), if function unbind occurs, ffs_func_unbind() will
kfree ffs ep, once the task wake up, it still dereference the ffs ep to
obtain the request status.

Fix it by moving the request status to io_data which is stack-safe.

Cc: <stable@vger.kernel.org> # 5.15
Reported-by: NMichael Wu <michael@allwinnertech.com>
Tested-by: NMichael Wu <michael@allwinnertech.com>
Reviewed-by: NJohn Keeping <john@metanate.com>
Signed-off-by: NLinyu Yuan <quic_linyyuan@quicinc.com>
Link: https://lore.kernel.org/r/1654863478-26228-2-git-send-email-quic_linyyuan@quicinc.comSigned-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 802dcafc
...@@ -122,8 +122,6 @@ struct ffs_ep { ...@@ -122,8 +122,6 @@ struct ffs_ep {
struct usb_endpoint_descriptor *descs[3]; struct usb_endpoint_descriptor *descs[3];
u8 num; u8 num;
int status; /* P: epfile->mutex */
}; };
struct ffs_epfile { struct ffs_epfile {
...@@ -227,6 +225,9 @@ struct ffs_io_data { ...@@ -227,6 +225,9 @@ struct ffs_io_data {
bool use_sg; bool use_sg;
struct ffs_data *ffs; struct ffs_data *ffs;
int status;
struct completion done;
}; };
struct ffs_desc_helper { struct ffs_desc_helper {
...@@ -707,12 +708,15 @@ static const struct file_operations ffs_ep0_operations = { ...@@ -707,12 +708,15 @@ static const struct file_operations ffs_ep0_operations = {
static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
{ {
struct ffs_io_data *io_data = req->context;
ENTER(); ENTER();
if (req->context) { if (req->status)
struct ffs_ep *ep = _ep->driver_data; io_data->status = req->status;
ep->status = req->status ? req->status : req->actual; else
complete(req->context); io_data->status = req->actual;
}
complete(&io_data->done);
} }
static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
...@@ -1050,7 +1054,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ...@@ -1050,7 +1054,6 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
WARN(1, "%s: data_len == -EINVAL\n", __func__); WARN(1, "%s: data_len == -EINVAL\n", __func__);
ret = -EINVAL; ret = -EINVAL;
} else if (!io_data->aio) { } else if (!io_data->aio) {
DECLARE_COMPLETION_ONSTACK(done);
bool interrupted = false; bool interrupted = false;
req = ep->req; req = ep->req;
...@@ -1066,7 +1069,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ...@@ -1066,7 +1069,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
io_data->buf = data; io_data->buf = data;
req->context = &done; init_completion(&io_data->done);
req->context = io_data;
req->complete = ffs_epfile_io_complete; req->complete = ffs_epfile_io_complete;
ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
...@@ -1075,7 +1079,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ...@@ -1075,7 +1079,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
spin_unlock_irq(&epfile->ffs->eps_lock); spin_unlock_irq(&epfile->ffs->eps_lock);
if (wait_for_completion_interruptible(&done)) { if (wait_for_completion_interruptible(&io_data->done)) {
/* /*
* To avoid race condition with ffs_epfile_io_complete, * To avoid race condition with ffs_epfile_io_complete,
* dequeue the request first then check * dequeue the request first then check
...@@ -1083,17 +1087,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) ...@@ -1083,17 +1087,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
* condition with req->complete callback. * condition with req->complete callback.
*/ */
usb_ep_dequeue(ep->ep, req); usb_ep_dequeue(ep->ep, req);
wait_for_completion(&done); wait_for_completion(&io_data->done);
interrupted = ep->status < 0; interrupted = io_data->status < 0;
} }
if (interrupted) if (interrupted)
ret = -EINTR; ret = -EINTR;
else if (io_data->read && ep->status > 0) else if (io_data->read && io_data->status > 0)
ret = __ffs_epfile_read_data(epfile, data, ep->status, ret = __ffs_epfile_read_data(epfile, data, io_data->status,
&io_data->data); &io_data->data);
else else
ret = ep->status; ret = io_data->status;
goto error_mutex; goto error_mutex;
} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) { } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
ret = -ENOMEM; ret = -ENOMEM;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册