Como posso virar um único bit em um arquivo?

34

Eu quero danificar intencionalmente um arquivo para testar as alegações de que o btrfs pode curar-se . O artigo fala sobre tirar o sistema de arquivos, danificar uma foto "lançando" um único bit e depois remontá-lo. Em sistemas de arquivos mais antigos, isso seria corrompido, mas deveria ser corrigido no btrfs. Em teoria, isso faz sentido, mas eu realmente quero testá-lo.

O problema é que o artigo não explica como fazer nada disso.
Como eu mudaria um único bit em uma parte muito específica de um sistema de arquivos?

Eu também devo salientar que isso deve ser feito em um sistema de arquivos offline para que o btrfs não veja minha gravação como intencional.

Edit: Enquanto a questão (e discussão) fala muito sobre btrfs, eu gostaria de saber se existem métodos independentes de sistema de arquivos para implementar este tipo de corrupção (para que possa ser comparado em diferentes tipos / controladores de RAID / etc).

    
por Oli 16.01.2014 / 17:25

5 respostas

20

Não sou especialista, mas o pacote btrfs-progs inclui uma ferramenta específica para isso, embora talvez seja necessário criar a partir do código-fonte. Em qualquer caso, uma vez que você tenha instalado ou criado o btrfs-progs , você deve ser capaz de usar a ferramenta btrfs-corrupt-block , que é usada pelos desenvolvedores do btrfs para testar o sistema de arquivos.

Agora, como eu disse, não tive muito tempo para brincar com o btrfs, então não sei o uso exato dessa ferramenta. Mas com isso, você deve ser capaz de corromper um sistema de arquivos offline, que será corrigido quando o arquivo corrompido for lido (supondo que você tenha configurado o RAID ou algo assim para que haja outra cópia a ser usada).

    
por strugee 16.01.2014 / 18:45
15
  1. Obtenha o valor de um único setor no dispositivo de bloco (por exemplo, /dev/sda1 ) com um deslocamento de 1 milhão de setores compensados (apenas um exemplo):

    sudo dd if=/dev/sda1 of=/root/mysector bs=512 count=1 skip=1M
    

    Este deslocamento arbitrário de 1M * 512 bytes escolhido é apenas para garantir que você esteja fora da parte de metadados do sistema de arquivos e, na verdade, em um setor que contém dados.

  2. Edite os dados brutos do setor alterando o conteúdo com um editor hexadecimal. Veja, por exemplo, Precisa de um bom editor hexadecimal para Linux .

  3. Coloque de volta o setor na unidade com os argumentos if e of invertidos:

    sudo dd if=/root/mysector of=/dev/sda1 bs=512 count=1 seek=1M
    
por gertvdijk 16.01.2014 / 17:44
15

@Oli - oi, eu sou Jim Salter, o cara que realmente escreveu esse artigo. Eu estava trabalhando com uma máquina virtual, que simplificava as coisas. O que fiz foi começar com um arquivo JPEG e abri-lo em um editor hexadecimal. O especial que eu usei foi o Bless, que você pode instalar no Ubuntu com um simples apt-get install abençoe .

Depois de abrir o JPEG em Bless, acertei algumas vezes a página para entrar na "carne" do JPEG e depois destaquei apenas cerca de cinquenta bytes de dados, copiei e colei em um editor de texto. (no meu caso, gEdit). Isso me deu algo para procurar.

Agora salvei o JPEG em cada array na VM. O armazenamento por trás dos arrays era uma série de arquivos .qcow2. Uma vez que eu salvei o JPEG nos arrays, eu poderia carregar os arquivos .qcow2 associados a cada array em Bless, e procurá-los - eles não eram muito grandes, nada além do JPEG e alguns metadados - para aquele padrão de cinquenta bytes Eu destaquei e copiei do JPEG. Voila, eu tive o bloqueio para corromper! Neste ponto, eu poderia apenas editar manualmente bytes individuais do JPEG como armazenados no disco virtual da VM usando Bless - e, mais importante, fazê-lo exatamente da mesma maneira em cada array.

A única ruga é que, no caso do array RAID5 testado no artigo, eu tive que ter certeza de que editei a cópia real dos dados na faixa, e não a paridade para a faixa em si - era uma pequena imagem em uma matriz de outra forma vazia, portanto, não havia nenhum dado no bloco FOLLOWING na faixa, fazendo com que o bloco de paridade contivesse os dados inalterados do bloco de dados. Se eu tivesse editado acidentalmente o bloco de paridade em vez do bloco de dados, a imagem teria aparecido inalterada.

Uma observação final - você NÃO PRECISA de máquinas virtuais para fazer isso - você poderia fazer as mesmas coisas da mesma maneira com o bare metal; seria apenas mais uma dor na bunda, porque você precisaria trabalhar com unidades brutas inteiras em vez de com arquivos .qcow2 bem pequenos, e você teria que puxar as unidades e colocá-las em uma máquina diferente, ou inicialize em um ambiente ao vivo (ou apenas alternativo) para mexer com eles. (Eu testei a recuperação de dados do ZFS exatamente dessa maneira, mas em máquinas bare-metal reais, 7 anos atrás, quando me interessei pela primeira vez em sistemas de arquivos next-gen.)

Espero que isso ajude!

    
por Jim Salter 27.01.2014 / 23:17
4

Você pode experimentar um pequeno programa que execute FIBMAP ioctl(2) no arquivo aberto.

Por uma rápida pesquisa na web, encontrei esta postagem no blog link detalhando como fazer isso - ele vai te dar um link para um programa de amostra que você pode compilar e executar sozinho.

$ git clone git://kernel.ubuntu.com/cking/debug-code
$ cd debug-code/block-mapper-fibmap
$ make
$ sudo ./fibmap /path/to/your/image-file.jpg

É exatamente assim que o hdparm --fibmap (mencionado pelo @falconer) é implementado.

Depois de encontrar os números dos blocos, você pode usar dd gongfu para modificar o arquivo, como @gertvdijk, esboçado. Ou talvez você poderia apenas modificar o programa fibmap.c acima para fazer o bit flip para você, escrevendo diretamente no arquivo do dispositivo ignorando a camada do sistema de arquivos (três parâmetros para o programa: 1. o caminho para o arquivo, 2. arquivo de dispositivo contendo o sistema de arquivos, 3. deslocamento e bit que você deseja modificar).

( Aviso: Eu não testei e não posso garantir que o FIBMAP ioctl(2) funcionará para um arquivo no dispositivo de loopback ou no sistema de arquivos btrfs, mas eu esperaria que sim. Estou adivinhando hdparm irá verificar o tipo de dispositivo antes de executar o ioctl(2) no arquivo e, portanto, está falhando.)

    
por FooF 17.01.2014 / 06:58
3
sudo hdparm --fibmap /PATH/TO/FILE

fornecerá os LBAs onde o arquivo está localizado. Depois disso, você pode usar a resposta do @gertvdijk.

    
por falconer 16.01.2014 / 19:14