Commit 81ebd43c authored by Michael Zimmermann's avatar Michael Zimmermann Committed by Greg Kroah-Hartman
Browse files

usb: gadget: f_hid: don't call cdev_init while cdev in use

When calling unbind, then bind again, cdev_init reinitialized the cdev,
even though there may still be references to it. That's the case when
the /dev/hidg* device is still opened. This obviously unsafe behavior
like oopes.

This fixes this by using cdev_alloc to put the cdev on the heap. That
way, we can simply allocate a new one in hidg_bind.

Closes: https://lore.kernel.org/linux-usb/CAN9vWDKZn0Ts5JyV2_xcAmbnBEi0znMLg_USMFrShRryXrgWGQ@mail.gmail.com/T/#m2cb0dba3633b67b2a679c98499508267d1508881


Cc: stable <stable@kernel.org>
Signed-off-by: default avatarMichael Zimmermann <sigmaepsilon92@gmail.com>
Link: https://patch.msgid.link/20260327192209.59945-1-sigmaepsilon92@gmail.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0c893564
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ struct f_hidg {
	struct list_head		report_list;

	struct device			dev;
	struct cdev			cdev;
	struct cdev			*cdev;
	struct usb_function		func;

	struct usb_ep			*in_ep;
@@ -749,8 +749,9 @@ static int f_hidg_release(struct inode *inode, struct file *fd)

static int f_hidg_open(struct inode *inode, struct file *fd)
{
	struct kobject *parent = inode->i_cdev->kobj.parent;
	struct f_hidg *hidg =
		container_of(inode->i_cdev, struct f_hidg, cdev);
		container_of(parent, struct f_hidg, dev.kobj);

	fd->private_data = hidg;

@@ -1285,8 +1286,12 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
	}

	/* create char device */
	cdev_init(&hidg->cdev, &f_hidg_fops);
	status = cdev_device_add(&hidg->cdev, &hidg->dev);
	hidg->cdev = cdev_alloc();
	if (!hidg->cdev)
		goto fail_free_all;
	hidg->cdev->ops = &f_hidg_fops;

	status = cdev_device_add(hidg->cdev, &hidg->dev);
	if (status)
		goto fail_free_all;

@@ -1588,7 +1593,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
{
	struct f_hidg *hidg = func_to_hidg(f);

	cdev_device_del(&hidg->cdev, &hidg->dev);
	cdev_device_del(hidg->cdev, &hidg->dev);
	destroy_workqueue(hidg->workqueue);
	usb_free_all_descriptors(f);
}