aboutsummaryrefslogtreecommitdiff
path: root/tftf/tests/extensions/pauth/test_pauth.c
blob: 30b78ef19492e5c69238de97966644fd1306aeca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
 * Copyright (c) 2019, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <pauth.h>
#include <psci.h>
#include <smccc.h>
#include <test_helpers.h>
#include <tftf_lib.h>
#include <tftf.h>
#include <tsp.h>
#include <string.h>

#ifdef __aarch64__

/* Number of ARMv8.3-PAuth keys */
#define NUM_KEYS	5

static const char * const key_name[] = {"IA", "IB", "DA", "DB", "GA"};

static uint128_t pauth_keys_before[NUM_KEYS];
static uint128_t pauth_keys_after[NUM_KEYS];

/* Check if ARMv8.3-PAuth key is enabled */
static bool is_pauth_key_enabled(uint64_t key_bit)
{
	return (IS_IN_EL2() ?
		((read_sctlr_el2() & key_bit) != 0U) :
		((read_sctlr_el1() & key_bit) != 0U));
}

static test_result_t compare_pauth_keys(void)
{
	test_result_t result = TEST_RESULT_SUCCESS;

	for (unsigned int i = 0; i < NUM_KEYS; ++i) {
		if (pauth_keys_before[i] != pauth_keys_after[i]) {
			ERROR("AP%sKey_EL1 read 0x%llx:%llx "
			"expected 0x%llx:%llx\n", key_name[i],
			(uint64_t)(pauth_keys_after[i] >> 64),
			(uint64_t)(pauth_keys_after[i]),
			(uint64_t)(pauth_keys_before[i] >> 64),
			(uint64_t)(pauth_keys_before[i]));

			result = TEST_RESULT_FAIL;
		}
	}
	return result;
}

/*
 * Program or read ARMv8.3-PAuth keys (if already enabled)
 * and store them in <pauth_keys_before> buffer
 */
static void set_store_pauth_keys(void)
{
	uint128_t plat_key;

	memset(pauth_keys_before, 0, NUM_KEYS * sizeof(uint128_t));

	if (is_armv8_3_pauth_apa_api_present()) {
		if (is_pauth_key_enabled(SCTLR_EnIA_BIT)) {
			/* Read APIAKey_EL1 */
			plat_key = read_apiakeylo_el1() |
				((uint128_t)(read_apiakeyhi_el1()) << 64);
			INFO("EnIA is set\n");
		} else {
			/* Program APIAKey_EL1 */
			plat_key = init_apkey();
			write_apiakeylo_el1((uint64_t)plat_key);
			write_apiakeyhi_el1((uint64_t)(plat_key >> 64));
		}
		pauth_keys_before[0] = plat_key;

		if (is_pauth_key_enabled(SCTLR_EnIB_BIT)) {
			/* Read APIBKey_EL1 */
			plat_key = read_apibkeylo_el1() |
				((uint128_t)(read_apibkeyhi_el1()) << 64);
			INFO("EnIB is set\n");
		} else {
			/* Program APIBKey_EL1 */
			plat_key = init_apkey();
			write_apibkeylo_el1((uint64_t)plat_key);
			write_apibkeyhi_el1((uint64_t)(plat_key >> 64));
		}
		pauth_keys_before[1] = plat_key;

		if (is_pauth_key_enabled(SCTLR_EnDA_BIT)) {
			/* Read APDAKey_EL1 */
			plat_key = read_apdakeylo_el1() |
				((uint128_t)(read_apdakeyhi_el1()) << 64);
			INFO("EnDA is set\n");
		} else {
			/* Program APDAKey_EL1 */
			plat_key = init_apkey();
			write_apdakeylo_el1((uint64_t)plat_key);
			write_apdakeyhi_el1((uint64_t)(plat_key >> 64));
		}
		pauth_keys_before[2] = plat_key;

		if (is_pauth_key_enabled(SCTLR_EnDB_BIT)) {
			/* Read APDBKey_EL1 */
			plat_key = read_apdbkeylo_el1() |
				((uint128_t)(read_apdbkeyhi_el1()) << 64);
			INFO("EnDB is set\n");
		} else {
			/* Program APDBKey_EL1 */
			plat_key = init_apkey();
			write_apdbkeylo_el1((uint64_t)plat_key);
			write_apdbkeyhi_el1((uint64_t)(plat_key >> 64));
		}
		pauth_keys_before[3] = plat_key;
	}

	/*
	 * It is safe to assume that Generic Pointer authentication code key
	 * APGAKey_EL1 can be re-programmed, as this key is not set in
	 * TF-A Test suite and PACGA instruction is not used.
	 */
	if (is_armv8_3_pauth_gpa_gpi_present()) {
		/* Program APGAKey_EL1 */
		plat_key = init_apkey();
		write_apgakeylo_el1((uint64_t)plat_key);
		write_apgakeyhi_el1((uint64_t)(plat_key >> 64));
		pauth_keys_before[4] = plat_key;
	}

	isb();
}

