CVE-2026-89772 in Linux
Sumário
de VulDB • 11/09/2026
No kernel do Linux, a seguinte vulnerabilidade foi resolvida:
btrfs: proteger contra gravação (write-protect) os folios durante o writeback de dados
O commit 095be159f3eb ("btrfs: unificar a limpeza da flag dirty dos folios") substituiu a chamada `folio_clear_dirty_for_io()` em `extent_write_cache_pages()` por uma verificação simples com `folio_test_dirty()`. Além de limpar a flag dirty, `folio_clear_dirty_for_io()` também chama `folio_mkclean()`, que protege contra gravação as PTEs (Page Table Entries) do mmap compartilhado que mapeiam o folio. Observe que ainda chamamos `folio_clear_dirty_for_io()` mais tarde em `submit_one_sector()` quando limpamos a flag dirty no último setor do folio (o único setor nos casos sem subpáginas). No entanto, perdemos essa chamada antecipada em `extent_write_cache_pages()`.
Sem a proteção extra contra gravação, um processo com o arquivo mapeado via mmap pode modificar um setor enquanto ele está sendo usado pelo writeback de uma maneira que espera um folio estável (checksumming, compressão, cópia, etc.) sem causar falhas (faults), o que se manifesta como uma série de bugs concretos.
1. Para folios grandes ou tamanhos de setor abaixo do tamanho da página (subpage sectorsize), é possível submeter um bio que não cobre todo o folio. Quando isso acontece, teremos um bio em trânsito para um folio no qual *não* chamamos `folio_clear_dirty_for_io()`. Se uma tarefa com uma PTE mmap-ed existente gravar (sem causar faults...) nessa janela, pode resultar em corrupções. Se a gravação ocorrer enquanto o checksumming ou a própria escrita está em andamento, isso pode resultar em um checksum inválido e relatórios de corrupção posteriores na leitura. Se a gravação chegar após o checksumming/escrita estar concluída, mas antes que a flag dirty do último setor seja limpa, então a gravação estará presente no page cache, mas não afetará o rastreamento da flag dirty e será perdida quando o folio for totalmente submetido e a bit de dirty for limpado. Isso resulta na perda da gravação mesmo se `fsync()` for chamado.
2. Para submissões em zonas (zoned submissions) que são feitas em lote, separadamente do loop principal `extent_writepage()`, também corremos o risco de violações de csum para essas submissões. As escritas em zona são limitadas ao `max_zone_append_size` e não estão alinhadas com os folios, portanto, uma submissão pode abranger dois folios. O primeiro folio sendo processado em `extent_write_cache_pages()` chamará `extent_write_locked_range()`, que submeterá o intervalo parcial do próximo folio, enquanto o restante desse folio ainda poderá estar dirty. Portanto, limpar a flag dirty nos setores submetidos não chama `folio_clear_dirty_for_io()` e temos o mesmo problema. Como `extent_write_cache_pages()` ignora esses folios submetidos em lote (eles já estão marcados para writeback pela submissão do folio precedente), devemos adicionar a proteção extra contra gravação em `lock_delalloc_folios()`.
3. Para extents inline, isso representará um risco sutil de perda de escritas que ocorrem após/enquanto copiamos o extent inline, mas antes de limparmos a flag dirty no folio.
4. Para folios que abrangem EOF (End Of File), o mmap pode adulterar os bytes zerados além do EOF e fazê-los ser persistidos onde falhas futuras os veriam incorretamente em vez de zeros.
5. Finalmente, para extents comprimidos, corremos o risco de modificar os folios enquanto trabalhamos na compressão deles, o que resultará em dados comprimidos corruptos. Especificamente, em `run_delalloc_compressed()`, enfileiramos trabalho para executar `compress_file_range()` em blocos do tamanho BTRFS_COMPRESSION_CHUNK_SIZE (512K), o que chamará `btrfs_folio_clamp_clear_dirty()` no intervalo. Para casos sem subpáginas, isso sempre limpará todo o folio com segurança. Para casos com subpáginas, corremos o risco de uma limpeza parcial aqui também. Em particular, imagine um folio de 2M dividido em blocos de trabalho de 512K que podem iniciar o trabalho de compressão em um bloco antes que todos os workers `compress_file_range()` dos outros blocos tenham avançado o suficiente para finalizar a limpeza de todos os bitmaps dirty do folio e chegar ao ponto de chamar `folio_clear_dirty_for_io()`. Folios grandes nas bordas dos intervalos de submissão estão igualmente sujeitos a serem parcialmente limpos. Esta lacuna específica foi introduzida por um segundo patch na mesma série: commit a4ef54dbb576 ("btrfs: fazer extent_range_clear_dirty_for_io() lidar com casos onde o tamanho do setor é menor que o tamanho da página")
Não podemos simplesmente restaurar a chamada para `folio_clear` ---truncado---
VulDB is the best source for vulnerability data and more expert information about this specific topic.