From 587c0e19a32ac49e681c8e05926e10cb9a9a43a7 Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Tue, 24 May 2022 17:02:56 +0800 Subject: MA-20303-1 Support rollback index check for single bootloader Add support to check the rollback index of next stage images (ATF, TEE, u-boot proper) in SPL to harden the security. And because there is no backup bootloader image to fall back to so the board would hang in SPL if rollback index is rejected. Change-Id: I4c7d1f084dd5b3d37899a9e4c4755c03145542c7 Signed-off-by: Ji Luo --- arch/arm/mach-imx/parse-container.c | 3 +- arch/arm/mach-imx/spl.c | 7 +- common/spl/spl_fit.c | 4 +- common/spl/spl_mmc.c | 4 +- disk/part_efi.c | 14 +-- include/part.h | 4 +- include/spl.h | 2 +- lib/avb/fsl/fsl_avbkey.c | 12 +- lib/avb/fsl/fsl_avbkey.h | 2 +- lib/avb/fsl/fsl_bootctrl.c | 219 +++++++++++++++++++++++------------- 10 files changed, 167 insertions(+), 104 deletions(-) diff --git a/arch/arm/mach-imx/parse-container.c b/arch/arm/mach-imx/parse-container.c index 503d2cf796c..334fe3b12e1 100644 --- a/arch/arm/mach-imx/parse-container.c +++ b/arch/arm/mach-imx/parse-container.c @@ -139,8 +139,7 @@ static int read_auth_container(struct spl_image_info *spl_image, } } -#if defined(CONFIG_SPL_BUILD) && \ - defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_IMX_TRUSTY_OS) +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX_TRUSTY_OS) /* Everything checks out, get the sw_version now. */ spl_image->rbindex = (uint64_t)container->sw_version; #endif diff --git a/arch/arm/mach-imx/spl.c b/arch/arm/mach-imx/spl.c index 2995ba42813..ea709d15a53 100644 --- a/arch/arm/mach-imx/spl.c +++ b/arch/arm/mach-imx/spl.c @@ -458,10 +458,15 @@ void board_spl_fit_post_load(const void *fit, struct spl_image_info *spl_image) } #ifdef CONFIG_IMX_TRUSTY_OS +int check_rollback_index(struct spl_image_info *spl_image, struct mmc *mmc); int check_rpmb_blob(struct mmc *mmc); -int mmc_image_load_late(struct mmc *mmc) +int mmc_image_load_late(struct spl_image_info *spl_image, struct mmc *mmc) { + /* Check the rollback index of next stage image */ + if (check_rollback_index(spl_image, mmc) < 0) + return -1; + /* Check the rpmb key blob for trusty enabled platfrom. */ return check_rpmb_blob(mmc); } diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c index b40d604c059..9d5a6dccec2 100644 --- a/common/spl/spl_fit.c +++ b/common/spl/spl_fit.c @@ -67,7 +67,7 @@ static int find_node_from_desc(const void *fit, int node, const char *str) return -ENOENT; } -#ifdef CONFIG_DUAL_BOOTLOADER +#ifdef CONFIG_IMX_TRUSTY_OS extern int spl_fit_get_rbindex(const void *fit); #endif @@ -741,7 +741,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image, if (ret < 0) return ret; -#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_IMX_TRUSTY_OS) +#ifdef CONFIG_IMX_TRUSTY_OS int rbindex; rbindex = spl_fit_get_rbindex(ctx.fit); if (rbindex < 0) { diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 591c238a632..cbbd166eb3f 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -82,7 +82,7 @@ int mmc_load_image_raw_sector_dual_uboot(struct spl_image_info *spl_image, struct mmc *mmc); #endif -int __weak mmc_image_load_late(struct mmc *mmc) +int __weak mmc_image_load_late(struct spl_image_info *spl_image, struct mmc *mmc) { return 0; } @@ -140,7 +140,7 @@ end: return -1; } - ret = mmc_image_load_late(mmc); + ret = mmc_image_load_late(spl_image, mmc); return ret; } diff --git a/disk/part_efi.c b/disk/part_efi.c index e810d9e9386..e1d9dced033 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -272,7 +272,7 @@ void part_print_efi(struct blk_desc *dev_desc) printf("\tguid:\t%pUl\n", uuid); } -#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD) +#if !(defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) || !defined(CONFIG_SPL_BUILD) /* Remember to free pte */ free(gpt_pte); #endif @@ -299,7 +299,7 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part, !is_pte_valid(&gpt_pte[part - 1])) { debug("%s: *** ERROR: Invalid partition number %d ***\n", __func__, part); -#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD) +#if !(defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) || !defined(CONFIG_SPL_BUILD) free(gpt_pte); #endif return -1; @@ -328,7 +328,7 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part, debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__, info->start, info->size, info->name); -#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD) +#if !(defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) || !defined(CONFIG_SPL_BUILD) /* Heap memory is very limited in SPL, if the dual bootloader is * enabled, just load pte to dram instead of oc-ram. In such case, * this part of memory shouldn't be freed. But in common routine, @@ -339,7 +339,7 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part, return 0; } -#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD) +#if (defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) && defined(CONFIG_SPL_BUILD) int part_get_info_efi_by_name(struct blk_desc *dev_desc, const char *name, struct disk_partition *info) { @@ -393,7 +393,7 @@ int part_get_info_efi_by_name(struct blk_desc *dev_desc, const char *name, return -1; } -#endif /* CONFIG_DUAL_BOOTLOADER && CONFIG_SPL_BUILD */ +#endif /* (CONFIG_DUAL_BOOTLOADER || CONFIG_IMX_TRUSTY_OS) && CONFIG_SPL_BUILD */ static int part_test_efi(struct blk_desc *dev_desc) { @@ -1196,7 +1196,7 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc, * don't forget to free the memory after use. */ if (count != 0) { -#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD) +#if (defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) && defined(CONFIG_SPL_BUILD) pte = (gpt_entry *)CONFIG_SYS_SPL_PTE_RAM_BASE; #else pte = memalign(ARCH_DMA_MINALIGN, @@ -1215,7 +1215,7 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc, blk_cnt = BLOCK_CNT(count, dev_desc); if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) { printf("*** ERROR: Can't read GPT Entries ***\n"); -#if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD) +#if !(defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) || !defined(CONFIG_SPL_BUILD) free(pte); #endif return NULL; diff --git a/include/part.h b/include/part.h index 85942511662..1db0db4d9c2 100644 --- a/include/part.h +++ b/include/part.h @@ -297,7 +297,7 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface, # define part_print_ptr(x) NULL # if defined(CONFIG_SPL_FS_EXT4) || defined(CONFIG_SPL_FS_FAT) || \ defined(CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION) || \ - defined(CONFIG_DUAL_BOOTLOADER) + defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS) # define part_get_info_ptr(x) x # else # define part_get_info_ptr(x) NULL @@ -479,7 +479,7 @@ int gpt_verify_partitions(struct blk_desc *dev_desc, */ int get_disk_guid(struct blk_desc *dev_desc, char *guid); -#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD) +#if (defined(CONFIG_DUAL_BOOTLOADER) || defined(CONFIG_IMX_TRUSTY_OS)) && defined(CONFIG_SPL_BUILD) int part_get_info_efi_by_name(struct blk_desc *dev_desc, const char *name, struct disk_partition *info); #endif diff --git a/include/spl.h b/include/spl.h index d44903fc0ca..951616b8951 100644 --- a/include/spl.h +++ b/include/spl.h @@ -229,7 +229,7 @@ struct spl_image_info { ulong dcrc_length; ulong dcrc; #endif -#ifdef CONFIG_DUAL_BOOTLOADER +#ifdef CONFIG_IMX_TRUSTY_OS uint64_t rbindex; #endif }; diff --git a/lib/avb/fsl/fsl_avbkey.c b/lib/avb/fsl/fsl_avbkey.c index d01b1931cb3..096492dbe6c 100644 --- a/lib/avb/fsl/fsl_avbkey.c +++ b/lib/avb/fsl/fsl_avbkey.c @@ -483,7 +483,7 @@ fail: } int rpmb_init(void) { -#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_DUAL_BOOTLOADER) +#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_IMX_TRUSTY_OS) int i; #endif kblb_hdr_t hdr; @@ -502,7 +502,7 @@ int rpmb_init(void) { * RPMB which is different from the rollback index for vbmeta and * ATX key versions. */ -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_DUAL_BOOTLOADER) +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX_TRUSTY_OS) if (rpmb_read(mmc_dev, (uint8_t *)&hdr, sizeof(hdr), BOOTLOADER_RBIDX_OFFSET) != 0) { #else @@ -516,7 +516,7 @@ int rpmb_init(void) { else printf("initialize rollback index...\n"); /* init rollback index */ -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_DUAL_BOOTLOADER) +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX_TRUSTY_OS) offset = BOOTLOADER_RBIDX_START; rbidx_len = BOOTLOADER_RBIDX_LEN; rbidx = malloc(rbidx_len); @@ -536,7 +536,7 @@ int rpmb_init(void) { } if (rbidx != NULL) free(rbidx); -#else /* CONFIG_SPL_BUILD && CONFIG_DUAL_BOOTLOADER */ +#else /* CONFIG_SPL_BUILD && CONFIG_IMX_TRUSTY_OS */ offset = AVB_RBIDX_START; rbidx_len = AVB_RBIDX_LEN; rbidx = malloc(rbidx_len); @@ -582,11 +582,11 @@ int rpmb_init(void) { if (rbidx != NULL) free(rbidx); #endif -#endif /* CONFIG_SPL_BUILD && CONFIG_DUAL_BOOTLOADER */ +#endif /* CONFIG_SPL_BUILD && CONFIG_IMX_TRUSTY_OS */ /* init hdr */ memcpy(hdr.magic, AVB_KBLB_MAGIC, AVB_KBLB_MAGIC_LEN); -#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_DUAL_BOOTLOADER) +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX_TRUSTY_OS) if (rpmb_write(mmc_dev, (uint8_t *)&hdr, sizeof(hdr), BOOTLOADER_RBIDX_OFFSET) != 0) { #else diff --git a/lib/avb/fsl/fsl_avbkey.h b/lib/avb/fsl/fsl_avbkey.h index a4343e06d32..2d6adf02be7 100644 --- a/lib/avb/fsl/fsl_avbkey.h +++ b/lib/avb/fsl/fsl_avbkey.h @@ -66,7 +66,7 @@ struct kblb_hdr { /* Rollback index for bootloader is managed by SPL and * will be stored in RPMB. */ -#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD) +#if defined(CONFIG_IMX_TRUSTY_OS) && defined(CONFIG_SPL_BUILD) kblb_tag_t bootloader_rbk_tags; #endif /* public key keyblb tag */ diff --git a/lib/avb/fsl/fsl_bootctrl.c b/lib/avb/fsl/fsl_bootctrl.c index 36db39eea96..797503a857f 100755 --- a/lib/avb/fsl/fsl_bootctrl.c +++ b/lib/avb/fsl/fsl_bootctrl.c @@ -455,55 +455,11 @@ out: return ret; } - -/* Below are the A/B AVB flow in spl and uboot proper. */ -#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD) - -#define PARTITION_NAME_LEN 13 -#define PARTITION_BOOTLOADER "bootloader" - -extern int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value); - -/* Pre-declaration of h_spl_load_read(), see detail implementation in - * common/spl/spl_mmc.c. - */ -ulong h_spl_load_read(struct spl_load_info *load, ulong sector, - ulong count, void *buf); - -/* Writes A/B metadata to disk only if it has changed. - */ -int fsl_save_metadata_if_changed_dual_uboot(struct blk_desc *dev_desc, - struct bootloader_control* ab_data, - struct bootloader_control* ab_data_orig) { - struct bootloader_control serialized; - size_t num_bytes; - struct disk_partition info; - - /* Save metadata if changed. */ - if (memcmp(ab_data, ab_data_orig, sizeof(struct bootloader_control)) != 0) { - /* Get misc partition info */ - if (part_get_info_efi_by_name(dev_desc, FASTBOOT_PARTITION_MISC, &info) == -1) { - printf("Can't get partition info of partition: misc\n"); - return -1; - } - - /* Writing A/B metadata to disk. */ - fsl_avb_ab_data_update_crc_and_byteswap(ab_data, &serialized); - if (write_to_partition_in_bytes(dev_desc, &info, - FSL_AB_METADATA_MISC_PARTITION_OFFSET, - sizeof(struct bootloader_control), - (void *)&serialized, &num_bytes) || - (num_bytes != sizeof(struct bootloader_control))) { - printf("Error--write metadata fail!\n"); - return -1; - } - } - return 0; -} - +#ifdef CONFIG_SPL_BUILD /* Load metadate from misc partition. */ -int fsl_load_metadata_dual_uboot(struct blk_desc *dev_desc, +#if defined(CONFIG_IMX_TRUSTY_OS) || defined(CONFIG_DUAL_BOOTLOADER) +int spl_fsl_load_metadata(struct blk_desc *dev_desc, struct bootloader_control* ab_data, struct bootloader_control* ab_data_orig) { struct disk_partition info; @@ -549,8 +505,9 @@ int fsl_load_metadata_dual_uboot(struct blk_desc *dev_desc, } } } +#endif /* CONFIG_IMX_TRUSTY_OS || CONFIG_DUAL_BOOTLOADER */ -#if !defined(CONFIG_XEN) && defined(CONFIG_IMX_TRUSTY_OS) +#ifdef CONFIG_IMX_TRUSTY_OS static int spl_verify_rbidx(struct mmc *mmc, struct slot_metadata *slot, struct spl_image_info *spl_image) { @@ -610,7 +567,139 @@ static int spl_verify_rbidx(struct mmc *mmc, struct slot_metadata *slot, } } -#endif /* !CONFIG_XEN && CONFIG_IMX_TRUSTY_OS */ +/* + * spl_fit_get_rbindex(): Get rollback index of the bootloader. + * @fit: Pointer to the FDT blob. + * + * Return: the rollback index value of bootloader or a negative + * error number. + */ +int spl_fit_get_rbindex(const void *fit) +{ + const char *str; + uint64_t index; + int conf_node; + int len; + + conf_node = fit_find_config_node(fit); + if (conf_node < 0) { + return conf_node; + } + + str = fdt_getprop(fit, conf_node, "rbindex", &len); + if (!str) { + debug("cannot find property 'rbindex'\n"); + return -EINVAL; + } + + index = simple_strtoul(str, NULL, 10); + + return index; +} + +int check_rollback_index(struct spl_image_info *spl_image, struct mmc *mmc) +{ + struct disk_partition info; + struct blk_desc *desc; + struct bootloader_control ab_data, ab_data_orig; + size_t target_slot; + int ret = -1; + unsigned char original_part; + + /* Only checks rollback index when rpmb key is set */ + if (!rpmbkey_is_set()) { + printf("RPMB key is not set.\n"); + return 0; + } + + /* Check if gpt is valid */ + desc = mmc_get_blk_desc(mmc); + if (desc) { + /* switch to user partition of eMMC */ + original_part = desc->hwpart; + if (desc->hwpart != 0) { + if (mmc_switch_part(mmc, 0) != 0) + return -1; + desc->hwpart = 0; + } + + if (part_get_info(desc, 1, &info)) { + printf("GPT is invalid, please flash correct GPT!\n"); + ret = -1; + goto fail; + } + } else { + printf("Get block desc fail!\n"); + return -1; + } + + /* Load AB metadata from misc partition */ + if (spl_fsl_load_metadata(desc, &ab_data, &ab_data_orig)) { + ret = -1; + goto fail; + } + target_slot = (ab_data.slot_info[1].priority > ab_data.slot_info[0].priority) ? 1 : 0; + + ret = spl_verify_rbidx(mmc, &ab_data.slot_info[target_slot], spl_image); + +fail: + /* Return to original partition */ + if (desc->hwpart != original_part) { + if (mmc_switch_part(mmc, original_part) != 0) + ret = -1; + else + desc->hwpart = original_part; + } + + return ret; +} +#endif /* CONFIG_IMX_TRUSTY_OS */ +#endif /* CONFIG_SPL_BUILD */ + +/* Below are the A/B AVB flow in spl and uboot proper. */ +#if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD) + +#define PARTITION_NAME_LEN 13 +#define PARTITION_BOOTLOADER "bootloader" + +extern int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value); + +/* Pre-declaration of h_spl_load_read(), see detail implementation in + * common/spl/spl_mmc.c. + */ +ulong h_spl_load_read(struct spl_load_info *load, ulong sector, + ulong count, void *buf); + +/* Writes A/B metadata to disk only if it has changed. + */ +int fsl_save_metadata_if_changed_dual_uboot(struct blk_desc *dev_desc, + struct bootloader_control* ab_data, + struct bootloader_control* ab_data_orig) { + struct bootloader_control serialized; + size_t num_bytes; + struct disk_partition info; + + /* Save metadata if changed. */ + if (memcmp(ab_data, ab_data_orig, sizeof(struct bootloader_control)) != 0) { + /* Get misc partition info */ + if (part_get_info_efi_by_name(dev_desc, FASTBOOT_PARTITION_MISC, &info) == -1) { + printf("Can't get partition info of partition: misc\n"); + return -1; + } + + /* Writing A/B metadata to disk. */ + fsl_avb_ab_data_update_crc_and_byteswap(ab_data, &serialized); + if (write_to_partition_in_bytes(dev_desc, &info, + FSL_AB_METADATA_MISC_PARTITION_OFFSET, + sizeof(struct bootloader_control), + (void *)&serialized, &num_bytes) || + (num_bytes != sizeof(struct bootloader_control))) { + printf("Error--write metadata fail!\n"); + return -1; + } + } + return 0; +} int mmc_load_image_raw_sector_dual_uboot(struct spl_image_info *spl_image, struct mmc *mmc) @@ -652,7 +741,7 @@ int mmc_load_image_raw_sector_dual_uboot(struct spl_image_info *spl_image, #endif /* Load AB metadata from misc partition */ - if (fsl_load_metadata_dual_uboot(dev_desc, &ab_data, + if (spl_fsl_load_metadata(dev_desc, &ab_data, &ab_data_orig)) { return -1; } @@ -825,36 +914,6 @@ end: return 0; } -/* - * spl_fit_get_rbindex(): Get rollback index of the bootloader. - * @fit: Pointer to the FDT blob. - * - * Return: the rollback index value of bootloader or a negative - * error number. - */ -int spl_fit_get_rbindex(const void *fit) -{ - const char *str; - uint64_t index; - int conf_node; - int len; - - conf_node = fit_find_config_node(fit); - if (conf_node < 0) { - return conf_node; - } - - str = fdt_getprop(fit, conf_node, "rbindex", &len); - if (!str) { - debug("cannot find property 'rbindex'\n"); - return -EINVAL; - } - - index = simple_strtoul(str, NULL, 10); - - return index; -} - /* For normal build */ #elif !defined(CONFIG_SPL_BUILD) -- cgit v1.2.3