xref: /optee_os/core/kernel/ree_fs_ta.c (revision c04a96a45ffe0e665a4d86e542ec921fae932aa8)
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  */
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 *)&params[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 	if ((*mobj)->size < params[1].u.memref.size) {
105 		res = TEE_ERROR_SHORT_BUFFER;
106 		goto exit;
107 	}
108 
109 	*ta = mobj_get_va(*mobj, 0);
110 	/* We don't expect NULL as thread_rpc_alloc_payload() was successful */
111 	assert(*ta);
112 	*ta_size = params[1].u.memref.size;
113 
114 	params[0].attr = THREAD_PARAM_ATTR_VALUE_IN;
115 	tee_uuid_to_octets((void *)&params[0].u.value, uuid);
116 	params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT;
117 	params[1].u.memref.offs = 0;
118 	params[1].u.memref.mobj = *mobj;
119 
120 	res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params);
121 exit:
122 	if (res != TEE_SUCCESS)
123 		thread_rpc_free_payload(*mobj);
124 
125 	return res;
126 }
127 
128 static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
129 				 struct ts_store_handle **h)
130 {
131 	struct ree_fs_ta_handle *handle;
132 	struct shdr *shdr = NULL;
133 	struct mobj *mobj = NULL;
134 	void *hash_ctx = NULL;
135 	struct shdr *ta = NULL;
136 	size_t ta_size = 0;
137 	TEE_Result res;
138 	size_t offs;
139 	struct shdr_bootstrap_ta *bs_hdr = NULL;
140 	struct shdr_encrypted_ta *ehdr = NULL;
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 	offs = SHDR_GET_SIZE(shdr);
183 
184 	if (shdr->img_type == SHDR_BOOTSTRAP_TA ||
185 	    shdr->img_type == SHDR_ENCRYPTED_TA) {
186 		TEE_UUID bs_uuid;
187 
188 		if (ta_size < SHDR_GET_SIZE(shdr) + sizeof(*bs_hdr)) {
189 			res = TEE_ERROR_SECURITY;
190 			goto error_free_hash;
191 		}
192 
193 		bs_hdr = malloc(sizeof(*bs_hdr));
194 		if (!bs_hdr) {
195 			res = TEE_ERROR_OUT_OF_MEMORY;
196 			goto error_free_hash;
197 		}
198 
199 		memcpy(bs_hdr, (uint8_t *)ta + offs, sizeof(*bs_hdr));
200 
201 		/*
202 		 * There's a check later that the UUID embedded inside the
203 		 * ELF is matching, but since we now have easy access to
204 		 * the expected uuid of the TA we check it a bit earlier
205 		 * here.
206 		 */
207 		tee_uuid_from_octets(&bs_uuid, bs_hdr->uuid);
208 		if (memcmp(&bs_uuid, uuid, sizeof(TEE_UUID))) {
209 			res = TEE_ERROR_SECURITY;
210 			goto error_free_hash;
211 		}
212 
213 		res = crypto_hash_update(hash_ctx, (uint8_t *)bs_hdr,
214 					 sizeof(*bs_hdr));
215 		if (res != TEE_SUCCESS)
216 			goto error_free_hash;
217 		offs += sizeof(*bs_hdr);
218 		handle->bs_hdr = bs_hdr;
219 	}
220 
221 	if (shdr->img_type == SHDR_ENCRYPTED_TA) {
222 		struct shdr_encrypted_ta img_ehdr;
223 
224 		if (ta_size < SHDR_GET_SIZE(shdr) +
225 		    sizeof(struct shdr_bootstrap_ta) + sizeof(img_ehdr)) {
226 			res = TEE_ERROR_SECURITY;
227 			goto error_free_hash;
228 		}
229 
230 		memcpy(&img_ehdr, ((uint8_t *)ta + offs), sizeof(img_ehdr));
231 
232 		ehdr = malloc(SHDR_ENC_GET_SIZE(&img_ehdr));
233 		if (!ehdr) {
234 			res = TEE_ERROR_OUT_OF_MEMORY;
235 			goto error_free_hash;
236 		}
237 
238 		memcpy(ehdr, ((uint8_t *)ta + offs),
239 		       SHDR_ENC_GET_SIZE(&img_ehdr));
240 
241 		res = crypto_hash_update(hash_ctx, (uint8_t *)ehdr,
242 					 SHDR_ENC_GET_SIZE(ehdr));
243 		if (res != TEE_SUCCESS)
244 			goto error_free_hash;
245 
246 		res = tee_ta_decrypt_init(&handle->enc_ctx, ehdr,
247 					  shdr->img_size);
248 		if (res != TEE_SUCCESS)
249 			goto error_free_hash;
250 
251 		offs += SHDR_ENC_GET_SIZE(ehdr);
252 		handle->ehdr = ehdr;
253 	}
254 
255 	if (ta_size != offs + shdr->img_size) {
256 		res = TEE_ERROR_SECURITY;
257 		goto error_free_hash;
258 	}
259 
260 	handle->nw_ta = ta;
261 	handle->nw_ta_size = ta_size;
262 	handle->offs = offs;
263 	handle->hash_ctx = hash_ctx;
264 	handle->shdr = shdr;
265 	handle->mobj = mobj;
266 	*h = (struct ts_store_handle *)handle;
267 	return TEE_SUCCESS;
268 
269 error_free_hash:
270 	crypto_hash_free_ctx(hash_ctx);
271 error_free_payload:
272 	thread_rpc_free_payload(mobj);
273 error:
274 	free(ehdr);
275 	free(bs_hdr);
276 	shdr_free(shdr);
277 	free(handle);
278 	return res;
279 }
280 
281 static TEE_Result ree_fs_ta_get_size(const struct ts_store_handle *h,
282 				     size_t *size)
283 {
284 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
285 
286 	*size = handle->shdr->img_size;
287 	return TEE_SUCCESS;
288 }
289 
290 static TEE_Result ree_fs_ta_get_tag(const struct ts_store_handle *h,
291 				    uint8_t *tag, unsigned int *tag_len)
292 {
293 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
294 
295 	if (!tag || *tag_len < handle->shdr->hash_size) {
296 		*tag_len = handle->shdr->hash_size;
297 		return TEE_ERROR_SHORT_BUFFER;
298 	}
299 	*tag_len = handle->shdr->hash_size;
300 
301 	memcpy(tag, SHDR_GET_HASH(handle->shdr), handle->shdr->hash_size);
302 
303 	return TEE_SUCCESS;
304 }
305 
306 static TEE_Result check_digest(struct ree_fs_ta_handle *h)
307 {
308 	void *digest = NULL;
309 	TEE_Result res;
310 
311 	digest = malloc(h->shdr->hash_size);
312 	if (!digest)
313 		return TEE_ERROR_OUT_OF_MEMORY;
314 	res = crypto_hash_final(h->hash_ctx, digest, h->shdr->hash_size);
315 	if (res != TEE_SUCCESS) {
316 		res = TEE_ERROR_SECURITY;
317 		goto out;
318 	}
319 	if (memcmp(digest, SHDR_GET_HASH(h->shdr), h->shdr->hash_size))
320 		res = TEE_ERROR_SECURITY;
321 out:
322 	free(digest);
323 	return res;
324 }
325 
326 static TEE_Result check_update_version(struct shdr_bootstrap_ta *hdr)
327 {
328 	struct shdr_bootstrap_ta hdr_entry = { };
329 	const struct tee_file_operations *ops = NULL;
330 	struct tee_file_handle *fh = NULL;
331 	TEE_Result res = TEE_SUCCESS;
332 	bool entry_found = false;
333 	size_t len = 0;
334 	unsigned int i = 0;
335 	struct ta_ver_db_hdr db_hdr = { };
336 	struct tee_pobj pobj = {
337 		.obj_id = (void *)ta_ver_db_obj_id,
338 		.obj_id_len = sizeof(ta_ver_db_obj_id)
339 	};
340 
341 	mutex_lock(&ta_ver_db_mutex);
342 	ops = tee_svc_storage_file_ops(TEE_STORAGE_PRIVATE);
343 
344 	res = ops->open(&pobj, NULL, &fh);
345 	if (res != TEE_SUCCESS && res != TEE_ERROR_ITEM_NOT_FOUND)
346 		goto out;
347 
348 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
349 		res = ops->create(&pobj, false, NULL, 0, NULL, 0, NULL, 0, &fh);
350 		if (res != TEE_SUCCESS)
351 			goto out;
352 
353 		res = ops->write(fh, 0, &db_hdr, sizeof(db_hdr));
354 		if (res != TEE_SUCCESS)
355 			goto out;
356 	} else {
357 		len = sizeof(db_hdr);
358 
359 		res = ops->read(fh, 0, &db_hdr, &len);
360 		if (res != TEE_SUCCESS) {
361 			goto out;
362 		} else if (len != sizeof(db_hdr)) {
363 			res = TEE_ERROR_BAD_STATE;
364 			goto out;
365 		}
366 	}
367 
368 	for (i = 0; i < db_hdr.nb_entries; i++) {
369 		len = sizeof(hdr_entry);
370 
371 		res = ops->read(fh, sizeof(db_hdr) + (i * len), &hdr_entry,
372 				&len);
373 		if (res != TEE_SUCCESS) {
374 			goto out;
375 		} else if (len != sizeof(hdr_entry)) {
376 			res = TEE_ERROR_BAD_STATE;
377 			goto out;
378 		}
379 
380 		if (!memcmp(hdr->uuid, hdr_entry.uuid, sizeof(TEE_UUID))) {
381 			entry_found = true;
382 			break;
383 		}
384 	}
385 
386 	if (entry_found) {
387 		if (hdr_entry.ta_version > hdr->ta_version) {
388 			res = TEE_ERROR_ACCESS_CONFLICT;
389 			goto out;
390 		} else if (hdr_entry.ta_version < hdr->ta_version) {
391 			len = sizeof(*hdr);
392 			res = ops->write(fh, sizeof(db_hdr) + (i * len), hdr,
393 					 len);
394 			if (res != TEE_SUCCESS)
395 				goto out;
396 		}
397 	} else {
398 		len = sizeof(*hdr);
399 		res = ops->write(fh, sizeof(db_hdr) + (db_hdr.nb_entries * len),
400 				 hdr, len);
401 		if (res != TEE_SUCCESS)
402 			goto out;
403 
404 		db_hdr.nb_entries++;
405 		res = ops->write(fh, 0, &db_hdr, sizeof(db_hdr));
406 		if (res != TEE_SUCCESS)
407 			goto out;
408 	}
409 
410 out:
411 	ops->close(&fh);
412 	mutex_unlock(&ta_ver_db_mutex);
413 	return res;
414 }
415 
416 static TEE_Result ree_fs_ta_read(struct ts_store_handle *h, void *data,
417 				 size_t len)
418 {
419 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
420 
421 	uint8_t *src = (uint8_t *)handle->nw_ta + handle->offs;
422 	size_t next_offs = 0;
423 	uint8_t *dst = src;
424 	TEE_Result res = TEE_SUCCESS;
425 
426 	if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
427 	    next_offs > handle->nw_ta_size)
428 		return TEE_ERROR_BAD_PARAMETERS;
429 
430 	if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
431 		if (data) {
432 			dst = data; /* Hash secure buffer */
433 			res = tee_ta_decrypt_update(handle->enc_ctx, dst, src,
434 						    len);
435 			if (res != TEE_SUCCESS)
436 				return TEE_ERROR_SECURITY;
437 		} else {
438 			size_t num_bytes = 0;
439 			size_t b_size = MIN(1024U, len);
440 			uint8_t *b = malloc(b_size);
441 
442 			if (!b)
443 				return TEE_ERROR_OUT_OF_MEMORY;
444 
445 			dst = NULL;
446 			while (num_bytes < len) {
447 				size_t n = MIN(b_size, len - num_bytes);
448 
449 				res = tee_ta_decrypt_update(handle->enc_ctx, b,
450 							    src + num_bytes, n);
451 				if (res)
452 					break;
453 				num_bytes += n;
454 
455 				res = crypto_hash_update(handle->hash_ctx, b,
456 							 n);
457 				if (res)
458 					break;
459 			}
460 
461 			free(b);
462 			if (res != TEE_SUCCESS)
463 				return TEE_ERROR_SECURITY;
464 		}
465 	} else if (data) {
466 		dst = data; /* Hash secure buffer (shm might be modified) */
467 		memcpy(dst, src, len);
468 	}
469 
470 	if (dst) {
471 		res = crypto_hash_update(handle->hash_ctx, dst, len);
472 		if (res != TEE_SUCCESS)
473 			return TEE_ERROR_SECURITY;
474 	}
475 
476 	handle->offs = next_offs;
477 	if (handle->offs == handle->nw_ta_size) {
478 		if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
479 			/*
480 			 * Last read: time to finalize authenticated
481 			 * decryption.
482 			 */
483 			res = tee_ta_decrypt_final(handle->enc_ctx,
484 						   handle->ehdr, NULL, NULL, 0);
485 			if (res != TEE_SUCCESS)
486 				return TEE_ERROR_SECURITY;
487 		}
488 		/*
489 		 * Last read: time to check if our digest matches the expected
490 		 * one (from the signed header)
491 		 */
492 		res = check_digest(handle);
493 		if (res != TEE_SUCCESS)
494 			return res;
495 
496 		if (handle->bs_hdr)
497 			res = check_update_version(handle->bs_hdr);
498 	}
499 	return res;
500 }
501 
502 static void ree_fs_ta_close(struct ts_store_handle *h)
503 {
504 	struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h;
505 
506 	if (!handle)
507 		return;
508 	thread_rpc_free_payload(handle->mobj);
509 	crypto_hash_free_ctx(handle->hash_ctx);
510 	free(handle->shdr);
511 	free(handle->ehdr);
512 	free(handle->bs_hdr);
513 	free(handle);
514 }
515 
516 #ifndef CFG_REE_FS_TA_BUFFERED
517 REGISTER_TA_STORE(9) = {
518 	.description = "REE",
519 	.open = ree_fs_ta_open,
520 	.get_size = ree_fs_ta_get_size,
521 	.get_tag = ree_fs_ta_get_tag,
522 	.read = ree_fs_ta_read,
523 	.close = ree_fs_ta_close,
524 };
525 #endif
526 
527 #ifdef CFG_REE_FS_TA_BUFFERED
528 
529 /*
530  * This is a wrapper around the "REE FS" TA store.
531  * The whole TA/library is read into a temporary buffer during .open(). This
532  * allows the binary to be authenticated before any data is read and processed
533  * by the upper layer (ELF loader).
534  */
535 
536 struct buf_ree_fs_ta_handle {
537 	struct ts_store_handle *h; /* Note: a REE FS TA store handle */
538 	size_t ta_size;
539 	tee_mm_entry_t *mm;
540 	uint8_t *buf;
541 	size_t offs;
542 	uint8_t *tag;
543 	unsigned int tag_len;
544 };
545 
546 static TEE_Result buf_ta_open(const TEE_UUID *uuid,
547 			      struct ts_store_handle **h)
548 {
549 	struct buf_ree_fs_ta_handle *handle = NULL;
550 	TEE_Result res = TEE_SUCCESS;
551 
552 	handle = calloc(1, sizeof(*handle));
553 	if (!handle)
554 		return TEE_ERROR_OUT_OF_MEMORY;
555 	res = ree_fs_ta_open(uuid, &handle->h);
556 	if (res)
557 		goto err2;
558 	res = ree_fs_ta_get_size(handle->h, &handle->ta_size);
559 	if (res)
560 		goto err;
561 
562 	res = ree_fs_ta_get_tag(handle->h, NULL, &handle->tag_len);
563 	if (res != TEE_ERROR_SHORT_BUFFER) {
564 		res = TEE_ERROR_GENERIC;
565 		goto err;
566 	}
567 	handle->tag = malloc(handle->tag_len);
568 	if (!handle->tag) {
569 		res = TEE_ERROR_OUT_OF_MEMORY;
570 		goto err;
571 	}
572 	res = ree_fs_ta_get_tag(handle->h, handle->tag, &handle->tag_len);
573 	if (res)
574 		goto err;
575 
576 	handle->mm = tee_mm_alloc(&tee_mm_sec_ddr, handle->ta_size);
577 	if (!handle->mm) {
578 		res = TEE_ERROR_OUT_OF_MEMORY;
579 		goto err;
580 	}
581 	handle->buf = phys_to_virt(tee_mm_get_smem(handle->mm),
582 				   MEM_AREA_TA_RAM);
583 	if (!handle->buf) {
584 		res = TEE_ERROR_OUT_OF_MEMORY;
585 		goto err;
586 	}
587 	res = ree_fs_ta_read(handle->h, handle->buf, handle->ta_size);
588 	if (res)
589 		goto err;
590 	*h = (struct ts_store_handle *)handle;
591 err:
592 	ree_fs_ta_close(handle->h);
593 err2:
594 	if (res) {
595 		tee_mm_free(handle->mm);
596 		free(handle->tag);
597 		free(handle);
598 	}
599 	return res;
600 }
601 
602 static TEE_Result buf_ta_get_size(const struct ts_store_handle *h,
603 				  size_t *size)
604 {
605 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
606 
607 	*size = handle->ta_size;
608 	return TEE_SUCCESS;
609 }
610 
611 static TEE_Result buf_ta_read(struct ts_store_handle *h, void *data,
612 			      size_t len)
613 {
614 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
615 	uint8_t *src = handle->buf + handle->offs;
616 	size_t next_offs = 0;
617 
618 	if (ADD_OVERFLOW(handle->offs, len, &next_offs) ||
619 	    next_offs > handle->ta_size)
620 		return TEE_ERROR_BAD_PARAMETERS;
621 
622 	if (data)
623 		memcpy(data, src, len);
624 	handle->offs = next_offs;
625 	return TEE_SUCCESS;
626 }
627 
628 static TEE_Result buf_ta_get_tag(const struct ts_store_handle *h,
629 				 uint8_t *tag, unsigned int *tag_len)
630 {
631 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
632 
633 	*tag_len = handle->tag_len;
634 	if (!tag || *tag_len < handle->tag_len)
635 		return TEE_ERROR_SHORT_BUFFER;
636 
637 	memcpy(tag, handle->tag, handle->tag_len);
638 
639 	return TEE_SUCCESS;
640 }
641 
642 static void buf_ta_close(struct ts_store_handle *h)
643 {
644 	struct buf_ree_fs_ta_handle *handle = (struct buf_ree_fs_ta_handle *)h;
645 
646 	if (!handle)
647 		return;
648 	tee_mm_free(handle->mm);
649 	free(handle->tag);
650 	free(handle);
651 }
652 
653 REGISTER_TA_STORE(9) = {
654 	.description = "REE [buffered]",
655 	.open = buf_ta_open,
656 	.get_size = buf_ta_get_size,
657 	.get_tag = buf_ta_get_tag,
658 	.read = buf_ta_read,
659 	.close = buf_ta_close,
660 };
661 
662 #endif /* CFG_REE_FS_TA_BUFFERED */
663