mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-26 16:09:45 -05:00
192 lines
5.9 KiB
Bash
Executable File
192 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Show progress on pipes if `pv` is installed
|
|
# Otherwise use plain cat
|
|
if ! command -v pv &> /dev/null
|
|
then
|
|
PV="cat"
|
|
else
|
|
PV="pv"
|
|
fi
|
|
|
|
mount_partition () {
|
|
local partition_file=$1
|
|
local mountpoint=$2
|
|
|
|
# use guestmount if possible
|
|
if command -v guestmount &> /dev/null && guestmount -a "${partition_file}" -m /dev/sda "${mountpoint}"; then
|
|
return
|
|
fi
|
|
|
|
# second, try to mount as current user
|
|
if mount -o loop "${partition_file}" "${mountpoint}"; then
|
|
return
|
|
fi
|
|
|
|
# third, try to mount with sudo
|
|
sudo mount -o loop "${partition_file}" "${mountpoint}"
|
|
# temporarily change ownership of partition files
|
|
sudo chown -R "${USER}:${USER}" "${mountpoint}"
|
|
}
|
|
|
|
umount_partition () {
|
|
local mountpoint=$1
|
|
|
|
# use guestunmount if possible
|
|
if command -v guestunmount &> /dev/null && guestunmount "${mountpoint}"; then
|
|
return
|
|
fi
|
|
|
|
# second, try to umount as current user
|
|
if umount "${mountpoint}"; then
|
|
return
|
|
fi
|
|
|
|
# third, try to umount with sudo
|
|
# repair ownership of partition files
|
|
sudo chown -R root:root "${mountpoint}"
|
|
sudo umount "${mountpoint}"
|
|
}
|
|
|
|
# Unpacks finished cloud provider image to recalculate dm-verity hash
|
|
unpack () {
|
|
local cloudprovider=$1
|
|
local packed_image=$2
|
|
local unpacked_image=$3
|
|
|
|
case $cloudprovider in
|
|
|
|
gcp)
|
|
echo "📤 Unpacking GCP image..."
|
|
"${PV}" "$packed_image" | tar -xzf - -O > "$unpacked_image"
|
|
echo " Unpacked image stored in ${unpacked_image}"
|
|
;;
|
|
|
|
azure)
|
|
echo "📤 Unpacking Azure image..."
|
|
qemu-img convert -p -f vpc -O raw "$packed_image" "$unpacked_image"
|
|
echo " Unpacked image stored in ${unpacked_image}"
|
|
;;
|
|
|
|
*)
|
|
echo "unknown cloud provider"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
get_part_offset () {
|
|
local unpacked_image=$1
|
|
local part_number=$2
|
|
local offset
|
|
offset=$(parted -s "${unpacked_image}" unit s print | sed 's/^ //g' | grep "^${part_number}" | tr -s ' ' | cut -d ' ' -f2)
|
|
local offset=${offset::-1}
|
|
echo "${offset}"
|
|
}
|
|
|
|
get_part_size () {
|
|
local unpacked_image=$1
|
|
local part_number=$2
|
|
local size
|
|
size=$(parted -s "${unpacked_image}" unit s print | sed 's/^ //g' | grep "^${part_number}" | tr -s ' ' | cut -d ' ' -f4)
|
|
local size=${size::-1}
|
|
echo "${size}"
|
|
}
|
|
|
|
extract_partition () {
|
|
local unpacked_image=$1
|
|
local part_number=$2
|
|
local extracted_partition_path=$3
|
|
|
|
local part_offset
|
|
part_offset=$(get_part_offset "${unpacked_image}" "${part_number}")
|
|
local part_size
|
|
part_size=$(get_part_size "${unpacked_image}" "${part_number}")
|
|
dd status=progress "if=${unpacked_image}" "of=${extracted_partition_path}" bs=512 "skip=${part_offset}" "count=${part_size}" 2>/dev/null
|
|
}
|
|
|
|
overwrite_partition () {
|
|
local unpacked_image=$1
|
|
local part_number=$2
|
|
local extracted_partition_path=$3
|
|
|
|
local part_offset
|
|
part_offset=$(get_part_offset "${unpacked_image}" "${part_number}")
|
|
local part_size
|
|
part_size=$(get_part_size "${unpacked_image}" "${part_number}")
|
|
dd status=progress conv=notrunc "if=${extracted_partition_path}" "of=${unpacked_image}" bs=512 "seek=${part_offset}" "count=${part_size}" 2>/dev/null
|
|
}
|
|
|
|
update_verity () {
|
|
local tmp_dir=$1
|
|
local raw_image=$2
|
|
local boot_mountpoint=${tmp_dir}/boot.mount
|
|
local boot_partition=${tmp_dir}/part_boot.raw
|
|
local root_partition=${tmp_dir}/part_root.raw
|
|
local hashtree_partition=${tmp_dir}/part_hashtree.raw
|
|
|
|
echo "⬅️ Extracting partitions..."
|
|
extract_partition "${raw_image}" 3 "${boot_partition}"
|
|
extract_partition "${raw_image}" 4 "${root_partition}"
|
|
extract_partition "${raw_image}" 5 "${hashtree_partition}"
|
|
|
|
# recalculate verity hashtree
|
|
veritysetup_out=$(veritysetup format "${root_partition}" "${hashtree_partition}")
|
|
roothash=$(echo "${veritysetup_out}" | grep 'Root hash:' | sed --expression='s/Root hash:\s*//g')
|
|
echo "🧮 Recalculated dm-verity hashtree with roothash ${roothash}"
|
|
# update bootloader kernel cmdline
|
|
mkdir -p "${boot_mountpoint}"
|
|
mount_partition "${boot_partition}" "${boot_mountpoint}"
|
|
sed -i -r "s/verity.sysroot=[[:xdigit:]]+/verity.sysroot=${roothash}/g" "${boot_mountpoint}/loader.1/entries/ostree-1-fedora-coreos.conf"
|
|
echo "✍️ Updated bootloader kernel cmdline to include new dm-verity roothash: $(grep '^options ' "${boot_mountpoint}"/loader.1/entries/ostree-1-fedora-coreos.conf)"
|
|
umount_partition "${boot_mountpoint}"
|
|
rmdir "${boot_mountpoint}"
|
|
|
|
echo "➡️ Overwriting partitions..."
|
|
overwrite_partition "${raw_image}" 3 "${boot_partition}"
|
|
overwrite_partition "${raw_image}" 5 "${hashtree_partition}"
|
|
}
|
|
|
|
repack () {
|
|
local cloudprovider=$1
|
|
local unpacked_image=$2
|
|
local packed_image=$3
|
|
local unpacked_image_dir
|
|
unpacked_image_dir=$(dirname "${unpacked_image}")
|
|
local unpacked_image_filename
|
|
unpacked_image_filename=$(basename "${unpacked_image}")
|
|
local tmp_tar_file
|
|
tmp_tar_file=$(mktemp -t verity.XXXXXX.tar)
|
|
|
|
case $cloudprovider in
|
|
|
|
gcp)
|
|
echo "📥 Repacking GCP image..."
|
|
tar --owner=0 --group=0 -C "${unpacked_image_dir}" -Sch --format=oldgnu -f "${tmp_tar_file}" "${unpacked_image_filename}"
|
|
"${PV}" "${tmp_tar_file}" | pigz -9c > "${packed_image}"
|
|
rm "${tmp_tar_file}"
|
|
echo " Repacked image stored in ${packed_image}"
|
|
;;
|
|
|
|
azure)
|
|
echo "📥 Repacking Azure image..."
|
|
qemu-img convert -p -f raw -O vpc -o force_size,subformat=fixed "${unpacked_image}" "$packed_image"
|
|
echo " Repacked image stored in ${packed_image}"
|
|
;;
|
|
|
|
*)
|
|
echo "unknown cloud provider"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
echo "🔁 Recalculating dm-verity hashtree 🌳"
|
|
tmp_dir=$(mktemp -d -t verity-XXXXXXXXXX)
|
|
raw_image="${tmp_dir}/disk.raw"
|
|
unpack "$1" "$2" "${raw_image}"
|
|
update_verity "${tmp_dir}" "${raw_image}"
|
|
repack "$1" "${raw_image}" "${2}"
|
|
rm -r "${tmp_dir}"
|