[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