Pārlūkot izejas kodu

plat/arm: fvp: Protect GICR frames for fused/unused cores

Currently, BLs are mapping the GIC memory region as read-write
for all cores on boot-up.

This opens up the security hole where the active core can write
the GICR frame of fused/inactive core. To avoid this issue, disable
the GICR frame of all inactive cores as below:

1. After primary CPU boots up, map GICR region of all cores as
   read-only.
2. After primary CPU boots up, map its GICR region as read-write
   and initialize its redistributor interface.
3. After secondary CPU boots up, map its GICR region as read-write
   and initialize its redistributor interface.
4. All unused/fused core's redistributor regions remain read-only and
   write attempt to such protected regions results in an exception.

As mentioned above, this patch offers only the GICR memory-mapped
region protection considering there is no facility at the GIC IP
level to avoid writing the redistributor area.

These changes are currently done in BL31 of Arm FVP and guarded under
the flag 'FVP_GICR_REGION_PROTECTION'.

As of now, this patch is tested manually as below:
1. Disable the FVP cores (core 1, 2, 3) with core 0 as an active core.
2. Verify data abort triggered by manually updating the ‘GICR_CTLR’
   register of core 1’s(fused) redistributor from core 0(active).

Change-Id: I86c99c7b41bae137b2011cf2ac17fad0a26e776d
Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
Manish V Badarkhe 3 gadi atpakaļ
vecāks
revīzija
f98630fbbf

+ 17 - 0
plat/arm/board/fvp/fvp_common.c

@@ -48,6 +48,18 @@ arm_config_t arm_config;
 					DEVICE1_SIZE,			\
 					MT_DEVICE | MT_RW | MT_SECURE)
 
+#if FVP_GICR_REGION_PROTECTION
+#define MAP_GICD_MEM	MAP_REGION_FLAT(BASE_GICD_BASE,			\
+					BASE_GICD_SIZE,			\
+					MT_DEVICE | MT_RW | MT_SECURE)
+
+/* Map all core's redistributor memory as read-only. After boots up,
+ * per-core map its redistributor memory as read-write */
+#define MAP_GICR_MEM	MAP_REGION_FLAT(BASE_GICR_BASE,			\
+					(BASE_GICR_SIZE * PLATFORM_CORE_COUNT),\
+					MT_DEVICE | MT_RO | MT_SECURE)
+#endif /* FVP_GICR_REGION_PROTECTION */
+
 /*
  * Need to be mapped with write permissions in order to set a new non-volatile
  * counter value.
@@ -138,7 +150,12 @@ const mmap_region_t plat_arm_mmap[] = {
 	ARM_MAP_EL3_TZC_DRAM,
 	V2M_MAP_IOFPGA,
 	MAP_DEVICE0,
+#if FVP_GICR_REGION_PROTECTION
+	MAP_GICD_MEM,
+	MAP_GICR_MEM,
+#else
 	MAP_DEVICE1,
+#endif /* FVP_GICR_REGION_PROTECTION */
 	ARM_V2M_MAP_MEM_PROTECT,
 #if SPM_MM
 	ARM_SPM_BUF_EL3_MMAP,

+ 10 - 1
plat/arm/board/fvp/fvp_def.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -135,7 +135,16 @@
 
 /* Base FVP compatible GIC memory map */
 #define BASE_GICD_BASE			UL(0x2f000000)
+#define BASE_GICD_SIZE			UL(0x10000)
 #define BASE_GICR_BASE			UL(0x2f100000)
+
+#if GIC_ENABLE_V4_EXTN
+/* GICv4 redistributor size: 256KB */
+#define BASE_GICR_SIZE			UL(0x40000)
+#else
+#define BASE_GICR_SIZE			UL(0x20000)
+#endif /* GIC_ENABLE_V4_EXTN */
+
 #define BASE_GICC_BASE			UL(0x2c000000)
 #define BASE_GICH_BASE			UL(0x2c010000)
 #define BASE_GICV_BASE			UL(0x2c02f000)

