Skip to content

Commit 000b2a6

Browse files
Thadeu Lima de Souza Cascardogregkh
authored andcommitted
media: uvcvideo: Mark invalid entities with id UVC_INVALID_ENTITY_ID
commit 0e2ee70 upstream. Per UVC 1.1+ specification 3.7.2, units and terminals must have a non-zero unique ID. ``` Each Unit and Terminal within the video function is assigned a unique identification number, the Unit ID (UID) or Terminal ID (TID), contained in the bUnitID or bTerminalID field of the descriptor. The value 0x00 is reserved for undefined ID, ``` If we add a new entity with id 0 or a duplicated ID, it will be marked as UVC_INVALID_ENTITY_ID. In a previous attempt commit 3dd075f ("media: uvcvideo: Require entities to have a non-zero unique ID"), we ignored all the invalid units, this broke a lot of non-compatible cameras. Hopefully we are more lucky this time. This also prevents some syzkaller reproducers from triggering warnings due to a chain of entities referring to themselves. In one particular case, an Output Unit is connected to an Input Unit, both with the same ID of 1. But when looking up for the source ID of the Output Unit, that same entity is found instead of the input entity, which leads to such warnings. In another case, a backward chain was considered finished as the source ID was 0. Later on, that entity was found, but its pads were not valid. Here is a sample stack trace for one of those cases. [ 20.650953] usb 1-1: new high-speed USB device number 2 using dummy_hcd [ 20.830206] usb 1-1: Using ep0 maxpacket: 8 [ 20.833501] usb 1-1: config 0 descriptor?? [ 21.038518] usb 1-1: string descriptor 0 read error: -71 [ 21.038893] usb 1-1: Found UVC 0.00 device <unnamed> (2833:0201) [ 21.039299] uvcvideo 1-1:0.0: Entity type for entity Output 1 was not initialized! [ 21.041583] uvcvideo 1-1:0.0: Entity type for entity Input 1 was not initialized! [ 21.042218] ------------[ cut here ]------------ [ 21.042536] WARNING: CPU: 0 PID: 9 at drivers/media/mc/mc-entity.c:1147 media_create_pad_link+0x2c4/0x2e0 [ 21.043195] Modules linked in: [ 21.043535] CPU: 0 UID: 0 PID: 9 Comm: kworker/0:1 Not tainted 6.11.0-rc7-00030-g3480e43aeccf #444 [ 21.044101] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 [ 21.044639] Workqueue: usb_hub_wq hub_event [ 21.045100] RIP: 0010:media_create_pad_link+0x2c4/0x2e0 [ 21.045508] Code: fe e8 20 01 00 00 b8 f4 ff ff ff 48 83 c4 30 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 0f 0b eb e9 0f 0b eb 0a 0f 0b eb 06 <0f> 0b eb 02 0f 0b b8 ea ff ff ff eb d4 66 2e 0f 1f 84 00 00 00 00 [ 21.046801] RSP: 0018:ffffc9000004b318 EFLAGS: 00010246 [ 21.047227] RAX: ffff888004e5d458 RBX: 0000000000000000 RCX: ffffffff818fccf1 [ 21.047719] RDX: 000000000000007b RSI: 0000000000000000 RDI: ffff888004313290 [ 21.048241] RBP: ffff888004313290 R08: 0001ffffffffffff R09: 0000000000000000 [ 21.048701] R10: 0000000000000013 R11: 0001888004313290 R12: 0000000000000003 [ 21.049138] R13: ffff888004313080 R14: ffff888004313080 R15: 0000000000000000 [ 21.049648] FS: 0000000000000000(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000 [ 21.050271] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 21.050688] CR2: 0000592cc27635b0 CR3: 000000000431c000 CR4: 0000000000750ef0 [ 21.051136] PKRU: 55555554 [ 21.051331] Call Trace: [ 21.051480] <TASK> [ 21.051611] ? __warn+0xc4/0x210 [ 21.051861] ? media_create_pad_link+0x2c4/0x2e0 [ 21.052252] ? report_bug+0x11b/0x1a0 [ 21.052540] ? trace_hardirqs_on+0x31/0x40 [ 21.052901] ? handle_bug+0x3d/0x70 [ 21.053197] ? exc_invalid_op+0x1a/0x50 [ 21.053511] ? asm_exc_invalid_op+0x1a/0x20 [ 21.053924] ? media_create_pad_link+0x91/0x2e0 [ 21.054364] ? media_create_pad_link+0x2c4/0x2e0 [ 21.054834] ? media_create_pad_link+0x91/0x2e0 [ 21.055131] ? _raw_spin_unlock+0x1e/0x40 [ 21.055441] ? __v4l2_device_register_subdev+0x202/0x210 [ 21.055837] uvc_mc_register_entities+0x358/0x400 [ 21.056144] uvc_register_chains+0x1fd/0x290 [ 21.056413] uvc_probe+0x380e/0x3dc0 [ 21.056676] ? __lock_acquire+0x5aa/0x26e0 [ 21.056946] ? find_held_lock+0x33/0xa0 [ 21.057196] ? kernfs_activate+0x70/0x80 [ 21.057533] ? usb_match_dynamic_id+0x1b/0x70 [ 21.057811] ? find_held_lock+0x33/0xa0 [ 21.058047] ? usb_match_dynamic_id+0x55/0x70 [ 21.058330] ? lock_release+0x124/0x260 [ 21.058657] ? usb_match_one_id_intf+0xa2/0x100 [ 21.058997] usb_probe_interface+0x1ba/0x330 [ 21.059399] really_probe+0x1ba/0x4c0 [ 21.059662] __driver_probe_device+0xb2/0x180 [ 21.059944] driver_probe_device+0x5a/0x100 [ 21.060170] __device_attach_driver+0xe9/0x160 [ 21.060427] ? __pfx___device_attach_driver+0x10/0x10 [ 21.060872] bus_for_each_drv+0xa9/0x100 [ 21.061312] __device_attach+0xed/0x190 [ 21.061812] device_initial_probe+0xe/0x20 [ 21.062229] bus_probe_device+0x4d/0xd0 [ 21.062590] device_add+0x308/0x590 [ 21.062912] usb_set_configuration+0x7b6/0xaf0 [ 21.063403] usb_generic_driver_probe+0x36/0x80 [ 21.063714] usb_probe_device+0x7b/0x130 [ 21.063936] really_probe+0x1ba/0x4c0 [ 21.064111] __driver_probe_device+0xb2/0x180 [ 21.064577] driver_probe_device+0x5a/0x100 [ 21.065019] __device_attach_driver+0xe9/0x160 [ 21.065403] ? __pfx___device_attach_driver+0x10/0x10 [ 21.065820] bus_for_each_drv+0xa9/0x100 [ 21.066094] __device_attach+0xed/0x190 [ 21.066535] device_initial_probe+0xe/0x20 [ 21.066992] bus_probe_device+0x4d/0xd0 [ 21.067250] device_add+0x308/0x590 [ 21.067501] usb_new_device+0x347/0x610 [ 21.067817] hub_event+0x156b/0x1e30 [ 21.068060] ? process_scheduled_works+0x48b/0xaf0 [ 21.068337] process_scheduled_works+0x5a3/0xaf0 [ 21.068668] worker_thread+0x3cf/0x560 [ 21.068932] ? kthread+0x109/0x1b0 [ 21.069133] kthread+0x197/0x1b0 [ 21.069343] ? __pfx_worker_thread+0x10/0x10 [ 21.069598] ? __pfx_kthread+0x10/0x10 [ 21.069908] ret_from_fork+0x32/0x40 [ 21.070169] ? __pfx_kthread+0x10/0x10 [ 21.070424] ret_from_fork_asm+0x1a/0x30 [ 21.070737] </TASK> Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=0584f746fde3d52b4675 Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=dd320d114deb3f5bb79b Reported-by: Youngjun Lee <[email protected]> Fixes: a3fbc2e ("media: mc-entity.c: use WARN_ON, validate link pads") Cc: [email protected] Signed-off-by: Thadeu Lima de Souza Cascardo <[email protected]> Co-developed-by: Ricardo Ribalda <[email protected]> Signed-off-by: Ricardo Ribalda <[email protected]> Reviewed-by: Laurent Pinchart <[email protected]> Reviewed-by: Hans de Goede <[email protected]> Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Laurent Pinchart <[email protected]> Signed-off-by: Hans Verkuil <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fd5d3e6 commit 000b2a6

