Perché il mio initrd ha solo una directory, vale a dire "kernel"?


29

Sto usando debian live-build per lavorare su un sistema avviabile. Alla fine del processo ottengo i file tipici usati per avviare un sistema live: un file squashfs, alcuni moduli GRUB e file di configurazione, e un file initrd.img.

Posso avviare bene usando quei file, passando initrd al kernel tramite

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

nella riga di comando del bootloader. Ma quando provo ad esaminare il contenuto della mia immagine initrd, in questo modo:

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

l'albero dei file che ottengo è simile al seguente:

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

Dov'è l'albero dei filesystem vero e proprio, con il tipico / bin, / etc, / sbin ... che contiene i file reali usati durante l'avvio?


1
Il comando 'lsinitramfs' è stato progettato per questo.
Earlgrey,

Risposte:


32

Il metodo skip del blocco cpio fornito non funziona in modo affidabile. Questo perché le immagini initrd che stavo ottenendo non avevano entrambi gli archivi concatenati su un limite di 512 byte.

Invece, fai questo:

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

Usa l'ultimo numero (21136) che non si trova su un limite di 512 byte per me:

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

In effetti, la tua risposta batte la mia. Non ho mai pensato che l'allineamento sarebbe stato un problema. Mi chiedo, tuttavia, se cpio darebbe un output più interessante se la prima immagine contenuta nel file multi-immagine non fosse allineata a 512B.
user986730

Come ripristinare (reimballaggio allo stato originale) dopo la modifica, con la stessa gerarchia di cartelle?
EdiD,

2
Proprio cdnella directory in cui è stato estratto l'archivio cpio, corsa find | cpio -H newc -o > /tmp/my_archive.cpio, poi con gzip gzip /tmp/my_archive.cpioe, infine, concatenare con l'all'immagine microcodice con, se si ha uno: cat my_microcode_image.cpio /tmp/my_archive.cpio.gz > mynewinitrd.img. Se non disponevi di un'immagine con microcodice, puoi semplicemente utilizzare il tuo file gzipped come nel tuo bootloader
user986730

Nel leggere questa risposta sembra ovvio che funzionerà solo se i contenuti compressi con gzip sono passati a metà del file. Altrimenti, è necessario modificare la dimensione del blocco su 1 e impostare skip sul numero di byte da saltare. Qualche motivo per non farlo sempre?
TamaMcGlinn,

in secondo luogo, per scrivere effettivamente i file invece di elencarne solo alcuni, modificare il comando finale nella pipe cpio -iinvece che cpio -tdv | head.
TamaMcGlinn,

22

Se sai che è initrd.imgcostituito da un archivio cpio non compresso seguito da un archivio cpio compresso con gz, puoi usare quanto segue per estrarre tutti i file (da entrambi gli archivi) nella tua directory di lavoro corrente (testato in bash):

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

La riga di comando sopra passa il contenuto di initrd.imginput standard in una subshell che esegue i due comandi cpio -ide in zcat | cpio -idsequenza. Il primo comando ( cpio -id) termina dopo aver letto tutti i dati appartenenti al primo archivio cpio. Il contenuto rimanente viene quindi passato a zcat | cpio -id, che decomprime e decomprime il secondo archivio.


1
Questa sembra di gran lunga la soluzione più pulita
velis

1
Funziona magnificamente
TurboHz

Misteriosamente, la bella risposta di @ Woolpool è l'unica risposta che l'utente abbia mai pubblicato. Questo è stile. Se avessi pubblicato una sola risposta durante tutta la tua carriera di StackExchange, difficilmente potresti fare di meglio che pubblicarne una come questa. OP potrebbe prendere in considerazione la possibilità di modificare la risposta accettata a questa.
thb

16

Si scopre che initrd generato dal live-build di Debian (e con mia sorpresa, accettato dal kernel) è in realtà la concatenazione di due immagini:

  • un archivio CPIO contenente aggiornamenti di microcodici da applicare sul processore;
  • un archivio cpio gzip-ed, che in realtà contiene l'albero dei file initrd (con le directory / etc / bin / sbin / dev ... che erano previste).

Dopo aver estratto il file initrd.img originale, direttamente dall'output live-build, ho ottenuto questo output:

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

Ciò significa che l'estrazione di cpio è terminata dopo aver analizzato 896 blocchi di 512 byte ciascuno. Ma l'originale initrd.img era molto più grande di 896 * 512 = 458752B = 448 KB:

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

Quindi l'immagine initrd effettiva che stavo cercando è stata aggiunta subito dopo il primo archivio cpio (quello contenente gli aggiornamenti del microcodice) e si poteva accedere usando dd:

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

2

Puoi usare unmkinitramfsda initramfs-tools> = 0.126, incluso da Debian 9 (stretch) e Ubuntu 18.04 (bionic).


1

Sulla base dell'idea data nella risposta di @ woolpool ho scritto una funzione ricorsiva che funzionerà per qualsiasi archivio cpio indipendentemente dalla disposizione dei dati concatenati e non richiede strumenti speciali come binwalk. Ad esempio il mio mkinitramfs stava producendo un file cpio; cpio; gzip. Funziona estraendo ogni parte del file initrd concatenato, salvando il resto in un file temporaneo e quindi utilizzando il programma "file" per decidere cosa fare con la parte successiva.

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
}

Per usare type: uncpio initrdfilename


0

Se devi eseguire questa attività spesso, potresti voler creare una piccola funzione bash come la seguente (e magari aggiungerla al tuo .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 $@
}

Il codice si basa sulla risposta di Marc, ma è significativamente più veloce poiché binwalk cercherà solo i file gzip. Puoi invocarlo, in questo modo:

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

Dovrai binwalkinstallarlo per farlo funzionare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.