/*
 * Read ARMv8.3-PAuth keys and store them in
 * <pauth_keys_after> buffer
 */
static void read_pauth_keys(void)
{
	memset(pauth_keys_after, 0, NUM_KEYS * sizeof(uint128_t));

	if (is_armv8_3_pauth_apa_api_present()) {
		/* Read APIAKey_EL1 */
		pauth_keys_after[0] = read_apiakeylo_el1() |
			((uint128_t)(read_apiakeyhi_el1()) << 64);

		/* Read APIBKey_EL1 */
		pauth_keys_after[1] = read_apibkeylo_el1() |
			((uint128_t)(read_apibkeyhi_el1()) << 64);

		/* Read APDAKey_EL1 */
		pauth_keys_after[2] = read_apdakeylo_el1() |
			((uint128_t)(read_apdakeyhi_el1()) << 64);

		/* Read APDBKey_EL1 */
		pauth_keys_after[3] = read_apdbkeylo_el1() |
			((uint128_t)(read_apdbkeyhi_el1()) << 64);
	}

	if (is_armv8_3_pauth_gpa_gpi_present()) {
		/* Read APGAKey_EL1 */
		pauth_keys_after[4] = read_apgakeylo_el1() |
			((uint128_t)(read_apgakeyhi_el1()) << 64);
	}
}
#endif	/* __aarch64__ */

/*
 * 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();
#ifdef __aarch64__
	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
	read_pauth_keys();
	return TEST_RESULT_SUCCESS;
#endif	/* __aarch64__ */
}

/*
 * Makes a call to PSCI version, and checks that the EL3 pauth keys are not
 * leaked when it returns
 */
test_result_t test_pauth_leakage(void)
{
	SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
	set_store_pauth_keys();

	tftf_get_psci_version();

	read_pauth_keys();

	return compare_pauth_keys();
#endif	/* __aarch64__ */
}

/* Test execution of ARMv8.3-PAuth instructions */
test_result_t test_pauth_instructions(void)
{
	SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();

#if ARM_ARCH_AT_LEAST(8, 3)
	/* Pointer authentication instructions */
	__asm__ volatile (
		"paciasp\n"
		"autiasp\n"
		"paciasp\n"
		"xpaclri"
	);
	return TEST_RESULT_SUCCESS;
#else
	tftf_testcase_printf("Pointer Authentication instructions "
				"are not supported on ARMv%u.%u\n",
				ARM_ARCH_MAJOR, ARM_ARCH_MINOR);
	return TEST_RESULT_SKIPPED;
#endif	/* ARM_ARCH_AT_LEAST(8, 3) */

#endif	/* __aarch64__ */
}

/*
 * Makes a call to TSP ADD, and checks that the checks that the Secure World
 * pauth keys are not leaked
 */
test_result_t test_pauth_leakage_tsp(void)
{
	SKIP_TEST_IF_AARCH32();
#ifdef __aarch64__
	smc_args tsp_svc_params;
	smc_ret_values tsp_result = {0};

	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
	SKIP_TEST_IF_TSP_NOT_PRESENT();

	set_store_pauth_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();

	return compare_pauth_keys();
#endif	/* __aarch64__ */
}