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