Por que meu initrd possui apenas um diretório, a saber, 'kernel'?

29

Estou usando o debian live-build para trabalhar em um sistema inicializável. No final do processo, recebo os arquivos típicos usados ​​para inicializar um sistema ativo: um arquivo squashfs, alguns módulos GRUB e arquivos de configuração e um arquivo initrd.img.

Eu posso inicializar muito bem usando esses arquivos, passando o initrd para o kernel via

initrd=/path/to/my/initrd.img

na linha de comando do carregador de inicialização. Mas quando tento examinar o conteúdo da minha imagem initrd, é assim:

$file initrd.img
initrd.img: ASCII cpio archive (SVR4 with no CRC)
$mkdir initTree && cd initTree
$cpio -idv < ../initrd.img

a árvore de arquivos que recebo fica assim:

$tree --charset=ASCII
.
`-- kernel
    `-- x86
        `-- microcode
            `-- GenuineIntel.bin

Onde está a árvore do sistema de arquivos real, com o típico / bin, / etc, / sbin ... contendo os arquivos reais usados ​​durante a inicialização?

user986730
fonte
1
O comando 'lsinitramfs' foi projetado para isso.
earlgrey

Respostas:

32

O método cpio block skip fornecido não funciona de maneira confiável. Isso porque as imagens initrd que eu estava obtendo não tinham os dois arquivos concatenados em um limite de 512 bytes.

Em vez disso, faça o seguinte:

apt-get install binwalk
legolas [mc]# binwalk initrd.img 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ASCII cpio archive (SVR4 with no CRC), file name: "kernel", file name length: "0x00000007", file size: "0x00000000"
120           0x78            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86", file name length: "0x0000000B", file size: "0x00000000"
244           0xF4            ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode", file name length: "0x00000015", file size: "0x00000000"
376           0x178           ASCII cpio archive (SVR4 with no CRC), file name: "kernel/x86/microcode/GenuineIntel.bin", file name length: "0x00000026", file size: "0x00005000"
21004         0x520C          ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
21136         0x5290          gzip compressed data, from Unix, last modified: Sat Feb 28 09:46:24 2015

Use o último número (21136) que não está em um limite de 512 bytes para mim:

legolas [mc]# dd if=initrd.img bs=21136 skip=1 | gunzip | cpio -tdv | head
drwxr-xr-x   1 root     root            0 Feb 28 09:46 .
drwxr-xr-x   1 root     root            0 Feb 28 09:46 bin
-rwxr-xr-x   1 root     root       554424 Dec 17  2011 bin/busybox
lrwxrwxrwx   1 root     root            7 Feb 28 09:46 bin/sh -> busybox
-rwxr-xr-x   1 root     root       111288 Sep 23  2011 bin/loadkeys
-rwxr-xr-x   1 root     root         2800 Aug 19  2013 bin/cat
-rwxr-xr-x   1 root     root          856 Aug 19  2013 bin/chroot
-rwxr-xr-x   1 root     root         5224 Aug 19  2013 bin/cpio
-rwxr-xr-x   1 root     root         3936 Aug 19  2013 bin/dd
-rwxr-xr-x   1 root     root          984 Aug 19  2013 bin/dmesg
Marc Merlin
fonte
De fato, sua resposta supera a minha. Eu nunca pensei que o alinhamento seria um problema. Eu me pergunto, no entanto, se o cpio daria uma saída mais interessante se a primeira imagem contida no arquivo com várias imagens não tivesse 512B.
user986730
Como revertê-lo (reembalar para o estado original) após modificar, com a mesma hierarquia de pastas?
EdiD 25/05
2
Apenas cdpara o diretório onde você extraiu o arquivo cpio, run find | cpio -H newc -o > /tmp/my_archive.cpio, então gzip-lo com gzip /tmp/my_archive.cpioe, finalmente, concatenar-lo com a com a imagem microcódigo, se você tivesse um: cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img. Se você não tem uma imagem de microcódigo, então você pode apenas usá-lo compactado arquivo como está na sua bootloader
user986730
Ao ler esta resposta, parece óbvio que isso só funcionará se o conteúdo compactado em gzip estiver na metade do arquivo. Caso contrário, você deve alterar o tamanho do bloco para 1 e definir skip para o número de bytes a serem pulados. Alguma razão para nem sempre fazer isso?
TamaMcGlinn 24/09
segundo, para realmente escrever os arquivos em vez de apenas listar alguns deles, altere o comando final no canal para cpio -i, em vez de cpio -tdv | head.
TamaMcGlinn 24/09
22