File tree

2 files changed

+48
-27
lines changed

2 files changed

+48
-27
lines changed

drivers/media/usb/uvc/uvc_driver.c

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
135135
{
136136
struct uvc_entity *entity;
137137

138+
if (id == UVC_INVALID_ENTITY_ID)
139+
return NULL;
140+
138141
list_for_each_entry(entity, &dev->entities, list) {
139142
if (entity->id == id)
140143
return entity;
@@ -778,14 +781,27 @@ static const u8 uvc_media_transport_input_guid[16] =
778781
UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
779782
static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
780783

781-
static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
782-
unsigned int num_pads, unsigned int extra_size)
784+
static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type,
785+
u16 id, unsigned int num_pads,
786+
unsigned int extra_size)
783787
{
784788
struct uvc_entity *entity;
785789
unsigned int num_inputs;
786790
unsigned int size;
787791
unsigned int i;
788792

793+
/* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */
794+
if (id == 0) {
795+
dev_err(&dev->intf->dev, "Found Unit with invalid ID 0\n");
796+
id = UVC_INVALID_ENTITY_ID;
797+
}
798+
799+
/* Per UVC 1.1+ spec 3.7.2, the ID is unique. */
800+
if (uvc_entity_by_id(dev, id)) {
801+
dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id);
802+
id = UVC_INVALID_ENTITY_ID;
803+
}
804+
789805
extra_size = roundup(extra_size, sizeof(*entity->pads));
790806
if (num_pads)
791807
num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1;
@@ -795,7 +811,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
795811
+ num_inputs;
796812
entity = kzalloc(size, GFP_KERNEL);
797813
if (entity == NULL)
798-
return NULL;
814+
return ERR_PTR(-ENOMEM);
799815

