xref: /OK3568_Linux_fs/external/security/rk_tee_user/v2/host/xtest/sdp_basic.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  * All rights reserved.
5  */
6 
7 #include <err.h>
8 #include <fcntl.h>
9 #include <pta_invoke_tests.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/ioctl.h>
14 #include <sys/mman.h>
15 #include <tee_client_api.h>
16 #include <tee_client_api_extensions.h>
17 #include <unistd.h>
18 
19 #include "crypto_common.h"
20 #include "sdp_basic.h"
21 #include "xtest_helpers.h"
22 #include "xtest_test.h"
23 
24 #include "include/uapi/linux/ion_old.h"
25 
26 /*
27  * SDP basic test setup overview.
28  *
29  * - A dedicated trusted application (SDP basic TA) supports 3 commands:
30  *   - 'inject' data from a nonsecure buffer into a secure buffer
31  *   - 'transform' data inside a secure buffer (bitwise invert + unsigned incr)
32  *   - 'dump' data from a secure buffer into a nonsecure buffer
33 
34  * - This test client application (CA) invokes the TA for these 3 operations,
35  *   inject random value, trasforming them then dump them.
36  *
37  * To do so, CA allocates a 'SDP secure buffer' and invoke the TA for these 3
38  * operations (inject then transform then dump) over the allocate buffer.
39  *
40  * The secure buffer is currently allocation through ION support adn
41  * registered to OP-TEE and as shared memory.
42  *
43  * To enhance test coverage against buffer alignement usecase, the CA invokes
44  * the TA with a variable offset inside the buffer. As CA injects random data
45  * into the buffer, the CA uses one of the random bytes to set the value of the
46  * offset in the accessed secure buffer.
47  *
48  * For debugging support, the CA may map (in nonsecure world) the secure
49  * buffer to read its content. As this is unsafe on a hardened platform, this
50  * operation is default disable. When enable, error only print out a warning
51  * trace but does not actually fail the test. This also give an easy way to
52  * check that some HW complains on access violation when nonsecure accesses
53  * secure data.
54  */
55 
56 struct tee_ctx {
57 	TEEC_Context ctx;
58 	TEEC_Session sess;
59 };
60 
61 /*
62  * Old ION API to allocate and export a buffer
63  */
allocate_ion_buffer_old_api(size_t size,int heap_type_id,int ion)64 static int allocate_ion_buffer_old_api(size_t size, int heap_type_id, int ion)
65 {
66 	struct ion0_allocation_data alloc_data = { };
67 	struct ion0_handle_data hdl_data = { };
68 	struct ion0_fd_data fd_data = { };
69 	int fd = -1;
70 
71 	alloc_data.len = size;
72 	alloc_data.align = 0;
73 	alloc_data.flags = 0;
74 	alloc_data.heap_id_mask = 1 << heap_type_id;
75 	if (ioctl(ion, ION0_IOC_ALLOC, &alloc_data) == -1) {
76 		fprintf(stderr, "Error: old ION allocate API failed\n");
77 		return fd;
78 	}
79 
80 	fd_data.handle = alloc_data.handle;
81 	if (ioctl(ion, ION0_IOC_SHARE, &fd_data) != -1)
82 		fd = fd_data.fd;
83 	else
84 		fprintf(stderr, "Error: old ION share API failed\n");
85 
86 	hdl_data.handle = alloc_data.handle;
87 	(void)ioctl(ion, ION0_IOC_FREE, &hdl_data);
88 
89 	return fd;
90 }
91 
allocate_ion_buffer(size_t size,int heap_type_id,int verbosity)92 int allocate_ion_buffer(size_t size, int heap_type_id, int verbosity)
93 {
94 	struct ion_heap_query query_data = { };
95 	struct ion_heap_data heap_data[32] = { };
96 	struct ion_allocation_data alloc_data = { };
97 	int ion = 0;
98 	int fd = -1;
99 	unsigned int idx = 0;
100 
101 	ion = open("/dev/ion", O_RDWR);
102 	if (ion < 0) {
103 		fprintf(stderr, "Error: failed to open /dev/ion\n");
104 		verbose("Seems no ION heap is available.\n");
105 		verbose("To test ION allocation you can enable\n");
106 		verbose("CONFIG_ION and CONFIG_ION_DUMMY in your\n");
107 		verbose("linux kernel configuration.\n");
108 		return fd;
109 	}
110 
111 	if (heap_type_id < 0)
112 		heap_type_id = DEFAULT_ION_HEAP_TYPE;
113 
114 	if (ioctl(ion, ION_IOC_HEAP_QUERY, &query_data) < 0) {
115 		fprintf(stderr, "Error: failed to query the number of heaps\n");
116 		goto out;
117 	}
118 
119 	query_data.heaps = (__u64)(unsigned long)&heap_data;
120 	if (ioctl(ion, ION_IOC_HEAP_QUERY, &query_data) < 0) {
121 		fprintf(stderr, "Info: can't query heaps data, try old API\n");
122 		fd = allocate_ion_buffer_old_api(size, heap_type_id, ion);
123 		goto out;
124 	}
125 
126 	for (idx = 0; idx < query_data.cnt; idx++)
127 		if (heap_data[idx].type == (unsigned int)heap_type_id)
128 			break;
129 	if (idx == query_data.cnt) {
130 		fprintf(stderr, "Error: target heap type %d not found\n",
131 				heap_type_id);
132 		goto out;
133 	}
134 
135 	verbose("Allocate in ION heap '%s' (type=%u, id=%u)\n",
136 		heap_data[idx].name, heap_data[idx].type,
137 		heap_data[idx].heap_id);
138 
139 	alloc_data.len = size;
140 	alloc_data.flags = 0;
141 	alloc_data.heap_id_mask = 1 << heap_data[idx].heap_id;
142 	if (ioctl(ion, ION_IOC_ALLOC, &alloc_data) < 0) {
143 		fprintf(stderr, "Error: failed to allocate in target heap\n");
144 		goto out;
145 	}
146 
147 	fd = alloc_data.fd;
148 out:
149 	close(ion);
150 	return fd;
151 }
152 
finalize_tee_ctx(struct tee_ctx * ctx)153 static void finalize_tee_ctx(struct tee_ctx *ctx)
154 {
155 	if (!ctx)
156 		return;
157 
158 	TEEC_CloseSession(&ctx->sess);
159 	TEEC_FinalizeContext(&ctx->ctx);
160 }
161 
create_tee_ctx(struct tee_ctx * ctx,enum test_target_ta target_ta)162 static int create_tee_ctx(struct tee_ctx *ctx, enum test_target_ta target_ta)
163 {
164 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
165 	const TEEC_UUID *uuid = NULL;
166 	uint32_t err_origin = 0;
167 
168 	switch (target_ta) {
169 	case TEST_NS_TO_TA:
170 	case TEST_TA_TO_TA:
171 	case TEST_TA_TO_PTA:
172 		uuid = &sdp_basic_ta_uuid;
173 		break;
174 	case TEST_NS_TO_PTA:
175 		uuid = &pta_invoke_tests_ta_uuid;
176 		break;
177 	default:
178 		return -1;
179 	}
180 
181 	teerc = TEEC_InitializeContext(NULL, &ctx->ctx);
182 	if (teerc != TEEC_SUCCESS)
183 		return -1;
184 
185 	teerc = TEEC_OpenSession(&ctx->ctx, &ctx->sess, uuid,
186 			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
187 	if (teerc != TEEC_SUCCESS) {
188 		fprintf(stderr, "Error: open session to target test %s failed %x %d\n",
189 			(target_ta == TEST_NS_TO_PTA) ? "pTA" : "TA",
190 			teerc, err_origin);
191 
192 		TEEC_FinalizeContext(&ctx->ctx);
193 	}
194 	return (teerc == TEEC_SUCCESS) ? 0 : -1;
195 }
196 
tee_register_buffer(struct tee_ctx * ctx,void ** shm_ref,int fd)197 static int tee_register_buffer(struct tee_ctx *ctx, void **shm_ref, int fd)
198 {
199 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
200 	TEEC_SharedMemory *shm = malloc(sizeof(*shm));
201 
202 	if (!shm)
203 		return 1;
204 
205 	shm->flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
206 	teerc = TEEC_RegisterSharedMemoryFileDescriptor(&ctx->ctx, shm, fd);
207 	if (teerc != TEEC_SUCCESS) {
208 		fprintf(stderr, "Error: TEEC_RegisterMemoryFileDescriptor() failed %x\n",
209 			teerc);
210 		return 1;
211 	}
212 
213 	*shm_ref = shm;
214 	return 0;
215 }
216 
tee_deregister_buffer(struct tee_ctx * ctx,void * shm_ref)217 static void tee_deregister_buffer(struct tee_ctx *ctx, void *shm_ref)
218 {
219 	(void)ctx;
220 
221 	if (!shm_ref)
222 		return;
223 
224 	TEEC_ReleaseSharedMemory((TEEC_SharedMemory *)shm_ref);
225 	free(shm_ref);
226 }
227 
inject_sdp_data(struct tee_ctx * ctx,void * in,size_t offset,size_t len,void * shm_ref,int ind)228 static int inject_sdp_data(struct tee_ctx *ctx,
229 		    void *in, size_t offset, size_t len, void *shm_ref, int ind)
230 {
231 	TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
232 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
233 	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
234 	uint32_t err_origin = 0;
235 	unsigned int cmd = 0;
236 
237 	switch (ind) {
238 	case TEST_NS_TO_TA:
239 		cmd = TA_SDP_BASIC_CMD_INJECT;
240 		break;
241 	case TEST_TA_TO_TA:
242 		cmd = TA_SDP_BASIC_CMD_INVOKE_INJECT;
243 		break;
244 	case TEST_TA_TO_PTA:
245 		cmd = TA_SDP_BASIC_CMD_PTA_INJECT;
246 		break;
247 	case TEST_NS_TO_PTA:
248 		cmd = PTA_INVOKE_TESTS_CMD_COPY_NSEC_TO_SEC;
249 		break;
250 	default:
251 		return -1;
252 	}
253 
254 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
255 					 TEEC_MEMREF_PARTIAL_OUTPUT,
256 					 TEEC_NONE, TEEC_NONE);
257 
258 	op.params[0].tmpref.buffer = in;
259 	op.params[0].tmpref.size = len;
260 
261 	op.params[1].memref.parent = shm;
262 	op.params[1].memref.size = len;
263 	op.params[1].memref.offset = offset;
264 
265 	teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
266 	if (teerc != TEEC_SUCCESS)
267 		fprintf(stderr, "Error: invoke SDP test TA (inject) failed %x %d\n",
268 			teerc, err_origin);
269 
270 	return (teerc == TEEC_SUCCESS) ? 0 : -1;
271 }
272 
transform_sdp_data(struct tee_ctx * ctx,size_t offset,size_t len,void * shm_ref,int ind)273 static int transform_sdp_data(struct tee_ctx *ctx,
274 			size_t offset, size_t len, void *shm_ref, int ind)
275 {
276 	TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
277 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
278 	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
279 	uint32_t err_origin = 0;
280 	unsigned int cmd = 0;
281 
282 	switch (ind) {
283 	case TEST_NS_TO_TA:
284 		cmd = TA_SDP_BASIC_CMD_TRANSFORM;
285 		break;
286 	case TEST_TA_TO_TA:
287 		cmd = TA_SDP_BASIC_CMD_INVOKE_TRANSFORM;
288 		break;
289 	case TEST_TA_TO_PTA:
290 		cmd = TA_SDP_BASIC_CMD_PTA_TRANSFORM;
291 		break;
292 	case TEST_NS_TO_PTA:
293 		cmd = PTA_INVOKE_TESTS_CMD_READ_MODIFY_SEC;
294 		break;
295 	default:
296 		return -1;
297 	}
298 
299 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INOUT,
300 					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
301 	op.params[0].memref.parent = shm;
302 	op.params[0].memref.size = len;
303 	op.params[0].memref.offset = offset;
304 
305 	teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
306 	if (teerc != TEEC_SUCCESS)
307 		fprintf(stderr, "Error: invoke SDP test TA (transform) failed %x %d\n",
308 			teerc, err_origin);
309 
310 	return (teerc == TEEC_SUCCESS) ? 0 : -1;
311 }
312 
dump_sdp_data(struct tee_ctx * ctx,void * out,size_t offset,size_t len,void * shm_ref,int ind)313 static int dump_sdp_data(struct tee_ctx *ctx,
314 		  void *out, size_t offset, size_t len, void *shm_ref, int ind)
315 {
316 	TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
317 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
318 	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
319 	uint32_t err_origin = 0;
320 	unsigned int cmd = 0;
321 
322 	switch (ind) {
323 	case TEST_NS_TO_TA:
324 		cmd = TA_SDP_BASIC_CMD_DUMP;
325 		break;
326 	case TEST_TA_TO_TA:
327 		cmd = TA_SDP_BASIC_CMD_INVOKE_DUMP;
328 		break;
329 	case TEST_TA_TO_PTA:
330 		cmd = TA_SDP_BASIC_CMD_PTA_DUMP;
331 		break;
332 	case TEST_NS_TO_PTA:
333 		cmd = PTA_INVOKE_TESTS_CMD_COPY_SEC_TO_NSEC;
334 		break;
335 	default:
336 		return -1;
337 	}
338 
339 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INPUT,
340 					 TEEC_MEMREF_TEMP_OUTPUT,
341 					 TEEC_NONE, TEEC_NONE);
342 	op.params[0].memref.parent = shm;
343 	op.params[0].memref.size = len;
344 	op.params[0].memref.offset = offset;
345 
346 	op.params[1].tmpref.buffer = out;
347 	op.params[1].tmpref.size = len;
348 
349 	teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
350 	if (teerc != TEEC_SUCCESS)
351 		fprintf(stderr, "Error: invoke SDP test TA (dump) failed %x %d\n",
352 			teerc, err_origin);
353 
354 	return (teerc == TEEC_SUCCESS) ? 0 : -1;
355 }
356 
check_sdp_dumped(struct tee_ctx * ctx,void * ref,size_t len,void * out)357 static int check_sdp_dumped(struct tee_ctx *ctx, void *ref, size_t len,
358 								void *out)
359 {
360 	char *bref = (char *)ref;
361 	char *data = (char *)out;
362 	int err = 0;
363 
364 	(void)ctx;
365 
366 	while(len--)
367 		if (*data++ != (unsigned char)(~(*bref++) + 1))
368 			err++;
369 
370 	return err;
371 }
372 
373 /*
374  * Consider 32kByte + 1 of random data is sufficient for an accurate test
375  * whatever the test buffer size is. Random buffer is read as a ring buffer.
376  */
377 #define RANDOM_BUFFER_SIZE	(32 * 1024 + 1)
get_random_bytes(char * out,size_t len)378 static int get_random_bytes(char *out, size_t len)
379 {
380 	static char *rand_buf = NULL;
381 	static size_t rand_idx = 0;
382 	int rc = 0;
383 
384 	if (!rand_buf) {
385 		const char rand_dev[] = "/dev/urandom";
386 		int fd = 0;
387 
388 		rand_buf = malloc(RANDOM_BUFFER_SIZE);
389 		if (!rand_buf) {
390 			fprintf(stderr, "failed to random buffer memory (%d bytes)\n",
391 				RANDOM_BUFFER_SIZE);
392 			return -1;
393 		}
394 
395 		fd = open(rand_dev, O_RDONLY);
396 		if (fd < 0) {
397 			fprintf(stderr, "failed to open %s\n", rand_dev);
398 			return -1;
399 		}
400 
401 		rc = read(fd, rand_buf, RANDOM_BUFFER_SIZE);
402 		if (rc != RANDOM_BUFFER_SIZE) {
403 			fprintf(stderr, "failed to read %d bytes from %s\n",
404 				RANDOM_BUFFER_SIZE, rand_dev);
405 			return -1;
406 		}
407 		close(fd);
408 	}
409 
410 	while (len) {
411 		size_t t_len = (RANDOM_BUFFER_SIZE < len) ? RANDOM_BUFFER_SIZE : len;
412 
413 		if ((rand_idx + t_len) > RANDOM_BUFFER_SIZE) {
414 			int sz_end = RANDOM_BUFFER_SIZE - rand_idx;
415 			int sz_beg = t_len - sz_end;
416 
417 			memcpy(out, rand_buf + rand_idx, sz_end);
418 			memcpy(out + sz_end, rand_buf , sz_beg);
419 			rand_idx = sz_beg;
420 		} else {
421 			memcpy(out, rand_buf + rand_idx, t_len);
422 			rand_idx += t_len;
423 		}
424 		len -= t_len;
425 	}
426 	return 0;
427 }
428 
429 
sdp_basic_test(enum test_target_ta ta,size_t size,size_t loop,int ion_heap,int rnd_offset,int verbosity)430 int sdp_basic_test(enum test_target_ta ta, size_t size, size_t loop,
431 		   int ion_heap, int rnd_offset, int verbosity)
432 {
433 	struct tee_ctx *ctx = NULL;
434 	unsigned char *test_buf = NULL;
435 	unsigned char *ref_buf = NULL;
436 	void *shm_ref = NULL;
437 	unsigned int err = 1;
438 	int fd = -1;
439 	size_t sdp_size = size;
440 	size_t offset = 0;
441 	size_t loop_cnt = 0;
442 
443 	if (!loop) {
444 		fprintf(stderr, "Error: null loop value\n");
445 		return 1;
446 	}
447 
448 	/* reduce size to enable offset tests (max offset is 255 bytes) */
449 	if (rnd_offset)
450 		size -= 255;
451 
452 	test_buf = malloc(size);
453 	ref_buf = malloc(size);
454 	if (!test_buf || !ref_buf) {
455 		verbose("failed to allocate memory\n");
456 		goto bail1;
457 	}
458 
459 	fd = allocate_ion_buffer(sdp_size, ion_heap, verbosity);
460 	if (fd < 0) {
461 		verbose("Failed to allocate SDP buffer (%zu bytes) in ION heap %d: %d\n",
462 				sdp_size, ion_heap, fd);
463 		goto bail1;
464 	}
465 
466 	/* register secure buffer to TEE */
467 	ctx = malloc(sizeof(*ctx));
468 	if (!ctx)
469 		goto bail1;
470 	if (create_tee_ctx(ctx, ta))
471 		goto bail1;
472 	if (tee_register_buffer(ctx, &shm_ref, fd))
473 		goto bail2;
474 
475 	/* release registered fd: tee should still hold refcount on resource */
476 	close(fd);
477 	fd = -1;
478 
479 	/* invoke trusted application with secure buffer as memref parameter */
480 	for (loop_cnt = loop; loop_cnt; loop_cnt--) {
481 		/* get an buffer of random-like values */
482 		if (get_random_bytes((char *)ref_buf, size))
483 			goto bail2;
484 		memcpy(test_buf, ref_buf, size);
485 		/* random offset [0 255] */
486 		offset = (unsigned int)*ref_buf;
487 
488 		/* TA writes into SDP buffer */
489 		if (inject_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
490 			goto bail2;
491 
492 		/* TA reads/writes into SDP buffer */
493 		if (transform_sdp_data(ctx, offset, size, shm_ref, ta))
494 			goto bail2;
495 
496 		/* TA reads into SDP buffer */
497 		if (dump_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
498 			goto bail2;
499 
500 		/* check dumped data are the expected ones */
501 		if (check_sdp_dumped(ctx, ref_buf, size, test_buf)) {
502 			fprintf(stderr, "check SDP data: %d errors\n", err);
503 			goto bail2;
504 		}
505 	}
506 
507 	err = 0;
508 bail2:
509 	if (fd >= 0)
510 		close(fd);
511 	if (shm_ref)
512 		tee_deregister_buffer(ctx, shm_ref);
513 	finalize_tee_ctx(ctx);
514 bail1:
515 	free(ctx);
516 	free(ref_buf);
517 	free(test_buf);
518 	return err;
519 }
520 
invoke_out_of_bounds(struct tee_ctx * ctx,TEEC_SharedMemory * in,TEEC_SharedMemory * out,size_t offset,size_t size,bool valid_ref,int verbosity)521 static int invoke_out_of_bounds(struct tee_ctx *ctx,
522 				TEEC_SharedMemory *in, TEEC_SharedMemory *out,
523 				size_t offset, size_t size,
524 				bool valid_ref, int verbosity)
525 {
526 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
527 	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
528 	uint32_t orig = 0;
529 
530 	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INPUT,
531 					 TEEC_MEMREF_PARTIAL_OUTPUT,
532 					 TEEC_NONE, TEEC_NONE);
533 
534 	op.params[0].memref.parent = in;
535 	op.params[0].memref.offset = 0;
536 	op.params[0].memref.size = size;
537 
538 	op.params[1].memref.parent = out;
539 	op.params[1].memref.offset = offset;
540 	op.params[1].memref.size = size;
541 
542 	teerc = TEEC_InvokeCommand(&ctx->sess, TA_SDP_BASIC_CMD_INJECT,
543 				   &op, &orig);
544 
545 	/*
546 	 * Invocation with invalid references should be nicely rejected by
547 	 * the TEE.
548 	 * Invocation with valid references should reach the TA, whatever
549 	 * result is.
550 	 */
551 	if ((valid_ref && orig != TEEC_ORIGIN_TRUSTED_APP) ||
552 	    (!valid_ref && ((orig == TEEC_ORIGIN_TRUSTED_APP) ||
553 			    (teerc != TEEC_ERROR_GENERIC &&
554 			     teerc != TEEC_ERROR_BAD_PARAMETERS))))
555 		goto error;
556 
557 	verbose("Out of bounds memref test successful:\n");
558 	verbose("Shm size 0x%zx, offset 0x%zx/size 0x%zx: %s/0x%x from %s\n",
559 		out->size, offset, size,
560 		Do_ADBG_GetEnumName(teerc, ADBG_EnumTable_TEEC_Result), teerc,
561 		Do_ADBG_GetEnumName(orig, ADBG_EnumTable_TEEC_ErrorOrigin));
562 	return 0;
563 
564 error:
565 	fprintf(stderr, "Out of bounds memref test FAILURE:\n");
566 	fprintf(stderr,
567 		"Shm size 0x%zx, offset 0x%zx/size 0x%zx: %s/0x%x from %s\n",
568 		out->size, offset, size,
569 		Do_ADBG_GetEnumName(teerc, ADBG_EnumTable_TEEC_Result),	teerc,
570 		Do_ADBG_GetEnumName(orig, ADBG_EnumTable_TEEC_ErrorOrigin));
571 	return 1;
572 }
573 
sdp_out_of_bounds_memref_test(size_t size,int ion_heap,int verbosity)574 int sdp_out_of_bounds_memref_test(size_t size, int ion_heap, int verbosity)
575 {
576 	struct tee_ctx ctx = { };
577 	int err = 0;
578 	int fd = -1;
579 	TEEC_Result teerc = TEEC_ERROR_GENERIC;
580 	TEEC_SharedMemory in = { };
581 	TEEC_SharedMemory *out = NULL;
582 
583 	if (create_tee_ctx(&ctx, TEST_NS_TO_TA))
584 		return -1;
585 
586 	fd = allocate_ion_buffer(size, ion_heap, verbosity);
587 	if (fd < 0) {
588 		verbose("SDP alloc failed (%zu bytes) in ION heap %d: %d\n",
589 			size, ion_heap, fd);
590 		err = 1;
591 		goto bail;
592 	}
593 	if (tee_register_buffer(&ctx, (void **)&out, fd)) {
594 		err = 1;
595 		goto bail;
596 	}
597 
598 	/*
599 	 * The ION driver will decide how much SDP memory is being allocated.
600 	 * Rely on this size to test out of bounds reference cases.
601 	 */
602 	size = out->size;
603 
604 	in.size = size;
605 	in.flags = TEEC_MEM_INPUT;
606 	teerc = TEEC_AllocateSharedMemory(&ctx.ctx, &in);
607 	if (teerc) {
608 		verbose("failed to allocate memory\n");
609 		goto bail;
610 	}
611 
612 	if (verbosity) {
613 		/* Valid case: reference inside allocated buffer: last byte */
614 		err += invoke_out_of_bounds(&ctx, &in, out, size - 1, 1,
615 					    true, verbosity);
616 	}
617 
618 	/* Reference overflows allocated buffer by 1 byte */
619 	err += invoke_out_of_bounds(&ctx, &in, out, size - 1, 2,
620 				    false, verbosity);
621 
622 	/* Reference oveflows allocated buffer by more than 4kB byte */
623 	err += invoke_out_of_bounds(&ctx, &in, out, size - 1, 5000,
624 				    false, verbosity);
625 
626 	/* Offset exceeds allocated buffer size value by 1 byte */
627 	err += invoke_out_of_bounds(&ctx, &in, out, size, 1,
628 				    false, verbosity);
629 
630 	/* Offset exceeds allocated size value by 4kByte */
631 	err += invoke_out_of_bounds(&ctx, &in, out, size, 4096,
632 				    false, verbosity);
633 
634 	/* Offset + size overflows offset value */
635 	err += invoke_out_of_bounds(&ctx, &in, out, 2, ~0,
636 				    false, verbosity);
637 
638 	TEEC_ReleaseSharedMemory(&in);
639 bail:
640 	tee_deregister_buffer(&ctx, out);
641 	if (fd >= 0)
642 		close(fd);
643 	finalize_tee_ctx(&ctx);
644 
645 	return err;
646 }
647 
648 #define _TO_STR(x) #x
649 #define TO_STR(x) _TO_STR(x)
650 
usage(const char * progname,size_t size,int loop,int ion_heap)651 static void usage(const char *progname, size_t size, int loop, int ion_heap)
652 {
653 	fprintf(stderr, "Usage: %s [OPTION]\n", progname);
654 	fprintf(stderr,
655 		"Testing basic accesses to secure buffer (SDP) on OP-TEE.\n"
656 		"Allocates a secure buffer and invoke a TA to access it.\n"
657 		"TA is used to init/transform/dump the secure buffer.\n"
658 		"CA check dumped content.\n\n");
659 
660 	fprintf(stderr, "Options:\n");
661 	fprintf(stderr, " -h|--help      Print this help and exit\n");
662 	fprintf(stderr, " -v             Be verbose\n");
663 	fprintf(stderr, " -s SIZE        SDP buffer byte size [%zu]\n", size);
664 	fprintf(stderr, " -n LOOP        Test loop iterations [%u]\n", loop);
665 	fprintf(stderr, " --ion-heap ID  Target ION heap ID [%d]\n", ion_heap);
666 	fprintf(stderr, " --no-offset    No random offset [0 255] in buffer\n");
667 }
668 
669 #define NEXT_ARG(i) \
670 	do { \
671 		if (++i == argc) { \
672 			fprintf(stderr, "%s: %s: missing argument\n", \
673 				argv[0], argv[i-1]); \
674 			return 1; \
675 		} \
676 	} while (0);
677 
678 #define CHECK_RESULT(_res, _exp, _action) \
679 	if ((_res) == (_exp)) { \
680 		verbose("Test passed\n"); \
681 	} else { \
682 		verbose("Test failed!\n"); \
683 		_action; \
684 	}
685 
sdp_basic_runner_cmd_parser(int argc,char * argv[])686 int sdp_basic_runner_cmd_parser(int argc, char *argv[])
687 {
688 	size_t test_size = 5000;
689 	size_t test_loop = 1000;
690 	int ion_heap = DEFAULT_ION_HEAP_TYPE;
691 	int rnd_offset = 1;
692 	int verbosity = 1;
693 	int err = 0;
694 	int i = 0;
695 
696 	/* Parse command line */
697 	for (i = 1; i < argc; i++) {
698 		if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
699 			usage(argv[0], test_size, test_loop, ion_heap);
700 			return 0;
701 		}
702 	}
703 	for (i = 1; i < argc; i++) {
704 		if (!strcmp(argv[i], "-v")) {
705 			verbosity++;
706 		} else if (!strcmp(argv[i], "-s")) {
707 			NEXT_ARG(i);
708 			test_size = atoi(argv[i]);
709 		} else if (!strcmp(argv[i], "-n")) {
710 			NEXT_ARG(i);
711 			test_loop = atoi(argv[i]);
712 		} else if (!strcmp(argv[i], "--ion-heap")) {
713 			NEXT_ARG(i);
714 			ion_heap = atoi(argv[i]);
715 		} else if (!strcmp(argv[i], "--no-offset")) {
716 			rnd_offset = 0;
717 		} else {
718 			fprintf(stderr, "%s: invalid argument: %s\n",
719 				argv[0], argv[i]);
720 			usage(argv[0], test_size, test_loop, ion_heap);
721 			return 1;
722 		}
723 	}
724 
725 	verbose("\nSecure Data Path basic access: "
726 		"NS invokes SDP TA\n");
727 	err = sdp_basic_test(TEST_NS_TO_TA, test_size, test_loop, ion_heap,
728 			     rnd_offset, verbosity);
729 	CHECK_RESULT(err, 0, return 1);
730 
731 	verbose("\nSecure Data Path basic access: "
732 		"SDP TA invokes SDP TA\n");
733 	err = sdp_basic_test(TEST_TA_TO_TA, test_size, test_loop, ion_heap,
734 			     rnd_offset, verbosity);
735 	CHECK_RESULT(err, 0, return 1);
736 
737 	verbose("\nSecure Data Path basic access: "
738 		"SDP TA invokes SDP pTA\n");
739 	err = sdp_basic_test(TEST_TA_TO_PTA, test_size, test_loop, ion_heap,
740 			     rnd_offset, verbosity);
741 	CHECK_RESULT(err, 0, return 1);
742 
743 	verbose("\nSecure Data Path basic access: "
744 		"NS invokes SDP pTA (shall fail)\n");
745 	err = sdp_basic_test(TEST_NS_TO_PTA, test_size, test_loop, ion_heap,
746 			     rnd_offset, verbosity);
747 	CHECK_RESULT(err, 1, return 1);
748 
749 	verbose("\nSecure Data Path basic access: "
750 		"Invoke TA with out of bounds buffer references\n");
751 	err = sdp_out_of_bounds_memref_test(test_size, ion_heap, verbosity);
752 	CHECK_RESULT(err, 0, return 1);
753 
754 	return 0;
755 }
756