3.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Matthieu CASTET <[email protected]>

commit 4c7b417ecb756e85dfc955b0e7a04fd45585533e upstream.

If we don't read fast enough hidraw device, hidraw_report_event
will cycle and we will leak list->buffer.
Also list->buffer are not free on release.
After this patch, kmemleak report nothing.

Signed-off-by: Matthieu CASTET <[email protected]>
Signed-off-by: Jiri Kosina <[email protected]>
Signed-off-by: Ben Hutchings <[email protected]>
Cc: Yijing Wang <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 drivers/hid/hidraw.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -96,6 +96,7 @@ static ssize_t hidraw_read(struct file *
                }
 
                kfree(list->buffer[list->tail].value);
+               list->buffer[list->tail].value = NULL;
                list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
        }
 out:
@@ -300,6 +301,7 @@ static int hidraw_release(struct inode *
        struct hidraw *dev;
        struct hidraw_list *list = file->private_data;
        int ret;
+       int i;
 
        mutex_lock(&minors_lock);
        if (!hidraw_table[minor]) {
@@ -317,6 +319,9 @@ static int hidraw_release(struct inode *
                        kfree(list->hidraw);
                }
        }
+
+       for (i = 0; i < HIDRAW_BUFFER_SIZE; ++i)
+               kfree(list->buffer[i].value);
        kfree(list);
        ret = 0;
 unlock:
@@ -446,12 +451,17 @@ int hidraw_report_event(struct hid_devic
        int ret = 0;
 
        list_for_each_entry(list, &dev->list, node) {
+               int new_head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
+
+               if (new_head == list->tail)
+                       continue;
+
                if (!(list->buffer[list->head].value = kmemdup(data, len, 
GFP_ATOMIC))) {
                        ret = -ENOMEM;
                        break;
                }
                list->buffer[list->head].len = len;
-               list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
+               list->head = new_head;
                kill_fasync(&list->fasync, SIGIO, POLL_IN);
        }
 


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to