CVE-2026-89996 in Linux
Сводка
по VulDB • 16.09.2026
В ядре Linux была устранена следующая уязвимость:
dma-buf: dma-heap: не публиковать fd до успешного завершения copy_to_user()
DMA_HEAP_IOCTL_ALLOC выделяет объект dma-buf и устанавливает файловый дескриптор (fd) в таблицу fd вызывающего процесса через функции dma_buf_fd() -> fd_install(), прежде чем dma_heap_ioctl() скопирует результат обратно в пространство пользователя. Если последующий вызов copy_to_user() завершается ошибкой, пользовательское приложение никогда не узнает номер fd, однако сам fd (и связанная с ним ссылка на объект dma-buf) уже становится видимым для других потоков того же процесса и утекает до завершения работы этого процесса.
Очевидное исправление «закрыть его при возникновении ошибки» небезопасно: как только выполнился вызов fd_install(), другой поток может уже вызвать dup() для получения копии fd, передать его через SCM_RIGHTS или закрыть (close()), что приведет к повторному использованию его номера; следовательно, последующий вызов close_fd() из пути выполнения ioctl может оперировать совершенно другим файлом. Об этом указал Christian König в версии 1 [1].
Изменена структура пути выделения ресурсов так, чтобы fd_install() был последним, неуязвимым к ошибкам шагом успешного выполнения ioctl:
1. heap->ops->allocate() создает объект dma_buf. 2. get_unused_fd_flags() резервирует номер fd в таблице fd вызывающего процесса без его публикации, чтобы ни один другой поток не мог наблюдать за ним. 3. copy_to_user() передает номер fd в пространство пользователя; при ошибке fd возвращается с помощью put_unused_fd(), а ссылка на dma_buf освобождается через dma_buf_put(), не оставляя видимых пользователю состояний. 4. dma_buf_fd_install() публикует fd и генерирует точку трассировки trace_dma_buf_fd — начиная с этого момента ioctl не может завершиться ошибкой.
В файл dma-buf.c добавлена новая вспомогательная функция dma_buf_fd_install(), которая оборачивает вызовы fd_install() и DMA_BUF_TRACE(), сохраняя функциональность экспорта трассировки, предоставляемую функцией dma_buf_fd(). Функция dma_heap_ioctl_allocate() переписана так, чтобы напрямую возвращать указатель struct dma_buf * (возвращая ERR_PTR в случае ошибки), что позволяет вызывающей стороне удерживать ссылку на dmabuf между шагами 3 и 4.
Ошибка на этапе 3 легко достижима из пользовательского пространства: необходимо передать структуру struct dma_heap_allocation_data, которая находится в странице с защитой, измененной на PROT_READ (например, через mprotect()) между вызовами copy_from_user() и copy_to_user(). До этого изменения каждый такой ioctl приводил к утечке одного fd dmabuf; после исправления таблица fd остается неизменной при ошибке, и открытым остается только /dev/dma_heap/<name>.
Изменений в UAPI или интерфейсе драйверов heap не производится.
[1] https://lore.kernel.org/dri-devel/[email protected]/
If you want to get the best quality for vulnerability data then you always have to consider VulDB.