Skip to content

Commit 90bc2af

Browse files
AlanSterngregkh
authored andcommitted
USB: gadget: Fix double-free bug in raw_gadget driver
Re-reading a recently merged fix to the raw_gadget driver showed that it inadvertently introduced a double-free bug in a failure pathway. If raw_ioctl_init() encounters an error after the driver ID number has been allocated, it deallocates the ID number before returning. But when dev_free() runs later on, it will then try to deallocate the ID number a second time. Closely related to this issue is another error in the recent fix: The ID number is stored in the raw_dev structure before the code checks to see whether the structure has already been initialized, in which case the new ID number would overwrite the earlier value. The solution to both bugs is to keep the new ID number in a local variable, and store it in the raw_dev structure only after the check for prior initialization. No errors can occur after that point, so the double-free will never happen. Fixes: f2d8c26 ("usb: gadget: Fix non-unique driver names in raw-gadget driver") CC: Andrey Konovalov <[email protected]> CC: <[email protected]> Signed-off-by: Alan Stern <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8ffdc53 commit 90bc2af

File tree

1 file changed

+7
-6
lines changed

1 file changed

+7
-6
lines changed

drivers/usb/gadget/legacy/raw_gadget.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ static int raw_release(struct inode *inode, struct file *fd)
430430
static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
431431
{
432432
int ret = 0;
433+
int driver_id_number;
433434
struct usb_raw_init arg;
434435
char *udc_driver_name;
435436
char *udc_device_name;
@@ -452,18 +453,17 @@ static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
452453
return -EINVAL;
453454
}
454455

455-
ret = ida_alloc(&driver_id_numbers, GFP_KERNEL);
456-
if (ret < 0)
457-
return ret;
458-
dev->driver_id_number = ret;
456+
driver_id_number = ida_alloc(&driver_id_numbers, GFP_KERNEL);
457+
if (driver_id_number < 0)
458+
return driver_id_number;
459459

460460
driver_driver_name = kmalloc(DRIVER_DRIVER_NAME_LENGTH_MAX, GFP_KERNEL);
461461
if (!driver_driver_name) {
462462
ret = -ENOMEM;
463463
goto out_free_driver_id_number;
464464
}
465465
snprintf(driver_driver_name, DRIVER_DRIVER_NAME_LENGTH_MAX,
466-
DRIVER_NAME ".%d", dev->driver_id_number);
466+
DRIVER_NAME ".%d", driver_id_number);
467467

468468
udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
469469
if (!udc_driver_name) {
@@ -507,6 +507,7 @@ static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
507507
dev->driver.driver.name = driver_driver_name;
508508
dev->driver.udc_name = udc_device_name;
509509
dev->driver.match_existing_only = 1;
510+
dev->driver_id_number = driver_id_number;
510511

511512
dev->state = STATE_DEV_INITIALIZED;
512513
spin_unlock_irqrestore(&dev->lock, flags);
@@ -521,7 +522,7 @@ static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
521522
out_free_driver_driver_name:
522523
kfree(driver_driver_name);
523524
out_free_driver_id_number:
524-
ida_free(&driver_id_numbers, dev->driver_id_number);
525+
ida_free(&driver_id_numbers, driver_id_number);
525526
return ret;
526527
}
527528

0 commit comments

Comments
 (0)