fix(bti): Add branch protection for VHE host apps
This patch enables branch protection for EL0 host apps that are build
with the test infrastructure. This patch also edits the VM memory
sharing tests to add the BTI instruction in tests where executable
memory is shared/lent. This is because the test VMs use the same page
table library as the hypervisor and the GP bit gets set, when it is
compiled branch protection enabled.
Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: Ib8ba887fe386c8e47e3e65487255a14665a74bc4
diff --git a/build/toolchain/embedded.gni b/build/toolchain/embedded.gni
index 2b47c00..43ed8f8 100644
--- a/build/toolchain/embedded.gni
+++ b/build/toolchain/embedded.gni
@@ -280,6 +280,11 @@
extra_defines += " -DGICD_BASE=${invoker.gicd_base_address} -DGICR_BASE=${invoker.gicr_base_address}"
}
+ if (defined(invoker.branch_protection)) {
+ extra_cflags += " -mbranch-protection=${invoker.branch_protection}"
+ extra_defines += " -DBRANCH_PROTECTION=1"
+ }
+
toolchain_args = {
plat_boot_flow = invoker.boot_flow
plat_console = invoker.console
@@ -320,16 +325,12 @@
"max_image_size",
"max_vms",
"toolchain_args",
+ "branch_protection",
])
cpu = "${invoker.cpu}+nofp"
# Add a macro so files can tell whether they are not being built for a VM.
extra_defines = " -DVM_TOOLCHAIN=0"
-
- if (defined(invoker.branch_protection)) {
- extra_cflags = " -mbranch-protection=${invoker.branch_protection}"
- extra_defines += " -DBRANCH_PROTECTION=1"
- }
}
# Toolchain for building test VMs which run under Hafnium.
@@ -343,6 +344,7 @@
"max_cpus",
"toolchain_args",
"console",
+ "branch_protection",
])
cpu = "${invoker.cpu}+fp"
boot_flow = "//src/arch/fake:boot_flow"
diff --git a/project/reference b/project/reference
index c61dadd..510aa3e 160000
--- a/project/reference
+++ b/project/reference
@@ -1 +1 @@
-Subproject commit c61dadd1e4b9b1f173607bd00c2607b63ed90bf6
+Subproject commit 510aa3ecc4915bcb291660c9d487c6d33fae4650
diff --git a/test/hftest/hftest.py b/test/hftest/hftest.py
index 35cabdc..65e267e 100755
--- a/test/hftest/hftest.py
+++ b/test/hftest/hftest.py
@@ -367,8 +367,14 @@
f"cluster0.cpu0={self.FVP_PREBUILT_BL31}@{self.CPU_START_ADDRESS}",
"-C", "bp.ve_sysregs.mmbSiteDefault=0",
"-C", "bp.ve_sysregs.exit_on_shutdown=1",
- "-C", "cluster0.has_arm_v8-1=1",
- "-C", "cluster1.has_arm_v8-1=1",
+ "-C", "cluster0.has_arm_v8-5=1",
+ "-C", "cluster1.has_arm_v8-5=1",
+ "-C", "cluster0.has_branch_target_exception=1",
+ "-C", "cluster1.has_branch_target_exception=1",
+ "-C", "cluster0.restriction_on_speculative_execution=2",
+ "-C", "cluster1.restriction_on_speculative_execution=2",
+ "-C", "cluster0.restriction_on_speculative_execution_aarch32=2",
+ "-C", "cluster1.restriction_on_speculative_execution_aarch32=2",
]
if uart0_log_path and uart1_log_path:
@@ -520,12 +526,6 @@
fvp_args += [
"--data", f"cluster0.cpu0={dt.dtb}@{self.SPMC_DTB_ADDRESS}",
"--data", f"cluster0.cpu0={self.args.spmc}@{self.SPMC_ADDRESS}",
- "-C", "cluster0.has_arm_v8-5=1",
- "-C", "cluster1.has_arm_v8-5=1",
- "-C", "cluster0.has_branch_target_exception=1",
- "-C", "cluster1.has_branch_target_exception=1",
- "-C", "cluster0.restriction_on_speculative_execution=2",
- "-C", "cluster1.restriction_on_speculative_execution=2",
]
if secure_ctrl:
diff --git a/test/vmapi/el0_partitions/memory_sharing.c b/test/vmapi/el0_partitions/memory_sharing.c
index e08c37d..547a220 100644
--- a/test/vmapi/el0_partitions/memory_sharing.c
+++ b/test/vmapi/el0_partitions/memory_sharing.c
@@ -1474,8 +1474,11 @@
/* Initialise the memory before giving it. */
memset_s(ptr, sizeof(pages), 0, PAGE_SIZE);
- uint64_t *ptr2 = (uint64_t *)pages;
- /* Set memory to contain the RET instruction to attempt to execute. */
+ uint32_t *ptr2 = (uint32_t *)pages;
+ /* Set memory to contain the BTI+RET instruction to attempt to execute.
+ */
+ *ptr2 = 0xD50324DF; /* BTI jc */
+ ptr2++;
*ptr2 = 0xD65F03C0;
struct ffa_memory_region_constituent constituents[] = {
@@ -1509,8 +1512,11 @@
/* Initialise the memory before giving it. */
memset_s(ptr, sizeof(pages), 0, PAGE_SIZE);
- uint64_t *ptr2 = (uint64_t *)pages;
- /* Set memory to contain the RET instruction to attempt to execute. */
+ uint32_t *ptr2 = (uint32_t *)pages;
+ /* Set memory to contain the BTI+RET instruction to attempt to execute.
+ */
+ *ptr2 = 0xD50324DF; /* BTI jc */
+ ptr2++;
*ptr2 = 0xD65F03C0;
struct ffa_memory_region_constituent constituents[] = {
diff --git a/test/vmapi/el0_partitions/services/memory.c b/test/vmapi/el0_partitions/services/memory.c
index 0cd6c84..3917c1d 100644
--- a/test/vmapi/el0_partitions/services/memory.c
+++ b/test/vmapi/el0_partitions/services/memory.c
@@ -613,7 +613,7 @@
struct ffa_composite_memory_region *composite =
ffa_memory_region_get_composite(memory_region, 0);
struct ffa_memory_region_constituent constituents;
- uint64_t *ptr;
+ uint32_t *ptr;
/* ASSERT_TRUE isn't enough for clang-analyze. */
CHECK(composite != NULL);
@@ -622,13 +622,15 @@
&composite->constituents[0],
sizeof(composite->constituents[0]));
// NOLINTNEXTLINE(performance-no-int-to-ptr)
- ptr = (uint64_t *)constituents.address;
+ ptr = (uint32_t *)constituents.address;
/*
- * Verify that the instruction in memory is the encoded RET
- * instruction.
+ * Verify that the instructions in memory is the encoded BTI+
+ * RET instructions.
*/
- EXPECT_EQ(*ptr, 0xD65F03C0);
+
+ EXPECT_EQ(*ptr, 0xD50324DF);
+ EXPECT_EQ(*(ptr + 1), 0xD65F03C0);
/* Try to execute instruction from the shared memory region. */
__asm__ volatile("blr %0" ::"r"(ptr));
diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c
index 3a31d15..30a3671 100644
--- a/test/vmapi/primary_with_secondaries/memory_sharing.c
+++ b/test/vmapi/primary_with_secondaries/memory_sharing.c
@@ -1595,9 +1595,13 @@
/* Initialise the memory before giving it. */
memset_s(ptr, sizeof(pages), 0, PAGE_SIZE);
- uint64_t *ptr2 = (uint64_t *)pages;
- /* Set memory to contain the RET instruction to attempt to execute. */
+ uint32_t *ptr2 = (uint32_t *)pages;
+ /* Set memory to contain the BTI+RET instruction to attempt to execute.
+ */
+ *ptr2 = 0xD50324DF; /* BTI jc */
+ ptr2++;
*ptr2 = 0xD65F03C0;
+ ;
struct ffa_memory_region_constituent constituents[] = {
{.address = (uint64_t)pages, .page_count = 1},
@@ -1641,8 +1645,11 @@
/* Initialise the memory before giving it. */
memset_s(ptr, sizeof(pages), 0, PAGE_SIZE);
- uint64_t *ptr2 = (uint64_t *)pages;
- /* Set memory to contain the RET instruction to attempt to execute. */
+ uint32_t *ptr2 = (uint32_t *)pages;
+ /* Set memory to contain the BTI+RET instructions to attempt to execute.
+ */
+ *ptr2 = 0xD50324DF; /* BTI jc */
+ ptr2++;
*ptr2 = 0xD65F03C0;
struct ffa_memory_region_constituent constituents[] = {
diff --git a/test/vmapi/primary_with_secondaries/services/memory.c b/test/vmapi/primary_with_secondaries/services/memory.c
index 5e25237..315fe26 100644
--- a/test/vmapi/primary_with_secondaries/services/memory.c
+++ b/test/vmapi/primary_with_secondaries/services/memory.c
@@ -618,20 +618,22 @@
struct ffa_composite_memory_region *composite =
ffa_memory_region_get_composite(memory_region, 0);
struct ffa_memory_region_constituent *constituents;
- uint64_t *ptr;
+ uint32_t *ptr;
/* ASSERT_TRUE isn't enough for clang-analyze. */
CHECK(composite != NULL);
constituents = composite->constituents;
// NOLINTNEXTLINE(performance-no-int-to-ptr)
- ptr = (uint64_t *)constituents[0].address;
+ ptr = (uint32_t *)constituents[0].address;
/*
* Verify that the instruction in memory is the encoded RET
* instruction.
*/
- EXPECT_EQ(*ptr, 0xD65F03C0);
+ EXPECT_EQ(*ptr, 0xD50324DF);
+ EXPECT_EQ(*(ptr + 1), 0xD65F03C0);
+
/* Try to execute instruction from the shared memory region. */
__asm__ volatile("blr %0" ::"r"(ptr));