1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2017, 2019, Linaro Limited
4 * Copyright (c) 2020, Arm Limited.
5 */
6
7 /*
8 * Security properties of REE-FS TAs
9 * =================================
10 *
11 * Authentication only
12 * -------------------
13 *
14 * Required security properties:
15 * 1. Authentication and non-repudiation of a TA to Service Provider (SP).
16 * 2. Integrity of a TA.
17 *
18 * To satisfy (1) and (2), SP needs to sign TA and OP-TEE core needs to verify
19 * the signature using SP public key with computed hash of the TA.
20 *
21 * Authentication along with Confidentiality
22 * -----------------------------------------
23 *
24 * Required security properties:
25 * 1. Authentication and non-repudiation of a TA to Service Provider (SP).
26 * 2. Confidentiality of a TA.
27 * 3. Integrity of an encrypted TA blob.
28 *
29 * To satisfy (1), SP needs to sign plain TA and OP-TEE core needs to verify the
30 * signature using SP public key with computed hash of the TA.
31 *
32 * To satisfy (2) and (3), SP needs to do authenticated encryption of TA and
33 * OP-TEE core needs to do authenticated decryption of TA to retrieve its
34 * contents. Here encryption provides the confidentiality of TA and MAC tag
35 * provides the integrity of encrypted TA blob.
36 */
37
38 #include <assert.h>
39 #include <crypto/crypto.h>
40 #include <initcall.h>
41 #include <kernel/thread.h>
42 #include <kernel/ts_store.h>
43 #include <mm/core_memprot.h>
44 #include <mm/tee_mm.h>
45 #include <mm/mobj.h>
46 #include <optee_rpc_cmd.h>
47 #include <signed_hdr.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <tee_api_defines_extensions.h>
51 #include <tee_api_types.h>
52 #include <tee/tee_pobj.h>
53 #include <tee/tee_svc_storage.h>
54 #include <tee/tee_ta_enc_manager.h>
55 #include <tee/uuid.h>
56 #include <utee_defines.h>
57
58 struct ree_fs_ta_handle {
59 struct shdr *nw_ta; /* Non-secure (shared memory) */
60 size_t nw_ta_size;
61 struct mobj *mobj;
62 size_t offs;
63 struct shdr *shdr; /* Verified secure copy of @nw_ta's signed header */
64 void *hash_ctx;
65 void *enc_ctx;
66 struct shdr_bootstrap_ta *bs_hdr;
67 struct shdr_encrypted_ta *ehdr;
68 };
69
70 struct ta_ver_db_hdr {
71 uint32_t db_version;
72 uint32_t nb_entries;
73 };
74
75 static const char ta_ver_db_obj_id[] = "ta_ver.db";
76 static struct mutex ta_ver_db_mutex = MUTEX_INITIALIZER;
77
78 /*
79 * Load a TA via RPC with UUID defined by input param @uuid. The virtual
80 * address of the raw TA binary is received in out parameter @ta.
81 */
rpc_load(const TEE_UUID * uuid,struct shdr ** ta,size_t * ta_size,struct mobj ** mobj)82 static TEE_Result rpc_load(const TEE_UUID *uuid, struct shdr **ta,
83 size_t *ta_size, struct mobj **mobj)
84 {
85 TEE_Result res;
86 struct thread_param params[2];
87
88 if (!uuid || !ta || !mobj || !ta_size)
89 return TEE_ERROR_BAD_PARAMETERS;
90
91 memset(params, 0, sizeof(params));
92 params[0].attr = THREAD_PARAM_ATTR_VALUE_IN;
93 tee_uuid_to_octets((void *)¶ms[0].u.value, uuid);
94 params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT;
95
96 res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params);
97 if (res != TEE_SUCCESS)
98 return res;
99
100 *mobj = thread_rpc_alloc_payload(params[1].u.memref.size);
101 if (!*mobj)
102 return TEE_ERROR_OUT_OF_MEMORY;
103
104 *ta = mobj_get_va(*mobj, 0, params[1].u.memref.size);
105 if (!*ta) {
106 res = TEE_ERROR_SHORT_BUFFER;
107 goto exit;
108 }
109 /* We don't expect NULL as thread_rpc_alloc_payload() was successful */
110 assert(*ta);
111 *ta_size = params[1].u.memref.size;
112
113 params[0].attr = THREAD_PARAM_ATTR_VALUE_IN;
114 tee_uuid_to_octets((void *)¶ms[0].u.value, uuid);
115 params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT;
116 params[1].u.memref.offs = 0;
117 params[1].u.memref.mobj = *mobj;
118
119 res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params);
120 exit:
121 if (res != TEE_SUCCESS)
122 thread_rpc_free_payload(*mobj);
123
124 return res;
125 }
126
ree_fs_ta_open(const TEE_UUID * uuid,struct ts_store_handle ** h)127 static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
128 struct ts_store_handle **h)
129 {
130 struct ree_fs_ta_handle *handle;
131 struct shdr *shdr = NULL;
132 struct mobj *mobj = NULL;
133 void *hash_ctx = NULL;
134 struct shdr *ta = NULL;
135 size_t ta_size = 0;
136 TEE_Result res = TEE_SUCCESS;
137 size_t offs = 0;
138 struct shdr_bootstrap_ta *bs_hdr = NULL;
139 struct shdr_encrypted_ta *ehdr = NULL;
140 size_t shdr_sz = 0;
141
142 handle = calloc(1, sizeof(*handle));
143 if (!handle)
144 return TEE_ERROR_OUT_OF_MEMORY;
145
146 /* Request TA from tee-supplicant */
147 res = rpc_load(uuid, &ta, &ta_size, &mobj);
148 if (res != TEE_SUCCESS)
149 goto error;
150
151 /* Make secure copy of signed header */
152 shdr = shdr_alloc_and_copy(ta, ta_size);
153 if (!shdr) {
154 res = TEE_ERROR_SECURITY;
155 goto error_free_payload;
156 }
157
158 /* Validate header signature */
159 res = shdr_verify_signature(shdr);
160 if (res != TEE_SUCCESS)
161 goto error_free_payload;
162 if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA &&
163 shdr->img_type != SHDR_ENCRYPTED_TA) {
164 res = TEE_ERROR_SECURITY;
165 goto error_free_payload;
166 }
167
168 /*
169 * Initialize a hash context and run the algorithm over the signed
170 * header (less the final file hash and its signature of course)
171 */
172 res = crypto_hash_alloc_ctx(&hash_ctx,
173 TEE_DIGEST_HASH_TO_ALGO(shdr->algo));
174 if (res != TEE_SUCCESS)
175 goto error_free_payload;
176 res = crypto_hash_init(hash_ctx);
177 if (res != TEE_SUCCESS)
178 goto error_free_hash;
179 res = crypto_hash_update(hash_ctx, (uint8_t *)shdr, sizeof(*shdr));
180 if (res != TEE_SUCCESS)
181 goto error_free_hash;
182 shdr_sz = SHDR_GET_SIZE(shdr);
183 if (!shdr_sz) {
184 res = TEE_ERROR_SECURITY;
185 goto error_free_hash;
186 }
187 offs = shdr_sz;
188
189 if (shdr->img_type == SHDR_BOOTSTRAP_TA ||
190 shdr->img_type == SHDR_ENCRYPTED_TA) {
191 TEE_UUID bs_uuid = { };
192 size_t sz = shdr_sz;
193
194 if (ADD_OVERFLOW(sz, sizeof(*bs_hdr), &sz) || ta_size < sz) {
195 res = TEE_ERROR_SECURITY;
196 goto error_free_hash;
197 }
198
199 bs_hdr = malloc(sizeof(*bs_hdr));
200 if (!bs_hdr) {
201 res = TEE_ERROR_OUT_OF_MEMORY;
202 goto error_free_hash;
203 }
204
205 memcpy(bs_hdr, (uint8_t *)ta + offs, sizeof(*bs_hdr));
206
207 /*
208 * There's a check later that the UUID embedded inside the
209 * ELF is matching, but since we now have easy access to
210 * the expected uuid of the TA we check it a bit earlier
211 * here.
212 */
213 tee_uuid_from_octets(&bs_uuid, bs_hdr->uuid);
214 if (memcmp(&bs_uuid, uuid, sizeof(TEE_UUID))) {
215 res = TEE_ERROR_SECURITY;
216 goto error_free_hash;
217 }
218
219 res = crypto_hash_update(hash_ctx, (uint8_t *)bs_hdr,
220 sizeof(*bs_hdr));
221 if (res != TEE_SUCCESS)
222 goto error_free_hash;
223 offs += sizeof(*bs_hdr);
224 handle->bs_hdr = bs_hdr;
225 }
226
227 if (shdr->img_type == SHDR_ENCRYPTED_TA) {
228 struct shdr_encrypted_ta img_ehdr = { };
229 size_t sz = shdr_sz;
230 size_t ehdr_sz = 0;
231
232 if (ADD_OVERFLOW(sz, sizeof(struct shdr_bootstrap_ta), &sz) ||
233 ADD_OVERFLOW(sz, sizeof(img_ehdr), &sz) ||
234 ta_size < sz) {
235 res = TEE_ERROR_SECURITY;
236 goto error_free_hash;
237 }
238
239 memcpy(&img_ehdr, ((uint8_t *)ta + offs), sizeof(img_ehdr));
240 ehdr_sz = SHDR_ENC_GET_SIZE(&img_ehdr);
241 sz -= sizeof(img_ehdr);
242 if (!ehdr_sz || ADD_OVERFLOW(sz, ehdr_sz, &sz) ||
243 ta_size < sz) {
244 res = TEE_ERROR_SECURITY;
245 goto error_free_hash;
246 }
247
248
249 ehdr = malloc(ehdr_sz);
250 if (!ehdr) {
251 res = TEE_ERROR_OUT_OF_MEMORY;
252 goto error_free_hash;
253 }
254
255 memcpy(ehdr, ((uint8_t *)ta + offs), ehdr_sz);
256
257 res = crypto_hash_update(hash_ctx, (uint8_t *)ehdr, ehdr_sz);
258 if (res != TEE_SUCCESS)
259 goto error_free_hash;
260
261 res = tee_ta_decrypt_init(&handle->enc_ctx, ehdr,
262 shdr->img_size);
263 if (res != TEE_SUCCESS)
264 goto error_free_hash;
265
266 offs += ehdr_sz;
267 handle->ehdr = ehdr;
268 }
269
270 if (ta_size != offs + shdr->img_size) {
271 res = TEE_ERROR_SECURITY;
272 goto error_free_hash;
273 }
274
275 handle->nw_ta = ta;
276 handle->nw_ta_size = ta_size;
277 handle->offs = offs;
278 handle->hash_ctx = hash_ctx;
279 handle->shdr = shdr;
280 handle->mobj = mobj;
281 *h = (struct ts_store_handle *)handle;
282 return TEE_SUCCESS;
283
284 error_free_hash:
285 crypto_hash_free_ctx(hash_ctx);
286 error_free_payload:
287 thread_rpc_free_payload(mobj);
288 error:
289 free(ehdr);
290 free(bs_hdr);
291 shdr_free(shdr);
292 free(handle);
293 return res;
294 }
295
ree_fs_ta_get_size(const struct ts_store_handle * h,size_t * size)296 static TEE_Result ree_fs_ta_get_size(const struct ts_store_handle *h,
297 size_t *size)
298 {
299 struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
300
301 *size = handle->shdr->img_size;
302 return TEE_SUCCESS;
303 }
304
ree_fs_ta_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)305 static TEE_Result ree_fs_ta_get_tag(const struct ts_store_handle *h,
306 uint8_t *tag, unsigned int *tag_len)
307 {
308 struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
309
310 if (!tag || *tag_len < handle->shdr->hash_size) {
311 *tag_len = handle->shdr->hash_size;
312 return TEE_ERROR_SHORT_BUFFER;
313 }
314 *tag_len = handle->shdr->hash_size;
315
316 memcpy(tag, SHDR_GET_HASH(handle->shdr), handle->shdr->hash_size);
317
318 return TEE_SUCCESS;
319 }
320
check_digest(struct ree_fs_ta_handle * h)321 static TEE_Result check_digest(struct ree_fs_ta_handle *h)
322 {
323 void *digest = NULL;
324 TEE_Result res;
325
326 digest = malloc(h->shdr->hash_size);
327 if (!digest)
328 return TEE_ERROR_OUT_OF_MEMORY;
329 res = crypto_hash_final(h->hash_ctx, digest, h->shdr->hash_size);
330 if (res != TEE_SUCCESS) {
331 res = TEE_ERROR_SECURITY;
332 goto out;
333 }
334 if (memcmp(digest, SHDR_GET_HASH(h->shdr), h->shdr->hash_size))
335 res = TEE_ERROR_SECURITY;
336 out:
337 free(digest);
338 return res;
339 }
340
check_update_version(struct shdr_bootstrap_ta * hdr)341 static TEE_Result check_update_version(struct shdr_bootstrap_ta *hdr)
342 {
343 struct shdr_bootstrap_ta hdr_entry = { };
344 const struct tee_file_operations *ops = NULL;
345 struct tee_file_handle *fh = NULL;
346 TEE_Result res = TEE_SUCCESS;
347 bool entry_found = false;
348 size_t len = 0;
349 unsigned int i = 0;
350 struct ta_ver_db_hdr db_hdr = { };
351 struct tee_pobj pobj = {
352 .obj_id = (void *)ta_ver_db_obj_id,
353 .obj_id_len = sizeof(ta_ver_db_obj_id)
354 };
355
356 ops = tee_svc_storage_file_ops(TEE_STORAGE_PRIVATE);
357 if (!ops)
358 return TEE_SUCCESS; /* Compiled with no secure storage */
359
360 mutex_lock(&ta_ver_db_mutex);
361
362 res = ops->open(&pobj, NULL, &fh);
363 if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
364 goto out;
365
366 if (res == TEE_ERROR_ITEM_NOT_FOUND) {
367 res = ops->create(&pobj, false, NULL, 0, NULL, 0, NULL, 0, &fh);
368 if (res != TEE_SUCCESS)
369 goto out;
370
371 res = ops->write(fh, 0, &db_hdr, sizeof(db_hdr));
372 if (res != TEE_SUCCESS)
373 goto out;
374 } else {
375 len = sizeof(db_hdr);
376
377 res = ops->read(fh, 0, &db_hdr, &len);
378 if (res != TEE_SUCCESS) {
379 goto out;
380 } else if (len != sizeof(db_hdr)) {
381 res = TEE_ERROR_BAD_STATE;
382 goto out;
383 }
384 }
385
386 for (i = 0; i < db_hdr.nb_entries; i++) {
387 len = sizeof(hdr_entry);
388
389 res = ops->read(fh, sizeof(db_hdr) + (i * len), &hdr_entry,
390 &len);
391 if (res != TEE_SUCCESS) {
392 goto out;
393 } else if (len != sizeof(hdr_entry)) {
394 res = TEE_ERROR_BAD_STATE;
395 goto out;
396 }
397
398 if (!memcmp(hdr->uuid, hdr_entry.uuid, sizeof(TEE_UUID))) {
399 entry_found = true;
400 break;
401 }
402 }
403
404 if (entry_found) {
405 if (hdr_entry.ta_version > hdr->ta_version) {
406 res = TEE_ERROR_ACCESS_CONFLICT;
407 goto out;
408 } else if (hdr_entry.ta_version < hdr->ta_version) {
409 len = sizeof(*hdr);
410 res = ops->write(fh, sizeof(db_hdr) + (i * len), hdr,
411 len);
412 if (res != TEE_SUCCESS)
413 goto out;
414 }
415 } else {
416 len = sizeof(*hdr);
417 res = ops->write(fh, sizeof(db_hdr) + (db_hdr.nb_entries * len),
418 hdr, len);
419 if (res != TEE_SUCCESS)
420 goto out;
421
422 db_hdr.nb_entries++;
423 res = ops->write(fh, 0, &db_hdr, sizeof(db_hdr));
424 if (res != TEE_SUCCESS)
425 goto out;
426 }
427
428 out:
429 ops->close(&fh);
430 mutex_unlock(&ta_ver_db_mutex);
431 return res;
432 }
433
ree_fs_ta_read(struct ts_store_handle * h,void * data,size_t len)434 static TEE_Result ree_fs_ta_read(struct ts_store_handle *h, void *data,
435 size_t len)
436 {
437 struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
438
439 uint8_t *src = (uint8_t *)handle->nw_ta + handle->offs;
440 size_t next_offs = 0;
441 uint8_t *dst = src;
442 TEE_Result res = TEE_SUCCESS;
443
444 if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
445 next_offs > handle->nw_ta_size)
446 return TEE_ERROR_BAD_PARAMETERS;
447
448 if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
449 if (data) {
450 dst = data; /* Hash secure buffer */
451 res = tee_ta_decrypt_update(handle->enc_ctx, dst, src,
452 len);
453 if (res != TEE_SUCCESS)
454 return TEE_ERROR_SECURITY;
455 } else {
456 size_t num_bytes = 0;
457 size_t b_size = MIN(1024U, len);
458 uint8_t *b = malloc(b_size);
459
460 if (!b)
461 return TEE_ERROR_OUT_OF_MEMORY;
462
463 dst = NULL;
464 while (num_bytes < len) {
465 size_t n = MIN(b_size, len - num_bytes);
466
467 res = tee_ta_decrypt_update(handle->enc_ctx, b,
468 src + num_bytes, n);
469 if (res)
470 break;
471 num_bytes += n;
472
473 res = crypto_hash_update(handle->hash_ctx, b,
474 n);
475 if (res)
476 break;
477 }
478
479 free(b);
480 if (res != TEE_SUCCESS)
481 return TEE_ERROR_SECURITY;
482 }
483 } else if (data) {
484 dst = data; /* Hash secure buffer (shm might be modified) */
485 memcpy(dst, src, len);
486 }
487
488 if (dst) {
489 res = crypto_hash_update(handle->hash_ctx, dst, len);
490 if (res != TEE_SUCCESS)
491 return TEE_ERROR_SECURITY;
492 }
493
494 handle->offs = next_offs;
495 if (handle->offs == handle->nw_ta_size) {
496 if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
497 /*
498 * Last read: time to finalize authenticated
499 * decryption.
500 */
501 res = tee_ta_decrypt_final(handle->enc_ctx,
502 handle->ehdr, NULL, NULL, 0);
503 if (res != TEE_SUCCESS)
504 return TEE_ERROR_SECURITY;
505 }
506 /*
507 * Last read: time to check if our digest matches the expected
508 * one (from the signed header)
509 */
510 res = check_digest(handle);
511 if (res != TEE_SUCCESS)
512 return res;
513
514 if (handle->bs_hdr)
515 res = check_update_version(handle->bs_hdr);
516 }
517 return res;
518 }
519
ree_fs_ta_close(struct ts_store_handle * h)520 static void ree_fs_ta_close(struct ts_store_handle *h)
521 {
522 struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
523
524 if (!handle)
525 return;
526 thread_rpc_free_payload(handle->mobj);
527 crypto_hash_free_ctx(handle->hash_ctx);
528 free(handle->shdr);
529 free(handle->ehdr);
530 free(handle->bs_hdr);
531 free(handle);
532 }
533
534 #ifndef CFG_REE_FS_TA_BUFFERED
535 REGISTER_TA_STORE(9) = {
536 .description = "REE",
537 .open = ree_fs_ta_open,
538 .get_size = ree_fs_ta_get_size,
539 .get_tag = ree_fs_ta_get_tag,
540 .read = ree_fs_ta_read,
541 .close = ree_fs_ta_close,
542 };
543 #endif
544
545 #ifdef CFG_REE_FS_TA_BUFFERED
546
547 /*
548 * This is a wrapper around the "REE FS" TA store.
549 * The whole TA/library is read into a temporary buffer during .open(). This
550 * allows the binary to be authenticated before any data is read and processed
551 * by the upper layer (ELF loader).
552 */
553
554 struct buf_ree_fs_ta_handle {
555 struct ts_store_handle *h; /* Note: a REE FS TA store handle */
556 size_t ta_size;
557 tee_mm_entry_t *mm;
558 uint8_t *buf;
559 size_t offs;
560 uint8_t *tag;
561 unsigned int tag_len;
562 };
563
buf_ta_open(const TEE_UUID * uuid,struct ts_store_handle ** h)564 static TEE_Result buf_ta_open(const TEE_UUID *uuid,
565 struct ts_store_handle **h)
566 {
567 struct buf_ree_fs_ta_handle *handle = NULL;
568 TEE_Result res = TEE_SUCCESS;
569
570 handle = calloc(1, sizeof(*handle));
571 if (!handle)
572 return TEE_ERROR_OUT_OF_MEMORY;
573 res = ree_fs_ta_open(uuid, &handle->h);
574 if (res)
575 goto err2;
576 res = ree_fs_ta_get_size(handle->h, &handle->ta_size);
577 if (res)
578 goto err;
579
580 res = ree_fs_ta_get_tag(handle->h, NULL, &handle->tag_len);
581 if (res != TEE_ERROR_SHORT_BUFFER) {
582 res = TEE_ERROR_GENERIC;
583 goto err;
584 }
585 handle->tag = malloc(handle->tag_len);
586 if (!handle->tag) {
587 res = TEE_ERROR_OUT_OF_MEMORY;
588 goto err;
589 }
590 res = ree_fs_ta_get_tag(handle->h, handle->tag, &handle->tag_len);
591 if (res)
592 goto err;
593
594 handle->mm = tee_mm_alloc(&tee_mm_sec_ddr, handle->ta_size);
595 if (!handle->mm) {
596 res = TEE_ERROR_OUT_OF_MEMORY;
597 goto err;
598 }
599 handle->buf = phys_to_virt(tee_mm_get_smem(handle->mm),
600 MEM_AREA_TA_RAM, handle->ta_size);
601 if (!handle->buf) {
602 res = TEE_ERROR_OUT_OF_MEMORY;
603 goto err;
604 }
605 res = ree_fs_ta_read(handle->h, handle->buf, handle->ta_size);
606 if (res)
607 goto err;
608 *h = (struct ts_store_handle *)handle;
609 err:
610 ree_fs_ta_close(handle->h);
611 err2:
612 if (res) {
613 tee_mm_free(handle->mm);
614 free(handle->tag);
615 free(handle);
616 }
617 return res;
618 }
619
buf_ta_get_size(const struct ts_store_handle * h,size_t * size)620 static TEE_Result buf_ta_get_size(const struct ts_store_handle *h,
621 size_t *size)
622 {
623 struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
624
625 *size = handle->ta_size;
626 return TEE_SUCCESS;
627 }
628
buf_ta_read(struct ts_store_handle * h,void * data,size_t len)629 static TEE_Result buf_ta_read(struct ts_store_handle *h, void *data,
630 size_t len)
631 {
632 struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
633 uint8_t *src = handle->buf + handle->offs;
634 size_t next_offs = 0;
635
636 if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
637 next_offs > handle->ta_size)
638 return TEE_ERROR_BAD_PARAMETERS;
639
640 if (data)
641 memcpy(data, src, len);
642 handle->offs = next_offs;
643 return TEE_SUCCESS;
644 }
645
buf_ta_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)646 static TEE_Result buf_ta_get_tag(const struct ts_store_handle *h,
647 uint8_t *tag, unsigned int *tag_len)
648 {
649 struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
650
651 *tag_len = handle->tag_len;
652 if (!tag || *tag_len < handle->tag_len)
653 return TEE_ERROR_SHORT_BUFFER;
654
655 memcpy(tag, handle->tag, handle->tag_len);
656
657 return TEE_SUCCESS;
658 }
659
buf_ta_close(struct ts_store_handle * h)660 static void buf_ta_close(struct ts_store_handle *h)
661 {
662 struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
663
664 if (!handle)
665 return;
666 tee_mm_free(handle->mm);
667 free(handle->tag);
668 free(handle);
669 }
670
671 REGISTER_TA_STORE(9) = {
672 .description = "REE [buffered]",
673 .open = buf_ta_open,
674 .get_size = buf_ta_get_size,
675 .get_tag = buf_ta_get_tag,
676 .read = buf_ta_read,
677 .close = buf_ta_close,
678 };
679
680 #endif /* CFG_REE_FS_TA_BUFFERED */
681