Re: WARNING in hso_free_net_device

2019-09-05 Thread Hui Peng



On 9/5/2019 7:24 AM, Andrey Konovalov wrote:
> On Thu, Sep 5, 2019 at 4:20 AM Hui Peng  wrote:
>>
>> Can you guys have  a look at the attached patch?
> 
> Let's try it:
> 
> #syz test: https://github.com/google/kasan.git eea39f24
> 
> FYI: there are two more reports coming from this driver, which might
> (or might not) have the same root cause. One of them has a suggested
> fix by Oliver.
> 
> https://syzkaller.appspot.com/bug?extid=67b2bd0e34f952d0321e
> https://syzkaller.appspot.com/bug?extid=93f2f45b19519b289613
> 

I think they are different, though similar.
This one is resulted from unregistering a network device.
These 2 are resulted from unregistering a tty device.

>>
>> On 9/4/19 6:41 PM, Stephen Hemminger wrote:
>>> On Wed, 4 Sep 2019 16:27:50 -0400
>>> Hui Peng  wrote:
>>>
>>>> Hi, all:
>>>>
>>>> I looked at the bug a little.
>>>>
>>>> The issue is that in the error handling code, hso_free_net_device
>>>> unregisters
>>>>
>>>> the net_device (hso_net->net)  by calling unregister_netdev. In the
>>>> error handling code path,
>>>>
>>>> hso_net->net has not been registered yet.
>>>>
>>>> I think there are two ways to solve the issue:
>>>>
>>>> 1. fix it in drivers/net/usb/hso.c to avoiding unregistering the
>>>> net_device when it is still not registered
>>>>
>>>> 2. fix it in unregister_netdev. We can add a field in net_device to
>>>> record whether it is registered, and make unregister_netdev return if
>>>> the net_device is not registered yet.
>>>>
>>>> What do you guys think ?
>>> #1


Re: WARNING in hso_free_net_device

2019-09-04 Thread Hui Peng
Can you guys have  a look at the attached patch?

On 9/4/19 6:41 PM, Stephen Hemminger wrote:
> On Wed, 4 Sep 2019 16:27:50 -0400
> Hui Peng  wrote:
>
>> Hi, all:
>>
>> I looked at the bug a little.
>>
>> The issue is that in the error handling code, hso_free_net_device
>> unregisters
>>
>> the net_device (hso_net->net)  by calling unregister_netdev. In the
>> error handling code path,
>>
>> hso_net->net has not been registered yet.
>>
>> I think there are two ways to solve the issue:
>>
>> 1. fix it in drivers/net/usb/hso.c to avoiding unregistering the
>> net_device when it is still not registered
>>
>> 2. fix it in unregister_netdev. We can add a field in net_device to
>> record whether it is registered, and make unregister_netdev return if
>> the net_device is not registered yet.
>>
>> What do you guys think ?
> #1
From f3fdee8fc03aa2bc982f22da1d29bbf6bca72935 Mon Sep 17 00:00:00 2001
From: Hui Peng 
Date: Wed, 4 Sep 2019 21:38:35 -0400
Subject: [PATCH] Fix a wrong unregistering bug in hso_free_net_device

As shown below, hso_create_net_device may call hso_free_net_device
before the net_device is registered. hso_free_net_device will
unregister the network device no matter it is registered or not,
unregister_netdev is not able to handle unregistered net_device,
resulting in the bug reported by the syzbot.

```
static struct hso_device *hso_create_net_device(struct usb_interface *interface,
	   int port_spec)
{
	..
	net = alloc_netdev(sizeof(struct hso_net), "hso%d", NET_NAME_UNKNOWN,
  			hso_net_init);
	..
	if (!hso_net->out_endp) {
   	   	dev_err(&interface->dev, "Can't find BULK OUT endpoint\n");
		goto exit;
	}

	..
	result = register_netdev(net);
	..
exit:
	hso_free_net_device(hso_dev);
	return NULL;
}

static void hso_free_net_device(struct hso_device *hso_dev)
{
	..
	if (hso_net->net)
		unregister_netdev(hso_net->net);
	..
}

```

This patch adds a net_registered field in struct hso_net to record whether
the containing net_device is registered or not, and avoid unregistering it
if it is not registered yet.

