Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: uvc: Allocate uvc_requests one at a time

Currently, the uvc gadget driver allocates all uvc_requests as one array
and deallocates them all when the video stream stops. This includes
de-allocating all the usb_requests associated with those uvc_requests.
This can lead to use-after-free issues if any of those de-allocated
usb_requests were still owned by the usb controller.

This patch is 1 of 2 patches addressing the use-after-free issue.
Instead of bulk allocating all uvc_requests as an array, this patch
allocates uvc_requests one at a time, which should allows for similar
granularity when deallocating the uvc_requests. This patch has no
functional changes other than allocating each uvc_request separately,
and similarly freeing each of them separately.

Link: https://lore.kernel.org/7cd81649-2795-45b6-8c10-b7df1055020d@google.com
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Suggested-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Tested-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: Avichal Rakesh <arakesh@google.com>
Link: https://lore.kernel.org/r/20231109004104.3467968-2-arakesh@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Avichal Rakesh and committed by
Greg Kroah-Hartman
aeb686a9 991544dc

+52 -41
+2 -1
drivers/usb/gadget/function/uvc.h
··· 81 81 struct sg_table sgt; 82 82 u8 header[UVCG_REQUEST_HEADER_LEN]; 83 83 struct uvc_buffer *last_buf; 84 + struct list_head list; 84 85 }; 85 86 86 87 struct uvc_video { ··· 103 102 104 103 /* Requests */ 105 104 unsigned int req_size; 106 - struct uvc_request *ureq; 105 + struct list_head ureqs; /* all uvc_requests allocated by uvc_video */ 107 106 struct list_head req_free; 108 107 spinlock_t req_lock; 109 108
+50 -40
drivers/usb/gadget/function/uvc_video.c
··· 227 227 * Request handling 228 228 */ 229 229 230 + static void 231 + uvc_video_free_request(struct uvc_request *ureq, struct usb_ep *ep) 232 + { 233 + sg_free_table(&ureq->sgt); 234 + if (ureq->req && ep) { 235 + usb_ep_free_request(ep, ureq->req); 236 + ureq->req = NULL; 237 + } 238 + 239 + kfree(ureq->req_buffer); 240 + ureq->req_buffer = NULL; 241 + 242 + if (!list_empty(&ureq->list)) 243 + list_del_init(&ureq->list); 244 + 245 + kfree(ureq); 246 + } 247 + 230 248 static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) 231 249 { 232 250 int ret; ··· 311 293 static int 312 294 uvc_video_free_requests(struct uvc_video *video) 313 295 { 314 - unsigned int i; 296 + struct uvc_request *ureq, *temp; 315 297 316 - if (video->ureq) { 317 - for (i = 0; i < video->uvc_num_requests; ++i) { 318 - sg_free_table(&video->ureq[i].sgt); 298 + list_for_each_entry_safe(ureq, temp, &video->ureqs, list) 299 + uvc_video_free_request(ureq, video->ep); 319 300 320 - if (video->ureq[i].req) { 321 - usb_ep_free_request(video->ep, video->ureq[i].req); 322 - video->ureq[i].req = NULL; 323 - } 324 - 325 - if (video->ureq[i].req_buffer) { 326 - kfree(video->ureq[i].req_buffer); 327 - video->ureq[i].req_buffer = NULL; 328 - } 329 - } 330 - 331 - kfree(video->ureq); 332 - video->ureq = NULL; 333 - } 334 - 301 + INIT_LIST_HEAD(&video->ureqs); 335 302 INIT_LIST_HEAD(&video->req_free); 336 303 video->req_size = 0; 337 304 return 0; ··· 325 322 static int 326 323 uvc_video_alloc_requests(struct uvc_video *video) 327 324 { 325 + struct uvc_request *ureq; 328 326 unsigned int req_size; 329 327 unsigned int i; 330 328 int ret = -ENOMEM; ··· 336 332 * max_t(unsigned int, video->ep->maxburst, 1) 337 333 * (video->ep->mult); 338 334 339 - video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL); 340 - if (video->ureq == NULL) 341 - return -ENOMEM; 342 - 343 - for (i = 0; i < video->uvc_num_requests; ++i) { 344 - video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL); 345 - if (video->ureq[i].req_buffer == NULL) 335 + for (i = 0; i < video->uvc_num_requests; i++) { 336 + ureq = kzalloc(sizeof(struct uvc_request), GFP_KERNEL); 337 + if (ureq == NULL) 346 338 goto error; 347 339 348 - video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL); 349 - if (video->ureq[i].req == NULL) 340 + INIT_LIST_HEAD(&ureq->list); 341 + 342 + list_add_tail(&ureq->list, &video->ureqs); 343 + 344 + ureq->req_buffer = kmalloc(req_size, GFP_KERNEL); 345 + if (ureq->req_buffer == NULL) 350 346 goto error; 351 347 352 - video->ureq[i].req->buf = video->ureq[i].req_buffer; 353 - video->ureq[i].req->length = 0; 354 - video->ureq[i].req->complete = uvc_video_complete; 355 - video->ureq[i].req->context = &video->ureq[i]; 356 - video->ureq[i].video = video; 357 - video->ureq[i].last_buf = NULL; 348 + ureq->req = usb_ep_alloc_request(video->ep, GFP_KERNEL); 349 + if (ureq->req == NULL) 350 + goto error; 358 351 359 - list_add_tail(&video->ureq[i].req->list, &video->req_free); 352 + ureq->req->buf = ureq->req_buffer; 353 + ureq->req->length = 0; 354 + ureq->req->complete = uvc_video_complete; 355 + ureq->req->context = ureq; 356 + ureq->video = video; 357 + ureq->last_buf = NULL; 358 + 359 + list_add_tail(&ureq->req->list, &video->req_free); 360 360 /* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */ 361 - sg_alloc_table(&video->ureq[i].sgt, 361 + sg_alloc_table(&ureq->sgt, 362 362 DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN, 363 363 PAGE_SIZE) + 2, GFP_KERNEL); 364 364 } ··· 497 489 */ 498 490 int uvcg_video_enable(struct uvc_video *video, int enable) 499 491 { 500 - unsigned int i; 501 492 int ret; 493 + struct uvc_request *ureq; 502 494 503 495 if (video->ep == NULL) { 504 496 uvcg_info(&video->uvc->func, ··· 510 502 cancel_work_sync(&video->pump); 511 503 uvcg_queue_cancel(&video->queue, 0); 512 504 513 - for (i = 0; i < video->uvc_num_requests; ++i) 514 - if (video->ureq && video->ureq[i].req) 515 - usb_ep_dequeue(video->ep, video->ureq[i].req); 505 + list_for_each_entry(ureq, &video->ureqs, list) { 506 + if (ureq->req) 507 + usb_ep_dequeue(video->ep, ureq->req); 508 + } 516 509 517 510 uvc_video_free_requests(video); 518 511 uvcg_queue_enable(&video->queue, 0); ··· 545 536 */ 546 537 int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) 547 538 { 539 + INIT_LIST_HEAD(&video->ureqs); 548 540 INIT_LIST_HEAD(&video->req_free); 549 541 spin_lock_init(&video->req_lock); 550 542 INIT_WORK(&video->pump, uvcg_video_pump);