Add unit tests for Pointer Authentication
Add unit tests to:
Test access to the key registers.
Use the pointer authentication instructions.
Call psci version and check the EL3 pointer authentication keys
aren't leaked.
Make a tsp call and check the secure world keys aren't leaked.
Change-Id: Ic7940757e6f9fc905ccef8c035e0c22b47b35cd7
Signed-off-by: Joel Hutton <Joel.Hutton@Arm.com>
diff --git a/tftf/tests/extensions/ptrauth/test_ptrauth.c b/tftf/tests/extensions/ptrauth/test_ptrauth.c
new file mode 100644
index 0000000..a1f41e2
--- /dev/null
+++ b/tftf/tests/extensions/ptrauth/test_ptrauth.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <psci.h>
+#include <smccc.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+#include <tsp.h>
+#include <string.h>
+
+/* The length of the array used to hold the pauth keys */
+#define LENGTH_KEYS 10
+
+#ifndef AARCH32
+static void read_pauth_keys(uint64_t *pauth_keys, unsigned int len)
+{
+ assert(len >= LENGTH_KEYS);
+
+ memset(pauth_keys, 0, len * sizeof(uint64_t));
+
+ if (is_armv8_3_pauth_apa_api_present()) {
+ /* read instruction keys a and b (both 128 bit) */
+ pauth_keys[0] = read_apiakeylo_el1();
+ pauth_keys[1] = read_apiakeyhi_el1();
+
+ pauth_keys[2] = read_apibkeylo_el1();
+ pauth_keys[3] = read_apibkeyhi_el1();
+
+ /* read data keys a and b (both 128 bit) */
+ pauth_keys[4] = read_apdakeylo_el1();
+ pauth_keys[5] = read_apdakeyhi_el1();
+
+ pauth_keys[6] = read_apdbkeylo_el1();
+ pauth_keys[7] = read_apdbkeyhi_el1();
+ }
+
+ if (is_armv8_3_pauth_gpa_gpi_present()) {
+ /* read generic key */
+ pauth_keys[8] = read_apgakeylo_el1();
+ pauth_keys[9] = read_apgakeyhi_el1();
+ }
+
+}
+#endif
+
+/*
+ * TF-A is expected to allow access to key registers from lower EL's,
+ * reading the keys excercises this, on failure this will trap to
+ * EL3 and crash.
+ */
+test_result_t test_pauth_reg_access(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+ uint64_t pauth_keys[LENGTH_KEYS];
+ SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+ read_pauth_keys(pauth_keys, LENGTH_KEYS);
+ return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/*
+ * Makes a call to psci version, and checks that the EL3 pauth keys are not
+ * leaked when it returns
+ */
+#if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 0)
+__attribute__((target("sign-return-address=all")))
+#endif
+test_result_t test_pauth_leakage(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+ uint64_t pauth_keys_before[LENGTH_KEYS];
+ uint64_t pauth_keys_after[LENGTH_KEYS];
+ SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+
+ read_pauth_keys(pauth_keys_before, LENGTH_KEYS);
+
+ tftf_get_psci_version();
+
+ read_pauth_keys(pauth_keys_after, LENGTH_KEYS);
+
+ if (memcmp(pauth_keys_before, pauth_keys_after,
+ LENGTH_KEYS * sizeof(uint64_t)) != 0)
+ return TEST_RESULT_FAIL;
+ return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/* Uses the pauth instructions, this checks the enable PAUTH bit has been set */
+test_result_t test_pauth_instructions(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+ SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+ /*
+ * Pointer authentication instructions (explicit encoding for compilers
+ * that do not recognize these instructions)
+ */
+ /* paciasp */
+ __asm__ volatile (".inst 0xD503233F");
+ /* autiasp */
+ __asm__ volatile (".inst 0xD50323BF");
+ /* paciasp */
+ __asm__ volatile (".inst 0xD503233F");
+ /* xpaclri */
+ __asm__ volatile (".inst 0xD50320FF");
+ return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/*
+ * Makes a call to TSP ADD, and checks that the checks that the Secure World
+ * pauth keys are not leaked
+ */
+#if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 0)
+__attribute__((target("sign-return-address=all")))
+#endif
+test_result_t test_pauth_leakage_tsp(void)
+{
+ SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+ smc_args tsp_svc_params;
+ smc_ret_values tsp_result = {0};
+ uint64_t pauth_keys_before[LENGTH_KEYS];
+ uint64_t pauth_keys_after[LENGTH_KEYS];
+
+ SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+ SKIP_TEST_IF_TSP_NOT_PRESENT();
+
+ read_pauth_keys(pauth_keys_before, LENGTH_KEYS);
+
+ /* Standard SMC to ADD two numbers */
+ tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
+ tsp_svc_params.arg1 = 4;
+ tsp_svc_params.arg2 = 6;
+ tsp_result = tftf_smc(&tsp_svc_params);
+
+ /*
+ * Check the result of the addition-TSP_ADD will add
+ * the arguments to themselves and return
+ */
+ if (tsp_result.ret0 != 0 || tsp_result.ret1 != 8 ||
+ tsp_result.ret2 != 12) {
+ tftf_testcase_printf("TSP add returned wrong result:"
+ "got %d %d %d expected: 0 8 12\n",
+ (unsigned int)tsp_result.ret0,
+ (unsigned int)tsp_result.ret1,
+ (unsigned int)tsp_result.ret2);
+
+ return TEST_RESULT_FAIL;
+ }
+ read_pauth_keys(pauth_keys_after, LENGTH_KEYS);
+
+ if (memcmp(pauth_keys_before, pauth_keys_after,
+ LENGTH_KEYS * sizeof(uint64_t)) != 0)
+ return TEST_RESULT_FAIL;
+ return TEST_RESULT_SUCCESS;
+#endif
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index 38271dc..daf9528 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -10,4 +10,5 @@
extensions/sve/test_sve.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_1.c \
runtime_services/arm_arch_svc/smccc_arch_workaround_2.c \
+ extensions/ptrauth/test_ptrauth.c \
)
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index 666d5a0..4c3ad43 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -12,6 +12,10 @@
<testcase name="AMUv1 non-zero counters" function="test_amu_nonzero_ctr" />
<testcase name="AMUv1 suspend/resume" function="test_amu_suspend_resume" />
<testcase name="SVE support" function="test_sve_support" />
+ <testcase name="Access Pointer Authentication Registers" function="test_pauth_reg_access" />
+ <testcase name="Use Pointer Authentication Instructions" function="test_pauth_instructions" />
+ <testcase name="Check for Pointer Authentication key leakage from EL3" function="test_pauth_leakage" />
+ <testcase name="Check for Pointer Authentication key leakage from TSP" function="test_pauth_leakage_tsp" />
</testsuite>
<testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests">