
Уязвимость внеграничной записи в кэше readdir FUSE ядра Linux (CVE-2026-31694): вредоносный сервер FUSE переполняет страницу кэша страниц на 24 байта. Прилагается PoC и непривилегированный локальный эксплойт для получения root-доступа через повреждение кэша страниц /etc/passwd. Запускать только внутри ВМ.
Отсутствие проверки границ в fs/fuse/readdir.c:fuse_add_dirent_to_cache(). Сервер FUSE возвращает dirent с namelen = 4095, который сериализуется в запись размером 4120 байт. Ядро копирует её на одну страницу кэша страниц размером 4096 байт и переполняет на 24 байта, контролируемых сервером, на следующую физическую страницу.
Этот репозиторий содержит маркерный PoC для примитива записи и локальное повышение привилегий, которое направляет переполнение на копию /etc/passwd в кэше страниц и превращает root в учетную запись без пароля.
FUSE_NAME_MAX до PATH_MAX - 1 сделало путь readdir достижимым)51a8de6c50bf9 "fuse: reject oversized dirents in page cache" (один из пяти стабильных бэкпортов)Переполнение — это запись в ядро на любую физическую страницу, расположенную сразу после страницы кэша FUSE. Подготовка направляет эту запись на выбранную страницу, но это вероятностно. При промахе 24 байта могут попасть на несвязанную страницу:
Запускайте только в одноразовой виртуальной машине. Скрипты здесь всегда запускают эксплоит внутри QEMU/KVM, никогда на хосте.
exploit.c PoC и LPE (один файл, статическая сборка)
Makefile собирает ./exploit (статический)
vm/config.sh все пути и настройки (отредактируйте KERNEL_TREE)
vm/make_rootfs.sh сборка образа гостя Ubuntu 24.04 (запускать от root)
vm/build_vuln_kernel.sh сборка уязвимого bzImage из вашего дерева ядра
vm/run_vm.sh загрузка гостевой системы без графики
vm/provision_guest.sh настройка внутри гостя (выполняется по ssh)
vm/run_in_vm.sh одна команда: загрузка, настройка, запуск, проверка
Хост: Linux с KVM (/dev/kvm присутствует, ваш пользователь в группе kvm), а также:
qemu-system-x86_64, sshpass, gcc, makemake_rootfs.sh: debootstrap (и root)Вам также понадобится дерево исходников ядра Linux, чтобы собрать уязвимое ядро.
Отредактируйте vm/config.sh. Единственное значение, которое нужно установить — KERNEL_TREE: путь к копии исходного кода Linux. Используйте ревизию до исправления 51a8de6c50bf9 (любая копия 6.15..7.0 содержит ошибку). Если дерево уже содержит исправление, build_vuln_kernel.sh удалит защиту для сборки и восстановит файл после. Всё остальное (память, процессоры, SSH-порт, пути к образам) имеет значения по умолчанию, которые можно не трогать. Любое значение также можно задать через окружение, например KERNEL_TREE=/path/to/linux vm/run_in_vm.sh.
Соберите образ гостевой системы (Ubuntu 24.04, требуется root для debootstrap):
sudo vm/make_rootfs.sh
Это создаст пользователя sudo test:test, последовательную консоль, аутентификацию по паролю SSH и fuse3.
Соберите уязвимое ядро:
vm/build_vuln_kernel.sh
От начала до конца (загрузка, подготовка, маркерный PoC, LPE, проверка uid 0):
vm/run_in_vm.sh
Вручную:
vm/run_vm.sh & # загрузка без графики; консоль идёт в vm/serial.log
make # сборка статического эксплоита
# скопируйте ./exploit в гостевую систему, затем от имени пользователя test:
./exploit --poc -n 20 # маркерный тест
./exploit # разогрев, затем LPE
Остановка гостевой системы:
pkill -f bzImage-fuse-vuln
--poc только маркерный режим, без изменений /etc/passwd
-n N количество раундов
(без аргументов) 5 раундов разогрева, затем до 200 попыток LPE; в случае успеха записывает строку root без пароля в /etc/passwd и сбрасывает кэши
Маркерный режим выводит попадания по раундам и общее количество, например 20/20 (100.0%).
Режим LPE выводит Warmup: 5/5, затем строку LPE n/200 ... HIT!, изменяет первую строку /etc/passwd с root:x:0:0:root:/root:/bin/bash на root::0:0:root:/root:/bin/sh, и последующий su -s /bin/sh root с пустым паролем возвращает uid 0.
Путь кэша readdir копирует каждый dirent на страницу кэша страниц. Проверка размера только спрашивает, помещается ли dirent в оставшееся место текущей страницы; она никогда не спрашивает, помещается ли dirent в страницу вообще. При namelen = 4095 запись составляет 4120 байт, поэтому копирование выходит на 24 байта за конец новой страницы.
Эксплоит истощает списки свободных страниц на процессор (PCP), чтобы аллокатор выдавал физически смежные страницы из разбивок buddy, а затем размещает страницу кэша readdir и страницу-жертву рядом. Для LPE жертвой является копия /etc/passwd в кэше страниц: переполнение в 24 байта перезаписывает строку root, так что её поле пароля становится пустым, и с PAM nullok (по умолчанию в Ubuntu) su root затем успешно выполняется с пустым паролем.
Full writeup: https://cyberstan.co.uk/fuse-readdir-oob/
Сообщено вышестоящей разработке Ци Таном (Qi Tang) и Цзюнь Ху (Zijun Hu); исправление написано Сэмюэлем Пейджем (Samuel Page). Я обнаружил и сообщил об этом независимо. Заслуга вышестоящей разработки и CVE-2026-31694 принадлежит им. Ошибка исправлена в основной линии и в стабильных ветках.
MIT, см. LICENSE. Только для обучения и авторизованного тестирования.