Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6992effe authored by Ezequiel Garcia's avatar Ezequiel Garcia Committed by Mauro Carvalho Chehab
Browse files

media: gspca: Kill all URBs before releasing any of them



Some subdrivers access the gspca_dev->urb array in the completion handler.
To prevent use-after-free (actually, NULL dereferences) we need to
synchronously kill all the URBs before we release them.

In particular, this is currently the case for drivers such
as sn9c20x and sonixj, which access the gspca_dev->urb[0]
in the context of completion handler for *any* of the URBs.

This commit changes the destroy_urb implementation, so it kills
all URBs first, and then proceed to set the URBs to NULL in the
array and release them.

Signed-off-by: default avatarEzequiel Garcia <ezequiel@collabora.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent df95e82f
Loading
Loading
Loading
Loading
+11 −4
Original line number Original line Diff line number Diff line
@@ -472,13 +472,20 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
	unsigned int i;
	unsigned int i;


	gspca_dbg(gspca_dev, D_STREAM, "kill transfer\n");
	gspca_dbg(gspca_dev, D_STREAM, "kill transfer\n");

	/* Killing all URBs guarantee that no URB completion
	 * handler is running. Therefore, there shouldn't
	 * be anyone trying to access gspca_dev->urb[i]
	 */
	for (i = 0; i < MAX_NURBS; i++)
		usb_kill_urb(gspca_dev->urb[i]);

	gspca_dbg(gspca_dev, D_STREAM, "releasing urbs\n");
	for (i = 0; i < MAX_NURBS; i++) {
	for (i = 0; i < MAX_NURBS; i++) {
		urb = gspca_dev->urb[i];
		urb = gspca_dev->urb[i];
		if (urb == NULL)
		if (!urb)
			break;
			continue;

		gspca_dev->urb[i] = NULL;
		gspca_dev->urb[i] = NULL;
		usb_kill_urb(urb);
		usb_free_coherent(gspca_dev->dev,
		usb_free_coherent(gspca_dev->dev,
				  urb->transfer_buffer_length,
				  urb->transfer_buffer_length,
				  urb->transfer_buffer,
				  urb->transfer_buffer,