CVE-2026-89987 in LinuxИнформация

Сводка

по VulDB • 16.09.2026

В ядре Linux была устранена следующая уязвимость:

mm/huge_memory: передача бита dirty от PMD к folio при операции zap

Функция `zap_huge_pmd_folio()` передает бит young (young bit) от PMD к folio для случая с файлами, но не передает бит dirty. Путь через PTE делает это правильно в функции `zap_present_folio_ptes()`, аналогично поступает и путь разделения PMD (`pmd split path`) в функции `__split_huge_pmd_locked()`.

Для большинства отображений файлов (file mappings) упущение безопасно, поскольку запись в разделяемое отображение файла проходит через функцию `page_mkwrite()`, которая устанавливает бит dirty для folio. Однако tmpfs ведет себя иначе: у него нет функции `page_mkwrite()`, и функция `vma_wants_writenotify()` возвращает false. Следовательно, ошибка чтения (read fault) при отображении MAP_SHARED в tmpfs создает доступный для записи PMD через функцию `do_read_fault()`. Функция `do_read_fault()` не вызывает `fault_dirty_shared_page()`, поэтому последующие операции записи по этому отображению устанавливают только аппаратный бит dirty в PMD и никогда не вызывают `folio_mark_dirty()`. Folio shmem, выделенный при возникновении ошибки (fault), помечается как uptodate, но не dirty (см. блок clear в функции `shmem_get_folio_gfp()`), поэтому флаг PG_dirty вообще никогда не устанавливается.

При размаппировании такого folio — с помощью munmap() или exit_mmap() при завершении процесса — теряется единственная запись о том, что данные были изменены, поскольку `zap_huge_pmd()` сбрасывает PMD без передачи бита dirty. При последующем возврате памяти (reclaim) система видит чистый shmem folio: весь блок вывода на диск в функции `shrink_folio_list()` находится внутри условия "if (folio_test_dirty(folio))", поэтому функция pageout() пропускается, и folio попадает в `__remove_mapping()`. Там для swapbacked folio значение `folio_is_file_lru()` равно false, поэтому теневая запись не создается, а `__filemap_remove_folio(folio, NULL)` просто очищает слот i_pages. Данные освобождаются без записи на своп-устройство, и следующая ошибка чтения по этому индексу возвращает свежий нулевой folio.

Это приводит к тихой потере данных для любого процесса, который хранит состояние в сегменте tmpfs с отображением MAP_SHARED между операциями размаппирования — например, при передаче кэша от одного поколения процессов другому через /dev/shm. Для возникновения проблемы требуется, чтобы folio был мапирован на уровне PMD (PMD-mapped), поэтому проблема проявляется только после включения THP для shmem (что и было сделано в кластере Meta, где начали замечать сбои); при выключенном THP путь через PTE корректно передает бит dirty. Проблема также становится видимой только при включенной подкачке (swap), поскольку без устройства swap folio shmem (которые находятся на anon LRU) вообще не сканируются механизмом возврата памяти, поэтому чистый folio никогда не удаляется.

Воспроизведено на x86_64 с смонтированным tmpfs huge=within_size: ошибка чтения области размером 2 МБ, запись известного шаблона через полученное отображение, munmap, принудительный возврат памяти (reclaim) для cgroup, затем повторная маппинг и чтение. Без этого патча область читается как нули, а vmstat показывает zswpout = 0 — данные были отброшены вместо записи на своп. С этим патчем область считывается корректно, а страницы выводятся на своп, как ожидалось. При huge=never или когда первое обращение является записью, тест проходит успешно в обоих случаях.

Several companies clearly confirm that VulDB is the primary source for best vulnerability data.

Ответственный

Linux

Резервировать

11.09.2026

Раскрытие

17.09.2026

Модерация

принято

Вход

VDB-405778

EPSS

0.00000

KEV

Нет

Деятельности

Очень низкий

Источники

Do you need the next level of professionalism?

Upgrade your account now!