blob: 5749714fbcdc16f651b552f26674fbd22b9ae0e0 [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
Etienne Carriere3a34b982017-10-24 15:31:34 +020024#include "include/uapi/linux/ion_old.h"
25
Etienne Carriere41343db2017-03-17 15:38:52 +010026/*
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
Etienne Carriere41343db2017-03-17 15:38:52 +010056struct tee_ctx {
57 TEEC_Context ctx;
58 TEEC_Session sess;
59};
60
Etienne Carriere3a34b982017-10-24 15:31:34 +020061/*
62 * Old ION API to allocate and export a buffer
63 */
64static int allocate_ion_buffer_old_api(size_t size, int heap_type_id, int ion)
65{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010066 struct ion0_allocation_data alloc_data = { };
67 struct ion0_handle_data hdl_data = { };
68 struct ion0_fd_data fd_data = { };
Etienne Carriere3a34b982017-10-24 15:31:34 +020069 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
Etienne Carriere8bc31422017-08-24 14:48:30 +020092int allocate_ion_buffer(size_t size, int heap_type_id, int verbosity)
Etienne Carriere41343db2017-03-17 15:38:52 +010093{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010094 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;
Etienne Carriere41343db2017-03-17 15:38:52 +010098 int fd = -1;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010099 unsigned int idx = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100100
101 ion = open("/dev/ion", O_RDWR);
102 if (ion < 0) {
Etienne Carriere8bc31422017-08-24 14:48:30 +0200103 fprintf(stderr, "Error: failed to open /dev/ion\n");
Etienne Carriere41343db2017-03-17 15:38:52 +0100104 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
Etienne Carriere8bc31422017-08-24 14:48:30 +0200111 if (heap_type_id < 0)
112 heap_type_id = DEFAULT_ION_HEAP_TYPE;
Etienne Carriere41343db2017-03-17 15:38:52 +0100113
Etienne Carriere8bc31422017-08-24 14:48:30 +0200114 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) {
Etienne Carriere3a34b982017-10-24 15:31:34 +0200121 fprintf(stderr, "Info: can't query heaps data, try old API\n");
122 fd = allocate_ion_buffer_old_api(size, heap_type_id, ion);
Etienne Carriere8bc31422017-08-24 14:48:30 +0200123 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);
Etienne Carriere41343db2017-03-17 15:38:52 +0100138
139 alloc_data.len = size;
Etienne Carriere41343db2017-03-17 15:38:52 +0100140 alloc_data.flags = 0;
Etienne Carriere8bc31422017-08-24 14:48:30 +0200141 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");
Etienne Carriere41343db2017-03-17 15:38:52 +0100144 goto out;
Etienne Carriere8bc31422017-08-24 14:48:30 +0200145 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100146
Etienne Carriere8bc31422017-08-24 14:48:30 +0200147 fd = alloc_data.fd;
Etienne Carriere41343db2017-03-17 15:38:52 +0100148out:
149 close(ion);
150 return fd;
151}
152
153static 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
Etienne Carrierec45d9762017-03-21 15:45:13 +0100162static int create_tee_ctx(struct tee_ctx *ctx, enum test_target_ta target_ta)
Etienne Carriere41343db2017-03-17 15:38:52 +0100163{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100164 TEEC_Result teerc = TEEC_ERROR_GENERIC;
165 const TEEC_UUID *uuid = NULL;
166 uint32_t err_origin = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100167
Etienne Carrierec45d9762017-03-21 15:45:13 +0100168 switch (target_ta) {
169 case TEST_NS_TO_TA:
170 case TEST_TA_TO_TA:
171 case TEST_TA_TO_PTA:
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100172 uuid = &sdp_basic_ta_uuid;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100173 break;
174 case TEST_NS_TO_PTA:
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100175 uuid = &pta_invoke_tests_ta_uuid;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100176 break;
177 default:
178 return -1;
179 }
180
Etienne Carriere41343db2017-03-17 15:38:52 +0100181 teerc = TEEC_InitializeContext(NULL, &ctx->ctx);
182 if (teerc != TEEC_SUCCESS)
183 return -1;
184
Etienne Carrierec45d9762017-03-21 15:45:13 +0100185 teerc = TEEC_OpenSession(&ctx->ctx, &ctx->sess, uuid,
Etienne Carriere41343db2017-03-17 15:38:52 +0100186 TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200187 if (teerc != TEEC_SUCCESS) {
Etienne Carrierec45d9762017-03-21 15:45:13 +0100188 fprintf(stderr, "Error: open session to target test %s failed %x %d\n",
189 (target_ta == TEST_NS_TO_PTA) ? "pTA" : "TA",
Etienne Carriere41343db2017-03-17 15:38:52 +0100190 teerc, err_origin);
191
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200192 TEEC_FinalizeContext(&ctx->ctx);
193 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100194 return (teerc == TEEC_SUCCESS) ? 0 : -1;
195}
196
197static int tee_register_buffer(struct tee_ctx *ctx, void **shm_ref, int fd)
198{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100199 TEEC_Result teerc = TEEC_ERROR_GENERIC;
200 TEEC_SharedMemory *shm = malloc(sizeof(*shm));
Etienne Carriere41343db2017-03-17 15:38:52 +0100201
Etienne Carriere41343db2017-03-17 15:38:52 +0100202 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
217static 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
228static int inject_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100229 void *in, size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100230{
231 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100232 TEEC_Result teerc = TEEC_ERROR_GENERIC;
233 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
234 uint32_t err_origin = 0;
235 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100236
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 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100253
Etienne Carriere41343db2017-03-17 15:38:52 +0100254 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
Etienne Carrieref690b912017-03-21 15:44:13 +0100265 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100266 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
273static int transform_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100274 size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100275{
276 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100277 TEEC_Result teerc = TEEC_ERROR_GENERIC;
278 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
279 uint32_t err_origin = 0;
280 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100281
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 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100298
Etienne Carriere41343db2017-03-17 15:38:52 +0100299 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
Etienne Carrieref690b912017-03-21 15:44:13 +0100305 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100306 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
313static int dump_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100314 void *out, size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100315{
316 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100317 TEEC_Result teerc = TEEC_ERROR_GENERIC;
318 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
319 uint32_t err_origin = 0;
320 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100321
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 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100338
Etienne Carriere41343db2017-03-17 15:38:52 +0100339 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
Etienne Carrieref690b912017-03-21 15:44:13 +0100349 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100350 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
357static 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)
378static int get_random_bytes(char *out, size_t len)
379{
380 static char *rand_buf = NULL;
381 static size_t rand_idx = 0;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100382 int rc = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100383
384 if (!rand_buf) {
385 const char rand_dev[] = "/dev/urandom";
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100386 int fd = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100387
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
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100430int sdp_basic_test(enum test_target_ta ta, size_t size, size_t loop,
Etienne Carriereb9a95822017-04-26 15:03:53 +0200431 int ion_heap, int rnd_offset, int verbosity)
Etienne Carriere41343db2017-03-17 15:38:52 +0100432{
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;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100440 size_t offset = 0;
441 size_t loop_cnt = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100442
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");
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200456 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100457 }
458
Etienne Carriereb9a95822017-04-26 15:03:53 +0200459 fd = allocate_ion_buffer(sdp_size, ion_heap, verbosity);
Etienne Carriere41343db2017-03-17 15:38:52 +0100460 if (fd < 0) {
Etienne Carriere5fdf6352017-03-24 11:49:50 +0100461 verbose("Failed to allocate SDP buffer (%zu bytes) in ION heap %d: %d\n",
Etienne Carriere41343db2017-03-17 15:38:52 +0100462 sdp_size, ion_heap, fd);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200463 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100464 }
465
466 /* register secure buffer to TEE */
467 ctx = malloc(sizeof(*ctx));
468 if (!ctx)
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200469 goto bail1;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100470 if (create_tee_ctx(ctx, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200471 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100472 if (tee_register_buffer(ctx, &shm_ref, fd))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200473 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100474
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 */
Etienne Carrieref690b912017-03-21 15:44:13 +0100480 for (loop_cnt = loop; loop_cnt; loop_cnt--) {
Etienne Carriere41343db2017-03-17 15:38:52 +0100481 /* get an buffer of random-like values */
482 if (get_random_bytes((char *)ref_buf, size))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200483 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100484 memcpy(test_buf, ref_buf, size);
485 /* random offset [0 255] */
486 offset = (unsigned int)*ref_buf;
487
488 /* TA writes into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100489 if (inject_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200490 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100491
492 /* TA reads/writes into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100493 if (transform_sdp_data(ctx, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200494 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100495
496 /* TA reads into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100497 if (dump_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200498 goto bail2;
Etienne Carrieref690b912017-03-21 15:44:13 +0100499
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);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200503 goto bail2;
Etienne Carrieref690b912017-03-21 15:44:13 +0100504 }
505 }
506
Etienne Carriere41343db2017-03-17 15:38:52 +0100507 err = 0;
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200508bail2:
Etienne Carriere41343db2017-03-17 15:38:52 +0100509 if (fd >= 0)
510 close(fd);
511 if (shm_ref)
512 tee_deregister_buffer(ctx, shm_ref);
513 finalize_tee_ctx(ctx);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200514bail1:
Etienne Carriere41343db2017-03-17 15:38:52 +0100515 free(ctx);
516 free(ref_buf);
517 free(test_buf);
518 return err;
519}
520
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200521static 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
Jerome Forissierf2971082020-04-09 09:53:45 +0200547 * the TEE.
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200548 * Invocation with valid references should reach the TA, whatever
549 * result is.
550 */
551 if ((valid_ref && orig != TEEC_ORIGIN_TRUSTED_APP) ||
Jerome Forissierf2971082020-04-09 09:53:45 +0200552 (!valid_ref && ((orig == TEEC_ORIGIN_TRUSTED_APP) ||
Jerome Forissiere8f35d12020-04-09 09:36:19 +0200553 (teerc != TEEC_ERROR_GENERIC &&
554 teerc != TEEC_ERROR_BAD_PARAMETERS))))
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200555 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
564error:
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
574int 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);
639bail:
640 tee_deregister_buffer(&ctx, out);
641 if (fd >= 0)
642 close(fd);
643 finalize_tee_ctx(&ctx);
644
645 return err;
646}
647
Etienne Carriere41343db2017-03-17 15:38:52 +0100648#define _TO_STR(x) #x
649#define TO_STR(x) _TO_STR(x)
650
651static 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
Jerome Forissiere1342522017-05-19 09:25:53 +0200678#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
Etienne Carriere41343db2017-03-17 15:38:52 +0100686int 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;
Etienne Carriereb9a95822017-04-26 15:03:53 +0200692 int verbosity = 1;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100693 int err = 0;
694 int i = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100695
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
Jerome Forissiere1342522017-05-19 09:25:53 +0200725 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);
Etienne Carriere41343db2017-03-17 15:38:52 +0100730
Jerome Forissiere1342522017-05-19 09:25:53 +0200731 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);
Etienne Carrierec45d9762017-03-21 15:45:13 +0100736
Jerome Forissiere1342522017-05-19 09:25:53 +0200737 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);
Etienne Carriere41343db2017-03-17 15:38:52 +0100742
Jerome Forissiere1342522017-05-19 09:25:53 +0200743 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);
Etienne Carriered1655822017-03-21 15:45:24 +0100748
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200749 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
Etienne Carriere41343db2017-03-17 15:38:52 +0100754 return 0;
755}