On Thu, 28 Jun 2012, Matthieu CASTET wrote:

> 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 <matthieu.cas...@parrot.com>
> ---
>  drivers/hid/hidraw.c |   12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
> index 36fa77b..3b6f7bf 100644
> --- a/drivers/hid/hidraw.c
> +++ b/drivers/hid/hidraw.c
> @@ -96,6 +96,7 @@ static ssize_t hidraw_read(struct file *file, char __user 
> *buffer, size_t count,
>               }
>  
>               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 * inode, struct 
> file * file)
>       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 * inode, struct 
> file * file)
>                       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_device *hid, u8 
> *data, int len)
>       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);
>       }
>  

Applied, thank you Matthieu.

-- 
Jiri Kosina
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to