blob: c8abd51baf47334458937788d552d233193d1b2f [file] [log] [blame]
Etienne Carriere9b7b70d2020-05-16 10:27:23 +02001// SPDX-License-Identifier: BSD-2-Clause
Etienne Carriere41343db2017-03-17 15:38:52 +01002/*
3 * Copyright (c) 2016, Linaro Limited
4 * All rights reserved.
Etienne Carriere41343db2017-03-17 15:38:52 +01005 */
6
7#include <err.h>
8#include <fcntl.h>
Etienne Carrierec45d9762017-03-21 15:45:13 +01009#include <pta_invoke_tests.h>
Etienne Carriere41343db2017-03-17 15:38:52 +010010#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
Etienne Carriere41343db2017-03-17 15:38:52 +010019#include "crypto_common.h"
Etienne Carriere50abf9a2017-03-24 11:33:50 +010020#include "sdp_basic.h"
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010021#include "xtest_helpers.h"
Etienne Carriere50abf9a2017-03-24 11:33:50 +010022#include "xtest_test.h"
Etienne Carriere41343db2017-03-17 15:38:52 +010023
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
Etienne Carriere41343db2017-03-17 15:38:52 +010054struct tee_ctx {
55 TEEC_Context ctx;
56 TEEC_Session sess;
57};
58
Olivier Masseda5282a2022-04-07 11:24:08 +020059int 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
88out:
89 close(fd_mem_sec);
90 return fd;
91}
Etienne Carriere41343db2017-03-17 15:38:52 +010092
93static 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
Etienne Carrierec45d9762017-03-21 15:45:13 +0100102static int create_tee_ctx(struct tee_ctx *ctx, enum test_target_ta target_ta)
Etienne Carriere41343db2017-03-17 15:38:52 +0100103{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100104 TEEC_Result teerc = TEEC_ERROR_GENERIC;
105 const TEEC_UUID *uuid = NULL;
106 uint32_t err_origin = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100107
Etienne Carrierec45d9762017-03-21 15:45:13 +0100108 switch (target_ta) {
109 case TEST_NS_TO_TA:
110 case TEST_TA_TO_TA:
111 case TEST_TA_TO_PTA:
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100112 uuid = &sdp_basic_ta_uuid;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100113 break;
114 case TEST_NS_TO_PTA:
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100115 uuid = &pta_invoke_tests_ta_uuid;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100116 break;
117 default:
118 return -1;
119 }
120
Etienne Carriere41343db2017-03-17 15:38:52 +0100121 teerc = TEEC_InitializeContext(NULL, &ctx->ctx);
122 if (teerc != TEEC_SUCCESS)
123 return -1;
124
Etienne Carrierec45d9762017-03-21 15:45:13 +0100125 teerc = TEEC_OpenSession(&ctx->ctx, &ctx->sess, uuid,
Etienne Carriere41343db2017-03-17 15:38:52 +0100126 TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200127 if (teerc != TEEC_SUCCESS) {
Etienne Carrierec45d9762017-03-21 15:45:13 +0100128 fprintf(stderr, "Error: open session to target test %s failed %x %d\n",
129 (target_ta == TEST_NS_TO_PTA) ? "pTA" : "TA",
Etienne Carriere41343db2017-03-17 15:38:52 +0100130 teerc, err_origin);
131
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200132 TEEC_FinalizeContext(&ctx->ctx);
133 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100134 return (teerc == TEEC_SUCCESS) ? 0 : -1;
135}
136
137static int tee_register_buffer(struct tee_ctx *ctx, void **shm_ref, int fd)
138{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100139 TEEC_Result teerc = TEEC_ERROR_GENERIC;
140 TEEC_SharedMemory *shm = malloc(sizeof(*shm));
Etienne Carriere41343db2017-03-17 15:38:52 +0100141
Etienne Carriere41343db2017-03-17 15:38:52 +0100142 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
157static 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
168static int inject_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100169 void *in, size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100170{
171 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100172 TEEC_Result teerc = TEEC_ERROR_GENERIC;
173 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
174 uint32_t err_origin = 0;
175 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100176
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 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100193
Etienne Carriere41343db2017-03-17 15:38:52 +0100194 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
Etienne Carrieref690b912017-03-21 15:44:13 +0100205 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100206 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
213static int transform_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100214 size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100215{
216 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100217 TEEC_Result teerc = TEEC_ERROR_GENERIC;
218 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
219 uint32_t err_origin = 0;
220 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100221
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 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100238
Etienne Carriere41343db2017-03-17 15:38:52 +0100239 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
Etienne Carrieref690b912017-03-21 15:44:13 +0100245 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100246 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
253static int dump_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100254 void *out, size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100255{
256 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100257 TEEC_Result teerc = TEEC_ERROR_GENERIC;
258 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
259 uint32_t err_origin = 0;
260 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100261
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 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100278
Etienne Carriere41343db2017-03-17 15:38:52 +0100279 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
Etienne Carrieref690b912017-03-21 15:44:13 +0100289 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100290 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
297static 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)
318static int get_random_bytes(char *out, size_t len)
319{
320 static char *rand_buf = NULL;
321 static size_t rand_idx = 0;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100322 int rc = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100323
324 if (!rand_buf) {
325 const char rand_dev[] = "/dev/urandom";
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100326 int fd = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100327
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);
Cyrille Fleury458e4b62021-10-28 13:37:40 +0200345 close(fd);
Etienne Carriere41343db2017-03-17 15:38:52 +0100346 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
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100371int sdp_basic_test(enum test_target_ta ta, size_t size, size_t loop,
Jerome Forissier03aa2792023-02-07 14:22:24 +0100372 const char *heap_name, int rnd_offset, int verbosity)
Etienne Carriere41343db2017-03-17 15:38:52 +0100373{
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;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100381 size_t offset = 0;
382 size_t loop_cnt = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100383
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");
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200397 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100398 }
399
Jerome Forissier03aa2792023-02-07 14:22:24 +0100400 fd = allocate_buffer(sdp_size, heap_name, verbosity);
Etienne Carriere41343db2017-03-17 15:38:52 +0100401 if (fd < 0) {
Jerome Forissier03aa2792023-02-07 14:22:24 +0100402 verbose("Failed to allocate SDP buffer (%zu bytes) in %s: %d\n",
403 sdp_size, heap_name, fd);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200404 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100405 }
406
407 /* register secure buffer to TEE */
408 ctx = malloc(sizeof(*ctx));
409 if (!ctx)
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200410 goto bail1;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100411 if (create_tee_ctx(ctx, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200412 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100413 if (tee_register_buffer(ctx, &shm_ref, fd))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200414 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100415
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 */
Etienne Carrieref690b912017-03-21 15:44:13 +0100421 for (loop_cnt = loop; loop_cnt; loop_cnt--) {
Etienne Carriere41343db2017-03-17 15:38:52 +0100422 /* get an buffer of random-like values */
423 if (get_random_bytes((char *)ref_buf, size))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200424 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100425 memcpy(test_buf, ref_buf, size);
426 /* random offset [0 255] */
427 offset = (unsigned int)*ref_buf;
428
429 /* TA writes into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100430 if (inject_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200431 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100432
433 /* TA reads/writes into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100434 if (transform_sdp_data(ctx, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200435 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100436
437 /* TA reads into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100438 if (dump_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200439 goto bail2;
Etienne Carrieref690b912017-03-21 15:44:13 +0100440
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);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200444 goto bail2;
Etienne Carrieref690b912017-03-21 15:44:13 +0100445 }
446 }
447
Etienne Carriere41343db2017-03-17 15:38:52 +0100448 err = 0;
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200449bail2:
Etienne Carriere41343db2017-03-17 15:38:52 +0100450 if (fd >= 0)
451 close(fd);
452 if (shm_ref)
453 tee_deregister_buffer(ctx, shm_ref);
454 finalize_tee_ctx(ctx);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200455bail1:
Etienne Carriere41343db2017-03-17 15:38:52 +0100456 free(ctx);
457 free(ref_buf);
458 free(test_buf);
459 return err;
460}
461
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200462static 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
Jerome Forissierf2971082020-04-09 09:53:45 +0200488 * the TEE.
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200489 * Invocation with valid references should reach the TA, whatever
490 * result is.
491 */
492 if ((valid_ref && orig != TEEC_ORIGIN_TRUSTED_APP) ||
Jerome Forissierf2971082020-04-09 09:53:45 +0200493 (!valid_ref && ((orig == TEEC_ORIGIN_TRUSTED_APP) ||
Jerome Forissiere8f35d12020-04-09 09:36:19 +0200494 (teerc != TEEC_ERROR_GENERIC &&
495 teerc != TEEC_ERROR_BAD_PARAMETERS))))
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200496 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
505error:
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
Jerome Forissier03aa2792023-02-07 14:22:24 +0100515int sdp_out_of_bounds_memref_test(size_t size, const char *heap_name,
516 int verbosity)
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200517{
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
Jerome Forissier03aa2792023-02-07 14:22:24 +0100528 fd = allocate_buffer(size, heap_name, verbosity);
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200529 if (fd < 0) {
Jerome Forissier03aa2792023-02-07 14:22:24 +0100530 verbose("SDP alloc failed (%zu bytes) in %s: %d\n",
531 size, heap_name, fd);
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200532 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);
581bail:
582 tee_deregister_buffer(&ctx, out);
583 if (fd >= 0)
584 close(fd);
585 finalize_tee_ctx(&ctx);
586
587 return err;
588}
589
Etienne Carriere41343db2017-03-17 15:38:52 +0100590#define _TO_STR(x) #x
591#define TO_STR(x) _TO_STR(x)
592
Jerome Forissier03aa2792023-02-07 14:22:24 +0100593static void usage(const char *progname, size_t size, int loop, const char *heap_name)
Etienne Carriere41343db2017-03-17 15:38:52 +0100594{
595 fprintf(stderr, "Usage: %s [OPTION]\n", progname);
596 fprintf(stderr,
597 "Testing basic accesses to secure buffer (SDP) on OP-TEE.\n"
598 "Allocates a secure buffer and invoke a TA to access it.\n"
599 "TA is used to init/transform/dump the secure buffer.\n"
600 "CA check dumped content.\n\n");
601
602 fprintf(stderr, "Options:\n");
Olivier Masseda5282a2022-04-07 11:24:08 +0200603 fprintf(stderr, " -h|--help Print this help and exit\n");
604 fprintf(stderr, " -v Be verbose\n");
605 fprintf(stderr, " -s SIZE SDP buffer byte size [%zu]\n", size);
606 fprintf(stderr, " -n LOOP Test loop iterations [%u]\n", loop);
Olivier Masseda5282a2022-04-07 11:24:08 +0200607 fprintf(stderr, " --heap-name NAME Target heap name [%s]\n", heap_name);
608 fprintf(stderr, " --no-offset No random offset [0 255] in buffer\n");
Etienne Carriere41343db2017-03-17 15:38:52 +0100609}
610
611#define NEXT_ARG(i) \
612 do { \
613 if (++i == argc) { \
614 fprintf(stderr, "%s: %s: missing argument\n", \
615 argv[0], argv[i-1]); \
616 return 1; \
617 } \
618 } while (0);
619
Jerome Forissiere1342522017-05-19 09:25:53 +0200620#define CHECK_RESULT(_res, _exp, _action) \
621 if ((_res) == (_exp)) { \
622 verbose("Test passed\n"); \
623 } else { \
624 verbose("Test failed!\n"); \
625 _action; \
626 }
627
Etienne Carriere41343db2017-03-17 15:38:52 +0100628int sdp_basic_runner_cmd_parser(int argc, char *argv[])
629{
630 size_t test_size = 5000;
631 size_t test_loop = 1000;
Olivier Masseda5282a2022-04-07 11:24:08 +0200632 const char *heap_name = DEFAULT_HEAP_NAME;
Etienne Carriere41343db2017-03-17 15:38:52 +0100633 int rnd_offset = 1;
Etienne Carriereb9a95822017-04-26 15:03:53 +0200634 int verbosity = 1;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100635 int err = 0;
636 int i = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100637
638 /* Parse command line */
639 for (i = 1; i < argc; i++) {
640 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
Jerome Forissier03aa2792023-02-07 14:22:24 +0100641 usage(argv[0], test_size, test_loop, heap_name);
Etienne Carriere41343db2017-03-17 15:38:52 +0100642 return 0;
643 }
644 }
645 for (i = 1; i < argc; i++) {
646 if (!strcmp(argv[i], "-v")) {
647 verbosity++;
648 } else if (!strcmp(argv[i], "-s")) {
649 NEXT_ARG(i);
650 test_size = atoi(argv[i]);
651 } else if (!strcmp(argv[i], "-n")) {
652 NEXT_ARG(i);
653 test_loop = atoi(argv[i]);
Olivier Masseda5282a2022-04-07 11:24:08 +0200654 } else if (!strcmp(argv[i], "--heap-name")) {
655 NEXT_ARG(i);
656 heap_name = argv[i];
Etienne Carriere41343db2017-03-17 15:38:52 +0100657 } else if (!strcmp(argv[i], "--no-offset")) {
658 rnd_offset = 0;
659 } else {
660 fprintf(stderr, "%s: invalid argument: %s\n",
661 argv[0], argv[i]);
Jerome Forissier03aa2792023-02-07 14:22:24 +0100662 usage(argv[0], test_size, test_loop, heap_name);
Etienne Carriere41343db2017-03-17 15:38:52 +0100663 return 1;
664 }
665 }
666
Jerome Forissiere1342522017-05-19 09:25:53 +0200667 verbose("\nSecure Data Path basic access: "
668 "NS invokes SDP TA\n");
Jerome Forissier03aa2792023-02-07 14:22:24 +0100669 err = sdp_basic_test(TEST_NS_TO_TA, test_size, test_loop, heap_name,
Jerome Forissiere1342522017-05-19 09:25:53 +0200670 rnd_offset, verbosity);
671 CHECK_RESULT(err, 0, return 1);
Etienne Carriere41343db2017-03-17 15:38:52 +0100672
Jerome Forissiere1342522017-05-19 09:25:53 +0200673 verbose("\nSecure Data Path basic access: "
674 "SDP TA invokes SDP TA\n");
Jerome Forissier03aa2792023-02-07 14:22:24 +0100675 err = sdp_basic_test(TEST_TA_TO_TA, test_size, test_loop, heap_name,
Jerome Forissiere1342522017-05-19 09:25:53 +0200676 rnd_offset, verbosity);
677 CHECK_RESULT(err, 0, return 1);
Etienne Carrierec45d9762017-03-21 15:45:13 +0100678
Jerome Forissiere1342522017-05-19 09:25:53 +0200679 verbose("\nSecure Data Path basic access: "
680 "SDP TA invokes SDP pTA\n");
Jerome Forissier03aa2792023-02-07 14:22:24 +0100681 err = sdp_basic_test(TEST_TA_TO_PTA, test_size, test_loop, heap_name,
Jerome Forissiere1342522017-05-19 09:25:53 +0200682 rnd_offset, verbosity);
683 CHECK_RESULT(err, 0, return 1);
Etienne Carriere41343db2017-03-17 15:38:52 +0100684
Jerome Forissiere1342522017-05-19 09:25:53 +0200685 verbose("\nSecure Data Path basic access: "
686 "NS invokes SDP pTA (shall fail)\n");
Jerome Forissier03aa2792023-02-07 14:22:24 +0100687 err = sdp_basic_test(TEST_NS_TO_PTA, test_size, test_loop, heap_name,
Jerome Forissiere1342522017-05-19 09:25:53 +0200688 rnd_offset, verbosity);
689 CHECK_RESULT(err, 1, return 1);
Etienne Carriered1655822017-03-21 15:45:24 +0100690
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200691 verbose("\nSecure Data Path basic access: "
692 "Invoke TA with out of bounds buffer references\n");
Jerome Forissier03aa2792023-02-07 14:22:24 +0100693 err = sdp_out_of_bounds_memref_test(test_size, heap_name, verbosity);
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200694 CHECK_RESULT(err, 0, return 1);
695
Etienne Carriere41343db2017-03-17 15:38:52 +0100696 return 0;
697}