summaryrefslogtreecommitdiff
path: root/drivers/misc/mei/main.c
diff options
context:
space:
mode:
authorAlexander Usyskin <alexander.usyskin@intel.com>2016-02-11 00:57:26 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-12 06:23:28 +0300
commit6cbb097fd3903fd6b419303ee8dc7f72b47d06f0 (patch)
tree13d2152de62e022094670c248962f5c83c702f55 /drivers/misc/mei/main.c
parent3ca9b1ac28398c6fe0bed335d2d71a35e1c5f7c9 (diff)
downloadlinux-6cbb097fd3903fd6b419303ee8dc7f72b47d06f0.tar.xz
mei: fix double freeing of a cb during link reset
Fix double freeing of the cb that can happen if link reset kicks in the middle of blocked write from a device on the cl bus. Free cb inside mei_cl_write function on failure and drop cb free operation from callers, during a link reset the mei_cl_write function returns with an error, but the caller doesn't know if the cb was already queued or not so it doesn't know if the cb will be freed upon queue reclaim or it has to free it itself. Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei/main.c')
-rw-r--r--drivers/misc/mei/main.c26
1 files changed, 10 insertions, 16 deletions
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 17970163eacc..05775a6f7c88 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -267,7 +267,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
- struct mei_cl_cb *write_cb = NULL;
+ struct mei_cl_cb *cb;
struct mei_device *dev;
int rets;
@@ -305,36 +305,30 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
}
*offset = 0;
- write_cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
- if (!write_cb) {
+ cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file);
+ if (!cb) {
rets = -ENOMEM;
goto out;
}
- rets = copy_from_user(write_cb->buf.data, ubuf, length);
+ rets = copy_from_user(cb->buf.data, ubuf, length);
if (rets) {
dev_dbg(dev->dev, "failed to copy data from userland\n");
rets = -EFAULT;
+ mei_io_cb_free(cb);
goto out;
}
if (cl == &dev->iamthif_cl) {
- rets = mei_amthif_write(cl, write_cb);
-
- if (rets) {
- dev_err(dev->dev,
- "amthif write failed with status = %d\n", rets);
- goto out;
- }
- mutex_unlock(&dev->device_lock);
- return length;
+ rets = mei_amthif_write(cl, cb);
+ if (!rets)
+ rets = length;
+ goto out;
}
- rets = mei_cl_write(cl, write_cb, false);
+ rets = mei_cl_write(cl, cb, false);
out:
mutex_unlock(&dev->device_lock);
- if (rets < 0)
- mei_io_cb_free(write_cb);
return rets;
}