diff mbox series

Prevent buffer overflow in UVC Gadget setup handler

Message ID 20221201122141.8739-1-szymon.heidrich@gmail.com (mailing list archive)
State New, archived
Headers show
Series Prevent buffer overflow in UVC Gadget setup handler | expand

Commit Message

Szymon Heidrich Dec. 1, 2022, 12:21 p.m. UTC
Setup function uvc_function_setup permits control transfer
requests with up to 64 bytes of payload (UVC_MAX_REQUEST_SIZE),
data stage handler for OUT transfer uses memcpy to copy req->actual
bytes to uvc_event->data.data array of size 60. This may result
in an overflow of 4 bytes.

Signed-off-by: Szymon Heidrich <szymon.heidrich@gmail.com>
---
 drivers/usb/gadget/function/f_uvc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Greg KH Dec. 1, 2022, 12:28 p.m. UTC | #1
On Thu, Dec 01, 2022 at 01:21:41PM +0100, Szymon Heidrich wrote:
> Setup function uvc_function_setup permits control transfer
> requests with up to 64 bytes of payload (UVC_MAX_REQUEST_SIZE),
> data stage handler for OUT transfer uses memcpy to copy req->actual
> bytes to uvc_event->data.data array of size 60. This may result
> in an overflow of 4 bytes.
> 
> Signed-off-by: Szymon Heidrich <szymon.heidrich@gmail.com>
> ---
>  drivers/usb/gadget/function/f_uvc.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)

What commit id does this fix?  Is it needed for stable kernels?

thanks,

greg k-h
Szymon Heidrich Dec. 1, 2022, 12:44 p.m. UTC | #2
On 01/12/2022 13:28, Greg Kroah-Hartman wrote:
> On Thu, Dec 01, 2022 at 01:21:41PM +0100, Szymon Heidrich wrote:
>> Setup function uvc_function_setup permits control transfer
>> requests with up to 64 bytes of payload (UVC_MAX_REQUEST_SIZE),
>> data stage handler for OUT transfer uses memcpy to copy req->actual
>> bytes to uvc_event->data.data array of size 60. This may result
>> in an overflow of 4 bytes.
>>
>> Signed-off-by: Szymon Heidrich <szymon.heidrich@gmail.com>
>> ---
>>  drivers/usb/gadget/function/f_uvc.c | 5 +++--
>>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> What commit id does this fix?  Is it needed for stable kernels?
> 
> thanks,
> 
> greg k-h

As far as I understand this would be the original commit so cdda479f15cd13fa50a913ca85129c0437cc7b91.
I guess that it is also needed for stable kernels, yet please correct me if I'm wrong.

Best regards,
Szymon
Daniel Scally Dec. 1, 2022, 1:49 p.m. UTC | #3
Hello - thanks for the patch

On 01/12/2022 12:21, Szymon Heidrich wrote:
> Setup function uvc_function_setup


You've written uvc_function_setup here, but the code changes 
uvc_function_ep0_complete.

>   permits control transfer
> requests with up to 64 bytes of payload (UVC_MAX_REQUEST_SIZE),
> data stage handler for OUT transfer uses memcpy to copy req->actual
> bytes to uvc_event->data.data array of size 60. This may result
> in an overflow of 4 bytes.
>
> Signed-off-by: Szymon Heidrich <szymon.heidrich@gmail.com>


Good catch

> ---
>   drivers/usb/gadget/function/f_uvc.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
> index 6e196e061..69c5eb3a3 100644
> --- a/drivers/usb/gadget/function/f_uvc.c
> +++ b/drivers/usb/gadget/function/f_uvc.c
> @@ -216,8 +216,9 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
>   
>   		memset(&v4l2_event, 0, sizeof(v4l2_event));
>   		v4l2_event.type = UVC_EVENT_DATA;
> -		uvc_event->data.length = req->actual;
> -		memcpy(&uvc_event->data.data, req->buf, req->actual);
> +		uvc_event->data.length = (req->actual > sizeof(uvc_event->data.data) ?
> +			sizeof(uvc_event->data.data) : req->actual);


There's a clamp() macro in f_uvc.c, can we use that?

> +		memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length);
>   		v4l2_event_queue(&uvc->vdev, &v4l2_event);
>   	}
>   }
Szymon Heidrich Dec. 1, 2022, 2:22 p.m. UTC | #4
On 01/12/2022 14:49, Dan Scally wrote:
> Hello - thanks for the patch
> 
> On 01/12/2022 12:21, Szymon Heidrich wrote:
>> Setup function uvc_function_setup
> 
> 
> You've written uvc_function_setup here, but the code changes uvc_function_ep0_complete.

Yes, this was intentional as uvc_function_setup prevents handling of control
transfer requests with wLength grater than UVC_MAX_REQUEST_SIZE.
The uvc_function_ep0_complete function handles data phase thus was modified.

> 
>>   permits control transfer
>> requests with up to 64 bytes of payload (UVC_MAX_REQUEST_SIZE),
>> data stage handler for OUT transfer uses memcpy to copy req->actual
>> bytes to uvc_event->data.data array of size 60. This may result
>> in an overflow of 4 bytes.
>>
>> Signed-off-by: Szymon Heidrich <szymon.heidrich@gmail.com>
> 
> 
> Good catch
> 
>> ---
>>   drivers/usb/gadget/function/f_uvc.c | 5 +++--
>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
>> index 6e196e061..69c5eb3a3 100644
>> --- a/drivers/usb/gadget/function/f_uvc.c
>> +++ b/drivers/usb/gadget/function/f_uvc.c
>> @@ -216,8 +216,9 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
>>             memset(&v4l2_event, 0, sizeof(v4l2_event));
>>           v4l2_event.type = UVC_EVENT_DATA;
>> -        uvc_event->data.length = req->actual;
>> -        memcpy(&uvc_event->data.data, req->buf, req->actual);
>> +        uvc_event->data.length = (req->actual > sizeof(uvc_event->data.data) ?
>> +            sizeof(uvc_event->data.data) : req->actual);
> 
> 
> There's a clamp() macro in f_uvc.c, can we use that?
> 
>> +        memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length);
>>           v4l2_event_queue(&uvc->vdev, &v4l2_event);
>>       }
>>   }

If it is more appropriate I will use min_t(unsigned int, req->actual, sizeof(uvc_event->data.data)).
diff mbox series

Patch

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 6e196e061..69c5eb3a3 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -216,8 +216,9 @@  uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
 
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_DATA;
-		uvc_event->data.length = req->actual;
-		memcpy(&uvc_event->data.data, req->buf, req->actual);
+		uvc_event->data.length = (req->actual > sizeof(uvc_event->data.data) ?
+			sizeof(uvc_event->data.data) : req->actual);
+		memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length);
 		v4l2_event_queue(&uvc->vdev, &v4l2_event);
 	}
 }