Commit 4e1538b1 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull MMC fixes from Ulf Hansson:

 - vub300: Fix use-after-free and NULL-deref on disconnect

* tag 'mmc-v7.0-rc1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: vub300: fix use-after-free on disconnect
  mmc: vub300: fix NULL-deref on disconnect
parents d58305b2 8f4d20a7
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -369,11 +369,14 @@ struct vub300_mmc_host {
static void vub300_delete(struct kref *kref)
{				/* kref callback - softirq */
	struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
	struct mmc_host *mmc = vub300->mmc;

	usb_free_urb(vub300->command_out_urb);
	vub300->command_out_urb = NULL;
	usb_free_urb(vub300->command_res_urb);
	vub300->command_res_urb = NULL;
	usb_put_dev(vub300->udev);
	mmc_free_host(mmc);
	/*
	 * and hence also frees vub300
	 * which is contained at the end of struct mmc
@@ -2112,7 +2115,7 @@ static int vub300_probe(struct usb_interface *interface,
		goto error1;
	}
	/* this also allocates memory for our VUB300 mmc host device */
	mmc = devm_mmc_alloc_host(&udev->dev, sizeof(*vub300));
	mmc = mmc_alloc_host(sizeof(*vub300), &udev->dev);
	if (!mmc) {
		retval = -ENOMEM;
		dev_err(&udev->dev, "not enough memory for the mmc_host\n");
@@ -2269,7 +2272,7 @@ static int vub300_probe(struct usb_interface *interface,
		dev_err(&vub300->udev->dev,
		    "Could not find two sets of bulk-in/out endpoint pairs\n");
		retval = -EINVAL;
		goto error4;
		goto err_free_host;
	}
	retval =
		usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
@@ -2278,14 +2281,14 @@ static int vub300_probe(struct usb_interface *interface,
				0x0000, 0x0000, &vub300->hc_info,
				sizeof(vub300->hc_info), 1000);
	if (retval < 0)
		goto error4;
		goto err_free_host;
	retval =
		usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
				SET_ROM_WAIT_STATES,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				firmware_rom_wait_states, 0x0000, NULL, 0, 1000);
	if (retval < 0)
		goto error4;
		goto err_free_host;
	dev_info(&vub300->udev->dev,
		 "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
		 (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
@@ -2300,7 +2303,7 @@ static int vub300_probe(struct usb_interface *interface,
				0x0000, 0x0000, &vub300->system_port_status,
				sizeof(vub300->system_port_status), 1000);
	if (retval < 0) {
		goto error4;
		goto err_free_host;
	} else if (sizeof(vub300->system_port_status) == retval) {
		vub300->card_present =
			(0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
@@ -2308,7 +2311,7 @@ static int vub300_probe(struct usb_interface *interface,
			(0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
	} else {
		retval = -EINVAL;
		goto error4;
		goto err_free_host;
	}
	usb_set_intfdata(interface, vub300);
	INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
@@ -2338,6 +2341,8 @@ static int vub300_probe(struct usb_interface *interface,
	return 0;
error6:
	timer_delete_sync(&vub300->inactivity_timer);
err_free_host:
	mmc_free_host(mmc);
	/*
	 * and hence also frees vub300
	 * which is contained at the end of struct mmc
@@ -2365,8 +2370,8 @@ static void vub300_disconnect(struct usb_interface *interface)
			usb_set_intfdata(interface, NULL);
			/* prevent more I/O from starting */
			vub300->interface = NULL;
			kref_put(&vub300->kref, vub300_delete);
			mmc_remove_host(mmc);
			kref_put(&vub300->kref, vub300_delete);
			pr_info("USB vub300 remote SDIO host controller[%d]"
				" now disconnected", ifnum);
			return;