struct printer_dev contains 3 list heads: tx_reqs, rx_reqs and rx_buffers.
There is just one instance of this structure in the driver and it is
file static, and as such initialized with all zeros.

If device_create() or cdev_add() fails then "goto fail" branch is taken,
which results in printer_cfg_unbind() call. The latter checks if
tx_reqs, rx_reqs and rx_buffers lists are empty. The check for emptiness
is in fact a check whether the "next" member of struct list_head points
to the head of the list. But the heads of the lists in question have
not been initialized yet and, as mentioned above, contain all zeros,
so list_empty() returns false and respective "while" loop body starts
executing. Here, container_of() just subtracts the offset of a struct
usb_request member from an address of this same member, which results in
a value somewhere near 0 or 0xfff...ff. And the argument to list_del()
dereferences such a pointer which causes a disaster.

This patch moves respective INIT_LIST_HEAD() invocations to a point before
"goto fail" branch can be taken.

Signed-off-by: Andrzej Pietrasiewicz <andrze...@samsung.com>
---
 drivers/usb/gadget/legacy/printer.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/legacy/printer.c 
b/drivers/usb/gadget/legacy/printer.c
index 21ea317..12247d3 100644
--- a/drivers/usb/gadget/legacy/printer.c
+++ b/drivers/usb/gadget/legacy/printer.c
@@ -1190,6 +1190,9 @@ static int __init printer_bind_config(struct 
usb_configuration *c)
        dev->function.unbind = printer_func_unbind;
        dev->function.set_alt = printer_func_set_alt;
        dev->function.disable = printer_func_disable;
+       INIT_LIST_HEAD(&dev->tx_reqs);
+       INIT_LIST_HEAD(&dev->rx_reqs);
+       INIT_LIST_HEAD(&dev->rx_buffers);
 
        status = usb_add_function(c, &dev->function);
        if (status)
@@ -1233,11 +1236,8 @@ static int __init printer_bind_config(struct 
usb_configuration *c)
 
        spin_lock_init(&dev->lock);
        mutex_init(&dev->lock_printer_io);
-       INIT_LIST_HEAD(&dev->tx_reqs);
        INIT_LIST_HEAD(&dev->tx_reqs_active);
-       INIT_LIST_HEAD(&dev->rx_reqs);
        INIT_LIST_HEAD(&dev->rx_reqs_active);
-       INIT_LIST_HEAD(&dev->rx_buffers);
        init_waitqueue_head(&dev->rx_wait);
        init_waitqueue_head(&dev->tx_wait);
        init_waitqueue_head(&dev->tx_flush_wait);
-- 
1.9.1

--
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