fix(rcar3): fix load address range check
Fixed the check of the address range which the program is loaded to.
Use the addresses and sizes in the BL31 and BL32 certificates to check
that they are within the range of the target address and size
defined inside the TF-A.
It also uses the addresses and sizes in the BL33x certificates to check
that they are outside the protected area defined inside the TF-A.
Signed-off-by: Hideyuki Nitta <hideyuki.nitta.jf@hitachi.com>
Signed-off-by: Toshiyuki Ogasahara <toshiyuki.ogasahara.bo@hitachi.com>
Signed-off-by: Yoshifumi Hosoya <yoshifumi.hosoya.wj@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org> # Code clean up
Change-Id: Iade15431fc86587489fb0ca9106f6baaf7e926e2
diff --git a/plat/renesas/rcar/bl2_plat_setup.c b/plat/renesas/rcar/bl2_plat_setup.c
index 81ee93e..6b1d4fc 100644
--- a/plat/renesas/rcar/bl2_plat_setup.c
+++ b/plat/renesas/rcar/bl2_plat_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2018-2023, Renesas Electronics Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -417,44 +417,61 @@
}
#endif
-int bl2_plat_handle_pre_image_load(unsigned int image_id)
+static uint64_t check_secure_load_area(uintptr_t base, uint32_t size,
+ uintptr_t dest, uint32_t len)
{
- u_register_t *boot_kind = (void *) BOOT_KIND_BASE;
- bl_mem_params_node_t *bl_mem_params;
-
- bl_mem_params = get_bl_mem_params_node(image_id);
+ uintptr_t free_end, requested_end;
-#if RCAR_GEN3_BL33_GZIP == 1
- if (image_id == BL33_IMAGE_ID) {
- image_decompress_prepare(&bl_mem_params->image_info);
+ /*
+ * Handle corner cases first.
+ *
+ * The order of the 2 tests is important, because if there's no space
+ * left (i.e. free_size == 0) but we don't ask for any memory
+ * (i.e. size == 0) then we should report that the memory is free.
+ */
+ if (len == 0U) {
+ WARN("BL2: load data size is zero\n");
+ return 0; /* A zero-byte region is always free */
}
-#endif
-
- if (image_id != BL31_IMAGE_ID)
- return 0;
-
- if (is_ddr_backup_mode() == RCAR_COLD_BOOT)
- goto cold_boot;
-
- *boot_kind = RCAR_WARM_BOOT;
- flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+ if (size == 0U) {
+ goto err;
+ }
- console_flush();
- bl2_plat_flush_bl31_params();
+ /*
+ * Check that the end addresses don't overflow.
+ * If they do, consider that this memory region is not free, as this
+ * is an invalid scenario.
+ */
+ if (check_uptr_overflow(base, size - 1U)) {
+ goto err;
+ }
+ free_end = base + (size - 1U);
- /* will not return */
- bl2_enter_bl31(&bl_mem_params->ep_info);
+ if (check_uptr_overflow(dest, len - 1U)) {
+ goto err;
+ }
+ requested_end = dest + (len - 1U);
-cold_boot:
- *boot_kind = RCAR_COLD_BOOT;
- flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+ /*
+ * Finally, check that the requested memory region lies within the free
+ * region.
+ */
+ if ((dest < base) || (requested_end > free_end)) {
+ goto err;
+ }
return 0;
+
+err:
+ ERROR("BL2: load data is outside the loadable area.\n");
+ ERROR("BL2: dst=0x%lx, len=%d(0x%x)\n", dest, len, len);
+ return 1;
}
-static uint64_t rcar_get_dest_addr_from_cert(uint32_t certid, uintptr_t *dest)
+static uint64_t rcar_get_dest_addr_from_cert(uint32_t certid, uintptr_t *dest,
+ uint32_t *len)
{
- uint32_t cert, len;
+ uint32_t cert;
int ret;
ret = rcar_get_certificate(certid, &cert);
@@ -463,17 +480,112 @@
return 1;
}
- rcar_read_certificate((uint64_t) cert, &len, dest);
+ rcar_read_certificate((uint64_t) cert, len, dest);
return 0;
}
+int bl2_plat_handle_pre_image_load(unsigned int image_id)
+{
+ u_register_t *boot_kind = (void *) BOOT_KIND_BASE;
+ bl_mem_params_node_t *bl_mem_params;
+ uintptr_t dev_handle;
+ uintptr_t image_spec;
+ uintptr_t dest;
+ uint32_t len;
+ uint64_t ui64_ret;
+ int iret;
+
+ bl_mem_params = get_bl_mem_params_node(image_id);
+ if (bl_mem_params == NULL) {
+ ERROR("BL2: Failed to get loading parameter.\n");
+ return 1;
+ }
+
+ switch (image_id) {
+ case BL31_IMAGE_ID:
+ if (is_ddr_backup_mode() == RCAR_COLD_BOOT) {
+ iret = plat_get_image_source(image_id, &dev_handle,
+ &image_spec);
+ if (iret != 0) {
+ return 1;
+ }
+
+ ui64_ret = rcar_get_dest_addr_from_cert(
+ SOC_FW_CONTENT_CERT_ID, &dest, &len);
+ if (ui64_ret != 0U) {
+ return 1;
+ }
+
+ ui64_ret = check_secure_load_area(
+ BL31_BASE, BL31_LIMIT - BL31_BASE,
+ dest, len);
+ if (ui64_ret != 0U) {
+ return 1;
+ }
+
+ *boot_kind = RCAR_COLD_BOOT;
+ flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+
+ bl_mem_params->image_info.image_base = dest;
+ bl_mem_params->image_info.image_size = len;
+ } else {
+ *boot_kind = RCAR_WARM_BOOT;
+ flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind));
+
+ console_flush();
+ bl2_plat_flush_bl31_params();
+
+ /* will not return */
+ bl2_enter_bl31(&bl_mem_params->ep_info);
+ }
+
+ return 0;
+#ifndef SPD_NONE
+ case BL32_IMAGE_ID:
+ ui64_ret = rcar_get_dest_addr_from_cert(
+ TRUSTED_OS_FW_CONTENT_CERT_ID, &dest, &len);
+ if (ui64_ret != 0U) {
+ return 1;
+ }
+
+ ui64_ret = check_secure_load_area(
+ BL32_BASE, BL32_LIMIT - BL32_BASE, dest, len);
+ if (ui64_ret != 0U) {
+ return 1;
+ }
+
+ bl_mem_params->image_info.image_base = dest;
+ bl_mem_params->image_info.image_size = len;
+
+ return 0;
+#endif
+ case BL33_IMAGE_ID:
+ /* case of image_id == BL33_IMAGE_ID */
+ ui64_ret = rcar_get_dest_addr_from_cert(
+ NON_TRUSTED_FW_CONTENT_CERT_ID,
+ &dest, &len);
+
+ if (ui64_ret != 0U) {
+ return 1;
+ }
+
+#if RCAR_GEN3_BL33_GZIP == 1
+ image_decompress_prepare(&bl_mem_params->image_info);
+#endif
+
+ return 0;
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
int bl2_plat_handle_post_image_load(unsigned int image_id)
{
static bl2_to_bl31_params_mem_t *params;
bl_mem_params_node_t *bl_mem_params;
- uintptr_t dest;
- int ret;
if (!params) {
params = (bl2_to_bl31_params_mem_t *) PARAMS_BASE;
@@ -481,25 +593,23 @@
}
bl_mem_params = get_bl_mem_params_node(image_id);
+ if (!bl_mem_params) {
+ ERROR("BL2: Failed to get loading parameter.\n");
+ return 1;
+ }
switch (image_id) {
case BL31_IMAGE_ID:
- ret = rcar_get_dest_addr_from_cert(SOC_FW_CONTENT_CERT_ID,
- &dest);
- if (!ret)
- bl_mem_params->image_info.image_base = dest;
- break;
+ bl_mem_params->ep_info.pc = bl_mem_params->image_info.image_base;
+ return 0;
case BL32_IMAGE_ID:
- ret = rcar_get_dest_addr_from_cert(TRUSTED_OS_FW_CONTENT_CERT_ID,
- &dest);
- if (!ret)
- bl_mem_params->image_info.image_base = dest;
-
+ bl_mem_params->ep_info.pc = bl_mem_params->image_info.image_base;
memcpy(¶ms->bl32_ep_info, &bl_mem_params->ep_info,
sizeof(entry_point_info_t));
- break;
+ return 0;
case BL33_IMAGE_ID:
#if RCAR_GEN3_BL33_GZIP == 1
+ int ret;
if ((mmio_read_32(BL33_COMP_BASE) & 0xffff) == 0x8b1f) {
/* decompress gzip-compressed image */
ret = image_decompress(&bl_mem_params->image_info);
@@ -514,7 +624,9 @@
#endif
memcpy(¶ms->bl33_ep_info, &bl_mem_params->ep_info,
sizeof(entry_point_info_t));
- break;
+ return 0;
+ default:
+ return 1;
}
return 0;