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

Commit c44a699d authored by Amit Pundir's avatar Amit Pundir
Browse files

usb: gadget: fix NULL ptr derefer while symlinking PTP func



Fix NULL pointer dereference while trying to link PTP
function to a gadget configuration without creating
MTP function.

PTP piggyback on MTP function so make sure we have
MTP function created beforehand. Otherwise we run
into following kernel panic:
-----------------------
[   70.329957] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[   70.330738] pgd = dd8ec000
[   70.330916] [00000000] *pgd=00000000
[   70.331663] Internal error: Oops: 805 [#1] SMP THUMB2
[   70.332155] CPU: 0 PID: 2067 Comm: ln Not tainted 3.18.0-00587-gdfa582e #1
[   70.332511] task: dd9c92c0 ti: dd822000 task.ti: dd822000
[   70.333094] PC is at function_alloc_mtp_ptp+0xe/0x68
[   70.333311] LR is at usb_get_function+0x11/0x1c
[   70.333489] pc : [<c034ec12>]    lr : [<c033cce9>]    psr: 60070033
<..snip..>
[   70.384111] 3fc0: bec14ae4 00000004 bec14c0a 00000053 00000004 b6f0422d 00000000 bec14adc
[   70.384369] 3fe0: bec14af8 bec14a98 b6f071f3 b6e8977c 20070010 bec14c0d 00000000 00000000
[   70.384832] [<c034ec12>] (function_alloc_mtp_ptp) from [<c033cce9>] (usb_get_function+0x11/0x1c)
[   70.385146] [<c033cce9>] (usb_get_function) from [<c033da9b>] (config_usb_cfg_link+0x87/0xa8)
[   70.385421] [<c033da9b>] (config_usb_cfg_link) from [<c011f417>] (configfs_symlink+0xb7/0x1c8)
[   70.385696] [<c011f417>] (configfs_symlink) from [<c00dcd8d>] (vfs_symlink+0x85/0xc0)
[   70.386010] [<c00dcd8d>] (vfs_symlink) from [<c00dce0b>] (SyS_symlinkat+0x43/0x70)
[   70.386261] [<c00dce0b>] (SyS_symlinkat) from [<c000ce41>] (ret_fast_syscall+0x1/0x5c)
[   70.386610] Code: eb04 4a0f 6e03 480f (e883) 0005
[   70.387346] ---[ end trace 8dba7c552e02f8fa ]---
[   70.387647] Kernel panic - not syncing: Fatal exception
[   70.387980] ---[ end Kernel panic - not syncing: Fatal exception
-----------------------

Steps to reproduce the kernel panic:

mount -t configfs none /config
mkdir /config/usb_gadget/g1
cd /config/usb_gadget/g1
echo 0x18d1 > idVendor
echo 0x4e26 > idProduct
mkdir strings/0x409
echo 0123459876 > strings/0x409/serialnumber
echo Asus > strings/0x409/manufacturer
echo Nexus7 > strings/0x409/product
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "Conf 1" > configs/c.1/strings/0x409/configuration
echo 120 > configs/c.1/MaxPower
mkdir functions/ptp.ptp
ln -s functions/ptp.ptp configs/c.1/ptp.ptp

Also MTP and PTP are mutually exclusive functions
so make sure we have only one of it linked to a
configuration at a time. Otherwise it opens up
another set of bug(s?).

Signed-off-by: default avatarAmit Pundir <amit.pundir@linaro.org>
parent dfa582e6
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -436,6 +436,11 @@ static int config_usb_cfg_link(
	}

	f = usb_get_function(fi);
	if (f == NULL) {
		/* Are we trying to symlink PTP without MTP function? */
		ret = -EINVAL; /* Invalid Configuration */
		goto out;
	}
	if (IS_ERR(f)) {
		ret = PTR_ERR(f);
		goto out;
+17 −1
Original line number Diff line number Diff line
@@ -1426,8 +1426,24 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi,
					bool mtp_config)
{
	struct mtp_instance *fi_mtp = to_fi_mtp(fi);
	struct mtp_dev *dev = fi_mtp->dev;
	struct mtp_dev *dev;

	/*
	 * PTP piggybacks on MTP function so make sure we have
	 * created MTP function before we associate this PTP
	 * function with a gadget configuration.
	 */
	if (fi_mtp->dev == NULL) {
		pr_err("Error: Create MTP function before linking"
				" PTP function with a gadget configuration\n");
		pr_err("\t1: Delete existing PTP function if any\n");
		pr_err("\t2: Create MTP function\n");
		pr_err("\t3: Create and symlink PTP function"
				" with a gadget configuration\n");
		return NULL;
	}

	dev = fi_mtp->dev;
	dev->function.name = DRIVER_NAME;
	dev->function.strings = mtp_strings;
	if (mtp_config) {
+1 −1
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ struct usb_function *usb_get_function(struct usb_function_instance *fi)
	struct usb_function *f;

	f = fi->fd->alloc_func(fi);
	if (IS_ERR(f))
	if ((f == NULL) || IS_ERR(f))
		return f;
	f->fi = fi;
	return f;