+ 39 - 1
plat/arm/board/fvp/fvp_gicv3.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,11 @@
 #include <plat/arm/common/fconf_sec_intr_config.h>
 #include <plat/common/platform.h>
 
+#if FVP_GICR_REGION_PROTECTION
+/* To indicate GICR region of the core initialized as Read-Write */
+static bool fvp_gicr_rw_region_init[PLATFORM_CORE_COUNT] = {false};
+#endif /* FVP_GICR_REGION_PROTECTION */
+
 /* The GICv3 driver only needs to be initialized in EL3 */
 static uintptr_t fvp_rdistif_base_addrs[PLATFORM_CORE_COUNT];
 
@@ -61,8 +66,39 @@ static gicv3_driver_data_t fvp_gic_data = {
 	.mpidr_to_core_pos = fvp_gicv3_mpidr_hash
 };
 
+/******************************************************************************
+ * This function gets called per core to make its redistributor frame rw
+ *****************************************************************************/
+static void fvp_gicv3_make_rdistrif_rw(void)
+{
+#if FVP_GICR_REGION_PROTECTION
+	unsigned int core_pos = plat_my_core_pos();
+
+	/* Make the redistributor frame RW if it is not done previously */
+	if (fvp_gicr_rw_region_init[core_pos] != true) {
+		int ret = xlat_change_mem_attributes(BASE_GICR_BASE +
+						     (core_pos * BASE_GICR_SIZE),
+						     BASE_GICR_SIZE,
+						     MT_EXECUTE_NEVER |
+						     MT_DEVICE | MT_RW |
+						     MT_SECURE);
+
+		if (ret != 0) {
+			ERROR("Failed to make redistributor frame \
+			       read write = %d\n", ret);
+			panic();
+		} else {
+			fvp_gicr_rw_region_init[core_pos] = true;
+		}
+	}
+#else
+	return;
+#endif /* FVP_GICR_REGION_PROTECTION */
+}
+
 void plat_arm_gic_driver_init(void)
 {
+	fvp_gicv3_make_rdistrif_rw();
 	/*
 	 * Get GICD and GICR base addressed through FCONF APIs.
 	 * FCONF is not supported in BL32 for FVP.
@@ -117,6 +153,8 @@ void plat_arm_gic_pcpu_init(void)
 	int result;
 	const uint64_t *plat_gicr_frames = fvp_gicr_frames;
 
+	fvp_gicv3_make_rdistrif_rw();
+
 	do {
 		result = gicv3_rdistif_probe(*plat_gicr_frames);
 

+ 8 - 1
plat/arm/board/fvp/platform.mk

@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -16,6 +16,10 @@ FVP_MAX_CPUS_PER_CLUSTER	:= 4
 # Default number of threads per CPU on FVP
 FVP_MAX_PE_PER_CPU	:= 1
 
+# Disable redistributor frame of inactive/fused CPU cores by marking it as read
+# only; enable redistributor frames of all CPU cores by default.
+FVP_GICR_REGION_PROTECTION		:= 0
+
 FVP_DT_PREFIX		:= fvp-base-gicv3-psci
 
 # The FVP platform depends on this macro to build with correct GIC driver.
@@ -30,6 +34,9 @@ $(eval $(call add_define,FVP_MAX_CPUS_PER_CLUSTER))
 # Pass FVP_MAX_PE_PER_CPU to the build system.
 $(eval $(call add_define,FVP_MAX_PE_PER_CPU))
 
+# Pass FVP_GICR_REGION_PROTECTION to the build system.
+$(eval $(call add_define,FVP_GICR_REGION_PROTECTION))
+
 # Sanity check the cluster count and if FVP_CLUSTER_COUNT <= 2,
 # choose the CCI driver , else the CCN driver
 ifeq ($(FVP_CLUSTER_COUNT), 0)