1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  */
5 
6 #include <compiler.h>
7 #include <kernel/panic.h>
8 #include <kernel/pseudo_ta.h>
9 #include <kernel/tee_ta_manager.h>
10 #include <kernel/ts_manager.h>
11 #include <mm/core_memprot.h>
12 #include <pta_invoke_tests.h>
13 #include <string.h>
14 #include <tee_api_defines.h>
15 #include <tee_api_types.h>
16 #include <tee/cache.h>
17 #include <trace.h>
18 #include <types_ext.h>
19 
20 #include "misc.h"
21 
22 #define TA_NAME		"invoke_tests.pta"
23 
test_trace(uint32_t param_types __unused,TEE_Param params[TEE_NUM_PARAMS]__unused)24 static TEE_Result test_trace(uint32_t param_types __unused,
25 			TEE_Param params[TEE_NUM_PARAMS] __unused)
26 {
27 	IMSG("pseudo TA \"%s\" says \"Hello world !\"", TA_NAME);
28 
29 	return TEE_SUCCESS;
30 }
31 
test_v2p2v(void * va,size_t size)32 static int test_v2p2v(void *va, size_t size)
33 {
34 	struct ts_session *session = NULL;
35 	paddr_t p = 0;
36 	void *v = NULL;
37 
38 	if  (!va)
39 		return 0;
40 
41 	session = ts_get_current_session();
42 	p = virt_to_phys(va);
43 
44 	/* 0 is not a valid physical address */
45 	if (!p)
46 		return 1;
47 
48 	if (to_ta_session(session)->clnt_id.login == TEE_LOGIN_TRUSTED_APP) {
49 		v = phys_to_virt(p, MEM_AREA_TS_VASPACE, size);
50 	} else {
51 		v = phys_to_virt(p, MEM_AREA_NSEC_SHM, size);
52 		if (!v)
53 			v = phys_to_virt(p, MEM_AREA_SDP_MEM, size);
54 		if (!v)
55 			v = phys_to_virt(p, MEM_AREA_SHM_VASPACE, size);
56 	}
57 
58 	/*
59 	 * Return an error only the vaddr found mismatches input address.
60 	 * Finding a virtual address from a physical address cannot be painful
61 	 * in some case (i.e pager). Moreover this operation is more debug
62 	 * related. Thus do not report error if phys_to_virt failed
63 	 */
64 	if (v && va != v) {
65 		EMSG("Failed to p2v/v2p on caller TA memref arguments");
66 		EMSG("va %p -> pa 0x%" PRIxPA " -> va %p", va, p, v);
67 		return 1;
68 	}
69 
70 	return 0;
71 }
72 
73 /*
74  * Check PTA can be invoked with a memory reference on a NULL buffer
75  */
test_entry_memref_null(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])76 static TEE_Result test_entry_memref_null(uint32_t type,
77 					 TEE_Param p[TEE_NUM_PARAMS])
78 {
79 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
80 					  TEE_PARAM_TYPE_NONE,
81 					  TEE_PARAM_TYPE_NONE,
82 					  TEE_PARAM_TYPE_NONE);
83 
84 	if (exp_pt != type)
85 		return TEE_ERROR_BAD_PARAMETERS;
86 
87 	if (p[0].memref.buffer || p[0].memref.size)
88 		return TEE_ERROR_BAD_PARAMETERS;
89 
90 	return TEE_SUCCESS;
91 }
92 
93 /*
94  * Supported tests on parameters
95  * (I, J, K, L refer to param index)
96  *
97  * Case 1: command parameters type are: 1 in/out value, 3 empty.
98  *         => process outI.a = inI.a + inI.b
99  * Case 2: command parameters type are: 3 input value, 1 output value
100  *         => process = outI.a = inJ.a + inK.a + inL.a
101  * Case 3: command parameters type are: 1 in/out memref, 3 empty.
102  *         => process = outI[0] = sum(inI[0..len-1])
103  */
test_entry_params(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])104 static TEE_Result test_entry_params(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
105 {
106 	size_t i;
107 	uint8_t d8, *in;
108 
109 	/* case 1a: 1 input/output value argument */
110 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INOUT) &&
111 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
112 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
113 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
114 		p[0].value.a = p[0].value.a + p[0].value.b;
115 		return TEE_SUCCESS;
116 	}
117 	/* case 1b: 1 input/output value argument */
118 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
119 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INOUT) &&
120 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
121 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
122 		p[1].value.a = p[1].value.a + p[1].value.b;
123 		return TEE_SUCCESS;
124 	}
125 	/* case 1c: 1 input/output value argument */
126 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
127 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
128 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INOUT) &&
129 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
130 		p[2].value.a = p[2].value.a + p[2].value.b;
131 		return TEE_SUCCESS;
132 	}
133 	/* case 1d: 1 input/output value argument */
134 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
135 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
136 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
137 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INOUT)) {
138 		p[3].value.a = p[3].value.a + p[3].value.b;
139 		return TEE_SUCCESS;
140 	}
141 
142 	/* case 2a: 3 input value arguments, 1 output value argument */
143 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_OUTPUT) &&
144 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INPUT) &&
145 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INPUT) &&
146 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INPUT)) {
147 		p[0].value.a = p[1].value.a + p[2].value.a + p[3].value.a;
148 		p[0].value.b = p[1].value.b + p[2].value.b + p[3].value.b;
149 		return TEE_SUCCESS;
150 	}
151 	/* case 2a: 3 input value arguments, 1 output value argument */
152 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INPUT) &&
153 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_OUTPUT) &&
154 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INPUT) &&
155 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INPUT)) {
156 		p[1].value.a = p[0].value.a + p[2].value.a + p[3].value.a;
157 		p[1].value.b = p[0].value.b + p[2].value.b + p[3].value.b;
158 		return TEE_SUCCESS;
159 	}
160 	/* case 2a: 3 input value arguments, 1 output value argument */
161 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INPUT) &&
162 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INPUT) &&
163 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_OUTPUT) &&
164 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_INPUT)) {
165 		p[2].value.a = p[0].value.a + p[1].value.a + p[3].value.a;
166 		p[2].value.b = p[0].value.b + p[1].value.b + p[3].value.b;
167 		return TEE_SUCCESS;
168 	}
169 	/* case 2a: 3 input value arguments, 1 output value argument */
170 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_VALUE_INPUT) &&
171 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_VALUE_INPUT) &&
172 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_VALUE_INPUT) &&
173 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_VALUE_OUTPUT)) {
174 		p[3].value.a = p[0].value.a + p[1].value.a + p[2].value.a;
175 		p[3].value.b = p[0].value.b + p[1].value.b + p[2].value.b;
176 		return TEE_SUCCESS;
177 	}
178 
179 	DMSG("expect memref params: %p/%" PRIu32 " - %p/%" PRIu32 "zu - %p/%" PRIu32 "zu - %p/%" PRIu32 "zu",
180 			p[0].memref.buffer, p[0].memref.size,
181 			p[1].memref.buffer, p[1].memref.size,
182 			p[2].memref.buffer, p[2].memref.size,
183 			p[3].memref.buffer, p[3].memref.size);
184 
185 	/* case 3a: 1 in/out memref argument */
186 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_MEMREF_INOUT) &&
187 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
188 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
189 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
190 		in = (uint8_t *)p[0].memref.buffer;
191 		if (test_v2p2v(in, p[0].memref.size))
192 			return TEE_ERROR_SECURITY;
193 		d8 = 0;
194 		for (i = 0; i < p[0].memref.size; i++)
195 			d8 += in[i];
196 		*(uint8_t *)p[0].memref.buffer = d8;
197 		return TEE_SUCCESS;
198 	}
199 	/* case 3b: 1 in/out memref argument */
200 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
201 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_MEMREF_INOUT) &&
202 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
203 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
204 		in = (uint8_t *)p[1].memref.buffer;
205 		if (test_v2p2v(in, p[1].memref.size))
206 			return TEE_ERROR_SECURITY;
207 		d8 = 0;
208 		for (i = 0; i < p[1].memref.size; i++)
209 			d8 += in[i];
210 		*(uint8_t *)p[1].memref.buffer = d8;
211 		return TEE_SUCCESS;
212 	}
213 	/* case 3c: 1 in/out memref argument */
214 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
215 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
216 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_MEMREF_INOUT) &&
217 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_NONE)) {
218 		in = (uint8_t *)p[2].memref.buffer;
219 		if (test_v2p2v(in, p[2].memref.size))
220 			return TEE_ERROR_SECURITY;
221 		d8 = 0;
222 		for (i = 0; i < p[2].memref.size; i++)
223 			d8 += in[i];
224 		*(uint8_t *)p[2].memref.buffer = d8;
225 		return TEE_SUCCESS;
226 	}
227 	/* case 3d: 1 in/out memref argument */
228 	if ((TEE_PARAM_TYPE_GET(type, 0) == TEE_PARAM_TYPE_NONE) &&
229 		(TEE_PARAM_TYPE_GET(type, 1) == TEE_PARAM_TYPE_NONE) &&
230 		(TEE_PARAM_TYPE_GET(type, 2) == TEE_PARAM_TYPE_NONE) &&
231 		(TEE_PARAM_TYPE_GET(type, 3) == TEE_PARAM_TYPE_MEMREF_INOUT)) {
232 		in = (uint8_t *)p[3].memref.buffer;
233 		if (test_v2p2v(in, p[3].memref.size))
234 			return TEE_ERROR_SECURITY;
235 		d8 = 0;
236 		for (i = 0; i < p[3].memref.size; i++)
237 			d8 += in[i];
238 		*(uint8_t *)p[3].memref.buffer = d8;
239 		return TEE_SUCCESS;
240 	}
241 
242 	EMSG("unexpected parameters");
243 	return TEE_ERROR_BAD_PARAMETERS;
244 }
245 
246 /*
247  * Test access to Secure Data Path memory from pseudo TAs
248  */
249 
test_inject_sdp(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])250 static TEE_Result test_inject_sdp(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
251 {
252 	char *src = p[0].memref.buffer;
253 	char *dst = p[1].memref.buffer;
254 	size_t sz = p[0].memref.size;
255 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
256 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
257 					  TEE_PARAM_TYPE_NONE,
258 					  TEE_PARAM_TYPE_NONE);
259 
260 	if (exp_pt != type) {
261 		DMSG("bad parameter types");
262 		return TEE_ERROR_BAD_PARAMETERS;
263 	}
264 
265 	if (p[1].memref.size < sz) {
266 		p[1].memref.size = sz;
267 		return TEE_ERROR_SHORT_BUFFER;
268 	}
269 
270 	if (!core_vbuf_is(CORE_MEM_NON_SEC, src, sz) ||
271 	    !core_vbuf_is(CORE_MEM_SDP_MEM, dst, sz)) {
272 		DMSG("bad memref secure attribute");
273 		return TEE_ERROR_BAD_PARAMETERS;
274 	}
275 
276 	if (!sz)
277 		return TEE_SUCCESS;
278 
279 	/* Check that core can p2v and v2p over memory reference arguments */
280 	if (test_v2p2v(src, sz) || test_v2p2v(dst, sz))
281 		return TEE_ERROR_SECURITY;
282 
283 	if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
284 		return TEE_ERROR_GENERIC;
285 
286 	memcpy(dst, src, sz);
287 
288 	if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
289 		return TEE_ERROR_GENERIC;
290 
291 	return TEE_SUCCESS;
292 }
293 
test_transform_sdp(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])294 static TEE_Result test_transform_sdp(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
295 {
296 	char *buf = p[0].memref.buffer;
297 	size_t sz = p[0].memref.size;
298 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
299 					  TEE_PARAM_TYPE_NONE,
300 					  TEE_PARAM_TYPE_NONE,
301 					  TEE_PARAM_TYPE_NONE);
302 
303 	if (exp_pt != type) {
304 		DMSG("bad parameter types");
305 		return TEE_ERROR_BAD_PARAMETERS;
306 	}
307 
308 	if (!core_vbuf_is(CORE_MEM_SDP_MEM, buf, sz)) {
309 		DMSG("bad memref secure attribute");
310 		return TEE_ERROR_BAD_PARAMETERS;
311 	}
312 
313 	if (!sz)
314 		return TEE_SUCCESS;
315 
316 	/* Check that core can p2v and v2p over memory reference arguments */
317 	if (test_v2p2v(buf, sz))
318 		return TEE_ERROR_SECURITY;
319 
320 	if (cache_operation(TEE_CACHEFLUSH, buf, sz) != TEE_SUCCESS)
321 		return TEE_ERROR_GENERIC;
322 
323 	for (; sz; sz--, buf++)
324 		*buf = ~(*buf) + 1;
325 
326 	if (cache_operation(TEE_CACHEFLUSH, buf, sz) != TEE_SUCCESS)
327 		return TEE_ERROR_GENERIC;
328 
329 	return TEE_SUCCESS;
330 }
331 
test_dump_sdp(uint32_t type,TEE_Param p[TEE_NUM_PARAMS])332 static TEE_Result test_dump_sdp(uint32_t type, TEE_Param p[TEE_NUM_PARAMS])
333 {
334 	char *src = p[0].memref.buffer;
335 	char *dst = p[1].memref.buffer;
336 	size_t sz = p[0].memref.size;
337 	uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
338 					  TEE_PARAM_TYPE_MEMREF_OUTPUT,
339 					  TEE_PARAM_TYPE_NONE,
340 					  TEE_PARAM_TYPE_NONE);
341 
342 	if (exp_pt != type) {
343 		DMSG("bad parameter types");
344 		return TEE_ERROR_BAD_PARAMETERS;
345 	}
346 
347 	if (p[1].memref.size < sz) {
348 		p[1].memref.size = sz;
349 		return TEE_ERROR_SHORT_BUFFER;
350 	}
351 
352 	if (!core_vbuf_is(CORE_MEM_SDP_MEM, src, sz) ||
353 	    !core_vbuf_is(CORE_MEM_NON_SEC, dst, sz)) {
354 		DMSG("bad memref secure attribute");
355 		return TEE_ERROR_BAD_PARAMETERS;
356 	}
357 
358 	if (!sz)
359 		return TEE_SUCCESS;
360 
361 	/* Check that core can p2v and v2p over memory reference arguments */
362 	if (test_v2p2v(src, sz) || test_v2p2v(dst, sz))
363 		return TEE_ERROR_SECURITY;
364 
365 	if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
366 		return TEE_ERROR_GENERIC;
367 
368 	memcpy(dst, src, sz);
369 
370 	if (cache_operation(TEE_CACHEFLUSH, dst, sz) != TEE_SUCCESS)
371 		return TEE_ERROR_GENERIC;
372 
373 	return TEE_SUCCESS;
374 }
375 
376 /*
377  * Trusted Application Entry Points
378  */
379 
create_ta(void)380 static TEE_Result create_ta(void)
381 {
382 	DMSG("create entry point for pseudo TA \"%s\"", TA_NAME);
383 	return TEE_SUCCESS;
384 }
385 
destroy_ta(void)386 static void destroy_ta(void)
387 {
388 	DMSG("destroy entry point for pseudo ta \"%s\"", TA_NAME);
389 }
390 
open_session(uint32_t nParamTypes __unused,TEE_Param pParams[TEE_NUM_PARAMS]__unused,void ** ppSessionContext __unused)391 static TEE_Result open_session(uint32_t nParamTypes __unused,
392 		TEE_Param pParams[TEE_NUM_PARAMS] __unused,
393 		void **ppSessionContext __unused)
394 {
395 	DMSG("open entry point for pseudo ta \"%s\"", TA_NAME);
396 	return TEE_SUCCESS;
397 }
398 
close_session(void * pSessionContext __unused)399 static void close_session(void *pSessionContext __unused)
400 {
401 	DMSG("close entry point for pseudo ta \"%s\"", TA_NAME);
402 }
403 
invoke_command(void * pSessionContext __unused,uint32_t nCommandID,uint32_t nParamTypes,TEE_Param pParams[TEE_NUM_PARAMS])404 static TEE_Result invoke_command(void *pSessionContext __unused,
405 		uint32_t nCommandID, uint32_t nParamTypes,
406 		TEE_Param pParams[TEE_NUM_PARAMS])
407 {
408 	FMSG("command entry point for pseudo ta \"%s\"", TA_NAME);
409 
410 	switch (nCommandID) {
411 	case PTA_INVOKE_TESTS_CMD_TRACE:
412 		return test_trace(nParamTypes, pParams);
413 	case PTA_INVOKE_TESTS_CMD_PARAMS:
414 		return test_entry_params(nParamTypes, pParams);
415 	case PTA_INVOKE_TESTS_CMD_MEMREF_NULL:
416 		return test_entry_memref_null(nParamTypes, pParams);
417 	case PTA_INVOKE_TESTS_CMD_COPY_NSEC_TO_SEC:
418 		return test_inject_sdp(nParamTypes, pParams);
419 	case PTA_INVOKE_TESTS_CMD_READ_MODIFY_SEC:
420 		return test_transform_sdp(nParamTypes, pParams);
421 	case PTA_INVOKE_TESTS_CMD_COPY_SEC_TO_NSEC:
422 		return test_dump_sdp(nParamTypes, pParams);
423 	case PTA_INVOKE_TESTS_CMD_SELF_TESTS:
424 		return core_self_tests(nParamTypes, pParams);
425 #if defined(CFG_REE_FS) && defined(CFG_WITH_USER_TA)
426 	case PTA_INVOKE_TESTS_CMD_FS_HTREE:
427 		return core_fs_htree_tests(nParamTypes, pParams);
428 #endif
429 	case PTA_INVOKE_TESTS_CMD_MUTEX:
430 		return core_mutex_tests(nParamTypes, pParams);
431 	case PTA_INVOKE_TESTS_CMD_LOCKDEP:
432 		return core_lockdep_tests(nParamTypes, pParams);
433 	case PTA_INVOKE_TEST_CMD_AES_PERF:
434 		return core_aes_perf_tests(nParamTypes, pParams);
435 	case PTA_INVOKE_TESTS_CMD_DT_DRIVER_TESTS:
436 		return core_dt_driver_tests(nParamTypes, pParams);
437 	default:
438 		break;
439 	}
440 	return TEE_ERROR_BAD_PARAMETERS;
441 }
442 
443 pseudo_ta_register(.uuid = PTA_INVOKE_TESTS_UUID, .name = TA_NAME,
444 		   .flags = PTA_DEFAULT_FLAGS | TA_FLAG_SECURE_DATA_PATH |
445 			    TA_FLAG_CONCURRENT | TA_FLAG_DEVICE_ENUM,
446 		   .create_entry_point = create_ta,
447 		   .destroy_entry_point = destroy_ta,
448 		   .open_session_entry_point = open_session,
449 		   .close_session_entry_point = close_session,
450 		   .invoke_command_entry_point = invoke_command);
451