Se você sabe que initrd.imgconsiste em um arquivo cpio descompactado seguido por um arquivo cpio compactado com gz, você pode usar o seguinte para extrair todos os arquivos (de ambos os arquivos) para o diretório de trabalho atual (testado no bash):

(cpio -id; zcat | cpio -id) < /path/to/initrd.img

A linha de comando acima passa o conteúdo initrd.imgcomo entrada padrão para um subshell que executa os dois comandos cpio -ide zcat | cpio -idsequencialmente. O primeiro comando ( cpio -id) termina depois de ler todos os dados pertencentes ao primeiro arquivo cpio. O conteúdo restante é passado para zcat | cpio -id, que descompacta e descompacta o segundo arquivo morto.


fonte
1
Esta parece ser a solução mais limpa de longe
velis
1
Ele funciona muito bem
TurboHz
Misteriosamente, a boa resposta de @ woolpool é a única resposta que o usuário já postou. Isso é estilo. Se você iria postar apenas uma resposta durante toda a sua carreira no StackExchange, dificilmente poderia fazer melhor do que postar uma como essa. O OP pode considerar alterar a resposta aceita para esta.
Thb
16

Acontece que o initrd gerado pelo live-build do Debian (e para minha surpresa, aceito pelo kernel) é na verdade a concatenação de duas imagens:

  • um arquivo CPIO contendo atualizações de microcódigo a serem aplicadas no processador;
  • um arquivo cpio gzip-ed, que realmente contém a árvore de arquivos initrd (com os diretórios / etc / bin / sbin / dev ... que eram esperados).

Ao extrair o initrd.img original, direto da saída do live-build, obtive esta saída:

$cpio -idv ../initrd.img
kernel
kernel/x86
kernel/x86/microcode
kernel/x86/microcode/GenuineIntel.bin
896 blocks

O que significa que a extração do cpio terminou após analisar 896 blocos de 512 bytes cada. Mas o initrd.img original era muito maior que 896 * 512 = 458752B = 448 KB:

$ls -liah initrd.img
3933924 -r--r--r-- 1 root root 21M Oct 21 10:05 initrd.img

Portanto, a imagem initrd que eu estava procurando foi anexada logo após o primeiro arquivo cpio (aquele que contém as atualizações de microcódigo) e pode ser acessada usando o dd:

$dd if=initrd.img of=myActualInitrdImage.img.gz bs=512 skip=896
user986730
fonte
2

Você pode usar unmkinitramfsinitramfs-tools> = 0.126, que está incluído desde o Debian 9 (stretch) e Ubuntu 18.04 (biônico).

Benjamin Drung
fonte
1

Com base na idéia dada na resposta do @ woolpool, escrevi uma função recursiva que funcionará para qualquer arquivo cpio, independentemente da organização dos dados concatenados, e não requer ferramentas especiais como o binwalk. Por exemplo, meu mkinitramfs estava produzindo um arquivo cpio; cpio; gzip. Ele funciona extraindo cada parte do arquivo initrd concatenado, salvando o restante em um arquivo temporário e, em seguida, usando o programa "arquivo" para decidir o que fazer com a próxima parte.

uncpio(){
if [[ $(wc -c $1 | cut -d ' ' -f1) -eq 0 ]]; then
    return
fi

type=$(cat $1 | file -)
local tmpfile=$(date +%s.%N)
echo -e "\n$type"
if [[ $type =~ .*cpio.* ]]; then
    cat $1 | (cpio -id; cat >$tmpfile)
elif [[ $type =~ .*gzip.* ]]; then
    zcat $1 | (cpio -id; cat >$tmpfile)
else
    return
fi
uncpio $tmpfile 
rm $tmpfile
}

Para usar o tipo: uncpio initrdfilename

SurpriseDog
fonte
0

Se você precisar executar essa tarefa com frequência, convém criar uma pequena função bash como a seguinte (e talvez adicioná-la ao seu .bashrc):

initramfs-extract() {
    local target=$1
    local offset=$(binwalk -y gzip $1 | awk '$3 ~ /gzip/ { print $1; exit }')
    shift
    dd if=$target bs=$offset skip=1 | zcat | cpio -id --no-absolute-filenames $@
}

O código é baseado na resposta de Marc, mas é significativamente mais rápido, pois o binwalk procurará apenas arquivos gzip. Você pode invocá-lo, assim:

$ initramfs-extract /boot/initrd.img -v

Você precisará binwalkinstalado para fazê-lo funcionar.

tyrion
fonte