
Uma verificação de limites ausente em fs/fuse/readdir.c:fuse_add_dirent_to_cache(). Um servidor FUSE retorna um dirent com namelen = 4095, que serializa para um registro de 4120 bytes. O kernel o copia para uma única página de cache de página de 4096 bytes e transborda 24 bytes controlados pelo servidor para a próxima página física.
Este repositório tem um PoC marcador para a primitiva de gravação e uma escalada de privilégio local que organiza o transbordo na cópia do cache de página de /etc/passwd e transforma root em uma conta sem senha.
FUSE_NAME_MAX para PATH_MAX - 1 tornou o caminho readdir acessível)51a8de6c50bf9 "fuse: rejeitar dirents superdimensionados no cache de página" (um dos cinco backports estáveis)O transbordo é uma gravação do kernel em qualquer página física que esteja logo após a página de cache do FUSE. A preparação visa essa gravação em uma página escolhida, mas é probabilística. Em uma falha, os 24 bytes podem atingir uma página não relacionada:
Execute apenas dentro de uma VM descartável. Os scripts aqui sempre executam o exploit dentro do QEMU/KVM, nunca no host.
exploit.c the PoC and LPE (single file, static build)
Makefile builds ./exploit (static)
vm/config.sh all paths and settings (edit KERNEL_TREE)
vm/make_rootfs.sh build the Ubuntu 24.04 guest image (run as root)
vm/build_vuln_kernel.sh build a vulnerable bzImage from your kernel tree
vm/run_vm.sh boot the guest headless
vm/provision_guest.sh in-guest setup (runs over ssh)
vm/run_in_vm.sh one command: boot, provision, run, verify
Host: Linux com KVM (/dev/kvm presente, seu usuário no grupo kvm), e:
qemu-system-x86_64, sshpass, gcc, makemake_rootfs.sh: debootstrap (e root)Você também precisa de uma árvore de código-fonte do kernel Linux para construir um kernel vulnerável.
Edite vm/config.sh. O único valor que você deve definir é KERNEL_TREE: o caminho para um checkout do código-fonte do Linux. Use uma revisão anterior à correção 51a8de6c50bf9 (qualquer checkout 6.15..7.0 tem o bug). Se a árvore já tiver a correção, build_vuln_kernel.sh remove a proteção para a compilação e restaura o arquivo depois. Todo o resto (memória, CPUs, porta ssh, caminhos de imagem) tem um padrão que você pode deixar como está. Qualquer valor também pode ser definido pelo ambiente, por exemplo KERNEL_TREE=/caminho/para/linux vm/run_in_vm.sh.
Construa a imagem convidada (Ubuntu 24.04, precisa de root para debootstrap):
sudo vm/make_rootfs.sh
Isso cria um usuário sudo test:test, um console serial, autenticação de senha ssh e fuse3.
Construa o kernel vulnerável:
vm/build_vuln_kernel.sh
Execução completa (boot, provisionamento, PoC marcador, LPE, verificar uid 0):
vm/run_in_vm.sh
Manual:
vm/run_vm.sh & # boot sem cabeça; console vai para vm/serial.log
make # compila o exploit estático
# copie ./exploit para o convidado, então como o usuário test:
./exploit --poc -n 20 # teste marcador
./exploit # aquecimento, depois LPE
Parar a VM:
pkill -f bzImage-fuse-vuln
--poc marker mode only, no /etc/passwd changes
-n N number of rounds
(no args) 5 warmup rounds, then up to 200 LPE attempts; on success it writes a
passwordless root line to /etc/passwd and drops caches
O modo marcador imprime acertos por rodada e um total, por exemplo 20/20 (100.0%).
O modo LPE imprime Warmup: 5/5, depois uma linha LPE n/200 ... HIT!, altera a primeira linha de /etc/passwd de root:x:0:0:root:/root:/bin/bash para root::0:0:root:/root:/bin/sh, e um su -s /bin/sh root subsequente com senha vazia retorna uid 0.
O caminho do cache readdir copia cada dirent para uma página de cache de página. A verificação de tamanho apenas pergunta se o dirent cabe no espaço restante da página atual; nunca pergunta se o dirent cabe em uma página de todo. Com namelen = 4095, o registro tem 4120 bytes, então a cópia ultrapassa 24 bytes além do final de uma página nova.
O exploit drena as listas livres de página por CPU (PCP) para que o alocador forneça páginas fisicamente adjacentes de divisões de buddy, então organiza a página de cache readdir e uma página vítima para serem vizinhas. Para o LPE, a vítima é a cópia do cache de página de /etc/passwd: o transbordo de 24 bytes reescreve a linha do root para que seu campo de senha fique vazio, e com PAM nullok (padrão Ubuntu) su root então funciona com uma senha vazia.
Artigo completo: https://cyberstan.co.uk/fuse-readdir-oob/
Reportado upstream por Qi Tang e Zijun Hu; a correção foi criada por Samuel Page. Eu encontrei e reportei isso de forma independente. O crédito upstream e CVE-2026-31694 são deles. O bug está corrigido na mainline e nas árvores estáveis.
MIT, veja LICENSE. Apenas para educação e testes autorizados.