From 402f9775b98ef59c6af3a12d76a8eb04258c1b67 Mon Sep 17 00:00:00 2001 From: Gabriel Valcazar Date: Thu, 6 May 2021 18:26:04 +0200 Subject: [PATCH] recovery-initramfs: manage update partition correctly with partition encryption Since the update partition might be involved during a software update, we need to make sure that its contents are accesible and safe when using the partition encryption feature at the same time. Mount and unmount the partition correctly if it's encrypted and cancel any operations that will result in the deletion of the update package. https://onedigi.atlassian.net/browse/DEL-7174 https://onedigi.atlassian.net/browse/DEL-7422 Signed-off-by: Gabriel Valcazar --- .../recovery-initramfs-init | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/meta-digi-dey/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init b/meta-digi-dey/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init index aad87abd3..dea6d2f71 100644 --- a/meta-digi-dey/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init +++ b/meta-digi-dey/recipes-core/recovery/recovery-initramfs/recovery-initramfs-init @@ -278,6 +278,17 @@ format_emmc_block() { psplash_message "Formatting '${1}' partition..." psplash_progress "0" + # If partition is encrypted, it might be open and even mounted at this point. + local mapped_block="/dev/mapper/crypt${1}" + if [ -e "${mapped_block}" ]; then + # Umount in case partition is mounted, ignore errors. + if grep -qs "${mapped_block}" /proc/mounts; then + umount "${mapped_block}" >/dev/null 2>&1 + fi + # Close mapped device + cryptsetup close crypt${1} + fi + # Find partition block number. local partition_block="/dev/mmcblk0p$(fdisk -l /dev/mmcblk0 | sed -ne "s,^[^0-9]*\([0-9]\+\).*\<${1}\>.*,\1,g;T;p")" if [ -b "${partition_block}" ]; then @@ -542,6 +553,22 @@ for p in ${BLACKLISTED}; do encrypt_partitions=$(remove_entry "${encrypt_partitions}" "${p}") done +# On eMMC, if the 'update' partition is encrypted, we need to mount it manually +if [ "$(is_nand)" = "no" ] && contains "${ENC_PARTS}" "update"; then + update_block="/dev/mmcblk0p$(fdisk -l /dev/mmcblk0 | sed -ne "s,^[^0-9]*\([0-9]\+\).*\.*,\1,g;T;p")" + trustfence-tool ${update_block} cryptupdate + if [ "$?" = "0" ]; then + # Reset block path to the decrypted mapped device + update_block="/dev/mapper/cryptupdate" + + mkdir -p ${UPDATE_MOUNT_DIR} + FSTYPE="$(blkid ${update_block} | sed -e 's,.*TYPE="\([^"]\+\)".*,\1,g')" + mount ${FSTYPE:+-t ${FSTYPE}} ${update_block} ${UPDATE_MOUNT_DIR} + else + quit_with_error "Error mounting encrypted update partition" + fi +fi + # Sanity checks. if [ -n "${update_package_bool}" ]; then check_swu_package "${update_package}" @@ -550,6 +577,11 @@ fi # Format UBI partitions if [ "$(is_nand)" = "yes" -a -n "${wipe_ubi_partitions}" ]; then for p in ${wipe_ubi_partitions}; do + # Only format 'update' partition if it doesn't have a pending + # update package. + [ "${p}" = "update" ] && \ + echo "${update_package}" | grep -qs "^${UPDATE_MOUNT_DIR}" && continue + # To protect against manually injected commands, only format # partitions that exist and aren't blacklisted. contains "${PART_LIST}" "${p}" && \ @@ -579,6 +611,41 @@ if [ "${DEFAULT_ENC_PARTS}" = "no" ]; then done fi +# If we have an update package in the 'update' partition and we also need to +# format said partition, avoid doing so by aborting the operation or by +# avoiding the formatting. +if echo "${update_package}" | grep -qs "^${UPDATE_MOUNT_DIR}"; then + # In the case of a state change (encrypted->unencrypted or + # unencrypted->encrypted), we can simply cancel it and continue with + # the update. Make sure to remove leading/trailing whitespaces from + # the diffs. + if contains "${UNENC_DIFF}" "update"; then + log_warning "Update package in 'update' partition, skip the partition's unencryption process." + + encrypt_partitions="${encrypt_partitions} update" + UNENC_DIFF=$(remove_entry "${UNENC_DIFF}" "update") + elif contains "${ENC_DIFF}" "update"; then + log_warning "Update package in 'update' partition, skip the partition's encryption process." + + encrypt_partitions=$(remove_entry "${encrypt_partitions}" "update") + ENC_DIFF=$(remove_entry "${ENC_DIFF}" "update") + fi + + # Worst case scenario: the partition remains encrypted, but the key is + # going to be changed. Since this affects all encrypted partitions, + # which might also include the rootfs, we can't cancel the key change + # and continue with the update. To avoid unexpected behaviour, abort + # both operations and quit. + if [ -n "${encryption_key_bool}" ] && \ + contains "${ENC_PARTS}" "update" && \ + contains "${encrypt_partitions}" "update"; then + quit_with_error "Cannot change the encryption key with an update package in an encrypted 'update' partition." + fi +fi + +# Remove leading/trailing whitespaces from the new encrypted partitions list. +encrypt_partitions=$(echo "${encrypt_partitions}" | xargs) + # Check if encryption key command is configured. if [ -n "${encryption_key_bool}" ]; then log "Trustfence encryption key setup requested (new key: ${encryption_key:-random})"