From b23656df314faacf2de86e310c5685f667f98b62 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Thu, 20 May 2021 00:14:42 +0800 Subject: [PATCH] Support AVB signing for BOARD_PREBUILT_BOOTIMAGE Devices using GKI architecture will use a prebuilt boot.img. However, we should still sign this prebuilt boot.img with device-specific AVB keys. Steps to test the CL. 1. In a device BoardConfig.mk: # Uses a prebuilt boot.img TARGET_NO_KERNEL := true BOARD_PREBUILT_BOOTIMAGE := device/google/redbull/boot.img # Enable chained vbmeta for the boot image. # The following can be absent, where the hash descriptor of the # 'boot' partition will be stored then signed in vbmeta.img instead. BOARD_AVB_BOOT_KEY_PATH := external/avb/test/data/testkey_rsa4096.pem BOARD_AVB_BOOT_ALGORITHM := SHA256_RSA4096 BOARD_AVB_BOOT_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP) BOARD_AVB_BOOT_ROLLBACK_INDEX_LOCATION := 2 2. `make bootimage`, then `avbtool info_image --image $OUT/boot.img`, checks the image is re-signed with a device-specific key 3. `make dist` to generate out/dist/TF.zip 4. `unzip out/dist/TF.zip IMAGES/boot.img` 5. `avbtool info_image --image out/dist/IMAGES/boot.img`, checks the image is re-signed with a device-specific key 6. `sign_target_files_apks \ --avb_boot_key=external/avb/test/data/testkey_rsa8192.pem \ --avb_boot_algorithm=SHA256_RSA8192 \ --avb_boot_extra_args="--prop test:sign" \ ./out/dist/*-target_files-eng.*.zip signed.zip`, resign the TF.zip 7. `unzip signed.zip IMAGES/boot.img`, then use `avbtool info_image` to check the boot.img is re-signed with the --avb_boot_key in step 6. Bug: 188485657 Test: above steps Change-Id: I7ee8b3ffe6a86aaca34bbb7a8898a97b3f8bd801 Merged-In: I7ee8b3ffe6a86aaca34bbb7a8898a97b3f8bd801 (cherry picked from commit cf9ead8972dd2b7c90772b6a1fd26bd4311a7c74) --- core/Makefile | 20 ++++++++++++++- core/board_config.mk | 2 ++ tools/releasetools/common.py | 47 +++++++++++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/core/Makefile b/core/Makefile index 233c51547e..7452a66fa0 100644 --- a/core/Makefile +++ b/core/Makefile @@ -1036,7 +1036,20 @@ else # TARGET_NO_KERNEL == "true" ifdef BOARD_PREBUILT_BOOTIMAGE INTERNAL_PREBUILT_BOOTIMAGE := $(BOARD_PREBUILT_BOOTIMAGE) INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img -$(eval $(call copy-one-file,$(INTERNAL_PREBUILT_BOOTIMAGE),$(INSTALLED_BOOTIMAGE_TARGET))) + +ifeq ($(BOARD_AVB_ENABLE),true) +$(INSTALLED_BOOTIMAGE_TARGET): $(INTERNAL_PREBUILT_BOOTIMAGE) $(AVBTOOL) $(BOARD_AVB_BOOT_KEY_PATH) + cp $(INTERNAL_PREBUILT_BOOTIMAGE) $@ + $(AVBTOOL) add_hash_footer \ + --image $@ \ + --partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \ + --partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \ + $(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS) +else +$(INSTALLED_BOOTIMAGE_TARGET): $(INTERNAL_PREBUILT_BOOTIMAGE) + cp $(INTERNAL_PREBUILT_BOOTIMAGE) $@ +endif # BOARD_AVB_ENABLE + else # BOARD_PREBUILT_BOOTIMAGE not defined INSTALLED_BOOTIMAGE_TARGET := endif # BOARD_PREBUILT_BOOTIMAGE @@ -5107,12 +5120,17 @@ ifdef BOARD_PREBUILT_SYSTEM_EXTIMAGE $(hide) mkdir -p $(zip_root)/IMAGES $(hide) cp $(INSTALLED_SYSTEM_EXTIMAGE_TARGET) $(zip_root)/IMAGES/ endif +ifndef BOARD_PREBUILT_BOOTIMAGE ifneq (,$(INTERNAL_PREBUILT_BOOTIMAGE) $(filter true,$(BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES))) ifdef INSTALLED_BOOTIMAGE_TARGET $(hide) mkdir -p $(zip_root)/IMAGES $(hide) cp $(INSTALLED_BOOTIMAGE_TARGET) $(zip_root)/IMAGES/ endif # INSTALLED_BOOTIMAGE_TARGET endif # INTERNAL_PREBUILT_BOOTIMAGE != "" || BOARD_COPY_BOOT_IMAGE_TO_TARGET_FILES == true +else # BOARD_PREBUILT_BOOTIMAGE is defined + $(hide) mkdir -p $(zip_root)/PREBUILT_IMAGES + $(hide) cp $(INSTALLED_BOOTIMAGE_TARGET) $(zip_root)/PREBUILT_IMAGES/ +endif # BOARD_PREBUILT_BOOTIMAGE ifdef BOARD_PREBUILT_ODMIMAGE $(hide) mkdir -p $(zip_root)/IMAGES $(hide) cp $(INSTALLED_ODMIMAGE_TARGET) $(zip_root)/IMAGES/ diff --git a/core/board_config.mk b/core/board_config.mk index 9061342b87..1b08f9a0b4 100644 --- a/core/board_config.mk +++ b/core/board_config.mk @@ -379,6 +379,8 @@ BUILDING_BOOT_IMAGE := ifeq ($(PRODUCT_BUILD_BOOT_IMAGE),) ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true) BUILDING_BOOT_IMAGE := + else ifdef BOARD_PREBUILT_BOOTIMAGE + BUILDING_BOOT_IMAGE := else ifdef BOARD_BOOTIMAGE_PARTITION_SIZE BUILDING_BOOT_IMAGE := true else ifneq (,$(foreach kernel,$(BOARD_KERNEL_BINARIES),$(BOARD_$(call to-upper,$(kernel))_BOOTIMAGE_PARTITION_SIZE))) diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py index 5e2a50dab6..985a21ab77 100644 --- a/tools/releasetools/common.py +++ b/tools/releasetools/common.py @@ -1710,6 +1710,38 @@ def _BuildBootableImage(image_name, sourcedir, fs_config_file, info_dict=None, return data +def _SignBootableImage(image_path, prebuilt_name, partition_name, + info_dict=None): + """Performs AVB signing for a prebuilt boot.img. + + Args: + image_path: The full path of the image, e.g., /path/to/boot.img. + prebuilt_name: The prebuilt image name, e.g., boot.img, boot-5.4-gz.img, + boot-5.10.img, recovery.img. + partition_name: The partition name, e.g., 'boot' or 'recovery'. + info_dict: The information dict read from misc_info.txt. + """ + if info_dict is None: + info_dict = OPTIONS.info_dict + + # AVB: if enabled, calculate and add hash to boot.img or recovery.img. + if info_dict.get("avb_enable") == "true": + avbtool = info_dict["avb_avbtool"] + if partition_name == "recovery": + part_size = info_dict["recovery_size"] + else: + part_size = info_dict[prebuilt_name.replace(".img", "_size")] + + cmd = [avbtool, "add_hash_footer", "--image", image_path, + "--partition_size", str(part_size), "--partition_name", + partition_name] + AppendAVBSigningArgs(cmd, partition_name) + args = info_dict.get("avb_" + partition_name + "_add_hash_footer_args") + if args and args.strip(): + cmd.extend(shlex.split(args)) + RunAndCheckOutput(cmd) + + def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, info_dict=None, two_step_image=False): """Return a File object with the desired bootable image. @@ -1718,6 +1750,9 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, otherwise look for it under 'unpack_dir'/IMAGES, otherwise construct it from the source files in 'unpack_dir'/'tree_subdir'.""" + if info_dict is None: + info_dict = OPTIONS.info_dict + prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name) if os.path.exists(prebuilt_path): logger.info("using prebuilt %s from BOOTABLE_IMAGES...", prebuilt_name) @@ -1728,10 +1763,16 @@ def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, logger.info("using prebuilt %s from IMAGES...", prebuilt_name) return File.FromLocalFile(name, prebuilt_path) - logger.info("building image from target_files %s...", tree_subdir) + prebuilt_path = os.path.join(unpack_dir, "PREBUILT_IMAGES", prebuilt_name) + if os.path.exists(prebuilt_path): + logger.info("Re-signing prebuilt %s from PREBUILT_IMAGES...", prebuilt_name) + signed_img = MakeTempFile() + shutil.copy(prebuilt_path, signed_img) + partition_name = tree_subdir.lower() + _SignBootableImage(signed_img, prebuilt_name, partition_name, info_dict) + return File.FromLocalFile(name, signed_img) - if info_dict is None: - info_dict = OPTIONS.info_dict + logger.info("building image from target_files %s...", tree_subdir) # With system_root_image == "true", we don't pack ramdisk into the boot image. # Unless "recovery_as_boot" is specified, in which case we carry the ramdisk