From 7ea8f69a06300eba5d42b46a6f85daeacc2430a3 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 5 Apr 2023 18:45:32 +0200 Subject: [PATCH] Fix user-data decompression on all shells yash[1] and zsh does not handle 8-bit bytes in strings good. Work around it by using printf ... | cmp ... to compare the header. This should be 100% posix compatible. Also fix some of the compression header magic bytes: - unxz: Use octal aas the string '\3757zXZ\000' was misinterpreted by some shells. - lzma: the third byte represents compression mode[2], and we want support all compression modes not only '8', so we only check the first three bytes instead of 4. [1]: Upstream report: https://osdn.net/projects/yash/ticket/47772 [2]: https://github.com/frizb/FirmwareReverseEngineering/blob/master/IdentifyingCompressionAlgorithms.md#lzma --- .gitlab-ci.yml | 2 +- lib/tiny-cloud/init-main | 38 ++++++++++++++++++-------------------- tests/init-main.test | 5 +++-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1519c23..93ae0d3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,7 @@ test-default: image: alpine:latest stage: test script: - - apk add make kyua yx + - apk add make kyua yx xz lz4 zstd - make -j $(nproc) check tags: - docker-alpine diff --git a/lib/tiny-cloud/init-main b/lib/tiny-cloud/init-main index 2788dc8..1728d3a 100644 --- a/lib/tiny-cloud/init-main +++ b/lib/tiny-cloud/init-main @@ -40,11 +40,6 @@ set_ssh_keys() { imds @ssh-keys > "$keys_file" } -match_header() { - local bytes=$(echo -en "$1") - [ "$bytes" = "$(dd bs=1 count=${#bytes} if="$2" 2>/dev/null)" ] -} - save_userdata() { skip_action save_userdata && return @@ -55,22 +50,25 @@ save_userdata() { imds -e @userdata > "$tmpfile" cmd="cat" if ! skip_action decompress_userdata; then - if match_header '\037\213\010' "$tmpfile"; then - cmd="gzip -dc" - elif match_header 'BZh' "$tmpfile"; then - cmd="bzip2 -dc" - elif match_header '\3757zXZ\000' "$tmpfile"; then - cmd="unxz -c" - elif match_header '\135\0\0\0' "$tmpfile"; then - cmd="lzma -dc" - elif match_header '\211\114\132' "$tmpfile"; then - cmd="lzop -dc" - elif match_header '\004\042\115\030' "$tmpfile"; then - cmd="lz4 -dc" - elif match_header '(\265/\375' "$tmpfile"; then - cmd="zstd -dc" + if printf '\037\213\010' | cmp -s -n 3 "$tmpfile"; then + gzip -dc "$tmpfile" > "$userdata" + elif printf 'BZh' | cmp -s -n 3 "$tmpfile"; then + bzip2 -dc "$tmpfile" > "$userdata" + elif printf '\375\067\172\130\132\000' | cmp -s -n 6 "$tmpfile"; then + unxz -c "$tmpfile" > "$userdata" + elif printf '\135\000\000' | cmp -s -n 3 "$tmpfile"; then + lzma -dc "$tmpfile" > "$userdata" + elif printf '\211\114\132' | cmp -s -n 3 "$tmpfile"; then + lzop -dc "$tmpfile" > "$userdata" + elif printf '\004\042\115\030' | cmp -s -n 4 "$tmpfile"; then + lz4 -dc "$tmpfile" > "$userdata" + elif printf '(\265/\375' | cmp -s -n 4 "$tmpfile"; then + zstd -dc "$tmpfile" > "$userdata" + else + cp "$tmpfile" "$userdata" fi + else + cp "$tmpfile" "$userdata" fi - $cmd "$tmpfile" > "$userdata" rm "$tmpfile" } diff --git a/tests/init-main.test b/tests/init-main.test index 3350f8c..0206416 100755 --- a/tests/init-main.test +++ b/tests/init-main.test @@ -99,8 +99,9 @@ save_userdata_compressed_body() { set_nocloud_userdata_from_file tmpfile CLOUD="nocloud" atf_check \ sh -c ". \"$lib\"; save_userdata" - grep "^#cloud-config" var/lib/cloud/user-data \ - || atf_fail "$comp failed" + if ! grep "^#cloud-config" var/lib/cloud/user-data; then + atf_fail "$comp failed" + fi done }