Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
btrfs_fixes — Ferramentas de reparo BTRFS personalizadas para corrupção severa da árvore de extent onde btrfs check --repair falha (segfault, loop ou deadlock) | Kitploit
Ferramentas/GitHubGitHub/msedek/btrfs_fixes
Análise de VulnerabilidadesAnálise ForenseRecuperação de DadosPapers e PesquisaAprendizado e Educação
GitHubmsedek/btrfs_fixes

btrfs_fixes

Ferramentas de reparo BTRFS personalizadas para corrupção severa da árvore de extent onde btrfs check --repair falha (segfault, loop ou deadlock)

Ver Repositório
9há 4 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

btrfs_fixes: Ferramentas de Reparo BTRFS Personalizadas

Ferramentas personalizadas escritas durante a recuperação de um pool BTRFS de 12 TB com vários dispositivos e grave corrupção da árvore de extent (extent tree) que os comandos nativos (btrfs check --repair, --init-extent-tree, etc.) não conseguiram reparar.

Veja INCIDENT-ANALYSIS.md para um estudo de caso estruturado da recuperação, uma classificação de causa raiz e um conjunto de propostas construtivas para melhorias no btrfs-progs upstream que teriam evitado a necessidade da maioria dessas ferramentas.

Quando usar estas ferramentas

Use estas ferramentas APENAS se btrfs check --repair falhar com segfault, entrar em um loop infinito ou deixar o sistema de arquivos em pior estado do que antes.

