blob: b539dc7cd303326c92cae8289a0dbbdeb21b8f5b [file] [log] [blame]
Etienne Carriere41343db2017-03-17 15:38:52 +01001/*
2 * Copyright (c) 2016, Linaro Limited
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <err.h>
29#include <fcntl.h>
Etienne Carrierec45d9762017-03-21 15:45:13 +010030#include <pta_invoke_tests.h>
Etienne Carriere41343db2017-03-17 15:38:52 +010031#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/ioctl.h>
35#include <sys/mman.h>
36#include <tee_client_api.h>
37#include <tee_client_api_extensions.h>
38#include <unistd.h>
39
Etienne Carriere41343db2017-03-17 15:38:52 +010040#include "crypto_common.h"
Etienne Carriere50abf9a2017-03-24 11:33:50 +010041#include "sdp_basic.h"
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010042#include "xtest_helpers.h"
Etienne Carriere50abf9a2017-03-24 11:33:50 +010043#include "xtest_test.h"
Etienne Carriere41343db2017-03-17 15:38:52 +010044
Etienne Carriere3a34b982017-10-24 15:31:34 +020045#include "include/uapi/linux/ion_old.h"
46
Etienne Carriere41343db2017-03-17 15:38:52 +010047/*
48 * SDP basic test setup overview.
49 *
50 * - A dedicated trusted application (SDP basic TA) supports 3 commands:
51 * - 'inject' data from a nonsecure buffer into a secure buffer
52 * - 'transform' data inside a secure buffer (bitwise invert + unsigned incr)
53 * - 'dump' data from a secure buffer into a nonsecure buffer
54
55 * - This test client application (CA) invokes the TA for these 3 operations,
56 * inject random value, trasforming them then dump them.
57 *
58 * To do so, CA allocates a 'SDP secure buffer' and invoke the TA for these 3
59 * operations (inject then transform then dump) over the allocate buffer.
60 *
61 * The secure buffer is currently allocation through ION support adn
62 * registered to OP-TEE and as shared memory.
63 *
64 * To enhance test coverage against buffer alignement usecase, the CA invokes
65 * the TA with a variable offset inside the buffer. As CA injects random data
66 * into the buffer, the CA uses one of the random bytes to set the value of the
67 * offset in the accessed secure buffer.
68 *
69 * For debugging support, the CA may map (in nonsecure world) the secure
70 * buffer to read its content. As this is unsafe on a hardened platform, this
71 * operation is default disable. When enable, error only print out a warning
72 * trace but does not actually fail the test. This also give an easy way to
73 * check that some HW complains on access violation when nonsecure accesses
74 * secure data.
75 */
76
Etienne Carriere41343db2017-03-17 15:38:52 +010077struct tee_ctx {
78 TEEC_Context ctx;
79 TEEC_Session sess;
80};
81
Etienne Carriere3a34b982017-10-24 15:31:34 +020082/*
83 * Old ION API to allocate and export a buffer
84 */
85static int allocate_ion_buffer_old_api(size_t size, int heap_type_id, int ion)
86{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +010087 struct ion0_allocation_data alloc_data = { };
88 struct ion0_handle_data hdl_data = { };
89 struct ion0_fd_data fd_data = { };
Etienne Carriere3a34b982017-10-24 15:31:34 +020090 int fd = -1;
91
92 alloc_data.len = size;
93 alloc_data.align = 0;
94 alloc_data.flags = 0;
95 alloc_data.heap_id_mask = 1 << heap_type_id;
96 if (ioctl(ion, ION0_IOC_ALLOC, &alloc_data) == -1) {
97 fprintf(stderr, "Error: old ION allocate API failed\n");
98 return fd;
99 }
100
101 fd_data.handle = alloc_data.handle;
102 if (ioctl(ion, ION0_IOC_SHARE, &fd_data) != -1)
103 fd = fd_data.fd;
104 else
105 fprintf(stderr, "Error: old ION share API failed\n");
106
107 hdl_data.handle = alloc_data.handle;
108 (void)ioctl(ion, ION0_IOC_FREE, &hdl_data);
109
110 return fd;
111}
112
Etienne Carriere8bc31422017-08-24 14:48:30 +0200113int allocate_ion_buffer(size_t size, int heap_type_id, int verbosity)
Etienne Carriere41343db2017-03-17 15:38:52 +0100114{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100115 struct ion_heap_query query_data = { };
116 struct ion_heap_data heap_data[32] = { };
117 struct ion_allocation_data alloc_data = { };
118 int ion = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100119 int fd = -1;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100120 unsigned int idx = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100121
122 ion = open("/dev/ion", O_RDWR);
123 if (ion < 0) {
Etienne Carriere8bc31422017-08-24 14:48:30 +0200124 fprintf(stderr, "Error: failed to open /dev/ion\n");
Etienne Carriere41343db2017-03-17 15:38:52 +0100125 verbose("Seems no ION heap is available.\n");
126 verbose("To test ION allocation you can enable\n");
127 verbose("CONFIG_ION and CONFIG_ION_DUMMY in your\n");
128 verbose("linux kernel configuration.\n");
129 return fd;
130 }
131
Etienne Carriere8bc31422017-08-24 14:48:30 +0200132 if (heap_type_id < 0)
133 heap_type_id = DEFAULT_ION_HEAP_TYPE;
Etienne Carriere41343db2017-03-17 15:38:52 +0100134
Etienne Carriere8bc31422017-08-24 14:48:30 +0200135 if (ioctl(ion, ION_IOC_HEAP_QUERY, &query_data) < 0) {
136 fprintf(stderr, "Error: failed to query the number of heaps\n");
137 goto out;
138 }
139
140 query_data.heaps = (__u64)(unsigned long)&heap_data;
141 if (ioctl(ion, ION_IOC_HEAP_QUERY, &query_data) < 0) {
Etienne Carriere3a34b982017-10-24 15:31:34 +0200142 fprintf(stderr, "Info: can't query heaps data, try old API\n");
143 fd = allocate_ion_buffer_old_api(size, heap_type_id, ion);
Etienne Carriere8bc31422017-08-24 14:48:30 +0200144 goto out;
145 }
146
147 for (idx = 0; idx < query_data.cnt; idx++)
148 if (heap_data[idx].type == (unsigned int)heap_type_id)
149 break;
150 if (idx == query_data.cnt) {
151 fprintf(stderr, "Error: target heap type %d not found\n",
152 heap_type_id);
153 goto out;
154 }
155
156 verbose("Allocate in ION heap '%s' (type=%u, id=%u)\n",
157 heap_data[idx].name, heap_data[idx].type,
158 heap_data[idx].heap_id);
Etienne Carriere41343db2017-03-17 15:38:52 +0100159
160 alloc_data.len = size;
Etienne Carriere41343db2017-03-17 15:38:52 +0100161 alloc_data.flags = 0;
Etienne Carriere8bc31422017-08-24 14:48:30 +0200162 alloc_data.heap_id_mask = 1 << heap_data[idx].heap_id;
163 if (ioctl(ion, ION_IOC_ALLOC, &alloc_data) < 0) {
164 fprintf(stderr, "Error: failed to allocate in target heap\n");
Etienne Carriere41343db2017-03-17 15:38:52 +0100165 goto out;
Etienne Carriere8bc31422017-08-24 14:48:30 +0200166 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100167
Etienne Carriere8bc31422017-08-24 14:48:30 +0200168 fd = alloc_data.fd;
Etienne Carriere41343db2017-03-17 15:38:52 +0100169out:
170 close(ion);
171 return fd;
172}
173
174static void finalize_tee_ctx(struct tee_ctx *ctx)
175{
176 if (!ctx)
177 return;
178
179 TEEC_CloseSession(&ctx->sess);
180 TEEC_FinalizeContext(&ctx->ctx);
181}
182
Etienne Carrierec45d9762017-03-21 15:45:13 +0100183static int create_tee_ctx(struct tee_ctx *ctx, enum test_target_ta target_ta)
Etienne Carriere41343db2017-03-17 15:38:52 +0100184{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100185 TEEC_Result teerc = TEEC_ERROR_GENERIC;
186 const TEEC_UUID *uuid = NULL;
187 uint32_t err_origin = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100188
Etienne Carrierec45d9762017-03-21 15:45:13 +0100189 switch (target_ta) {
190 case TEST_NS_TO_TA:
191 case TEST_TA_TO_TA:
192 case TEST_TA_TO_PTA:
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100193 uuid = &sdp_basic_ta_uuid;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100194 break;
195 case TEST_NS_TO_PTA:
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100196 uuid = &pta_invoke_tests_ta_uuid;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100197 break;
198 default:
199 return -1;
200 }
201
Etienne Carriere41343db2017-03-17 15:38:52 +0100202 teerc = TEEC_InitializeContext(NULL, &ctx->ctx);
203 if (teerc != TEEC_SUCCESS)
204 return -1;
205
Etienne Carrierec45d9762017-03-21 15:45:13 +0100206 teerc = TEEC_OpenSession(&ctx->ctx, &ctx->sess, uuid,
Etienne Carriere41343db2017-03-17 15:38:52 +0100207 TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200208 if (teerc != TEEC_SUCCESS) {
Etienne Carrierec45d9762017-03-21 15:45:13 +0100209 fprintf(stderr, "Error: open session to target test %s failed %x %d\n",
210 (target_ta == TEST_NS_TO_PTA) ? "pTA" : "TA",
Etienne Carriere41343db2017-03-17 15:38:52 +0100211 teerc, err_origin);
212
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200213 TEEC_FinalizeContext(&ctx->ctx);
214 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100215 return (teerc == TEEC_SUCCESS) ? 0 : -1;
216}
217
218static int tee_register_buffer(struct tee_ctx *ctx, void **shm_ref, int fd)
219{
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100220 TEEC_Result teerc = TEEC_ERROR_GENERIC;
221 TEEC_SharedMemory *shm = malloc(sizeof(*shm));
Etienne Carriere41343db2017-03-17 15:38:52 +0100222
Etienne Carriere41343db2017-03-17 15:38:52 +0100223 if (!shm)
224 return 1;
225
226 shm->flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
227 teerc = TEEC_RegisterSharedMemoryFileDescriptor(&ctx->ctx, shm, fd);
228 if (teerc != TEEC_SUCCESS) {
229 fprintf(stderr, "Error: TEEC_RegisterMemoryFileDescriptor() failed %x\n",
230 teerc);
231 return 1;
232 }
233
234 *shm_ref = shm;
235 return 0;
236}
237
238static void tee_deregister_buffer(struct tee_ctx *ctx, void *shm_ref)
239{
240 (void)ctx;
241
242 if (!shm_ref)
243 return;
244
245 TEEC_ReleaseSharedMemory((TEEC_SharedMemory *)shm_ref);
246 free(shm_ref);
247}
248
249static int inject_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100250 void *in, size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100251{
252 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100253 TEEC_Result teerc = TEEC_ERROR_GENERIC;
254 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
255 uint32_t err_origin = 0;
256 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100257
258 switch (ind) {
259 case TEST_NS_TO_TA:
260 cmd = TA_SDP_BASIC_CMD_INJECT;
261 break;
262 case TEST_TA_TO_TA:
263 cmd = TA_SDP_BASIC_CMD_INVOKE_INJECT;
264 break;
265 case TEST_TA_TO_PTA:
266 cmd = TA_SDP_BASIC_CMD_PTA_INJECT;
267 break;
268 case TEST_NS_TO_PTA:
269 cmd = PTA_INVOKE_TESTS_CMD_COPY_NSEC_TO_SEC;
270 break;
271 default:
272 return -1;
273 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100274
Etienne Carriere41343db2017-03-17 15:38:52 +0100275 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
276 TEEC_MEMREF_PARTIAL_OUTPUT,
277 TEEC_NONE, TEEC_NONE);
278
279 op.params[0].tmpref.buffer = in;
280 op.params[0].tmpref.size = len;
281
282 op.params[1].memref.parent = shm;
283 op.params[1].memref.size = len;
284 op.params[1].memref.offset = offset;
285
Etienne Carrieref690b912017-03-21 15:44:13 +0100286 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100287 if (teerc != TEEC_SUCCESS)
288 fprintf(stderr, "Error: invoke SDP test TA (inject) failed %x %d\n",
289 teerc, err_origin);
290
291 return (teerc == TEEC_SUCCESS) ? 0 : -1;
292}
293
294static int transform_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100295 size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100296{
297 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100298 TEEC_Result teerc = TEEC_ERROR_GENERIC;
299 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
300 uint32_t err_origin = 0;
301 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100302
303 switch (ind) {
304 case TEST_NS_TO_TA:
305 cmd = TA_SDP_BASIC_CMD_TRANSFORM;
306 break;
307 case TEST_TA_TO_TA:
308 cmd = TA_SDP_BASIC_CMD_INVOKE_TRANSFORM;
309 break;
310 case TEST_TA_TO_PTA:
311 cmd = TA_SDP_BASIC_CMD_PTA_TRANSFORM;
312 break;
313 case TEST_NS_TO_PTA:
314 cmd = PTA_INVOKE_TESTS_CMD_READ_MODIFY_SEC;
315 break;
316 default:
317 return -1;
318 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100319
Etienne Carriere41343db2017-03-17 15:38:52 +0100320 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INOUT,
321 TEEC_NONE, TEEC_NONE, TEEC_NONE);
322 op.params[0].memref.parent = shm;
323 op.params[0].memref.size = len;
324 op.params[0].memref.offset = offset;
325
Etienne Carrieref690b912017-03-21 15:44:13 +0100326 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100327 if (teerc != TEEC_SUCCESS)
328 fprintf(stderr, "Error: invoke SDP test TA (transform) failed %x %d\n",
329 teerc, err_origin);
330
331 return (teerc == TEEC_SUCCESS) ? 0 : -1;
332}
333
334static int dump_sdp_data(struct tee_ctx *ctx,
Etienne Carrieref690b912017-03-21 15:44:13 +0100335 void *out, size_t offset, size_t len, void *shm_ref, int ind)
Etienne Carriere41343db2017-03-17 15:38:52 +0100336{
337 TEEC_SharedMemory *shm = (TEEC_SharedMemory *)shm_ref;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100338 TEEC_Result teerc = TEEC_ERROR_GENERIC;
339 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
340 uint32_t err_origin = 0;
341 unsigned int cmd = 0;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100342
343 switch (ind) {
344 case TEST_NS_TO_TA:
345 cmd = TA_SDP_BASIC_CMD_DUMP;
346 break;
347 case TEST_TA_TO_TA:
348 cmd = TA_SDP_BASIC_CMD_INVOKE_DUMP;
349 break;
350 case TEST_TA_TO_PTA:
351 cmd = TA_SDP_BASIC_CMD_PTA_DUMP;
352 break;
353 case TEST_NS_TO_PTA:
354 cmd = PTA_INVOKE_TESTS_CMD_COPY_SEC_TO_NSEC;
355 break;
356 default:
357 return -1;
358 }
Etienne Carriere41343db2017-03-17 15:38:52 +0100359
Etienne Carriere41343db2017-03-17 15:38:52 +0100360 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INPUT,
361 TEEC_MEMREF_TEMP_OUTPUT,
362 TEEC_NONE, TEEC_NONE);
363 op.params[0].memref.parent = shm;
364 op.params[0].memref.size = len;
365 op.params[0].memref.offset = offset;
366
367 op.params[1].tmpref.buffer = out;
368 op.params[1].tmpref.size = len;
369
Etienne Carrieref690b912017-03-21 15:44:13 +0100370 teerc = TEEC_InvokeCommand(&ctx->sess, cmd, &op, &err_origin);
Etienne Carriere41343db2017-03-17 15:38:52 +0100371 if (teerc != TEEC_SUCCESS)
372 fprintf(stderr, "Error: invoke SDP test TA (dump) failed %x %d\n",
373 teerc, err_origin);
374
375 return (teerc == TEEC_SUCCESS) ? 0 : -1;
376}
377
378static int check_sdp_dumped(struct tee_ctx *ctx, void *ref, size_t len,
379 void *out)
380{
381 char *bref = (char *)ref;
382 char *data = (char *)out;
383 int err = 0;
384
385 (void)ctx;
386
387 while(len--)
388 if (*data++ != (unsigned char)(~(*bref++) + 1))
389 err++;
390
391 return err;
392}
393
394/*
395 * Consider 32kByte + 1 of random data is sufficient for an accurate test
396 * whatever the test buffer size is. Random buffer is read as a ring buffer.
397 */
398#define RANDOM_BUFFER_SIZE (32 * 1024 + 1)
399static int get_random_bytes(char *out, size_t len)
400{
401 static char *rand_buf = NULL;
402 static size_t rand_idx = 0;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100403 int rc = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100404
405 if (!rand_buf) {
406 const char rand_dev[] = "/dev/urandom";
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100407 int fd = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100408
409 rand_buf = malloc(RANDOM_BUFFER_SIZE);
410 if (!rand_buf) {
411 fprintf(stderr, "failed to random buffer memory (%d bytes)\n",
412 RANDOM_BUFFER_SIZE);
413 return -1;
414 }
415
416 fd = open(rand_dev, O_RDONLY);
417 if (fd < 0) {
418 fprintf(stderr, "failed to open %s\n", rand_dev);
419 return -1;
420 }
421
422 rc = read(fd, rand_buf, RANDOM_BUFFER_SIZE);
423 if (rc != RANDOM_BUFFER_SIZE) {
424 fprintf(stderr, "failed to read %d bytes from %s\n",
425 RANDOM_BUFFER_SIZE, rand_dev);
426 return -1;
427 }
428 close(fd);
429 }
430
431 while (len) {
432 size_t t_len = (RANDOM_BUFFER_SIZE < len) ? RANDOM_BUFFER_SIZE : len;
433
434 if ((rand_idx + t_len) > RANDOM_BUFFER_SIZE) {
435 int sz_end = RANDOM_BUFFER_SIZE - rand_idx;
436 int sz_beg = t_len - sz_end;
437
438 memcpy(out, rand_buf + rand_idx, sz_end);
439 memcpy(out + sz_end, rand_buf , sz_beg);
440 rand_idx = sz_beg;
441 } else {
442 memcpy(out, rand_buf + rand_idx, t_len);
443 rand_idx += t_len;
444 }
445 len -= t_len;
446 }
447 return 0;
448}
449
450
Etienne Carriere50abf9a2017-03-24 11:33:50 +0100451int sdp_basic_test(enum test_target_ta ta, size_t size, size_t loop,
Etienne Carriereb9a95822017-04-26 15:03:53 +0200452 int ion_heap, int rnd_offset, int verbosity)
Etienne Carriere41343db2017-03-17 15:38:52 +0100453{
454 struct tee_ctx *ctx = NULL;
455 unsigned char *test_buf = NULL;
456 unsigned char *ref_buf = NULL;
457 void *shm_ref = NULL;
458 unsigned int err = 1;
459 int fd = -1;
460 size_t sdp_size = size;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100461 size_t offset = 0;
462 size_t loop_cnt = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100463
464 if (!loop) {
465 fprintf(stderr, "Error: null loop value\n");
466 return 1;
467 }
468
469 /* reduce size to enable offset tests (max offset is 255 bytes) */
470 if (rnd_offset)
471 size -= 255;
472
473 test_buf = malloc(size);
474 ref_buf = malloc(size);
475 if (!test_buf || !ref_buf) {
476 verbose("failed to allocate memory\n");
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200477 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100478 }
479
Etienne Carriereb9a95822017-04-26 15:03:53 +0200480 fd = allocate_ion_buffer(sdp_size, ion_heap, verbosity);
Etienne Carriere41343db2017-03-17 15:38:52 +0100481 if (fd < 0) {
Etienne Carriere5fdf6352017-03-24 11:49:50 +0100482 verbose("Failed to allocate SDP buffer (%zu bytes) in ION heap %d: %d\n",
Etienne Carriere41343db2017-03-17 15:38:52 +0100483 sdp_size, ion_heap, fd);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200484 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100485 }
486
487 /* register secure buffer to TEE */
488 ctx = malloc(sizeof(*ctx));
489 if (!ctx)
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200490 goto bail1;
Etienne Carrierec45d9762017-03-21 15:45:13 +0100491 if (create_tee_ctx(ctx, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200492 goto bail1;
Etienne Carriere41343db2017-03-17 15:38:52 +0100493 if (tee_register_buffer(ctx, &shm_ref, fd))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200494 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100495
496 /* release registered fd: tee should still hold refcount on resource */
497 close(fd);
498 fd = -1;
499
500 /* invoke trusted application with secure buffer as memref parameter */
Etienne Carrieref690b912017-03-21 15:44:13 +0100501 for (loop_cnt = loop; loop_cnt; loop_cnt--) {
Etienne Carriere41343db2017-03-17 15:38:52 +0100502 /* get an buffer of random-like values */
503 if (get_random_bytes((char *)ref_buf, size))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200504 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100505 memcpy(test_buf, ref_buf, size);
506 /* random offset [0 255] */
507 offset = (unsigned int)*ref_buf;
508
509 /* TA writes into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100510 if (inject_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200511 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100512
513 /* TA reads/writes into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100514 if (transform_sdp_data(ctx, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200515 goto bail2;
Etienne Carriere41343db2017-03-17 15:38:52 +0100516
517 /* TA reads into SDP buffer */
Etienne Carrierec45d9762017-03-21 15:45:13 +0100518 if (dump_sdp_data(ctx, test_buf, offset, size, shm_ref, ta))
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200519 goto bail2;
Etienne Carrieref690b912017-03-21 15:44:13 +0100520
521 /* check dumped data are the expected ones */
522 if (check_sdp_dumped(ctx, ref_buf, size, test_buf)) {
523 fprintf(stderr, "check SDP data: %d errors\n", err);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200524 goto bail2;
Etienne Carrieref690b912017-03-21 15:44:13 +0100525 }
526 }
527
Etienne Carriere41343db2017-03-17 15:38:52 +0100528 err = 0;
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200529bail2:
Etienne Carriere41343db2017-03-17 15:38:52 +0100530 if (fd >= 0)
531 close(fd);
532 if (shm_ref)
533 tee_deregister_buffer(ctx, shm_ref);
534 finalize_tee_ctx(ctx);
Etienne Carrierecc72dd22017-10-18 11:55:05 +0200535bail1:
Etienne Carriere41343db2017-03-17 15:38:52 +0100536 free(ctx);
537 free(ref_buf);
538 free(test_buf);
539 return err;
540}
541
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200542static int invoke_out_of_bounds(struct tee_ctx *ctx,
543 TEEC_SharedMemory *in, TEEC_SharedMemory *out,
544 size_t offset, size_t size,
545 bool valid_ref, int verbosity)
546{
547 TEEC_Result teerc = TEEC_ERROR_GENERIC;
548 TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
549 uint32_t orig = 0;
550
551 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INPUT,
552 TEEC_MEMREF_PARTIAL_OUTPUT,
553 TEEC_NONE, TEEC_NONE);
554
555 op.params[0].memref.parent = in;
556 op.params[0].memref.offset = 0;
557 op.params[0].memref.size = size;
558
559 op.params[1].memref.parent = out;
560 op.params[1].memref.offset = offset;
561 op.params[1].memref.size = size;
562
563 teerc = TEEC_InvokeCommand(&ctx->sess, TA_SDP_BASIC_CMD_INJECT,
564 &op, &orig);
565
566 /*
567 * Invocation with invalid references should be nicely rejected by
568 * the communication layer.
569 * Invocation with valid references should reach the TA, whatever
570 * result is.
571 */
572 if ((valid_ref && orig != TEEC_ORIGIN_TRUSTED_APP) ||
Jerome Forissiere8f35d12020-04-09 09:36:19 +0200573 (!valid_ref && ((orig != TEEC_ORIGIN_COMMS) ||
574 (teerc != TEEC_ERROR_GENERIC &&
575 teerc != TEEC_ERROR_BAD_PARAMETERS))))
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200576 goto error;
577
578 verbose("Out of bounds memref test successful:\n");
579 verbose("Shm size 0x%zx, offset 0x%zx/size 0x%zx: %s/0x%x from %s\n",
580 out->size, offset, size,
581 Do_ADBG_GetEnumName(teerc, ADBG_EnumTable_TEEC_Result), teerc,
582 Do_ADBG_GetEnumName(orig, ADBG_EnumTable_TEEC_ErrorOrigin));
583 return 0;
584
585error:
586 fprintf(stderr, "Out of bounds memref test FAILURE:\n");
587 fprintf(stderr,
588 "Shm size 0x%zx, offset 0x%zx/size 0x%zx: %s/0x%x from %s\n",
589 out->size, offset, size,
590 Do_ADBG_GetEnumName(teerc, ADBG_EnumTable_TEEC_Result), teerc,
591 Do_ADBG_GetEnumName(orig, ADBG_EnumTable_TEEC_ErrorOrigin));
592 return 1;
593}
594
595int sdp_out_of_bounds_memref_test(size_t size, int ion_heap, int verbosity)
596{
597 struct tee_ctx ctx = { };
598 int err = 0;
599 int fd = -1;
600 TEEC_Result teerc = TEEC_ERROR_GENERIC;
601 TEEC_SharedMemory in = { };
602 TEEC_SharedMemory *out = NULL;
603
604 if (create_tee_ctx(&ctx, TEST_NS_TO_TA))
605 return -1;
606
607 fd = allocate_ion_buffer(size, ion_heap, verbosity);
608 if (fd < 0) {
609 verbose("SDP alloc failed (%zu bytes) in ION heap %d: %d\n",
610 size, ion_heap, fd);
611 err = 1;
612 goto bail;
613 }
614 if (tee_register_buffer(&ctx, (void **)&out, fd)) {
615 err = 1;
616 goto bail;
617 }
618
619 /*
620 * The ION driver will decide how much SDP memory is being allocated.
621 * Rely on this size to test out of bounds reference cases.
622 */
623 size = out->size;
624
625 in.size = size;
626 in.flags = TEEC_MEM_INPUT;
627 teerc = TEEC_AllocateSharedMemory(&ctx.ctx, &in);
628 if (teerc) {
629 verbose("failed to allocate memory\n");
630 goto bail;
631 }
632
633 if (verbosity) {
634 /* Valid case: reference inside allocated buffer: last byte */
635 err += invoke_out_of_bounds(&ctx, &in, out, size - 1, 1,
636 true, verbosity);
637 }
638
639 /* Reference overflows allocated buffer by 1 byte */
640 err += invoke_out_of_bounds(&ctx, &in, out, size - 1, 2,
641 false, verbosity);
642
643 /* Reference oveflows allocated buffer by more than 4kB byte */
644 err += invoke_out_of_bounds(&ctx, &in, out, size - 1, 5000,
645 false, verbosity);
646
647 /* Offset exceeds allocated buffer size value by 1 byte */
648 err += invoke_out_of_bounds(&ctx, &in, out, size, 1,
649 false, verbosity);
650
651 /* Offset exceeds allocated size value by 4kByte */
652 err += invoke_out_of_bounds(&ctx, &in, out, size, 4096,
653 false, verbosity);
654
655 /* Offset + size overflows offset value */
656 err += invoke_out_of_bounds(&ctx, &in, out, 2, ~0,
657 false, verbosity);
658
659 TEEC_ReleaseSharedMemory(&in);
660bail:
661 tee_deregister_buffer(&ctx, out);
662 if (fd >= 0)
663 close(fd);
664 finalize_tee_ctx(&ctx);
665
666 return err;
667}
668
Etienne Carriere41343db2017-03-17 15:38:52 +0100669#define _TO_STR(x) #x
670#define TO_STR(x) _TO_STR(x)
671
672static void usage(const char *progname, size_t size, int loop, int ion_heap)
673{
674 fprintf(stderr, "Usage: %s [OPTION]\n", progname);
675 fprintf(stderr,
676 "Testing basic accesses to secure buffer (SDP) on OP-TEE.\n"
677 "Allocates a secure buffer and invoke a TA to access it.\n"
678 "TA is used to init/transform/dump the secure buffer.\n"
679 "CA check dumped content.\n\n");
680
681 fprintf(stderr, "Options:\n");
682 fprintf(stderr, " -h|--help Print this help and exit\n");
683 fprintf(stderr, " -v Be verbose\n");
684 fprintf(stderr, " -s SIZE SDP buffer byte size [%zu]\n", size);
685 fprintf(stderr, " -n LOOP Test loop iterations [%u]\n", loop);
686 fprintf(stderr, " --ion-heap ID Target ION heap ID [%d]\n", ion_heap);
687 fprintf(stderr, " --no-offset No random offset [0 255] in buffer\n");
688}
689
690#define NEXT_ARG(i) \
691 do { \
692 if (++i == argc) { \
693 fprintf(stderr, "%s: %s: missing argument\n", \
694 argv[0], argv[i-1]); \
695 return 1; \
696 } \
697 } while (0);
698
Jerome Forissiere1342522017-05-19 09:25:53 +0200699#define CHECK_RESULT(_res, _exp, _action) \
700 if ((_res) == (_exp)) { \
701 verbose("Test passed\n"); \
702 } else { \
703 verbose("Test failed!\n"); \
704 _action; \
705 }
706
Etienne Carriere41343db2017-03-17 15:38:52 +0100707int sdp_basic_runner_cmd_parser(int argc, char *argv[])
708{
709 size_t test_size = 5000;
710 size_t test_loop = 1000;
711 int ion_heap = DEFAULT_ION_HEAP_TYPE;
712 int rnd_offset = 1;
Etienne Carriereb9a95822017-04-26 15:03:53 +0200713 int verbosity = 1;
Etienne Carrieree4ec9e42019-03-28 13:30:21 +0100714 int err = 0;
715 int i = 0;
Etienne Carriere41343db2017-03-17 15:38:52 +0100716
717 /* Parse command line */
718 for (i = 1; i < argc; i++) {
719 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
720 usage(argv[0], test_size, test_loop, ion_heap);
721 return 0;
722 }
723 }
724 for (i = 1; i < argc; i++) {
725 if (!strcmp(argv[i], "-v")) {
726 verbosity++;
727 } else if (!strcmp(argv[i], "-s")) {
728 NEXT_ARG(i);
729 test_size = atoi(argv[i]);
730 } else if (!strcmp(argv[i], "-n")) {
731 NEXT_ARG(i);
732 test_loop = atoi(argv[i]);
733 } else if (!strcmp(argv[i], "--ion-heap")) {
734 NEXT_ARG(i);
735 ion_heap = atoi(argv[i]);
736 } else if (!strcmp(argv[i], "--no-offset")) {
737 rnd_offset = 0;
738 } else {
739 fprintf(stderr, "%s: invalid argument: %s\n",
740 argv[0], argv[i]);
741 usage(argv[0], test_size, test_loop, ion_heap);
742 return 1;
743 }
744 }
745
Jerome Forissiere1342522017-05-19 09:25:53 +0200746 verbose("\nSecure Data Path basic access: "
747 "NS invokes SDP TA\n");
748 err = sdp_basic_test(TEST_NS_TO_TA, test_size, test_loop, ion_heap,
749 rnd_offset, verbosity);
750 CHECK_RESULT(err, 0, return 1);
Etienne Carriere41343db2017-03-17 15:38:52 +0100751
Jerome Forissiere1342522017-05-19 09:25:53 +0200752 verbose("\nSecure Data Path basic access: "
753 "SDP TA invokes SDP TA\n");
754 err = sdp_basic_test(TEST_TA_TO_TA, test_size, test_loop, ion_heap,
755 rnd_offset, verbosity);
756 CHECK_RESULT(err, 0, return 1);
Etienne Carrierec45d9762017-03-21 15:45:13 +0100757
Jerome Forissiere1342522017-05-19 09:25:53 +0200758 verbose("\nSecure Data Path basic access: "
759 "SDP TA invokes SDP pTA\n");
760 err = sdp_basic_test(TEST_TA_TO_PTA, test_size, test_loop, ion_heap,
761 rnd_offset, verbosity);
762 CHECK_RESULT(err, 0, return 1);
Etienne Carriere41343db2017-03-17 15:38:52 +0100763
Jerome Forissiere1342522017-05-19 09:25:53 +0200764 verbose("\nSecure Data Path basic access: "
765 "NS invokes SDP pTA (shall fail)\n");
766 err = sdp_basic_test(TEST_NS_TO_PTA, test_size, test_loop, ion_heap,
767 rnd_offset, verbosity);
768 CHECK_RESULT(err, 1, return 1);
Etienne Carriered1655822017-03-21 15:45:24 +0100769
Etienne Carriered9be3dc2018-04-25 18:30:19 +0200770 verbose("\nSecure Data Path basic access: "
771 "Invoke TA with out of bounds buffer references\n");
772 err = sdp_out_of_bounds_memref_test(test_size, ion_heap, verbosity);
773 CHECK_RESULT(err, 0, return 1);
774
Etienne Carriere41343db2017-03-17 15:38:52 +0100775 return 0;
776}