From 78992a33f47ab9a0522fc75eb5b3b1b6fc27d975 Mon Sep 17 00:00:00 2001 From: Will Drewry Date: Wed, 21 Jul 2010 14:02:20 -0500 Subject: [PATCH] build_image, build_kernel_image, update_bootloaders: fix up rootfs_verification This change adds - --rootfs_hash_pad to specify the MBs reserved for the pad - the implementation of the above flag - check if total fs size + pad size exceeds the partition size - hash appending in make_image_bootable() Fixes: - a style for ROOT_FS_HASH usage - bad mount|grep - bad bash subst for root devices in all boot paths - fixed a typo in the update_bootloaders table creation - disables verified usb for now Adding the padding argument ensures that the generated hash tree for the root filesystem is appended to the image. Assuming the rootfs is _never_ mounted read-write again, that hash tree will be valid and vboot will be able to proceed. BUG=chromium-os:2693 TEST=manual build_image Review URL: http://codereview.chromium.org/3043011 Change-Id: I67d9b0f91cacdefa309c0cc2dd7fed1d2eddd7a7 --- build_image | 45 ++++++++++++++++++++++++--- build_kernel_image.sh | 9 +++--- create_legacy_bootloader_templates.sh | 12 +++---- update_bootloaders.sh | 5 ++- 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/build_image b/build_image index 492b160e78..0f8324bd00 100755 --- a/build_image +++ b/build_image @@ -51,6 +51,9 @@ DEFINE_integer rootfs_partition_size 1024 \ "rootfs parition size in MBs." DEFINE_integer rootfs_size 720 \ "rootfs filesystem size in MBs." +# ceil(0.1 * rootfs_size) is a good minimum. +DEFINE_integer rootfs_hash_pad 8 \ + "MBs reserved at the end of the rootfs image." DEFINE_integer statefulfs_size 1024 \ "stateful filesystem size in MBs." DEFINE_boolean preserve ${FLAGS_FALSE} \ @@ -91,8 +94,10 @@ if [ -z "${FLAGS_board}" ] ; then exit 1 fi -if [ "${FLAGS_rootfs_size}" -gt "${FLAGS_rootfs_partition_size}" ] ; then - error "rootfs (${FLAGS_rootfs_size} MB) is bigger than partition (${FLAGS_rootfs_partition_size} MB)." +if [ "$((FLAGS_rootfs_size + FLAGS_rootfs_hash_pad))" -gt \ + "${FLAGS_rootfs_partition_size}" ] ; then + error "rootfs ($((FLAGS_rootfs_size + FLAGS_rootfs_hash_pad)) MB) is \ +bigger than partition (${FLAGS_rootfs_partition_size} MB)." exit 1 fi @@ -293,8 +298,10 @@ make_image_bootable() { --image "${image_name}" -r "${ROOT_FS_DIR}" \ -s "${STATEFUL_FS_DIR}" + # The rootfs should never be mounted rw again after this point without + # re-calling make_image_bootable. sudo mount -o remount,ro "${ROOT_FS_DIR}" - root_dev=$(mount | grep -- "${ROOT_FS_DIR}" | cut -f1 -d' ' | tail -1) + root_dev=$(mount | grep -- "on ${ROOT_FS_DIR} type" | cut -f1 -d' ' | tail -1) DEVKEYSDIR="/usr/share/vboot/devkeys" @@ -308,7 +315,7 @@ make_image_bootable() { --working_dir="${OUTPUT_DIR}" \ --keep_work \ --rootfs_image=${root_dev} \ - --rootfs_hash=${OUTPUT_DIR}/rootfs.hash \ + --rootfs_hash=${ROOT_FS_HASH} \ --verity_hash_alg=${FLAGS_verity_algorithm} \ --verity_tree_depth=${FLAGS_verity_depth} \ --verity_max_ios=${FLAGS_verity_max_ios} \ @@ -316,6 +323,25 @@ make_image_bootable() { --root=${cros_root} \ --keys_dir="${DEVKEYSDIR}" + local rootfs_hash_size=$(stat -c '%s' ${ROOT_FS_HASH}) + info "Appending rootfs.hash (${rootfs_hash_size} bytes) to the root fs" + if [[ ${rootfs_hash_size} -gt $((FLAGS_rootfs_hash_pad * 1024 * 1024)) ]] + then + die "--rootfs_hash_pad reserves less than the needed ${rootfs_hash_size}" + fi + # Unfortunately, mount_gpt_image uses mount and not losetup to create the + # loop devices. This means that they are not the correct size. We have to + # write directly to the image to append the hash tree data. + local hash_offset="$(partoffset ${OUTPUT_DIR}/${image_name} 3)" + hash_offset=$((hash_offset + ((1024 * 1024 * ${FLAGS_rootfs_size}) / 512))) + sudo dd bs=512 \ + seek=${hash_offset} \ + if="${ROOT_FS_HASH}" \ + of="${OUTPUT_DIR}/${image_name}" \ + conv=notrunc + # We don't need to keep the file around anymore. + sudo rm "${ROOT_FS_HASH}" + # Move the verification block needed for the hard disk install to the # stateful partition. Mount stateful fs, copy file, and umount fs. # In original CL: http://codereview.chromium.org/2868044, this was done in @@ -510,7 +536,18 @@ create_base_image() { sudo losetup "${LOOP_DEV}" "${ROOT_FS_IMG}" sudo mkfs.ext3 "${LOOP_DEV}" + # Pad out 10% for the hash tree. This currently _exact_ for + # default configuration. More space may be needed for different options. + ROOT_HASH_PAD=$((FLAGS_rootfs_hash_pad * 1024 * 1024)) + info "Padding the rootfs image by ${ROOT_HASH_PAD} bytes for hash data" + dd if=/dev/zero of="${ROOT_FS_IMG}" bs=1 count=1 \ + seek=$((ROOT_SIZE_BYTES + ROOT_HASH_PAD - 1)) + # Update to reflect the new capacity in the loop device. + sudo losetup -c "${LOOP_DEV}" + # Tune and mount rootfs. + # TODO(wad) rename the disk label to match the GPT since we + # can't change it later. DISK_LABEL="C-KEYFOB" sudo tune2fs -L "${DISK_LABEL}" -U "${UUID}" -c 0 -i 0 "${LOOP_DEV}" sudo mount "${LOOP_DEV}" "${ROOT_FS_DIR}" diff --git a/build_kernel_image.sh b/build_kernel_image.sh index d78b150b65..fe90297a52 100755 --- a/build_kernel_image.sh +++ b/build_kernel_image.sh @@ -58,17 +58,16 @@ set -e verity_args= # Even with a rootfs_image, root= is not changed unless specified. if [[ -n "${FLAGS_rootfs_image}" && -n "${FLAGS_rootfs_hash}" ]]; then - info "Determining root fs block count." # Gets the number of blocks. 4096 byte blocks _are_ expected. root_fs_blocks=$(sudo dumpe2fs "${FLAGS_rootfs_image}" 2> /dev/null | grep "Block count" | tr -d ' ' | cut -f2 -d:) - info "Checking root fs block size." root_fs_block_sz=$(sudo dumpe2fs "${FLAGS_rootfs_image}" 2> /dev/null | grep "Block size" | tr -d ' ' | cut -f2 -d:) + info "rootfs is ${root_fs_blocks} blocks of ${root_fs_block_sz} bytes" if [[ ${root_fs_block_sz} -ne 4096 ]]; then error "Root file system blocks are not 4k!" fi @@ -87,10 +86,10 @@ if [[ -n "${FLAGS_rootfs_image}" && -n "${FLAGS_rootfs_hash}" ]]; then # the verified boot device. Doing so will claim /dev/sdDP out from # under the system. if [[ ${FLAGS_root} = "/dev/dm-0" ]]; then - table=${table//HASH_DEV/\/dev\/sd%D%P} - table=${table//ROOT_DEV/\/dev\/sd%D%P} + table=${table//HASH_DEV//dev/sd%D%P} + table=${table//ROOT_DEV//dev/sd%D%P} fi - verity_args="dm=\"${table}\"" + verity_args="dm=\"vroot none ro,${table}\"" info "dm-verity configuration: ${verity_args}" fi diff --git a/create_legacy_bootloader_templates.sh b/create_legacy_bootloader_templates.sh index 6c50f80787..36adbb7670 100755 --- a/create_legacy_bootloader_templates.sh +++ b/create_legacy_bootloader_templates.sh @@ -99,15 +99,13 @@ EOF info "Emitted ${SYSLINUX_DIR}/syslinux.cfg" if [[ ${FLAGS_enable_rootfs_verification} -eq ${FLAGS_TRUE} ]]; then - # To change the active target, only this file needs to change. - cat </dev/null -DEFAULT chromeos-vusb.A -EOF - else - cat </dev/null + # TODO(wad, tgao) enable usb vbooting with initramfs or device probing. + warn "USB booting will not use rootfs verification." + fi + # To change the active target, only this file needs to change. + cat </dev/null DEFAULT chromeos-usb.A EOF - fi info "Emitted ${SYSLINUX_DIR}/default.cfg" cat </dev/null diff --git a/update_bootloaders.sh b/update_bootloaders.sh index bdd7c09a0d..db443c40fd 100755 --- a/update_bootloaders.sh +++ b/update_bootloaders.sh @@ -72,8 +72,7 @@ if ! type -p update_x86_bootloaders; then sudo dd of="${esp_fs_dir}"/efi/boot/grub.cfg # Rewrite syslinux DM_TABLE - usb_target="${FLAGS_usb_disk//\//\\\/}" - syslinux_dm_table_usb=${dm_table//\/dev\/${old_root}/${usb_target}} + syslinux_dm_table_usb=${dm_table//\/dev\/${old_root}/${FLAGS_usb_disk}} sed -e "s|DMTABLEA|${syslinux_dm_table_usb}|g" \ "${template_dir}"/syslinux/usb.A.cfg | sudo dd of="${esp_fs_dir}"/syslinux/usb.A.cfg @@ -84,7 +83,7 @@ if ! type -p update_x86_bootloaders; then sudo dd of="${esp_fs_dir}"/syslinux/root.A.cfg syslinux_dm_table_b=${dm_table//\/dev\/${old_root}/HDROOTB} - sed -e "s|DMTABLEA|${syslinux_dm_table_a}|g" \ + sed -e "s|DMTABLEB|${syslinux_dm_table_b}|g" \ "${template_dir}"/syslinux/root.B.cfg | sudo dd of="${esp_fs_dir}"/syslinux/root.B.cfg