Casos documentados onde elas ajudam:

  • btrfs check --repair dá segfault em [3/8] checking extents (Issue #525)
  • btrfs check --init-extent-tree trava (deadlock)
  • btrfs check --repair entra em um loop infinito repetindo os mesmos reparos
  • Árvore de extent com milhares de METADATA_ITEMs carregando owner/level/generation errados
  • FS_TREE com ponteiros filhos obsoletos (stale) que referenciam blocos reutilizados por outras árvores
  • Pool só monta com rescue=all,ro, falha ao montar RW

Estas ferramentas NÃO são para corrupção leve. Para danos normais, tente btrfs check --repair primeiro.

Avisos

  • FAÇA BACKUP dos metadados ANTES de executar qualquer ferramenta com --write:
    root@kitploit:~
    for DEV in sda1 sdb1 sdc1; do
      sudo dd if=/dev/$DEV of=sb_${DEV}.bin bs=4096 count=1 skip=16
    done
    
  • Estas ferramentas fazem alterações irreversíveis no sistema de arquivos
  • Todas operam por padrão em modo apenas de varredura (--write é opt-in)
  • O sistema de arquivos deve estar desmontado ao executar estas ferramentas
  • Requer btrfs-progs v6.19.1 ou similar, com o patch EEXIST aplicado

Compilação

As ferramentas utilizam a API interna do btrfs-progs e devem ser compiladas dentro da árvore de fontes do btrfs-progs:

root@kitploit:~
# 1. Clone o btrfs-progs
git clone --depth 1 --branch v6.19.1 https://github.com/kdave/btrfs-progs.git
cd btrfs-progs

# 2. Aplique o patch EEXIST (necessário para injeção em lote de backrefs)
patch -p1 < caminho/para/btrfs_fixes/patches/alloc_reserved_tree_block_eexist.patch

# 3. Configure e compile o btrfs-progs base
./autogen.sh
./configure
make -j$(nproc)

# 4. Copie os arquivos .c deste repositório para o diretório btrfs-progs
cp caminho/para/btrfs_fixes/programs/*.c .

# 5. Para cada programa, adicione ao Makefile:
echo '
PROGNAME: PROGNAME.o $(objects) $(libs_shared)
	@echo "  [LD]    $@"
	$(Q)$(CC) -o $@ PROGNAME.o $(objects) $(libs_shared) $(LDFLAGS) $(LIBS)
' >> Makefile

# 6. Compile
make PROGNAME

Ferramentas

Ordem de execução recomendada:

1. scan_and_fix_all_backrefs.c (mais importante)

A ferramenta mais importante. Percorre recursivamente cada árvore no sistema de arquivos (ROOT, CHUNK, EXTENT, FS, DEV, CSUM, UUID, FREE_SPACE) e detecta blocos de metadados que estão sem um METADATA_ITEM backref na árvore de extent. Injeta todos os backrefs ausentes em uma única transação para evitar o problema de "árvore raiz se move entre commits".

Uso:

root@kitploit:~
sudo ./scan_and_fix_all_backrefs /dev/sdX          # apenas varredura
sudo ./scan_and_fix_all_backrefs /dev/sdX --write  # varredura + injeção

2. fix_owner_refs.c

Corrige o owner no TREE_BLOCK_REF inline quando ele não corresponde ao btrfs_header_owner() real do bloco. Inconsistências ocorrem quando blocos são reatribuídos entre árvores durante reparos com falha.

root@kitploit:~
sudo ./fix_owner_refs /dev/sdX          # varredura
sudo ./fix_owner_refs /dev/sdX --write  # correção

3. fix_bad_levels.c

Corrige entradas METADATA_ITEM e EXTENT_ITEM com nível incorreto. Níveis corrompidos (ex.: 50, 55, 237) são lixo deixado por btrfs check --repair ao entrar em loop. Verificado contra o btrfs_header_level() real do bloco.

root@kitploit:~
sudo ./fix_bad_levels /dev/sdX          # varredura
sudo ./fix_bad_levels /dev/sdX --write  # correção

4. fix_duplicate_extents.c

Exclui METADATA_ITEMs duplicados (mesmo bytenr, níveis diferentes na chave). Mantém aquele cujo nível corresponde a btrfs_header_level e exclui o outro.

root@kitploit:~
sudo ./fix_duplicate_extents /dev/sdX          # varredura
sudo ./fix_duplicate_extents /dev/sdX --write  # excluir duplicatas

5. remove_stale_ptrs.c

Varre cada nó de nível 1 da FS_TREE. Detecta ponteiros filhos obsoletos usando três verificações: incompatibilidade de owner, incompatibilidade de first_key ou uma first_key cujo tipo é inválido para a FS_TREE (ex.: BLOCK_GROUP_ITEM). Remove-os com btrfs_del_ptr.

root@kitploit:~
sudo ./remove_stale_ptrs /dev/sdX          # varredura
sudo ./remove_stale_ptrs /dev/sdX --write  # remoção

6. fix_uuid_tree.c / fix_csum_tree.c

Cria uma folha vazia para a árvore UUID / árvore CSUM, respectivamente. Útil quando o ROOT_ITEM aponta para um bloco que foi reatribuído a outra árvore. O kernel regenera a árvore UUID automaticamente na montagem RW. Com uma árvore CSUM vazia, arquivos sinalizados como NODATASUM não falham na verificação.

root@kitploit:~
sudo ./fix_uuid_tree /dev/sdX
sudo ./fix_csum_tree /dev/sdX

7. set_nodatasum.c

Define o sinalizador BTRFS_INODE_NODATASUM em inodes de arquivos regulares. Use isto se a árvore csum estiver vazia, mas os arquivos ainda tiverem checksums esperados, o que causa erros de leitura. Com NODATASUM, o kernel ignora as consultas de csum.

root@kitploit:~
sudo ./set_nodatasum /dev/sdX          # varredura
sudo ./set_nodatasum /dev/sdX --write  # aplicar

8. fix_fstree_node.c

Versão com uma lista codificada de blocos obsoletos. Prefira remove_stale_ptrs, que os detecta automaticamente. Use apenas se precisar de controle manual sobre quais blocos específicos remover.

9. add_backrefs.c

Versão inicial com uma lista codificada de backrefs ausentes. Prefira scan_and_fix_all_backrefs, que os detecta automaticamente.

Conjunto de ferramentas da Sessão 2 (2026-04-04/05): Recuperação estendida para corrupção massiva

Quando as ferramentas básicas acima foram insuficientes (pool com 200K+ erros espalhados por várias árvores), estas ferramentas adicionais foram construídas:

scan_fstree_extents.c + scan_extent_tree.c

Scanners da Passada 1 e Passada 2 que percorrem a FS_TREE e a árvore de extent, respectivamente, produzindo arquivos TSV com cada mapeamento ref/extent. Usado para criar a entrada para rebuild_extent_tree_apply quando a árvore de extent precisa ser reconstruída do zero.

rebuild_extent_tree_apply.c (escritor pesado)

O principal escritor da Fase 3. Pega uma lista previamente dobrada de refs (do diff de scan_fstree_extents + scan_extent_tree) e injeta 3M+ EXTENT_DATA_REFs na árvore de extent em blocos de 5000 por transação. Reduz a cada 50K itens para evitar paradas de re-shingle do DM-SMR. Verificado como bem-sucedido com 3.248.617 inserções em ~34 min em 3 discos SMR WD40EFAX.

root@kitploit:~
sudo ./rebuild_extent_tree_apply /dev/sdX1 refs_folded.txt to_insert.txt watermark.txt --dryrun
sudo ./rebuild_extent_tree_apply /dev/sdX1 refs_folded.txt to_insert.txt watermark.txt --write

patch_block_group_used.c

Corretor cirúrgico de campo único para BLOCK_GROUP_ITEM.used quando o escritor da Fase 3 deixa um bg específico com overshoot devido a itens file_extent sobrepostos pré-existentes. Usa o setter direto btrfs_set_block_group_used para evitar a contabilidade space_info de btrfs_update_block_group (que NÃO queremos aqui). Pré-valida flags & BTRFS_BLOCK_GROUP_DATA.

root@kitploit:~
sudo ./patch_block_group_used /dev/sdX1 <bg_bytenr> <bg_length> <new_used> --write

remove_extent_items_by_key.c

Exclui uma lista codificada de EXTENT_ITEMs (bytenr, num_bytes, expected_inode) da árvore de extent. Usado para limpar extents obsoletos sobrepostos em uma única folha que impedem a montagem RO. Verificações de sanidade por item antes da exclusão (7 invariantes, incluindo lista de permissão de inodes). Executado com rebuilding_extent_tree=1 + reinit_extent_tree=true para ignorar a contabilidade de espaço (o chamador corrige used manualmente primeiro via patch_block_group_used).

clean_orphan_dir_entries.c

Limpa entradas órfãs DIR_ITEM + DIR_INDEX da FS_TREE. Blocos de 100 entradas por transação. Atualiza i_size do INODE_ITEM pai (decrementa por namelen × 2: correção de bug crítico: v1 decrementava apenas por namelen, deixando diretórios em estado inválido). Lista de exclusão codificada para nomes críticos de diretórios de nível superior (ex.: pelis, series, music, backups, homestorage). NUNCA decremente i_size pelo namelen bruto: BTRFS armazena contabilidade namelen × 2.

clean_orphan_inode_refs.c

Percorre a FS_TREE em busca de itens INODE_REF cujo key.offset (inode pai) está em uma lista de pais órfãos. Ignora INODE_EXTREF para evitar falsos positivos (o key.offset do EXTREF é um hash, não um ID pai). Blocos de 32 por transação.

fix_dir_inode_counts.c

Recalcula i_size = sum(name_len × 2) e nlink = 1 para inodes DIR cujas contagens foram corrompidas por bugs anteriores de limpeza de órfãos. CRÍTICO para segurança: se qualquer DIR tiver nlink = 2, um único rm -rf em seu caminho excluirá silenciosamente milhares de subdiretórios (bomba rmdir). Percorre entradas DIR_INDEX, verifica cruzadamente DIR_ITEM para detecção de colisão de hash (0 colisões verificadas empiricamente).

remove_orphan_inode_subtrees.c

Remove subárvores de inodes órfãos (famílias DIR + REGs independentes) da FS_TREE. Para cada alvo: percorre e exclui EXTENT_DATA, INODE_REF, INODE_EXTREF, XATTR e, finalmente, INODE_ITEM. Transação por família DIR (atômica por subárvore), blocos de 50 para REGs independentes. Lista de exclusão paranóica codificada.

⚠️ AVISO MAIOR DE SEGURANÇA: veja "Critério de subconjunto à prova de balas" abaixo.

remove_stale_ptrs_v2.c

Versão melhorada de remove_stale_ptrs: detecta folhas vazias com parent expected_key (v1 ignorava este caso), varredura recursiva de 2 níveis (raiz→nível1 + nível1→folhas), buffer dinâmico (sem limite de 512), tolera falhas de read_tree_block.

insert_one_extent_poc.c

Prova de conceito para inserção de um único extent com validação. Usado para validar o caminho da API antes de executar rebuild_extent_tree_apply.

Critério de subconjunto à prova de balas (CRÍTICO)

Durante a sessão de 2026-04-05, remove_orphan_inode_subtrees travou duas vezes na mesma asserção BUG_ON por duas razões diferentes:

Vetor de travamento 1: btrfs_cow_block(leaf) direto sobre folha MISTA (gen 3601, contém inodes órfãos e vivos) → update_ref_for_cow percorre filhos → __btrfs_mod_ref(inc=1) sobre filhos irmãos obsoletos → btrfs_free_extent(phantom) retorna -ENOENT → BUG_ON → SIGABRT.

Vetor de travamento 2 (descoberto depois, evitado por filtragem): btrfs_del_items pós-limpeza drena uma folha abaixo de LEAF_DATA_SIZE/4 = 4096 bytes → invoca push_leaf_left(sibling) ou push_leaf_right(sibling) → se o irmão tiver gen ≤ last_snapshot = 3701, btrfs_block_can_be_shared retorna 1 → update_ref_for_cow entra no caminho refs > 1 → btrfs_inc_ref(cow_sibling, 0) → __btrfs_mod_ref(cow, level=0, inc=1) → itera todos os EXTENT_DATAs do irmão obsoleto → btrfs_inc_extent_ref(phantom_bytenr) → BUG_ON(err) em extent-tree.c:1302 → SIGABRT.

Os sinalizadores fs_info->rebuilding_extent_tree = 1 e trans->reinit_extent_tree = true NÃO salvam o caminho INC: eles só isentam BTRFS_DROP_DELAYED_REF (verificado em extent-tree.c:3885). BTRFS_ADD_DELAYED_REF (de btrfs_inc_ref) é fatal.

Critério à prova de balas para qualquer inode alvo que será excluído:

  1. A folha que hospeda o INODE_ITEM do inode tem gen > 3701 (pós-travamento)
  2. O nível 1 pai da folha tem gen > 3701
  3. Bytes used estimados pós-limpeza > 4096 (sem gatilho de rebalanceamento)
  4. TODOS os irmãos imediatos no nó pai têm gen > 3701 (mesmo que a condição 3 falhe, rebalanceamento para irmãos pós-travamento é seguro)
  5. Quaisquer alvos de backref (EXTENT_DATA disk_bytenr) resolvem na árvore de extent atual (sem -ENOENT na consulta de backref)

Violar qualquer uma das condições 3+4 desencadeia o vetor de travamento 2. A condição 5 é isenta por reinit_extent_tree para DROP, mas NÃO para INC (que é o que push_leaf_left invoca).

Padrão de validação empírica

Para qualquer conjunto de inodes órfãos candidatos, percorra o dump da FS_TREE e classifique cada folha alvo pelas 5 condições à prova de balas. Exemplo de padrão (anonimizado):

Folhas onde ≥90% dos itens são órfãos são a zona de perigo: elas drenarão abaixo do limite de rebalanceamento (LEAF_DATA_SIZE/4 = 4096 bytes) com certeza, forçando push_leaf_left/right. Se qualquer irmão imediato no nó pai tiver gen ≤ last_snapshot, o push desencadeia CoW nesse irmão, que entra no caminho btrfs_block_can_be_shared → refs > 1 → btrfs_inc_ref → __btrfs_mod_ref(inc=1) e trava com BUG_ON(err) em btrfs_inc_extent_ref.

Mitigação: exclua os inodes problemáticos do arquivo de entrada. A ferramenta processa o que passa na validação pré-voo; folhas com alvos seguros/inseguros mistos podem ser parcialmente processadas listando apenas o subconjunto seguro. A semântica de transação por família significa que cada família segura é confirmada atomicamente, mesmo que outras famílias sejam excluídas.

Resultado empírico de uma sessão: começando com N órfãos candidatos, após aplicar todas as 5 condições, o subconjunto seguro final foi ~14% da entrada, mas esse subconjunto foi confirmado sem um único BUG_ON, com diff de 0 bytes em um sha256 de linha de base de arquivos vivos capturados antes da escrita.

O patch: EEXIST em alloc_reserved_tree_block

patches/alloc_reserved_tree_block_eexist.patch modifica o btrfs-progs para que, quando alloc_reserved_tree_block encontra o METADATA_ITEM já existente, ele retorne 0 em vez de propagar EEXIST. Isso é necessário para que a injeção em lote de backrefs funcione: ao injetar muitos backrefs, o sistema de refs atrasadas também tenta criar METADATA_ITEMs para blocos recém-alocados via COW e colide com aqueles que já inserimos.

Fluxo de trabalho completo para recuperação severa

root@kitploit:~
# 1. Backup
mkdir -p backup
for DEV in /dev/sdX1 /dev/sdY1; do
  sudo dd if=$DEV of=backup/$(basename $DEV).sb bs=4096 count=1 skip=16
done

# 2. Certifique-se de que o sistema de arquivos está desmontado
sudo umount /mnt/pool 2>/dev/null

# 3. Zere a árvore de log (se aplicável)
sudo btrfs rescue zero-log /dev/sdX1

# 4. Varredura + correção de tudo (em ordem)
sudo ./scan_and_fix_all_backrefs /dev/sdX1 --write
sudo ./fix_bad_levels /dev/sdX1 --write
sudo ./fix_owner_refs /dev/sdX1 --write
sudo ./fix_duplicate_extents /dev/sdX1 --write
sudo ./remove_stale_ptrs /dev/sdX1 --write

# 5. Re-varredura para verificar convergência
sudo ./scan_and_fix_all_backrefs /dev/sdX1
sudo ./remove_stale_ptrs /dev/sdX1

# 6. Se a árvore csum estiver quebrada:
sudo ./fix_csum_tree /dev/sdX1
sudo ./set_nodatasum /dev/sdX1 --write

# 7. Tente montar RW
sudo mount -o rw /dev/sdX1 /mnt/pool

# 8. Se montar, verifique com btrfs check readonly
sudo btrfs check --force /dev/sdX1

Limitações conhecidas

  1. Cada reparo pode criar novos problemas através de COW: quando uma ferramenta modifica a árvore de extent, o btrfs faz COW nos nós afetados. Os novos nós copiam ponteiros dos antigos, o que pode propagar ponteiros obsoletos. Múltiplas passagens podem ser necessárias.

  2. Incompatibilidades de ref de extent de dados não são corrigidas: estas ferramentas tocam apenas backrefs de metadados. Contagens de ref incorretas em extents de dados (comuns após execuções com falha de btrfs check --repair) não são limpas.

  3. Inodes órfãos não são limpos: entradas de diretório órfão na FS_TREE (referências a inodes que não existem mais) não são removidas.

  4. Não substitui btrfs check --repair: estas ferramentas visam cenários específicos. Para danos leves ou moderados, btrfs check --repair é melhor.

Lições aprendidas

  1. NUNCA faça power-cycle abrupto em um sistema de arquivos BTRFS com vários dispositivos: a corrupção combinada da árvore de espaço livre + árvore de extent é extremamente difícil de reparar.

  2. NUNCA execute btrfs check --repair várias vezes seguidas se a primeira execução não resolveu tudo: pode entrar em um loop infinito e piorar drasticamente o sistema de arquivos.

  3. Sempre faça backup dos superblocos antes de cada operação de escrita.

  4. trans->reinit_extent_tree = true é fundamental para ignorar falhas de DROP em refs atrasadas para blocos sem backrefs.

  5. fs_info->rebuilding_extent_tree = 1 desativa verificações de espaço durante reparos.

  6. Um grande commit com muitas inserções é melhor do que muitos commits pequenos, porque commits intermediários movem a árvore raiz.

  7. backup_slots no SB NÃO são backups históricos: eles são uma janela deslizante dos 4 commits mais recentes apenas. Um loop de btrfs check --repair de 46.000+ commits girará cada slot ~11.000 vezes em minutos, obliterando qualquer estado pré-travamento recuperável do kernel. Para retenção real, você precisa de fluxos explícitos de btrfs subvolume snapshot ou btrfs send para outro dispositivo.

  8. reinit_extent_tree é ASSIMÉTRICO: só isenta , NÃO . Qualquer caminho de código que chame em uma folha obsoleta (incluindo durante rebalanceamento) ainda travará via → .

Aviso Legal

Estas ferramentas foram escritas para um caso de recuperação específico, onde as ferramentas nativas estavam falhando. Elas não foram testadas para casos de uso gerais. Use-as apenas se você entender o código e aceitar o risco de perda de dados.

Sempre copie seus dados antes de tentar qualquer reparo se possível.

Licença

GPL-2.0 (compatível com btrfs-progs, cuja API interna estas ferramentas utilizam).

Baixar ferramenta
FolhaGeraçãoItens órfãos / totalUsado pós-limpeza (estimado)Rebalancear?Irmãos imediatosVeredito
$LEAF_Após-travamentoprincipalmente órfão, limpeza pesadaabaixo do limiteSIMtodos pós-travamento✓ seguro
$LEAF_Bpós-travamentoprincipalmente vivo, limpeza leveacima do limiteNÃOpai limpo✓ seguro
$LEAF_Cpós-travamentoquase 100% órfãomuito abaixo de 4096SIM forçadoobsoleto pré-travamento❌ CRASH
BTRFS_DROP_DELAYED_REF
BTRFS_ADD_DELAYED_REF
btrfs_inc_ref
push_leaf_left/right
btrfs_inc_extent_ref
BUG_ON(err)
  • O critério de segurança para processar inodes em uma FS_TREE danificada deve incluir irmãos, não apenas a própria folha alvo. Veja seção "Critério de subconjunto à prova de balas".

  • O sha256 de linha de base de arquivos VIVOS é a única prova empírica de invariantes. Capture-o antes de qualquer operação de escrita, compare após. Qualquer incompatibilidade = rollback.

  • i_size de DIR é armazenado como sum(name_len × 2), NÃO sum(name_len). Qualquer ferramenta de limpeza de órfãos que decremente i_size ao remover uma entrada deve decrementar por namelen × 2. Errar isso deixa DIRs em um estado inválido que pode se manifestar como nlink = 2 mais tarde: o que desencadeia uma bomba rmdir se o pool estiver montado RW (um único rm -rf em um pai pode excluir milhares de subdiretórios silenciosamente).

  • Agentes revisores especialistas com evidência empírica são críticos. A sessão de 2026-04-05 usou dois revisores Opus paralelos (internos do btrfs + operações) que analisaram o plano proposto contra a saída de dump-tree. Eles detectaram um vetor de travamento determinístico (push_leaf_left → irmão obsoleto) que teria repetido as falhas anteriores. Uma revisão de plano textual sem análise empírica de dump-tree teria perdido isso.