Re: [PATCH 17/24] au0828: fix possible race condition in usage of dev->ctrlmsg
On Thu, Aug 9, 2012 at 7:48 PM, Mauro Carvalho Chehab
<mchehab@xxxxxxxxxx> wrote:
> Em 06-08-2012 23:47, Devin Heitmueller escreveu:
>> The register read function is referencing the dev->ctrlmsg structure outside
>> of the dev->mutex lock, which can cause corruption of the value if multiple
>> callers are invoking au0828_readreg() simultaneously.
>>
>> Use a stack variable to hold the result, and copy the buffer returned by
>> usb_control_msg() to that variable.
>
> It is NOT OK to use stack to send and/or receive control messages. The USB core
> uses DMA transfers for sending/receiving data via USB; the memory used by stack
> is not warranted to be at the DMA-able area. This problem is more frequent on
> ARM-based machines, but even on Intel, the urb_control_msg() may fail.
>
>>
>> In reality, the whole recv_control_msg() function can probably be collapsed
>> into au0288_readreg() since it is the only caller.
>>
>> Also get rid of cmd_msg_dump() since the only case in which the function is
>> ever called only is ever passed a single byte for the response (and it is
>> already logged).
>>
>> Signed-off-by: Devin Heitmueller <dheitmueller@xxxxxxxxxxxxxx>
>> ---
>> drivers/media/video/au0828/au0828-core.c | 40 +++++++++---------------------
>> 1 files changed, 12 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
>> index 65914bc..745a80a 100644
>> --- a/drivers/media/video/au0828/au0828-core.c
>> +++ b/drivers/media/video/au0828/au0828-core.c
>> @@ -56,9 +56,12 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
>>
>> u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
>> {
>> - recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
>> - dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]);
>> - return dev->ctrlmsg[0];
>> + u8 result = 0;
>> +
>> + recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
>
> As explained above, this won't work, as result is at stack, not warranted to be at the
> DMA-able area. So, either you could lock this function, or you'll need to allocate
> it with kmalloc() and free it after using the data.
>
>> + dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
>> +
>> + return result;
>> }
>>
>> u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
>> @@ -67,24 +70,6 @@ u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
>> return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
>> }
>>
>> -static void cmd_msg_dump(struct au0828_dev *dev)
>> -{
>> - int i;
>> -
>> - for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
>> - dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
>> - "%02x %02x %02x %02x %02x %02x %02x %02x\n",
>> - __func__,
>> - dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
>> - dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
>> - dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
>> - dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
>> - dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
>> - dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
>> - dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
>> - dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
>> -}
>> -
>> static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
>> u16 index)
>> {
>> @@ -118,24 +103,23 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
>> int status = -ENODEV;
>> mutex_lock(&dev->mutex);
>> if (dev->usbdev) {
>> -
>> - memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
>> -
>> - /* cp must be memory that has been allocated by kmalloc */
>> status = usb_control_msg(dev->usbdev,
>> usb_rcvctrlpipe(dev->usbdev, 0),
>> request,
>> USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
>> value, index,
>> - cp, size, 1000);
>> + dev->ctrlmsg, size, 1000);
>>
>> status = min(status, 0);
>>
>> if (status < 0) {
>> printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
>> __func__, status);
>> - } else
>> - cmd_msg_dump(dev);
>> + }
>> +
>> + /* the host controller requires heap allocated memory, which
>> + is why we didn't just pass "cp" into usb_control_msg */
>> + memcpy(cp, dev->ctrlmsg, size);
>> }
>> mutex_unlock(&dev->mutex);
>> return status;
>>
>
> Regards,
> Mauro
Hi Mauro,
You seem to have misinterpreted the patch description. The actual
call to usb_control_msg() does use a heap allocated memory region.
However we copy the result to a stack variable after the call to
usb_control_msg. This is done so that dev->ctrlmsg[] is used
exclusively inside of the mutex (and not accessed after the mutex is
unlocked).
The change basically goes from:
au0828_readreg() -> recv_control_msg(heap) -> usb_control_msg(heap)
to:
au0828_readreg() -> recv_control_msg(stack) -> usb_control_msg(heap)
In both cases the call into the USB stack provides heap allocated memory.
Please review the implementation of the static recv_control_msg()
function, and if you have any further questions let me know.
Thanks,
Devin
--
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
[Linux Input]
[Video for Linux]
[Mplayer Users]
[Linux USB Devel]
[Linux Audio Users]
[Photos]
[Yosemite Photos]
[Linux Kernel]
[Linux SCSI]
[XFree86]
[Devices]
[Yosemite Backpacking]