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 *)¶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 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 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 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 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 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 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 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 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 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 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 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 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