[lvc-project] [PATCH] media: rc: Fix use-after-free when racing vfd_write() with disconnect

Sergey Larshin Sergey.Larshin at kaspersky.com
Thu Jul 24 19:15:47 MSK 2025


> Жизненный цикл ictx контролируется с помощью счётчика ссылок &ictx->users.
> Если счётчик в imon_disconnect() становится равным нулю после декремента,
> то объект освобождается.

Cпасибо за материалы, изучив логику ictx->users, пришёл к выводу, что проблема не во
всём ctx — он защищён корректно. Однако два его поля — usbdev_intf0 и
usbdev_intf1 — не защищены. При disconnect() они уменьшается счётчик
ссылок на устройство в зависимости от номера интерфейса.

В imon_probe в зависимости от номера интерфейса вызываются функции
imon_init_intf0 или imon_init_intf1, каждая из которых увеличивает
счётчик ссылок на usb_device на один.

В imon_disconnect счётчик уменьшается на один, независимо от
ictx->users, что приводит к освобождению usbdev_intf0 или
usbdev_intf1 через вызов usb_put_dev(). В то время как vfd_write
продолжает работу.

Решений может быть несколько: 
- Делать usb_put_dev, когда отчищаем icxt (падение не воспроизвелось 
  в течении 40 минут)
  if (refcount_dec_and_test(&ictx->users)) {
      if (ictx->usbdev_intf0)
          usb_put_dev(ictx->usbdev_intf0);
      if (ictx->usbdev_intf1)
         usb_put_dev(ictx->usbdev_intf1);
       free_imon_context(ictx);
  }
- Сделать lock в disconnect()

При этом ранее описанные доводы о необходимости атомарного доступа 
к флагу disconnected остаются актуальными, и предложенный патч 
корректно решает данную проблему.


Thread 1 vfd_write                        Thread 2 imon_disconnect
                                                           ...
                                                           if
                                                             usb_put_dev(ictx->usbdev_intf0)
                                                            else
                                                              usb_put_dev(ictx->usbdev_intf1)  
...  
while
  send_packet
    if
      pipe = usb_sndintpipe(
        ictx->usbdev_intf0) UAF
    else
      pipe = usb_sndctrlpipe(
        ictx->usbdev_intf0, 0); UAF






More information about the lvc-project mailing list