From 71a80751257f11a64e6035cf91fc6b23e6c31863 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Fri, 22 Nov 2024 16:40:40 -0500 Subject: [PATCH 1/2] initrd/bin/unpack_initramfs.sh: no functional change, just format with tabs Signed-off-by: Thierry Laurion --- initrd/bin/unpack_initramfs.sh | 131 +++++++++++++++++---------------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/initrd/bin/unpack_initramfs.sh b/initrd/bin/unpack_initramfs.sh index db176fd6..12ce32b8 100755 --- a/initrd/bin/unpack_initramfs.sh +++ b/initrd/bin/unpack_initramfs.sh @@ -31,78 +31,81 @@ CPIO_ARGS=("$@") # Consume zero bytes, the first nonzero byte read (if any) is repeated on stdout consume_zeros() { - TRACE_FUNC - next_byte='00' - while [ "$next_byte" = "00" ]; do - # if we reach EOF, next_byte becomes empty (dd does not fail) - next_byte="$(dd bs=1 count=1 status=none | xxd -p | tr -d ' ')" - done - # if we finished due to nonzero byte (not EOF), then carry that byte - if [ -n "$next_byte" ]; then - echo -n "$next_byte" | xxd -p -r - fi + TRACE_FUNC + next_byte='00' + while [ "$next_byte" = "00" ]; do + # if we reach EOF, next_byte becomes empty (dd does not fail) + next_byte="$(dd bs=1 count=1 status=none | xxd -p | tr -d ' ')" + done + # if we finished due to nonzero byte (not EOF), then carry that byte + if [ -n "$next_byte" ]; then + echo -n "$next_byte" | xxd -p -r + fi } unpack_cpio() { - TRACE_FUNC - (cd "$dest_dir"; cpio -i "${CPIO_ARGS[@]}" 2>/dev/null) + TRACE_FUNC + ( + cd "$dest_dir" + cpio -i "${CPIO_ARGS[@]}" 2>/dev/null + ) } # unpack the first segment of an archive, then write the rest to another file unpack_first_segment() { - TRACE_FUNC - unpack_archive="$1" - dest_dir="$2" - rest_archive="$3" + TRACE_FUNC + unpack_archive="$1" + dest_dir="$2" + rest_archive="$3" - mkdir -p "$dest_dir" + mkdir -p "$dest_dir" - # peek the beginning of the file to determine what type of content is next - magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)" + # peek the beginning of the file to determine what type of content is next + magic="$(dd if="$unpack_archive" bs=6 count=1 status=none | xxd -p)" - # read this segment of the archive, then write the rest to the next file - ( - # Magic values correspond to Linux init/initramfs.c (zero, cpio) and - # lib/decompress.c (gzip) - case "$magic" in - 00*) - DEBUG "archive segment $magic: uncompressed cpio" - # Skip zero bytes and copy the first nonzero byte - consume_zeros - # Copy the remaining data - cat - ;; - 303730373031*|303730373032*) # plain cpio - DEBUG "archive segment $magic: plain cpio" - # Unpack the plain cpio, this stops reading after the trailer - unpack_cpio - # Copy the remaining data - cat - ;; - 1f8b*|1f9e*) # gzip - DEBUG "archive segment $magic: gzip" - # gunzip won't stop when reaching the end of the gzipped member, - # so we can't read another segment after this. We can't - # reasonably determine the member length either, this requires - # walking all the compressed blocks. - gunzip | unpack_cpio - ;; - 28b5*) # zstd - DEBUG "archive segment $magic: zstd" - # Like gunzip, this will not stop when reaching the end of the - # frame, and determining the frame length requires walking all - # of its blocks. - (zstd-decompress -d || true) | unpack_cpio - ;; - *) # unknown - die "Can't decompress initramfs archive, unknown type: $magic" - ;; - esac - ) <"$unpack_archive" >"$rest_archive" + # read this segment of the archive, then write the rest to the next file + ( + # Magic values correspond to Linux init/initramfs.c (zero, cpio) and + # lib/decompress.c (gzip) + case "$magic" in + 00*) + DEBUG "archive segment $magic: uncompressed cpio" + # Skip zero bytes and copy the first nonzero byte + consume_zeros + # Copy the remaining data + cat + ;; + 303730373031* | 303730373032*) # plain cpio + DEBUG "archive segment $magic: plain cpio" + # Unpack the plain cpio, this stops reading after the trailer + unpack_cpio + # Copy the remaining data + cat + ;; + 1f8b* | 1f9e*) # gzip + DEBUG "archive segment $magic: gzip" + # gunzip won't stop when reaching the end of the gzipped member, + # so we can't read another segment after this. We can't + # reasonably determine the member length either, this requires + # walking all the compressed blocks. + gunzip | unpack_cpio + ;; + 28b5*) # zstd + DEBUG "archive segment $magic: zstd" + # Like gunzip, this will not stop when reaching the end of the + # frame, and determining the frame length requires walking all + # of its blocks. + (zstd-decompress -d || true) | unpack_cpio + ;; + *) # unknown + die "Can't decompress initramfs archive, unknown type: $magic" + ;; + esac + ) <"$unpack_archive" >"$rest_archive" - orig_size="$(stat -c %s "$unpack_archive")" - rest_size="$(stat -c %s "$rest_archive")" - DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes" + orig_size="$(stat -c %s "$unpack_archive")" + rest_size="$(stat -c %s "$rest_archive")" + DEBUG "archive segment $magic: $((orig_size - rest_size)) bytes" } DEBUG "Unpacking $INITRAMFS_ARCHIVE to $DEST_DIR" @@ -112,7 +115,7 @@ rest_archive="/tmp/unpack_initramfs_rest" # Break when there is no remaining data while [ -s "$next_archive" ]; do - unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive" - next_archive="/tmp/unpack_initramfs_next" - mv "$rest_archive" "$next_archive" + unpack_first_segment "$next_archive" "$DEST_DIR" "$rest_archive" + next_archive="/tmp/unpack_initramfs_next" + mv "$rest_archive" "$next_archive" done From 95c6eb5c498bebc028cd92d62c83e33c2be3ed2e Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Fri, 22 Nov 2024 16:43:12 -0500 Subject: [PATCH 2/2] initrd/bin/unpack_initramfs.sh: add xz to unpack logic (add commented: bzip2, lzma, lzo and lz4) xz: tested working with tails test build and 6.8.1's initrd latest ubuntu 24.10: switched back to zstd, works as expected (tested) Magic numbers referred at: - https://github.com/torvalds/linux/blob/28eb75e178d389d325f1666e422bc13bbbb9804c/scripts/extract-vmlinux#L52C1-L58C43 - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/decompress.c#n51 Signed-off-by: Thierry Laurion --- initrd/bin/unpack_initramfs.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/initrd/bin/unpack_initramfs.sh b/initrd/bin/unpack_initramfs.sh index 12ce32b8..77213118 100755 --- a/initrd/bin/unpack_initramfs.sh +++ b/initrd/bin/unpack_initramfs.sh @@ -90,6 +90,10 @@ unpack_first_segment() { # walking all the compressed blocks. gunzip | unpack_cpio ;; + fd37*) # xz + DEBUG "archive segment $magic: xz" + unxz | unpack_cpio + ;; 28b5*) # zstd DEBUG "archive segment $magic: zstd" # Like gunzip, this will not stop when reaching the end of the @@ -99,6 +103,26 @@ unpack_first_segment() { ;; *) # unknown die "Can't decompress initramfs archive, unknown type: $magic" + # The following are magic values for other compression formats + # but not added because not tested. + # TODO: open an issue for unsupported magic number reported on die. + # + #425a*) # bzip2 + # DEBUG "archive segment $magic: bzip2" + # bunzip2 | unpack_cpio + #;; + #5d00*) # lzma + # DEBUG "archive segment $magic: lzma" + # unlzma | unpack_cpio + #;; + #894c*) # lzo + # DEBUG "archive segment $magic: lzo" + # lzop -d | unpack_cpio + #;; + #0221*) # lz4 + # DEBUG "archive segment $magic: lz4" + # lz4 -d | unpack_cpio + # ;; ;; esac ) <"$unpack_archive" >"$rest_archive"