800816
entity->id = id;
801817
entity->type = type;
@@ -907,10 +923,10 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
907923
break;
908924
}
909925

910-
unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3],
911-
p + 1, 2*n);
912-
if (unit == NULL)
913-
return -ENOMEM;
926+
unit = uvc_alloc_new_entity(dev, UVC_VC_EXTENSION_UNIT,
927+
buffer[3], p + 1, 2 * n);
928+
if (IS_ERR(unit))
929+
return PTR_ERR(unit);
914930

915931
memcpy(unit->guid, &buffer[4], 16);
916932
unit->extension.bNumControls = buffer[20];
@@ -1019,10 +1035,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
10191035
return -EINVAL;
10201036
}
10211037

1022-
term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
1023-
1, n + p);
1024-
if (term == NULL)
1025-
return -ENOMEM;
1038+
term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT,
1039+
buffer[3], 1, n + p);
1040+
if (IS_ERR(term))
1041+
return PTR_ERR(term);
10261042

10271043
if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
10281044
term->camera.bControlSize = n;
@@ -1078,10 +1094,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
10781094
return 0;
10791095
}
10801096

1081-
term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],
1082-
1, 0);
1083-
if (term == NULL)
1084-
return -ENOMEM;
1097+
term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT,
1098+
buffer[3], 1, 0);
1099+
if (IS_ERR(term))
1100+
return PTR_ERR(term);
10851101

10861102
memcpy(term->baSourceID, &buffer[7], 1);
10871103

@@ -1100,9 +1116,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
11001116
return -EINVAL;
11011117
}
11021118

1103-
unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0);
1104-
if (unit == NULL)
1105-
return -ENOMEM;
1119+
unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3],
1120+
p + 1, 0);
1121+
if (IS_ERR(unit))
1122+
return PTR_ERR(unit);
11061123

11071124
memcpy(unit->baSourceID, &buffer[5], p);
11081125

@@ -1122,9 +1139,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
11221139
return -EINVAL;
11231140
}
11241141

1125-
unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n);
1126-
if (unit == NULL)
1127-
return -ENOMEM;
1142+
unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], 2, n);
1143+
if (IS_ERR(unit))
1144+
return PTR_ERR(unit);
11281145

11291146
memcpy(unit->baSourceID, &buffer[4], 1);
11301147
unit->processing.wMaxMultiplier =
@@ -1151,9 +1168,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
11511168
return -EINVAL;
11521169
}
11531170

1154-
unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n);
1155-
if (unit == NULL)
1156-
return -ENOMEM;
1171+
unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3],
1172+
p + 1, n);
1173+
if (IS_ERR(unit))
1174+
return PTR_ERR(unit);
11571175

11581176
memcpy(unit->guid, &buffer[4], 16);
11591177
unit->extension.bNumControls = buffer[20];
@@ -1293,9 +1311,10 @@ static int uvc_gpio_parse(struct uvc_device *dev)
12931311
return dev_err_probe(&dev->intf->dev, irq,
12941312
"No IRQ for privacy GPIO\n");
12951313

1296-
unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1);
1297-
if (!unit)
1298-
return -ENOMEM;
1314+
unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT,
1315+
UVC_EXT_GPIO_UNIT_ID, 0, 1);
1316+
if (IS_ERR(unit))
1317+
return PTR_ERR(unit);
12991318

13001319
unit->gpio.gpio_privacy = gpio_privacy;
13011320
unit->gpio.irq = irq;

drivers/media/usb/uvc/uvcvideo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#define UVC_EXT_GPIO_UNIT 0x7ffe
4242
#define UVC_EXT_GPIO_UNIT_ID 0x100
4343

44+
#define UVC_INVALID_ENTITY_ID 0xffff
45+
4446
/* ------------------------------------------------------------------------
4547
* Driver specific constants.
4648
*/

0 commit comments

Comments
 (0)