
CVE-2022-25258 - Демонстрационный эксплойт, нацеленный на обработчик OS-дескриптора USB-гаджета
Подсистема USB Gadget содержит уязвимости в разделе обработки OS-дескрипторов функции composite_setup (composite.c). Обработка специально сформированных сообщений запросов управления передачей (control transfer) приводит к сбою устройства из-за разыменования нулевого указателя или повреждения памяти.
Раздел обработки OS-дескрипторов функции composite_setup для получателя интерфейса (interface recipient) реализован следующим образом.
case USB_RECIP_INTERFACE:
if (w_index != 0x5 || (w_value >> 8))
break;
interface = w_value & 0xFF;
buf[6] = w_index;
count = count_ext_prop(os_desc_cfg,
interface);
put_unaligned_le16(count, buf + 8);
count = len_ext_prop(os_desc_cfg,
interface);
put_unaligned_le32(count, buf);
value = w_length;
if (w_length > 0x0A) {
value = fill_ext_prop(os_desc_cfg,
interface, buf);
if (value >= 0)
value = min_t(u16, w_length, value);
}
break;
Переменная interface получается из w_value и в дальнейшем используется для индексации массива usb_configuration->interface в функциях count_ext_prop, len_ext_prop и fill_ext_prop. Поскольку массив c->interface имеет размер MAX_CONFIG_INTERFACES (16) элементов, а переменная interface не проверяется ни в разделе обработки OS-дескрипторов composite_setup, ни в вызываемых функциях, атакующий может индексировать массив c->interface за его фактическими границами. Если переменная interface имеет значение больше или равное MAX_CONFIG_INTERFACES, конечная точка должна быть переведена в состояние STALL.
В определённых случаях, в зависимости от фактического содержимого памяти, индексация за пределами массива c->interface может вызвать переполнение буфера req->buf через fill_ext_prop, когда wLength больше 0x0A. Если сумма ext_prop->name_len, ext_prop->data_len, 14 и 10 переполняет int, условие count + n >= USB_COMP_EP0_OS_DESC_BUFSIZ не будет выполнено, что допускает переполнение через memcpy в usb_ext_prop_put_binary. Однако вероятность такой ситуации довольно низка.
Кроме того, в функциях count_ext_prop, len_ext_prop и fill_ext_prop отсутствует проверка того, что указатель *usb_function, полученный из массива c->interface, действительно корректен, что приводит к разыменованию нулевого указателя. Если полученный указатель usb_function равен null, конечная точка должна быть переведена в состояние STALL.
static int count_ext_prop(struct usb_configuration *c, int interface)
{
struct usb_function *f;
int j;
f = c->interface[interface];
for (j = 0; j < f->os_desc_n; ++j) {
struct usb_os_desc *d;
if (interface != f->os_desc_table[j].if_id)
continue;
d = f->os_desc_table[j].os_desc;
if (d && d->ext_compat_id)
return d->ext_prop_count;
}
return 0;
}
Устройства под управлением Linux (и Android), предоставляющие USB-гаджеты с поддержкой OS-дескрипторов, могут быть произвольно аварийно завершены вредоносным хостом с помощью одного сообщения управления передачей (control transfer).
Патч, устраняющий описанную проблему, был принят и теперь доступен в поддерживаемых версиях ядра. Дополнительную информацию см. по ссылке ниже.