diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2018-07-18 05:25:13 +0100 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2018-07-18 05:50:17 +0100 |
commit | 28536f665ccbef9a76d775fde557d0902426df49 (patch) | |
tree | 369201bac0aa52fbe877a96da52eb66b063b5a84 | |
parent | 211e0507a80c2ede3bfbc78fa222be363561fe85 (diff) |
unmkinitramfs, lsinitramfs: Split multiple early initramfs sections
It is possible for the early initramfs to consist of multiple
sections, each a valid uncompressed cpio archive, for example if
amd64-microcode and intel-microcode are both installed and explicitly
enabled. Each cpio archive ends with an EOF marker consisting of four
zero bytes and possibly additional zero padding.
The kernel's early microcode loader simply skips the zero bytes, but
cpio will stop. So whenever we find such a group of zero bytes, we
need to stop parsing cpio headers, run cpio over what we found, and
then repeat the process on the following bytes.
Closes: #886424
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rwxr-xr-x | unmkinitramfs | 68 |
1 files changed, 45 insertions, 23 deletions
diff --git a/unmkinitramfs b/unmkinitramfs index 7e3d977..bd7bacf 100755 --- a/unmkinitramfs +++ b/unmkinitramfs @@ -55,42 +55,64 @@ splitinitramfs() dir="$2" shift 2 - # There may be a prepended uncompressed archive. cpio - # won't tell us the true size of this so we have to - # parse the headers and padding ourselves. This is - # very roughly based on linux/lib/earlycpio.c - offset=0 + count=0 + start=0 while true; do - if checkzero "$initramfs" $offset; then - offset=$((offset + 4)) - continue + # There may be prepended uncompressed archives. cpio + # won't tell us the true size of these so we have to + # parse the headers and padding ourselves. This is + # very roughly based on linux/lib/earlycpio.c + end=$start + while true; do + if checkzero "$initramfs" $end; then + # This is the EOF marker. There might + # be more zero padding before the next + # archive, so read through all of it. + end=$((end + 4)) + while checkzero "$initramfs" $end; do + end=$((end + 4)) + done + break + fi + magic="$(readhex "$initramfs" $end 6)" || break + test $magic = 070701 || test $magic = 070702 || break + namesize=0x$(readhex "$initramfs" $((end + 94)) 8) + filesize=0x$(readhex "$initramfs" $((end + 54)) 8) + end=$(((end + 110))) + end=$(((end + $namesize + 3) & ~3)) + end=$(((end + $filesize + 3) & ~3)) + done + if [ $end -eq $start ]; then + break fi - magic="$(readhex "$initramfs" $offset 6)" || break - test $magic = 070701 || test $magic = 070702 || break - namesize=0x$(readhex "$initramfs" $((offset + 94)) 8) - filesize=0x$(readhex "$initramfs" $((offset + 54)) 8) - offset=$(((offset + 110))) - offset=$(((offset + $namesize + 3) & ~3)) - offset=$(((offset + $filesize + 3) & ~3)) - done - if [ $offset -ne 0 ]; then - # uncompressed archive + # Extract to early, early2, ... subdirectories + count=$((count + 1)) + if [ $count -eq 1 ]; then + subdir=early + else + subdir=early$count + fi + dd < "$initramfs" skip=$start count=$((end - start)) iflag=skip_bytes 2> /dev/null | ( if [ -n "$dir" ]; then - mkdir -p -- "$dir/early" - cd -- "$dir/early" + mkdir -p -- "$dir/$subdir" + cd -- "$dir/$subdir" fi cpio -i "$@" - ) < "$initramfs" + ) + start=$end + done - # main archive + if [ $end -gt 0 ]; then + # Extract to main subdirectory subarchive=$(mktemp ${TMPDIR:-/var/tmp}/unmkinitramfs_XXXXXX) trap "rm -f '$subarchive'" EXIT - dd < "$initramfs" bs="$offset" skip=1 2> /dev/null \ + dd < "$initramfs" skip=$end iflag=skip_bytes 2> /dev/null \ > $subarchive xcpio "$subarchive" "${dir:+$dir/main}" -i "$@" else + # Don't use subdirectories (for backward compatibility) xcpio "$initramfs" "$dir" -i "$@" fi } |