Reported-by: syzbot+44d53c7255bb1aea2...@syzkaller.appspotmail.com
Signed-off-by: Hui Peng 
---
 drivers/net/usb/hso.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index ce78714..5b3df33 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -128,6 +128,7 @@ struct hso_shared_int {
 struct hso_net {
 	struct hso_device *parent;
 	struct net_device *net;
+	bool net_registered;
 	struct rfkill *rfkill;
 	char name[24];
 
@@ -2362,7 +2363,7 @@ static void hso_free_net_device(struct hso_device *hso_dev)
 
 	remove_net_device(hso_net->parent);
 
-	if (hso_net->net)
+	if (hso_net->net && hso_net->net_registered)
 		unregister_netdev(hso_net->net);
 
 	/* start freeing */
@@ -2544,6 +2545,7 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface,
 		dev_err(&interface->dev, "Failed to register device\n");
 		goto exit;
 	}
+	hso_net->net_registered = true;
 
 	hso_log_port(hso_dev);
 
-- 
2.7.4



pEpkey.asc
Description: application/pgp-keys


Re: WARNING in hso_free_net_device

2019-09-04 Thread Hui Peng
Hi, all:

I looked at the bug a little.

The issue is that in the error handling code, hso_free_net_device
unregisters

the net_device (hso_net->net)  by calling unregister_netdev. In the
error handling code path,

hso_net->net has not been registered yet.

I think there are two ways to solve the issue:

1. fix it in drivers/net/usb/hso.c to avoiding unregistering the
net_device when it is still not registered

2. fix it in unregister_netdev. We can add a field in net_device to
record whether it is registered, and make unregister_netdev return if
the net_device is not registered yet.

What do you guys think ?

On 9/3/19 8:08 AM, syzbot wrote:
> Hello,
>
> syzbot found the following crash on:
>
> HEAD commit:    eea39f24 usb-fuzzer: main usb gadget fuzzer driver
> git tree:   https://github.com/google/kasan.git usb-fuzzer
> console output: https://syzkaller.appspot.com/x/log.txt?x=15f17e6160
> kernel config: 
> https://syzkaller.appspot.com/x/.config?x=d0c62209eedfd54e
> dashboard link:
> https://syzkaller.appspot.com/bug?extid=44d53c7255bb1aea22d2
> compiler:   gcc (GCC) 9.0.0 20181231 (experimental)
> syz repro: 
> https://syzkaller.appspot.com/x/repro.syz?x=10ffdd1260
> C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=15a738fe60
>
> IMPORTANT: if you fix the bug, please add the following tag to the
> commit:
> Reported-by: syzbot+44d53c7255bb1aea2...@syzkaller.appspotmail.com
>
> usb 1-1: config 0 has no interface number 0
> usb 1-1: New USB device found, idVendor=0af0, idProduct=d257,
> bcdDevice=4e.87
> usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
> usb 1-1: config 0 descriptor??
> hso 1-1:0.15: Can't find BULK IN endpoint
> [ cut here ]
> WARNING: CPU: 1 PID: 83 at net/core/dev.c:8167
> rollback_registered_many.cold+0x41/0x1bc net/core/dev.c:8167
> Kernel panic - not syncing: panic_on_warn set ...
> CPU: 1 PID: 83 Comm: kworker/1:2 Not tainted 5.3.0-rc5+ #28
> Hardware name: Google Google Compute Engine/Google Compute Engine,
> BIOS Google 01/01/2011
> Workqueue: usb_hub_wq hub_event
> Call Trace:
>  __dump_stack lib/dump_stack.c:77 [inline]
>  dump_stack+0xca/0x13e lib/dump_stack.c:113
>  panic+0x2a3/0x6da kernel/panic.c:219
>  __warn.cold+0x20/0x4a kernel/panic.c:576
>  report_bug+0x262/0x2a0 lib/bug.c:186
>  fixup_bug arch/x86/kernel/traps.c:179 [inline]
>  fixup_bug arch/x86/kernel/traps.c:174 [inline]
>  do_error_trap+0x12b/0x1e0 arch/x86/kernel/traps.c:272
>  do_invalid_op+0x32/0x40 arch/x86/kernel/traps.c:291
>  invalid_op+0x23/0x30 arch/x86/entry/entry_64.S:1028
> RIP: 0010:rollback_registered_many.cold+0x41/0x1bc net/core/dev.c:8167
> Code: ff e8 c7 26 90 fc 48 c7 c7 40 ec 63 86 e8 24 c8 7a fc 0f 0b e9
> 93 be ff ff e8 af 26 90 fc 48 c7 c7 40 ec 63 86 e8 0c c8 7a fc <0f> 0b
> 4c 89 e7 e8 f9 12 34 fd 31 ff 41 89 c4 89 c6 e8 bd 27 90 fc
> RSP: 0018:8881d934f088 EFLAGS: 00010282
> RAX: 0024 RBX: 8881d2ad4400 RCX: 
> RDX:  RSI: 81288cfd RDI: ed103b269e03
> RBP: 8881d934f1b8 R08: 0024 R09: fbfff11ad794
> R10: fbfff11ad793 R11: 88d6bc9f R12: 8881d2ad4470
> R13: 8881d934f148 R14: dc00 R15: 
>  rollback_registered+0xf2/0x1c0 net/core/dev.c:8243
>  unregister_netdevice_queue net/core/dev.c:9290 [inline]
>  unregister_netdevice_queue+0x1d7/0x2b0 net/core/dev.c:9283
>  unregister_netdevice include/linux/netdevice.h:2631 [inline]
>  unregister_netdev+0x18/0x20 net/core/dev.c:9331
>  hso_free_net_device+0xff/0x300 drivers/net/usb/hso.c:2366
>  hso_create_net_device+0x76d/0x9c0 drivers/net/usb/hso.c:2554
>  hso_probe+0x28d/0x1a46 drivers/net/usb/hso.c:2931
>  usb_probe_interface+0x305/0x7a0 drivers/usb/core/driver.c:361
>  really_probe+0x281/0x6d0 drivers/base/dd.c:548
>  driver_probe_device+0x101/0x1b0 drivers/base/dd.c:721
>  __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:828
>  bus_for_each_drv+0x162/0x1e0 drivers/base/bus.c:454
>  __device_attach+0x217/0x360 drivers/base/dd.c:894
>  bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514
>  device_add+0xae6/0x16f0 drivers/base/core.c:2165
>  usb_set_configuration+0xdf6/0x1670 drivers/usb/core/message.c:2023
>  generic_probe+0x9d/0xd5 drivers/usb/core/generic.c:210
>  usb_probe_device+0x99/0x100 drivers/usb/core/driver.c:266
>  really_probe+0x281/0x6d0 drivers/base/dd.c:548
>  driver_probe_device+0x101/0x1b0 drivers/base/dd.c:721
>  __device_attach_driver+0x1c2/0x220 drivers/base/dd.c:828
>  bus_for_each_drv+0x162/0x1e0 drivers/base/bus.c:454
>  __device_attach+0x217/0x360 drivers/base/dd.c:894
>  bus_probe_device+0x1e4/0x290 drivers/base/bus.c:514
>  device_add+0xae6/0x16f0 drivers/base/core.c:2165
>  usb_new_device.cold+0x6a4/0xe79 drivers/usb/core/hub.c:2536
>  hub_port_connect drivers/usb/core/hub.c:5098 [inline]
>  hub_port_connect_change drivers/usb/core/hub.c:5213 [inline]
>  port_event drivers/usb/core/hub.c:5359 [inline]
>  hub_event+0x

Re: [PATCH 2/2] Fix a stack buffer overflow bug in check_input_term

2019-09-01 Thread Hui Peng

On 9/1/19 9:00 AM, Salvatore Bonaccorso wrote:
> Hi Hui,
>
> On Fri, Aug 30, 2019 at 05:47:29PM -0400, Hui Peng wrote:
>> `check_input_term` recursively calls itself with input from
>> device side (e.g., uac_input_terminal_descriptor.bCSourceID)
>> as argument (id). In `check_input_term`, if `check_input_term`
>> is called with the same `id` argument as the caller, it triggers
>> endless recursive call, resulting kernel space stack overflow.
>>
>> This patch fixes the bug by adding a bitmap to `struct mixer_build`
>> to keep track of the checked ids and stop the execution if some id
>> has been checked (similar to how parse_audio_unit handles unitid
>> argument).
>>
>> CVE: CVE-2018-15118
> Similar to the previous one, this should be CVE-2019-15118 as far I
> can tell.

Same here: CVE id updated.

Can you apply it to  v4.4.190 and v4.14.141?

Thanks.

>
> Regards,
> Salvatore
>From f5e478c4807b16f49c00316fb80485562b84340a Mon Sep 17 00:00:00 2001
From: Hui Peng 
Date: Fri, 30 Aug 2019 16:20:41 -0400
Subject: [PATCH 2/2] Fix a stack buffer overflow bug in check_input_term

`check_input_term` recursively calls itself with input from
device side (e.g., uac_input_terminal_descriptor.bCSourceID)
as argument (id). In `check_input_term`, if `check_input_term`
is called with the same `id` argument as the caller, it triggers
endless recursive call, resulting kernel space stack overflow.

This patch fixes the bug by adding a bitmap to `struct mixer_build`
to keep track of the checked ids and stop the execution if some id
has been checked (similar to how parse_audio_unit handles unitid
argument).

CVE: CVE-2019-15118

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 29 -
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 10ddec76f906..e24572fd6e30 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -81,6 +81,7 @@ struct mixer_build {
 	unsigned char *buffer;
 	unsigned int buflen;
 	DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
+	DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
 	struct usb_audio_term oterm;
 	const struct usbmix_name_map *map;
 	const struct usbmix_selector_map *selector_map;
@@ -709,15 +710,24 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm
  * parse the source unit recursively until it reaches to a terminal
  * or a branched unit.
  */
-static int check_input_term(struct mixer_build *state, int id,
+static int __check_input_term(struct mixer_build *state, int id,
 			struct usb_audio_term *term)
 {
 	int err;
 	void *p1;
+	unsigned char *hdr;
 
 	memset(term, 0, sizeof(*term));
-	while ((p1 = find_audio_control_unit(state, id)) != NULL) {
-		unsigned char *hdr = p1;
+	for (;;) {
+		/* a loop in the terminal chain? */
+		if (test_and_set_bit(id, state->termbitmap))
+			return -EINVAL;
+
+		p1 = find_audio_control_unit(state, id);
+		if (!p1)
+			break;
+
+		hdr = p1;
 		term->id = id;
 		switch (hdr[2]) {
 		case UAC_INPUT_TERMINAL:
@@ -732,7 +742,7 @@ static int check_input_term(struct mixer_build *state, int id,
 
 /* call recursively to verify that the
  * referenced clock entity is valid */
-err = check_input_term(state, d->bCSourceID, term);
+err = __check_input_term(state, d->bCSourceID, term);
 if (err < 0)
 	return err;
 
@@ -764,7 +774,7 @@ static int check_input_term(struct mixer_build *state, int id,
 		case UAC2_CLOCK_SELECTOR: {
 			struct uac_selector_unit_descriptor *d = p1;
 			/* call recursively to retrieve the channel info */
-			err = check_input_term(state, d->baSourceID[0], term);
+			err = __check_input_term(state, d->baSourceID[0], term);
 			if (err < 0)
 return err;
 			term->type = d->bDescriptorSubtype << 16; /* virtual type */
@@ -811,6 +821,15 @@ static int check_input_term(struct mixer_build *state, int id,
 	return -ENODEV;
 }
 
+
+static int check_input_term(struct mixer_build *state, int id,
+			struct usb_audio_term *term)
+{
+	memset(term, 0, sizeof(*term));
+	memset(state->termbitmap, 0, sizeof(state->termbitmap));
+	return __check_input_term(state, id, term);
+}
+
 /*
  * Feature Unit
  */
-- 
2.17.1



Re: [PATCH 1/2] Fix an OOB bug in parse_audio_mixer_unit

2019-09-01 Thread Hui Peng

On 9/1/19 8:58 AM, Salvatore Bonaccorso wrote:
> On Fri, Aug 30, 2019 at 05:46:49PM -0400, Hui Peng wrote:
>> The `uac_mixer_unit_descriptor` shown as below is read from the
>> device side. In `parse_audio_mixer_unit`, `baSourceID` field is
>> accessed from index 0 to `bNrInPins` - 1, the current implementation
>> assumes that descriptor is always valid (the length  of descriptor
>> is no shorter than 5 + `bNrInPins`). If a descriptor read from
>> the device side is invalid, it may trigger out-of-bound memory
>> access.
>>
>> ```
>> struct uac_mixer_unit_descriptor {
>>  __u8 bLength;
>>  __u8 bDescriptorType;
>>  __u8 bDescriptorSubtype;
>>  __u8 bUnitID;
>>  __u8 bNrInPins;
>>  __u8 baSourceID[];
>> }
>> ```
>>
>> This patch fixes the bug by add a sanity check on the length of
>> the descriptor.
>>
>> CVE: CVE-2018-15117
> FWIW, the correct CVE id should be probably CVE-2019-15117 here.

Yes, the CVE id was wrong. I have updated it in the attached patch.

> But there was already a patch queued and released in 5.2.10 and
> 4.19.68 for this issue (as far I can see; is this correct?)

Yes, it should have been fixed in those branches.

But google asked me to back port it to v4.4.190 and v4.14.141.

I have mentioned it in one previous email, but it was blocked by vger
because it was sent in html format.

Can you apply it to these 2 versions? (it applies to both versions)

Thanks.

> Regards,
> Salvatore
>From 09942398a53bbe730264b782673890d4a54068d0 Mon Sep 17 00:00:00 2001
From: Hui Peng 
Date: Fri, 30 Aug 2019 16:11:00 -0400
Subject: [PATCH 1/2] Fix an OOB bug in parse_audio_mixer_unit

The `uac_mixer_unit_descriptor` shown as below is read from the
device side. In `parse_audio_mixer_unit`, `baSourceID` field is
accessed from index 0 to `bNrInPins` - 1, the current implementation
assumes that descriptor is always valid (the length  of descriptor
is no shorter than 5 + `bNrInPins`). If a descriptor read from
the device side is invalid, it may trigger out-of-bound memory
access.

```
struct uac_mixer_unit_descriptor {
	__u8 bLength;
	__u8 bDescriptorType;
	__u8 bDescriptorSubtype;
	__u8 bUnitID;
	__u8 bNrInPins;
	__u8 baSourceID[];
}
```

This patch fixes the bug by add a sanity check on the length of
the descriptor.

CVE: CVE-2019-15117

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 1f7eb3816cd7..10ddec76f906 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1628,6 +1628,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
 	int pin, ich, err;
 
 	if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) ||
+	desc->bLength < sizeof(*desc) + desc->bNrInPins ||
 	!(num_outs = uac_mixer_unit_bNrChannels(desc))) {
 		usb_audio_err(state->chip,
 			  "invalid MIXER UNIT descriptor %d\n",
-- 
2.17.1



Re: [PATCH] Fix a double free bug in rsi_91x_deinit

2019-08-31 Thread Hui Peng
On 8/31/19 2:18 PM, Guenter Roeck wrote:
> On Mon, Aug 19, 2019 at 06:02:29PM -0400, Hui Peng wrote:
>> `dev` (struct rsi_91x_usbdev *) field of adapter
>> (struct rsi_91x_usbdev *) is allocated  and initialized in
>> `rsi_init_usb_interface`. If any error is detected in information
>> read from the device side,  `rsi_init_usb_interface` will be
>> freed. However, in the higher level error handling code in
>> `rsi_probe`, if error is detected, `rsi_91x_deinit` is called
>> again, in which `dev` will be freed again, resulting double free.
>>
>> This patch fixes the double free by removing the free operation on
>> `dev` in `rsi_init_usb_interface`, because `rsi_91x_deinit` is also
>> used in `rsi_disconnect`, in that code path, the `dev` field is not
>>  (and thus needs to be) freed.
>>
>> This bug was found in v4.19, but is also present in the latest version
>> of kernel.
>>
>> Reported-by: Hui Peng 
>> Reported-by: Mathias Payer 
>> Signed-off-by: Hui Peng 
> FWIW:
>
> Reviewed-by: Guenter Roeck 
>
> This patch is listed as fix for CVE-2019-15504, which has a CVSS 2.0 score
> of 10.0 (high) and CVSS 3.0 score of 9.8 (critical).
>
> Are there any plans to apply this patch to the upstream kernel anytime
> soon ? If not, are there reasons to believe that the problem is not as
> severe as its CVSS score may indicate ?
This patch is also still under review.
> Thanks,
> Guenter
>
>> ---
>>  drivers/net/wireless/rsi/rsi_91x_usb.c | 1 -
>>  1 file changed, 1 deletion(-)
>>
>> diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c 
>> b/drivers/net/wireless/rsi/rsi_91x_usb.c
>> index c0a163e40402..ac917227f708 100644
>> --- a/drivers/net/wireless/rsi/rsi_91x_usb.c
>> +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
>> @@ -640,7 +640,6 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
>>  kfree(rsi_dev->tx_buffer);
>>  
>>  fail_eps:
>> -kfree(rsi_dev);
>>  
>>  return status;
>>  }
>> -- 
>> 2.22.1
>>


[PATCH 1/2] Fix an OOB bug in parse_audio_mixer_unit

2019-08-30 Thread Hui Peng
The `uac_mixer_unit_descriptor` shown as below is read from the
device side. In `parse_audio_mixer_unit`, `baSourceID` field is
accessed from index 0 to `bNrInPins` - 1, the current implementation
assumes that descriptor is always valid (the length  of descriptor
is no shorter than 5 + `bNrInPins`). If a descriptor read from
the device side is invalid, it may trigger out-of-bound memory
access.

```
struct uac_mixer_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u8 bNrInPins;
__u8 baSourceID[];
}
```

This patch fixes the bug by add a sanity check on the length of
the descriptor.

CVE: CVE-2018-15117

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 1f7eb3816cd7..10ddec76f906 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1628,6 +1628,7 @@ static int parse_audio_mixer_unit(struct mixer_build 
*state, int unitid,
int pin, ich, err;
 
if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) ||
+   desc->bLength < sizeof(*desc) + desc->bNrInPins ||
!(num_outs = uac_mixer_unit_bNrChannels(desc))) {
usb_audio_err(state->chip,
  "invalid MIXER UNIT descriptor %d\n",
-- 
2.17.1



[PATCH 2/2] Fix a stack buffer overflow bug in check_input_term

2019-08-30 Thread Hui Peng
`check_input_term` recursively calls itself with input from
device side (e.g., uac_input_terminal_descriptor.bCSourceID)
as argument (id). In `check_input_term`, if `check_input_term`
is called with the same `id` argument as the caller, it triggers
endless recursive call, resulting kernel space stack overflow.

This patch fixes the bug by adding a bitmap to `struct mixer_build`
to keep track of the checked ids and stop the execution if some id
has been checked (similar to how parse_audio_unit handles unitid
argument).

CVE: CVE-2018-15118

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 29 -
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 10ddec76f906..e24572fd6e30 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -81,6 +81,7 @@ struct mixer_build {
unsigned char *buffer;
unsigned int buflen;
DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
+   DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
struct usb_audio_term oterm;
const struct usbmix_name_map *map;
const struct usbmix_selector_map *selector_map;
@@ -709,15 +710,24 @@ static int get_term_name(struct mixer_build *state, 
struct usb_audio_term *iterm
  * parse the source unit recursively until it reaches to a terminal
  * or a branched unit.
  */
-static int check_input_term(struct mixer_build *state, int id,
+static int __check_input_term(struct mixer_build *state, int id,
struct usb_audio_term *term)
 {
int err;
void *p1;
+   unsigned char *hdr;
 
memset(term, 0, sizeof(*term));
-   while ((p1 = find_audio_control_unit(state, id)) != NULL) {
-   unsigned char *hdr = p1;
+   for (;;) {
+   /* a loop in the terminal chain? */
+   if (test_and_set_bit(id, state->termbitmap))
+   return -EINVAL;
+
+   p1 = find_audio_control_unit(state, id);
+   if (!p1)
+   break;
+
+   hdr = p1;
term->id = id;
switch (hdr[2]) {
case UAC_INPUT_TERMINAL:
@@ -732,7 +742,7 @@ static int check_input_term(struct mixer_build *state, int 
id,
 
/* call recursively to verify that the
 * referenced clock entity is valid */
-   err = check_input_term(state, d->bCSourceID, 
term);
+   err = __check_input_term(state, d->bCSourceID, 
term);
if (err < 0)
return err;
 
@@ -764,7 +774,7 @@ static int check_input_term(struct mixer_build *state, int 
id,
case UAC2_CLOCK_SELECTOR: {
struct uac_selector_unit_descriptor *d = p1;
/* call recursively to retrieve the channel info */
-   err = check_input_term(state, d->baSourceID[0], term);
+   err = __check_input_term(state, d->baSourceID[0], term);
if (err < 0)
return err;
term->type = d->bDescriptorSubtype << 16; /* virtual 
type */
@@ -811,6 +821,15 @@ static int check_input_term(struct mixer_build *state, int 
id,
return -ENODEV;
 }
 
+
+static int check_input_term(struct mixer_build *state, int id,
+   struct usb_audio_term *term)
+{
+   memset(term, 0, sizeof(*term));
+   memset(state->termbitmap, 0, sizeof(state->termbitmap));
+   return __check_input_term(state, id, term);
+}
+
 /*
  * Feature Unit
  */
-- 
2.17.1



Re: [PATCH] Fix an OOB access bug in technisat_usb2_get_ir

2019-08-20 Thread Hui Peng
The following is the kasan report. This bug was found in v4.20-rc2, but
it is present in the latest version.

BUG: KASAN: slab-out-of-bounds in technisat_usb2_get_ir
drivers/media/usb/dvb-usb/technisat-usb2.c:664 [inline]
BUG: KASAN: slab-out-of-bounds in technisat_usb2_rc_query+0x598/0x5f0
drivers/media/usb/dvb-usb/technisat-usb2.c:679
Read of size 1 at addr 88805ee3d3a8 by task kworker/2:3/8681

CPU: 2 PID: 8681 Comm: kworker/2:3 Not tainted 4.20.0-rc2 #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
Ubuntu-1.8.2-1ubuntu1 04/01/2014
Workqueue: events dvb_usb_read_remote_control
Call Trace:
 __dump_stack lib/dump_stack.c:77 [inline]
 dump_stack+0xd2/0x148 lib/dump_stack.c:113
 print_address_description+0x71/0x239 mm/kasan/report.c:256
 kasan_report_error mm/kasan/report.c:354 [inline]
 kasan_report.cold.5+0x242/0x30b mm/kasan/report.c:412
 __asan_report_load1_noabort+0x19/0x20 mm/kasan/report.c:430
 technisat_usb2_get_ir drivers/media/usb/dvb-usb/technisat-usb2.c:664
[inline]
 technisat_usb2_rc_query+0x598/0x5f0
drivers/media/usb/dvb-usb/technisat-usb2.c:679
 dvb_usb_read_remote_control+0xbd/0x150
drivers/media/usb/dvb-usb/dvb-usb-remote.c:261
 process_one_work+0x816/0x14d0 kernel/workqueue.c:2153
 worker_thread+0x9b/0xce0 kernel/workqueue.c:2296
 kthread+0x33d/0x400 kernel/kthread.c:246
 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352

On 8/20/19 2:19 PM, Hui Peng wrote:
> In the while loop of technisat_usb2_get_ir, it scans through
> a fix-sized buffer read from the device side, the termination
> condition of the loop is `*b == 0xff`. If no `0xff` byte is read
> from the device side, OOB access happens.
>
> This patch fixes the bug by adding an upper bound in the while loop.
>
> Reported-by: Hui Peng 
> Reported-by: Mathias Payer 
> Signed-off-by: Hui Peng 
> ---
>  drivers/media/usb/dvb-usb/technisat-usb2.c | 5 +
>  1 file changed, 5 insertions(+)
>
> diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c 
> b/drivers/media/usb/dvb-usb/technisat-usb2.c
> index c659e18b358b..181f5f97af45 100644
> --- a/drivers/media/usb/dvb-usb/technisat-usb2.c
> +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
> @@ -612,6 +612,7 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
>   u8 *b;
>   int ret;
>   struct ir_raw_event ev;
> + int i = 0;
>  
>   buf[0] = GET_IR_DATA_VENDOR_REQUEST;
>   buf[1] = 0x08;
> @@ -656,11 +657,15 @@ static int technisat_usb2_get_ir(struct dvb_usb_device 
> *d)
>  
>   ev.pulse = 0;
>   while (1) {
> + // only `ret` bytes are read from the device side
> + if (i >= ret)
> + break;
>   ev.pulse = !ev.pulse;
>   ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * 
> FIRMWARE_CLOCK_TICK) / 1000;
>   ir_raw_event_store(d->rc_dev, &ev);
>  
>   b++;
> + i++;
>   if (*b == 0xff) {
>   ev.pulse = 0;
>   ev.duration = 88*2;


[PATCH] Fix an OOB access bug in technisat_usb2_get_ir

2019-08-20 Thread Hui Peng
In the while loop of technisat_usb2_get_ir, it scans through
a fix-sized buffer read from the device side, the termination
condition of the loop is `*b == 0xff`. If no `0xff` byte is read
from the device side, OOB access happens.

This patch fixes the bug by adding an upper bound in the while loop.

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 drivers/media/usb/dvb-usb/technisat-usb2.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c 
b/drivers/media/usb/dvb-usb/technisat-usb2.c
index c659e18b358b..181f5f97af45 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -612,6 +612,7 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
u8 *b;
int ret;
struct ir_raw_event ev;
+   int i = 0;
 
buf[0] = GET_IR_DATA_VENDOR_REQUEST;
buf[1] = 0x08;
@@ -656,11 +657,15 @@ static int technisat_usb2_get_ir(struct dvb_usb_device *d)
 
ev.pulse = 0;
while (1) {
+   // only `ret` bytes are read from the device side
+   if (i >= ret)
+   break;
ev.pulse = !ev.pulse;
ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * 
FIRMWARE_CLOCK_TICK) / 1000;
ir_raw_event_store(d->rc_dev, &ev);
 
b++;
+   i++;
if (*b == 0xff) {
ev.pulse = 0;
ev.duration = 88*2;
-- 
2.23.0



[PATCH] Fix a double free bug in rsi_91x_deinit

2019-08-19 Thread Hui Peng
`dev` (struct rsi_91x_usbdev *) field of adapter
(struct rsi_91x_usbdev *) is allocated  and initialized in
`rsi_init_usb_interface`. If any error is detected in information
read from the device side,  `rsi_init_usb_interface` will be
freed. However, in the higher level error handling code in
`rsi_probe`, if error is detected, `rsi_91x_deinit` is called
again, in which `dev` will be freed again, resulting double free.

This patch fixes the double free by removing the free operation on
`dev` in `rsi_init_usb_interface`, because `rsi_91x_deinit` is also
used in `rsi_disconnect`, in that code path, the `dev` field is not
 (and thus needs to be) freed.

This bug was found in v4.19, but is also present in the latest version
of kernel.

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 drivers/net/wireless/rsi/rsi_91x_usb.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c 
b/drivers/net/wireless/rsi/rsi_91x_usb.c
index c0a163e40402..ac917227f708 100644
--- a/drivers/net/wireless/rsi/rsi_91x_usb.c
+++ b/drivers/net/wireless/rsi/rsi_91x_usb.c
@@ -640,7 +640,6 @@ static int rsi_init_usb_interface(struct rsi_hw *adapter,
kfree(rsi_dev->tx_buffer);
 
 fail_eps:
-   kfree(rsi_dev);
 
return status;
 }
-- 
2.22.1



[PATCH] Fix an OOB bug in uac_mixer_unit_bmControls

2019-08-19 Thread Hui Peng
`uac_mixer_unit_get_channels` calls `uac_mixer_unit_bmControls`
to get pointer to bmControls field. The current implementation of
`uac_mixer_unit_get_channels` does properly check the size of
uac_mixer_unit_descriptor descriptor and may allow OOB access
in `uac_mixer_unit_bmControls`.

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 25 ++---
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index b5927c3d5bc0..00e6274a63c3 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -738,28 +738,39 @@ static int get_cluster_channels_v3(struct mixer_build 
*state, unsigned int clust
 static int uac_mixer_unit_get_channels(struct mixer_build *state,
   struct uac_mixer_unit_descriptor *desc)
 {
-   int mu_channels;
+   int mu_channels = 0;
void *c;
 
-   if (desc->bLength < sizeof(*desc))
-   return -EINVAL;
if (!desc->bNrInPins)
return -EINVAL;
-   if (desc->bLength < sizeof(*desc) + desc->bNrInPins)
-   return -EINVAL;
 
switch (state->mixer->protocol) {
case UAC_VERSION_1:
+   // limit derived from uac_mixer_unit_bmControls
+   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 4)
+   return 0;
+
+   mu_channels = uac_mixer_unit_bNrChannels(desc);
+   break;
+
case UAC_VERSION_2:
-   default:
-   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1)
+   // limit derived from uac_mixer_unit_bmControls
+   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 6)
return 0; /* no bmControls -> skip */
+
mu_channels = uac_mixer_unit_bNrChannels(desc);
break;
case UAC_VERSION_3:
+   // limit derived from uac_mixer_unit_bmControls
+   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 2)
+   return 0; /* no bmControls -> skip */
+
mu_channels = get_cluster_channels_v3(state,
uac3_mixer_unit_wClusterDescrID(desc));
break;
+
+   default:
+   break;
}
 
if (!mu_channels)
-- 
2.22.1



[PATCH] Fix an OOB bug in uac_mixer_unit_bmControls

2019-08-16 Thread Hui Peng
`uac_mixer_unit_get_channels` calls `uac_mixer_unit_bmControls`
to get pointer to bmControls field. The current implementation of
`uac_mixer_unit_get_channels` does properly check the size of
uac_mixer_unit_descriptor descriptor and may allow OOB access
in `uac_mixer_unit_bmControls`.

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 25 ++---
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index b5927c3d5bc0..00e6274a63c3 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -738,28 +738,39 @@ static int get_cluster_channels_v3(struct mixer_build 
*state, unsigned int clust
 static int uac_mixer_unit_get_channels(struct mixer_build *state,
   struct uac_mixer_unit_descriptor *desc)
 {
-   int mu_channels;
+   int mu_channels = 0;
void *c;
 
-   if (desc->bLength < sizeof(*desc))
-   return -EINVAL;
if (!desc->bNrInPins)
return -EINVAL;
-   if (desc->bLength < sizeof(*desc) + desc->bNrInPins)
-   return -EINVAL;
 
switch (state->mixer->protocol) {
case UAC_VERSION_1:
+   // limit derived from uac_mixer_unit_bmControls
+   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 4)
+   return 0;
+
+   mu_channels = uac_mixer_unit_bNrChannels(desc);
+   break;
+
case UAC_VERSION_2:
-   default:
-   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1)
+   // limit derived from uac_mixer_unit_bmControls
+   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 6)
return 0; /* no bmControls -> skip */
+
mu_channels = uac_mixer_unit_bNrChannels(desc);
break;
case UAC_VERSION_3:
+   // limit derived from uac_mixer_unit_bmControls
+   if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 2)
+   return 0; /* no bmControls -> skip */
+
mu_channels = get_cluster_channels_v3(state,
uac3_mixer_unit_wClusterDescrID(desc));
break;
+
+   default:
+   break;
}
 
if (!mu_channels)
-- 
2.22.1



Re: [PATCH] Fix a stack buffer overflow bug check_input_term

2019-08-14 Thread Hui Peng
The stack trace differs from test to test, the attached trace1 file is
taken from one of the tests.

The bug is confirmed by adding some printk statement in
`check_input_term`, the trace with output of printk is attached in
trace2 file.

This patch is a tentative fix to the bug, please give me feedback.

On 8/15/19 12:35 AM, Hui Peng wrote:
> `check_input_term` recursively calls itself with input
> from device side (e.g., uac_input_terminal_descriptor.bCSourceID)
> as argument (id). In `check_input_term`, if `check_input_term`
> is called with the same `id` argument as the caller, it triggers
> endless recursive call, resulting kernel space stack overflow.
>
> This patch fixes the bug by adding a bitmap to `struct mixer_build`
> to keep track of the checked ids by `check_input_term` and stop
> the execution if some id has been checked (similar to how
> parse_audio_unit handles unitid argument).
>
> Reported-by: Hui Peng 
> Reported-by: Mathias Payer 
> Signed-off-by: Hui Peng 
> ---
>  sound/usb/mixer.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index ea487378be17..1f6c8213df82 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -68,6 +68,7 @@ struct mixer_build {
>   unsigned char *buffer;
>   unsigned int buflen;
>   DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
> + DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
>   struct usb_audio_term oterm;
>   const struct usbmix_name_map *map;
>   const struct usbmix_selector_map *selector_map;
> @@ -782,6 +783,8 @@ static int check_input_term(struct mixer_build *state, 
> int id,
>   int err;
>   void *p1;
>  
> + if (test_and_set_bit(id, state->termbitmap))
> + return 0;
>   memset(term, 0, sizeof(*term));
>   while ((p1 = find_audio_control_unit(state, id)) != NULL) {
>   unsigned char *hdr = p1;
[7.839002] usb 1-1: new high-speed USB device number 2 using xhci_hcd
[7.966787] usb 1-1: Using ep0 maxpacket: 16
[7.969898] usb 1-1: string descriptor 0 read error: -22
[7.971507] usb 1-1: New USB device found, idVendor=046d, idProduct=0a44, 
bcdDevice= 1.27
[7.973874] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[7.979864] usb 1-1: current rate 16732531 is different from the runtime 
rate 48000
[7.982029] usb 1-1: current rate 11254477 is different from the runtime 
rate 48000
[7.987190] [parse_audio_unit:2797] reached
[7.987741] [parse_audio_unit:2814] reached
[7.988310] [parse_audio_feature_unit:1855] reached
[7.988982] [parse_audio_feature_unit:1915] reached
[7.989605] [parse_audio_unit:2797] reached
[7.990173] [parse_audio_unit:2804] reached
[7.999615] [parse_audio_unit:2797] reached
[8.000166] [parse_audio_unit:2814] reached
[8.000734] [parse_audio_feature_unit:1855] reached
[8.001361] [parse_audio_feature_unit:1915] reached
[8.002011] [parse_audio_unit:2797] reached
[8.002590] [parse_audio_unit:2811] reached
[8.003180] [parse_audio_unit:2797] reached
[8.003754] [parse_audio_unit:2814] reached
[8.004342] [parse_audio_feature_unit:1855] reached
[8.004992] [parse_audio_feature_unit:1915] reached
[8.005656] [parse_audio_feature_unit:1921] reached
[8.006324] [check_input_term:804] reached
[8.006881] [check_input_term:860] reached
[8.007451] [check_input_term:804] reached
[8.008038] [check_input_term:860] reached
[8.008596] [check_input_term:804] reached
[8.009129] [check_input_term:860] reached
[8.009686] [check_input_term:804] reached
[8.010217] [check_input_term:860] reached
[8.010834] [check_input_term:804] reached
[8.011430] [check_input_term:860] reached
[8.011945] [check_input_term:804] reached
[8.012577] [check_input_term:860] reached
[8.013109] [check_input_term:804] reached
[8.013704] [check_input_term:860] reached
[8.014319] [check_input_term:804] reached
[8.014848] [check_input_term:860] reached
[8.015415] [check_input_term:804] reached
[8.015964] [check_input_term:860] reached
[8.016525] [check_input_term:804] reached
[8.017055] [check_input_term:860] reached
[8.017612] [check_input_term:804] reached
[8.018168] [check_input_term:860] reached
[8.018701] [check_input_term:804] reached
[8.019273] [check_input_term:860] reached
[8.019805] [check_input_term:804] reached
[8.020362] [check_input_term:860] reached
[8.020893] [check_input_term:804] reached
[8.021440] [check_input_term:860] reached
[8.021972] [check_input_term:804] reached
[8.022536] [check_input_term:860] reached
[8.023127] [check_input_term:804] reached
[8.023664] [check_input_term:860] reached
[8.024213] [check_input_term:804] reached
[8.024791] [check_input_term:860] reached
[8.025351]

[PATCH] Fix a stack buffer overflow bug check_input_term

2019-08-14 Thread Hui Peng
`check_input_term` recursively calls itself with input
from device side (e.g., uac_input_terminal_descriptor.bCSourceID)
as argument (id). In `check_input_term`, if `check_input_term`
is called with the same `id` argument as the caller, it triggers
endless recursive call, resulting kernel space stack overflow.

This patch fixes the bug by adding a bitmap to `struct mixer_build`
to keep track of the checked ids by `check_input_term` and stop
the execution if some id has been checked (similar to how
parse_audio_unit handles unitid argument).

Reported-by: Hui Peng 
Reported-by: Mathias Payer 
Signed-off-by: Hui Peng 
---
 sound/usb/mixer.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index ea487378be17..1f6c8213df82 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -68,6 +68,7 @@ struct mixer_build {
unsigned char *buffer;
unsigned int buflen;
DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
+   DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
struct usb_audio_term oterm;
const struct usbmix_name_map *map;
const struct usbmix_selector_map *selector_map;
@@ -782,6 +783,8 @@ static int check_input_term(struct mixer_build *state, int 
id,
int err;
void *p1;
 
+   if (test_and_set_bit(id, state->termbitmap))
+   return 0;
memset(term, 0, sizeof(*term));
while ((p1 = find_audio_control_unit(state, id)) != NULL) {
unsigned char *hdr = p1;
-- 
2.22.1



[PATCH] Fix an OOB bug in parse_audio_mixer_unit

2019-08-13 Thread Hui Peng
The `uac_mixer_unit_descriptor` shown as below is read from the
device side. In `parse_audio_mixer_unit`, `baSourceID` field is
accessed from index 0 to `bNrInPins` - 1, the current implementation
assumes that descriptor is always valid (the length  of descriptor
is no shorter than 5 + `bNrInPins`). If a descriptor read from
the device side is invalid, it may trigger out-of-bound memory
access.

```
struct uac_mixer_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u8 bNrInPins;
__u8 baSourceID[];
}
```

This patch fixes the bug by add a sanity check on the length of
the descriptor.

Signed-off-by: Hui Peng 
Reported-by: Hui Peng 
Reported-by: Mathias Payer 
---
 sound/usb/mixer.c | 9 +
 1 file changed, 9 insertions(+)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 7498b5191b68..38202ce67237 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -2091,6 +2091,15 @@ static int parse_audio_mixer_unit(struct mixer_build 
*state, int unitid,
struct usb_audio_term iterm;
int input_pins, num_ins, num_outs;
int pin, ich, err;
+   int desc_len = (int) ((unsigned long) state->buffer +
+   state->buflen - (unsigned long) raw_desc);
+
+   if (desc_len < sizeof(*desc) + desc->bNrInPins) {
+   usb_audio_err(state->chip,
+ "descriptor %d too short\n",
+ unitid);
+   return -EINVAL;
+   }
 
err = uac_mixer_unit_get_channels(state, desc);
if (err < 0) {
-- 
2.22.1



[PATCH 1/2] Fix a NULL-ptr-deref bug in ath6kl_usb_alloc_urb_from_pipe

2019-08-03 Thread Hui Peng
The `ar_usb` field of `ath6kl_usb_pipe_usb_pipe` objects
are initialized to point to the containing `ath6kl_usb` object
according to endpoint descriptors read from the device side, as shown
below in `ath6kl_usb_setup_pipe_resources`:

for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;

// get the address from endpoint descriptor
pipe_num = ath6kl_usb_get_logical_pipe_num(ar_usb,
endpoint->bEndpointAddress,
&urbcount);
..
// select the pipe object
pipe = &ar_usb->pipes[pipe_num];

// initialize the ar_usb field
pipe->ar_usb = ar_usb;
}

The driver assumes that the addresses reported in endpoint
descriptors from device side  to be complete. If a device is
malicious and does not report complete addresses, it may trigger
NULL-ptr-deref `ath6kl_usb_alloc_urb_from_pipe` and
`ath6kl_usb_free_urb_to_pipe`.

This patch fixes the bug by preventing potential NULL-ptr-deref.

Signed-off-by: Hui Peng 
Reported-by: Hui Peng 
Reported-by: Mathias Payer 
---
 drivers/net/wireless/ath/ath6kl/usb.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/wireless/ath/ath6kl/usb.c 
b/drivers/net/wireless/ath/ath6kl/usb.c
index 4defb7a0330f..53b66e9434c9 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -132,6 +132,10 @@ ath6kl_usb_alloc_urb_from_pipe(struct ath6kl_usb_pipe 
*pipe)
struct ath6kl_urb_context *urb_context = NULL;
unsigned long flags;
 
+   /* bail if this pipe is not initialized */
+   if (!pipe->ar_usb)
+   return NULL;
+
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
if (!list_empty(&pipe->urb_list_head)) {
urb_context =
@@ -150,6 +154,10 @@ static void ath6kl_usb_free_urb_to_pipe(struct 
ath6kl_usb_pipe *pipe,
 {
unsigned long flags;
 
+   /* bail if this pipe is not initialized */
+   if (!pipe->ar_usb)
+   return;
+
spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags);
pipe->urb_cnt++;
 
-- 
2.22.0