
Доказательство концепции эксплуатации для CVE-2026-31431, локального повышения привилегий в ядре Linux через запись в page cache AF_ALG, позволяющего получить root на основных дистрибутивах.
algif_aead (запись в страничный кэш «Copy Fail»)
Автор: Van Glenndon Enad
Первоначальное обнаружение: Theori / Xint Code Research Team (Taeyang Lee)
Опубликовано: 29 апреля 2026 г.
Серьёзность: Высокая
Оценка CVSS v3.1: 7.8
Вектор CVSS v3.1: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-787 (запись за пределами границ), CWE-269 (некорректное управление привилегиями)
CVE-2026-31431, публично названная «Copy Fail», — это уязвимость высокой степени серьёзности, позволяющая повышать привилегии в локальной системе (LPE) в модуле ядра Linux algif_aead — интерфейсе шифров AEAD криптографического API ядра для пользовательского пространства (AF_ALG). Дефект возник из-за оптимизации производительности (операция «на месте»), внедрённой в 2017 году в коммите 72548b093ee3, которая непреднамеренно позволила размещать файловые страницы, поддерживаемые страничным кэшем, в записываемом списке рассеяния назначения во время криптографической операции AEAD.
Объединив три подсистемы ядра — сокеты AF_ALG, системный вызов splice() и поведение алгоритма authencesn при записи во временный буфер — непривилегированный локальный пользователь может выполнить контролируемую запись 4 байт в страничный кэш любого читаемого файла. Нацелившись на setuid-бинарник, такой как /usr/bin/su, эта запись повреждает образ исполняемого файла в памяти, не изменяя файл на диске, тем самым обходя инструменты проверки целостности файлов на диске. Результирующее повышение привилегий до root является детерминированным — не требуется ни состояния гонки, ни смещений ядра для конкретного дистрибутива, ни специальных привилегий. Публично выпущенный PoC-эксплойт на Python размером 732 байта предоставляет root-оболочки в Ubuntu, Amazon Linux, RHEL и SUSE за один неизменённый запуск.
| Компонент | Сведения |
|---|---|
| Затронутая подсистема | crypto/algif_aead.c — интерфейс AEAD AF_ALG ядра Linux |
| Уязвимость внедрена | Ядро Linux 4.14 (2017), коммит 72548b093ee38a6d4f2a19e6ef1948ae05c181f7 |
| Исправленные версии | 6.18.22, 6.19.12, 7.0 |
| Исправляющий коммит | a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5 |
| Проверенные дистрибутивы | Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 10.1, SUSE 16 |
| Неявно затронутые | Debian, Arch, Fedora, Rocky, AlmaLinux, Oracle Linux и любой дистрибутив с непропатченным ядром, собранным с 2017 года |
Уязвимость незаметно присутствует в каждом массовом дистрибутиве Linux уже почти девять лет. По данным Theori, AF_ALG включён в конфигурацию ядра по умолчанию практически во всех дистрибутивах, что означает отсутствие необходимости в специальных флагах сборки или конфигурациях для того, чтобы система была уязвимой.
Ядро Linux предоставляет криптографические примитивы пользовательскому пространству через интерфейс сокетов AF_ALG (crypto/algif_aead.c). В 2017 году была внедрена оптимизация производительности, которая позволила algif_aead выполнять операции AEAD на месте — повторно используя исходный буфер памяти в качестве назначения — чтобы избежать ненужного копирования данных.
Дефект проявляется, когда пользовательское пространство передаёт входные данные в сокет AF_ALG через системный вызов splice(). В этом случае страницы, помещённые в список рассеяния источника, являются страницами страничного кэша — общей памятью, управляемой ядром, поддерживающей переданный файл. Из-за оптимизации «на месте», устанавливающей req->src = req->dst, эти страницы страничного кэша попадают в записываемый список рассеяния назначения. Алгоритм authencesn впоследствии выполняет запись во временный буфер по адресу dst[assoclen + cryptlen], который разрешается в смещение внутри этих страниц страничного кэша — фактически записывая данные, контролируемые атакующим, в образ переданного файла в памяти.
Поскольку страничный кэш является общим для всего хоста, включая контейнеры, запись из одного процесса влияет на кэшированные страницы этого файла для всех процессов и контейнеров на том же ядре.
Оскорбительное изменение в algif_aead.c установило req->src = req->dst и связало страницы тега из списка рассеяния источника в выходной список рассеяния через sg_chain():
/* Оптимизация «на месте» 2017 года — коммит 72548b093ee3 */
req->src = req->dst; /* источник == назначение */
sg_chain(dst, n + 1, src_tag); /* страницы тега связаны в записываемый dst */
Когда splice() используется для передачи файла в сокет, страницы списка рассеяния поддерживаются страничным кэшем, а не приватной анонимной памятью. Связывание их в записываемый список рассеяния dst нарушает предположение о том, что назначение является записываемой приватной памятью.
authencesnШаблон authencesn записывает временное значение порядкового номера (seqno_lo, байты 4–7 AAD) по адресу dst[assoclen + cryptlen]. Поскольку dst теперь содержит страницы страничного кэша из переданного файла, эта запись попадает в смещение, контролируемое атакующим, внутри образа файла в памяти:
/* Временная запись authencesn — смещение определяется assoclen + cryptlen */
scatterwalk_map_and_copy(seqno, dst,
req->assoclen + req->cryptlen,
sizeof(seqno), 1); /* запись в страничный кэш */
Записанные 4 байта соответствуют seqno_lo, который атакующий контролирует через полезную нагрузку AAD, отправляемую через sendmsg().
Сокет AF_ALG (SOCK_SEQPACKET)
│
│ splice() — доставляет страницы файла в сокет
▼
Оптимизация «на месте» algif_aead
│ req->src = req->dst
│ страницы страничного кэша попадают в записываемый список рассеяния
▼
Временная запись authencesn
│ записывает seqno_lo по адресу dst[assoclen + cryptlen]
│ = выбранные атакующим 4 байта по выбранному атакующим смещению в файле
▼
Повреждение страничного кэша (без изменения на диске)
Исправление (a664bf3d603d) полностью отменяет оптимизацию «на месте» — algif_aead теперь всегда работает вне места, выделяя отдельный буфер назначения. Поскольку источник и назначение теперь поступают из разных отображений, страницы страничного кэша в src никогда не могут быть достигнуты путём записи в dst.