]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mei: fix possible integer overflow issue
authorTomas Winkler <tomas.winkler@intel.com>
Sun, 7 Feb 2016 21:35:19 +0000 (23:35 +0200)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 30 Apr 2016 22:05:49 +0000 (00:05 +0200)
commit f862b6b24f0ffd954633a55f39251a6873b664ca upstream.

There is a possible integer overflow following by a buffer overflow
when accumulating messages coming from the FW to compose a full payload.
Occurrence of wrap around has to be prevented for next message size
calculation.
For unsigned integer the addition overflow has occurred when the
result is smaller than one of the arguments.
To simplify the fix, the types of buf.size and buf_idx are set to the
same width, namely size_t also to be aligned with the type of length
parameter in file read/write ops.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.16:
 - Adjust context, indentation
 - Return error directly, rather than through cb->status and the completion list
 - Fix up additional format string in mei_cl_write()]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/misc/mei/amthif.c
drivers/misc/mei/client.c
drivers/misc/mei/interrupt.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h

index 0d6234db00fa126330a664007e4093aac14a6190..fb1c82f8db0214bd1dcaea3afa1e46f96d3a4574 100644 (file)
@@ -234,9 +234,8 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
                 * remove message from deletion list
                 */
 
-       dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer size - %d\n",
-           cb->response_buffer.size);
-       dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
+       dev_dbg(&dev->pdev->dev, "amthif cb->response_buffer.size - %zd cb->buf_idx - %zd\n",
+               cb->response_buffer.size, cb->buf_idx);
 
        /* length is being truncated to PAGE_SIZE, however,
         * the buf_idx may point beyond */
index 2da05c0e113d0b62d917e4de4b12e15b46defac8..57af788ea05f88b6d734b74ecf1edc769438c7be 100644 (file)
@@ -849,7 +849,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
                return 0;
        }
 
-       cl_dbg(dev, cl, "buf: size = %d idx = %lu\n",
+       cl_dbg(dev, cl, "buf: size = %zd idx = %zd\n",
                        cb->request_buffer.size, cb->buf_idx);
 
        rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx);
@@ -900,7 +900,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
 
        buf = &cb->request_buffer;
 
-       cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size);
+       cl_dbg(dev, cl, "mei_cl_write %zu\n", buf->size);
 
        rets = pm_runtime_get(&dev->pdev->dev);
        if (rets < 0 && rets != -EINPROGRESS) {
index 4e3cba6da3f5cccd32d4ee623f91fe5c03655816..bc1c4f51bf9dba03b38513c75602248ef3e46808 100644 (file)
@@ -102,6 +102,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
        struct mei_cl *cl;
        struct mei_cl_cb *cb, *next;
        unsigned char *buffer = NULL;
+       size_t buf_sz;
 
        list_for_each_entry_safe(cb, next, &dev->read_list.list, list) {
                cl = cb->cl;
@@ -117,13 +118,21 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
                        return -ENOMEM;
                }
 
-               if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) {
-                       cl_dbg(dev, cl, "message overflow. size %d len %d idx %ld\n",
+               buf_sz = mei_hdr->length + cb->buf_idx;
+               /* catch for integer overflow */
+               if (buf_sz < cb->buf_idx) {
+                       cl_err(dev, cl, "message is too big len %d idx %ld\n",
+                              mei_hdr->length, cb->buf_idx);
+       
+                       list_del(&cb->list);
+                       return -EMSGSIZE;
+               }
+       
+               if (cb->response_buffer.size < buf_sz) {
+                       cl_dbg(dev, cl, "message overflow. size %zd len %d idx %zd\n",
                                cb->response_buffer.size,
                                mei_hdr->length, cb->buf_idx);
-                       buffer = krealloc(cb->response_buffer.data,
-                                         mei_hdr->length + cb->buf_idx,
-                                         GFP_KERNEL);
+                       buffer = krealloc(cb->response_buffer.data, buf_sz, GFP_KERNEL);
 
                        if (!buffer) {
                                cl_err(dev, cl, "allocation failed.\n");
@@ -131,8 +140,7 @@ static int mei_cl_irq_read_msg(struct mei_device *dev,
                                return -ENOMEM;
                        }
                        cb->response_buffer.data = buffer;
-                       cb->response_buffer.size =
-                               mei_hdr->length + cb->buf_idx;
+                       cb->response_buffer.size = buf_sz;
                }
 
                buffer = cb->response_buffer.data + cb->buf_idx;
index 66f0a1a0645143b6b37d143b8fbfc43ce7a7d9a7..adeb3c745b949664ce21f7341b5c88abb1758f8b 100644 (file)
@@ -262,7 +262,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
        }
        /* now copy the data to user space */
 copy_buffer:
-       dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n",
+       dev_dbg(&dev->pdev->dev, "buf.size = %zd buf.idx = %zd\n",
            cb->response_buffer.size, cb->buf_idx);
        if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
                rets = -EMSGSIZE;
@@ -281,7 +281,8 @@ copy_buffer:
 
        rets = length;
        *offset += length;
-       if ((unsigned long)*offset < cb->buf_idx)
+       /* not all data was read, keep the cb */
+       if (*offset < cb->buf_idx)
                goto out;
 
 free:
index 5c7e990e2f22a7d5bda8e1d34c88150019754f2a..c5595089e4d8d7369b6dd0c04fd22e4f667b326e 100644 (file)
@@ -149,7 +149,7 @@ enum mei_cb_file_ops {
  * Intel MEI message data struct
  */
 struct mei_msg_data {
-       u32 size;
+       size_t size;
        unsigned char *data;
 };
 
@@ -195,7 +195,7 @@ struct mei_cl_cb {
        enum mei_cb_file_ops fop_type;
        struct mei_msg_data request_buffer;
        struct mei_msg_data response_buffer;
-       unsigned long buf_idx;
+       size_t buf_idx;
        unsigned long read_time;
        struct file *file_object;
        u32 internal:1;