xref: /optee_os/core/tee/tee_rpmb_fs.c (revision c3e8a2d91f8074062795e7ec9babba3cd5dffe65)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
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 <kernel/tee_common.h>
29 #include <kernel/handle.h>
30 #include <tee/tee_rpmb_fs.h>
31 #include <tee/tee_rpmb.h>
32 #include <tee/tee_fs_defs.h>
33 #include <tee/tee_fs.h>
34 #include <tee/tee_fs_key_manager.h>
35 #include <mm/tee_mm.h>
36 #include <trace.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <string_ext.h>
40 #include <util.h>
41 #include <sys/queue.h>
42 
43 #ifdef CFG_ENC_FS
44 #include <tee/tee_cryp_provider.h>
45 #endif
46 
47 #include "tee_fs_private.h"
48 
49 #define RPMB_STORAGE_START_ADDRESS      0
50 #define RPMB_FS_FAT_START_ADDRESS       512
51 #define RPMB_BLOCK_SIZE_SHIFT           8
52 
53 #define RPMB_FS_MAGIC                   0x52504D42
54 #define FS_VERSION                      2
55 #define N_ENTRIES                       8
56 
57 #define FILE_IS_ACTIVE                  (1u << 0)
58 #define FILE_IS_LAST_ENTRY              (1u << 1)
59 
60 /**
61  * FS parameters: Information often used by internal functions.
62  * fat_start_address will be set by rpmb_fs_setup().
63  * rpmb_fs_parameters can be read by any other function.
64  */
65 struct rpmb_fs_parameters {
66 	uint32_t fat_start_address;
67 	uint32_t max_rpmb_address;
68 };
69 
70 /**
71  * File entry for a single file in a RPMB_FS partition.
72  */
73 struct rpmb_fat_entry {
74 	uint32_t start_address;
75 	uint32_t data_size;
76 	uint32_t flags;
77 	uint32_t write_counter;
78 	uint8_t fek[TEE_FS_KM_FEK_SIZE];
79 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
80 };
81 
82 /**
83  * FAT entry context with reference to a FAT entry and its
84  * location in RPMB.
85  */
86 struct rpmb_file_handle {
87 	/* Pointer to a fat_entry */
88 	struct rpmb_fat_entry fat_entry;
89 	/* Pointer to a filename */
90 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
91 	/* Adress for current entry in RPMB */
92 	uint32_t rpmb_fat_address;
93 	/* Current position */
94 	uint32_t pos;
95 };
96 
97 /**
98  * RPMB_FS partition data
99  */
100 struct rpmb_fs_partition {
101 	uint32_t rpmb_fs_magic;
102 	uint32_t fs_version;
103 	uint32_t write_counter;
104 	uint32_t fat_start_address;
105 	/* Do not use reserved[] for other purpose than partition data. */
106 	uint8_t reserved[112];
107 };
108 
109 /**
110  * A node in a list of directory entries. entry->name is a
111  * pointer to name here.
112  */
113 struct tee_rpmb_fs_dirent {
114 	struct tee_fs_dirent entry;
115 	char name[TEE_RPMB_FS_FILENAME_LENGTH];
116 	SIMPLEQ_ENTRY(tee_rpmb_fs_dirent) link;
117 };
118 
119 /**
120  * The RPMB directory representation. It contains a queue of
121  * RPMB directory entries: 'next'.
122  * The current pointer points to the last directory entry
123  * returned by readdir().
124  */
125 struct tee_fs_dir {
126 	struct tee_rpmb_fs_dirent *current;
127 	SIMPLEQ_HEAD(next_head, tee_rpmb_fs_dirent) next;
128 };
129 
130 static TEE_Result get_fat_start_address(uint32_t *addr);
131 
132 static struct rpmb_fs_parameters *fs_par;
133 
134 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER;
135 
136 static void dump_fat(void)
137 {
138 	TEE_Result res = TEE_ERROR_GENERIC;
139 	struct rpmb_fat_entry *fat_entries = NULL;
140 	uint32_t fat_address;
141 	size_t size;
142 	int i;
143 	bool last_entry_found = false;
144 
145 	res = get_fat_start_address(&fat_address);
146 	if (res != TEE_SUCCESS)
147 		goto out;
148 
149 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
150 	fat_entries = malloc(size);
151 	if (!fat_entries) {
152 		res = TEE_ERROR_OUT_OF_MEMORY;
153 		goto out;
154 	}
155 
156 	while (!last_entry_found) {
157 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address,
158 				    (uint8_t *)fat_entries, size, NULL);
159 		if (res != TEE_SUCCESS)
160 			goto out;
161 
162 		for (i = 0; i < N_ENTRIES; i++) {
163 
164 			FMSG("flags 0x%x, size %d, address 0x%x, filename '%s'",
165 				fat_entries[i].flags,
166 				fat_entries[i].data_size,
167 				fat_entries[i].start_address,
168 				fat_entries[i].filename);
169 
170 			if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) {
171 				last_entry_found = true;
172 				break;
173 			}
174 
175 			/* Move to next fat_entry. */
176 			fat_address += sizeof(struct rpmb_fat_entry);
177 		}
178 	}
179 
180 out:
181 	free(fat_entries);
182 }
183 
184 #if (TRACE_LEVEL >= TRACE_DEBUG)
185 static void dump_fh(struct rpmb_file_handle *fh)
186 {
187 	DMSG("fh->filename=%s", fh->filename);
188 	DMSG("fh->pos=%u", fh->pos);
189 	DMSG("fh->rpmb_fat_address=%u", fh->rpmb_fat_address);
190 	DMSG("fh->fat_entry.start_address=%u", fh->fat_entry.start_address);
191 	DMSG("fh->fat_entry.data_size=%u", fh->fat_entry.data_size);
192 }
193 #else
194 static void dump_fh(struct rpmb_file_handle *fh __unused)
195 {
196 }
197 #endif
198 
199 static struct rpmb_file_handle *alloc_file_handle(const char *filename)
200 {
201 	struct rpmb_file_handle *fh = NULL;
202 
203 	fh = calloc(1, sizeof(struct rpmb_file_handle));
204 	if (!fh)
205 		return NULL;
206 
207 	if (filename)
208 		strlcpy(fh->filename, filename, sizeof(fh->filename));
209 
210 	return fh;
211 }
212 
213 /**
214  * write_fat_entry: Store info in a fat_entry to RPMB.
215  */
216 static TEE_Result write_fat_entry(struct rpmb_file_handle *fh,
217 				  bool update_write_counter)
218 {
219 	TEE_Result res = TEE_ERROR_GENERIC;
220 
221 	/* Protect partition data. */
222 	if (fh->rpmb_fat_address < sizeof(struct rpmb_fs_partition)) {
223 		res = TEE_ERROR_ACCESS_CONFLICT;
224 		goto out;
225 	}
226 
227 	if (fh->rpmb_fat_address % sizeof(struct rpmb_fat_entry) != 0) {
228 		res = TEE_ERROR_BAD_PARAMETERS;
229 		goto out;
230 	}
231 
232 	if (update_write_counter) {
233 		res = tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID,
234 						 &fh->fat_entry.write_counter);
235 		if (res != TEE_SUCCESS)
236 			goto out;
237 	}
238 
239 	res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, fh->rpmb_fat_address,
240 			     (uint8_t *)&fh->fat_entry,
241 			     sizeof(struct rpmb_fat_entry), NULL);
242 
243 	dump_fat();
244 
245 out:
246 	return res;
247 }
248 
249 /**
250  * rpmb_fs_setup: Setup rpmb fs.
251  * Set initial partition and FS values and write to RPMB.
252  * Store frequently used data in RAM.
253  */
254 static TEE_Result rpmb_fs_setup(void)
255 {
256 	TEE_Result res = TEE_ERROR_GENERIC;
257 	struct rpmb_fs_partition *partition_data = NULL;
258 	struct rpmb_file_handle *fh = NULL;
259 	uint32_t max_rpmb_block = 0;
260 
261 	if (fs_par) {
262 		res = TEE_SUCCESS;
263 		goto out;
264 	}
265 
266 	res = tee_rpmb_get_max_block(CFG_RPMB_FS_DEV_ID, &max_rpmb_block);
267 	if (res != TEE_SUCCESS)
268 		goto out;
269 
270 	partition_data = calloc(1, sizeof(struct rpmb_fs_partition));
271 	if (!partition_data) {
272 		res = TEE_ERROR_OUT_OF_MEMORY;
273 		goto out;
274 	}
275 
276 	res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS,
277 			    (uint8_t *)partition_data,
278 			    sizeof(struct rpmb_fs_partition), NULL);
279 	if (res != TEE_SUCCESS)
280 		goto out;
281 
282 #ifndef CFG_RPMB_RESET_FAT
283 	if (partition_data->rpmb_fs_magic == RPMB_FS_MAGIC) {
284 		if (partition_data->fs_version == FS_VERSION) {
285 			res = TEE_SUCCESS;
286 			goto store_fs_par;
287 		} else {
288 			/* Wrong software is in use. */
289 			res = TEE_ERROR_ACCESS_DENIED;
290 			goto out;
291 		}
292 	}
293 #else
294 	EMSG("**** Clearing Storage ****");
295 #endif
296 
297 	/* Setup new partition data. */
298 	partition_data->rpmb_fs_magic = RPMB_FS_MAGIC;
299 	partition_data->fs_version = FS_VERSION;
300 	partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS;
301 
302 	/* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */
303 	fh = alloc_file_handle(NULL);
304 	if (!fh) {
305 		res = TEE_ERROR_OUT_OF_MEMORY;
306 		goto out;
307 	}
308 	fh->fat_entry.flags = FILE_IS_LAST_ENTRY;
309 	fh->rpmb_fat_address = partition_data->fat_start_address;
310 
311 	/* Write init FAT entry and partition data to RPMB. */
312 	res = write_fat_entry(fh, true);
313 	if (res != TEE_SUCCESS)
314 		goto out;
315 
316 	res =
317 	    tee_rpmb_get_write_counter(CFG_RPMB_FS_DEV_ID,
318 				       &partition_data->write_counter);
319 	if (res != TEE_SUCCESS)
320 		goto out;
321 	res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, RPMB_STORAGE_START_ADDRESS,
322 			     (uint8_t *)partition_data,
323 			     sizeof(struct rpmb_fs_partition), NULL);
324 
325 #ifndef CFG_RPMB_RESET_FAT
326 store_fs_par:
327 #endif
328 
329 	/* Store FAT start address. */
330 	fs_par = calloc(1, sizeof(struct rpmb_fs_parameters));
331 	if (!fs_par) {
332 		res = TEE_ERROR_OUT_OF_MEMORY;
333 		goto out;
334 	}
335 
336 	fs_par->fat_start_address = partition_data->fat_start_address;
337 	fs_par->max_rpmb_address = max_rpmb_block << RPMB_BLOCK_SIZE_SHIFT;
338 
339 	dump_fat();
340 
341 out:
342 	free(fh);
343 	free(partition_data);
344 	return res;
345 }
346 
347 /**
348  * get_fat_start_address:
349  * FAT start_address from fs_par.
350  */
351 static TEE_Result get_fat_start_address(uint32_t *addr)
352 {
353 	if (!fs_par)
354 		return TEE_ERROR_NO_DATA;
355 
356 	*addr = fs_par->fat_start_address;
357 
358 	return TEE_SUCCESS;
359 }
360 
361 /**
362  * read_fat: Read FAT entries
363  * Return matching FAT entry for read, rm rename and stat.
364  * Build up memory pool and return matching entry for write operation.
365  * "Last FAT entry" can be returned during write.
366  */
367 static TEE_Result read_fat(struct rpmb_file_handle *fh, tee_mm_pool_t *p)
368 {
369 	TEE_Result res = TEE_ERROR_GENERIC;
370 	tee_mm_entry_t *mm = NULL;
371 	struct rpmb_fat_entry *fat_entries = NULL;
372 	uint32_t fat_address;
373 	size_t size;
374 	int i;
375 	bool entry_found = false;
376 	bool last_entry_found = false;
377 	bool expand_fat = false;
378 	struct rpmb_file_handle last_fh;
379 
380 	DMSG("fat_address %d", fh->rpmb_fat_address);
381 
382 	res = rpmb_fs_setup();
383 	if (res != TEE_SUCCESS)
384 		goto out;
385 
386 	res = get_fat_start_address(&fat_address);
387 	if (res != TEE_SUCCESS)
388 		goto out;
389 
390 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
391 	fat_entries = malloc(size);
392 	if (!fat_entries) {
393 		res = TEE_ERROR_OUT_OF_MEMORY;
394 		goto out;
395 	}
396 
397 	/*
398 	 * The pool is used to represent the current RPMB layout. To find
399 	 * a slot for the file tee_mm_alloc is called on the pool. Thus
400 	 * if it is not NULL the entire FAT must be traversed to fill in
401 	 * the pool.
402 	 */
403 	while (!last_entry_found && (!entry_found || p)) {
404 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address,
405 				    (uint8_t *)fat_entries, size, NULL);
406 		if (res != TEE_SUCCESS)
407 			goto out;
408 
409 		for (i = 0; i < N_ENTRIES; i++) {
410 			/*
411 			 * Look for an entry, matching filenames. (read, rm,
412 			 * rename and stat.). Only store first filename match.
413 			 */
414 			if (fh->filename &&
415 			    (strcmp(fh->filename,
416 				    fat_entries[i].filename) == 0) &&
417 			    (fat_entries[i].flags & FILE_IS_ACTIVE) &&
418 			    (!entry_found)) {
419 				entry_found = true;
420 				fh->rpmb_fat_address = fat_address;
421 				memcpy(&fh->fat_entry, &fat_entries[i],
422 				       sizeof(struct rpmb_fat_entry));
423 				if (!p)
424 					break;
425 			}
426 
427 			/* Add existing files to memory pool. (write) */
428 			if (p) {
429 				if ((fat_entries[i].flags & FILE_IS_ACTIVE) &&
430 				    (fat_entries[i].data_size > 0)) {
431 
432 					mm = tee_mm_alloc2
433 						(p,
434 						 fat_entries[i].start_address,
435 						 fat_entries[i].data_size);
436 					if (!mm) {
437 						res = TEE_ERROR_OUT_OF_MEMORY;
438 						goto out;
439 					}
440 				}
441 
442 				/* Unused FAT entries can be reused (write) */
443 				if (((fat_entries[i].flags & FILE_IS_ACTIVE) ==
444 				     0) && (fh->rpmb_fat_address == 0)) {
445 					fh->rpmb_fat_address = fat_address;
446 					memcpy(&fh->fat_entry, &fat_entries[i],
447 					       sizeof(struct rpmb_fat_entry));
448 				}
449 			}
450 
451 			if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) {
452 				last_entry_found = true;
453 
454 				/*
455 				 * If the last entry was reached and was chosen
456 				 * by the previous check, then the FAT needs to
457 				 * be expanded.
458 				 * fh->rpmb_fat_address is the address chosen
459 				 * to store the files FAT entry and fat_address
460 				 * is the current FAT entry address being
461 				 * compared.
462 				 */
463 				if (p && fh->rpmb_fat_address == fat_address)
464 					expand_fat = true;
465 				break;
466 			}
467 
468 			/* Move to next fat_entry. */
469 			fat_address += sizeof(struct rpmb_fat_entry);
470 		}
471 	}
472 
473 	/*
474 	 * Represent the FAT table in the pool.
475 	 */
476 	if (p) {
477 		/*
478 		 * Since fat_address is the start of the last entry it needs to
479 		 * be moved up by an entry.
480 		 */
481 		fat_address += sizeof(struct rpmb_fat_entry);
482 
483 		/* Make room for yet a FAT entry and add to memory pool. */
484 		if (expand_fat)
485 			fat_address += sizeof(struct rpmb_fat_entry);
486 
487 		mm = tee_mm_alloc2(p, RPMB_STORAGE_START_ADDRESS, fat_address);
488 		if (!mm) {
489 			res = TEE_ERROR_OUT_OF_MEMORY;
490 			goto out;
491 		}
492 
493 		if (expand_fat) {
494 			/*
495 			 * Point fat_address to the beginning of the new
496 			 * entry.
497 			 */
498 			fat_address -= sizeof(struct rpmb_fat_entry);
499 			memset(&last_fh, 0, sizeof(last_fh));
500 			last_fh.fat_entry.flags = FILE_IS_LAST_ENTRY;
501 			last_fh.rpmb_fat_address = fat_address;
502 			res = write_fat_entry(&last_fh, true);
503 			if (res != TEE_SUCCESS)
504 				goto out;
505 		}
506 	}
507 
508 	if (fh->filename && !fh->rpmb_fat_address)
509 		res = TEE_ERROR_FILE_NOT_FOUND;
510 
511 out:
512 	free(fat_entries);
513 	return res;
514 }
515 
516 #ifdef CFG_ENC_FS
517 static bool is_zero(const uint8_t *buf, size_t size)
518 {
519 	size_t i;
520 
521 	for (i = 0; i < size; i++)
522 		if (buf[i])
523 			return false;
524 	return true;
525 }
526 
527 static TEE_Result generate_fek(struct rpmb_fat_entry *fe)
528 {
529 	TEE_Result res;
530 
531 again:
532 	res = crypto_ops.prng.read(fe->fek, sizeof(fe->fek));
533 	if (res != TEE_SUCCESS)
534 		return res;
535 
536 	if (is_zero(fe->fek, sizeof(fe->fek)))
537 		goto again;
538 
539 	return res;
540 }
541 #else
542 static TEE_Result generate_fek(struct rpmb_fat_entry *fe)
543 {
544 	memset(fe->fek, 0, sizeof(fe->fek));
545 	return TEE_SUCCESS;
546 }
547 #endif
548 
549 int tee_rpmb_fs_open(const char *file, int flags, ...)
550 {
551 	int fd = -1;
552 	struct rpmb_file_handle *fh = NULL;
553 	size_t filelen;
554 	tee_mm_pool_t p;
555 	bool pool_result;
556 	TEE_Result res = TEE_ERROR_GENERIC;
557 
558 	if (!file) {
559 		res = TEE_ERROR_BAD_PARAMETERS;
560 		goto out;
561 	}
562 
563 	filelen = strlen(file);
564 	if (filelen >= TEE_RPMB_FS_FILENAME_LENGTH - 1 || filelen == 0) {
565 		res = TEE_ERROR_BAD_PARAMETERS;
566 		goto out;
567 	}
568 
569 	if (file[filelen - 1] == '/') {
570 		res = TEE_ERROR_BAD_PARAMETERS;
571 		goto out;
572 	}
573 
574 	fh = alloc_file_handle(file);
575 	if (!fh) {
576 		res = TEE_ERROR_OUT_OF_MEMORY;
577 		goto out;
578 	}
579 
580 	/* We need to do setup in order to make sure fs_par is filled in */
581 	res = rpmb_fs_setup();
582 	if (res != TEE_SUCCESS)
583 		goto out;
584 
585 	if (flags & TEE_FS_O_CREATE) {
586 		/* Upper memory allocation must be used for RPMB_FS. */
587 		pool_result = tee_mm_init(&p,
588 					  RPMB_STORAGE_START_ADDRESS,
589 					  fs_par->max_rpmb_address,
590 					  RPMB_BLOCK_SIZE_SHIFT,
591 					  TEE_MM_POOL_HI_ALLOC);
592 
593 		if (!pool_result) {
594 			res = TEE_ERROR_OUT_OF_MEMORY;
595 			goto out;
596 		}
597 
598 		res = read_fat(fh, &p);
599 		tee_mm_final(&p);
600 		if (res != TEE_SUCCESS)
601 			goto out;
602 	} else {
603 		res = read_fat(fh, NULL);
604 		if (res != TEE_SUCCESS)
605 			goto out;
606 	}
607 
608 	/* Add the handle to the db */
609 	fd = handle_get(&fs_handle_db, fh);
610 	if (fd == -1) {
611 		res = TEE_ERROR_OUT_OF_MEMORY;
612 		goto out;
613 	}
614 
615 	/*
616 	 * If this is opened with create and the entry found was not active
617 	 * then this is a new file and the FAT entry must be written
618 	 */
619 	if (flags & TEE_FS_O_CREATE) {
620 		if ((fh->fat_entry.flags & FILE_IS_ACTIVE) == 0) {
621 			memset(&fh->fat_entry, 0,
622 				sizeof(struct rpmb_fat_entry));
623 			memcpy(fh->fat_entry.filename, file, strlen(file));
624 			/* Start address and size are 0 */
625 			fh->fat_entry.flags = FILE_IS_ACTIVE;
626 
627 			res = generate_fek(&fh->fat_entry);
628 			if (res != TEE_SUCCESS) {
629 				handle_put(&fs_handle_db, fd);
630 				fd = -1;
631 				goto out;
632 			}
633 			DMSG("GENERATE FEK key: %p",
634 			     (void *)fh->fat_entry.fek);
635 			DHEXDUMP(fh->fat_entry.fek, sizeof(fh->fat_entry.fek));
636 
637 			res = write_fat_entry(fh, true);
638 			if (res != TEE_SUCCESS) {
639 				handle_put(&fs_handle_db, fd);
640 				fd = -1;
641 				goto out;
642 			}
643 		}
644 	}
645 
646 	res = TEE_SUCCESS;
647 
648 out:
649 	if (res != TEE_SUCCESS) {
650 		if (fh)
651 			free(fh);
652 
653 		fd = -1;
654 	}
655 
656 	return fd;
657 }
658 
659 int tee_rpmb_fs_close(int fd)
660 {
661 	struct rpmb_file_handle *fh;
662 
663 	fh = handle_put(&fs_handle_db, fd);
664 	if (fh) {
665 		free(fh);
666 		return 0;
667 	}
668 
669 	return -1;
670 }
671 
672 int tee_rpmb_fs_read(int fd, uint8_t *buf, size_t size)
673 {
674 	TEE_Result res = TEE_ERROR_GENERIC;
675 	struct rpmb_file_handle *fh;
676 	int read_size = -1;
677 
678 	if (!size)
679 		return 0;
680 
681 	if (!buf) {
682 		res = TEE_ERROR_BAD_PARAMETERS;
683 		goto out;
684 	}
685 
686 	fh = handle_lookup(&fs_handle_db, fd);
687 	if (!fh) {
688 		res = TEE_ERROR_BAD_PARAMETERS;
689 		goto out;
690 	}
691 	dump_fh(fh);
692 
693 	res = read_fat(fh, NULL);
694 	if (res != TEE_SUCCESS)
695 		goto out;
696 
697 	size = MIN(size, fh->fat_entry.data_size - fh->pos);
698 	if (size > 0) {
699 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
700 				    fh->fat_entry.start_address + fh->pos, buf,
701 				    size, fh->fat_entry.fek);
702 		if (res != TEE_SUCCESS)
703 			goto out;
704 	}
705 
706 	read_size = size;
707 	res = TEE_SUCCESS;
708 
709 out:
710 	if (res != TEE_SUCCESS)
711 		read_size = -1;
712 
713 	return read_size;
714 }
715 
716 int tee_rpmb_fs_write(int fd, uint8_t *buf, size_t size)
717 {
718 	TEE_Result res = TEE_ERROR_GENERIC;
719 	struct rpmb_file_handle *fh;
720 	tee_mm_pool_t p;
721 	bool pool_result = false;
722 	tee_mm_entry_t *mm;
723 	size_t end;
724 	size_t newsize;
725 	uint8_t *newbuf = NULL;
726 	uintptr_t newaddr;
727 	uint32_t start_addr;
728 
729 	if (!size)
730 		return 0;
731 
732 	if (!buf) {
733 		res = TEE_ERROR_BAD_PARAMETERS;
734 		goto out;
735 	}
736 
737 	if (!fs_par) {
738 		res = TEE_ERROR_GENERIC;
739 		goto out;
740 	}
741 
742 	fh = handle_lookup(&fs_handle_db, fd);
743 	if (!fh) {
744 		res = TEE_ERROR_BAD_PARAMETERS;
745 		goto out;
746 	}
747 	dump_fh(fh);
748 
749 	/* Upper memory allocation must be used for RPMB_FS. */
750 	pool_result = tee_mm_init(&p,
751 				  RPMB_STORAGE_START_ADDRESS,
752 				  fs_par->max_rpmb_address,
753 				  RPMB_BLOCK_SIZE_SHIFT,
754 				  TEE_MM_POOL_HI_ALLOC);
755 	if (!pool_result) {
756 		res = TEE_ERROR_OUT_OF_MEMORY;
757 		goto out;
758 	}
759 
760 	res = read_fat(fh, &p);
761 	if (res != TEE_SUCCESS)
762 		goto out;
763 
764 	TEE_ASSERT(!(fh->fat_entry.flags & FILE_IS_LAST_ENTRY));
765 
766 	end = fh->pos + size;
767 	start_addr = fh->fat_entry.start_address + fh->pos;
768 
769 	if (end <= fh->fat_entry.data_size &&
770 	    tee_rpmb_write_is_atomic(CFG_RPMB_FS_DEV_ID, start_addr, size)) {
771 
772 		DMSG("Updating data in-place");
773 		res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, start_addr, buf,
774 				     size, fh->fat_entry.fek);
775 		if (res != TEE_SUCCESS)
776 			goto out;
777 	} else {
778 		/*
779 		 * File must be extended, or update cannot be atomic: allocate,
780 		 * read, update, write.
781 		 */
782 
783 		DMSG("Need to re-allocate");
784 		newsize = MAX(end, fh->fat_entry.data_size);
785 		mm = tee_mm_alloc(&p, newsize);
786 		newbuf = calloc(newsize, 1);
787 		if (!mm || !newbuf) {
788 			res = TEE_ERROR_OUT_OF_MEMORY;
789 			goto out;
790 		}
791 
792 		if (fh->fat_entry.data_size) {
793 			res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
794 					    fh->fat_entry.start_address,
795 					    newbuf, fh->fat_entry.data_size,
796 					    fh->fat_entry.fek);
797 			if (res != TEE_SUCCESS)
798 				goto out;
799 		}
800 
801 		memcpy(newbuf + fh->pos, buf, size);
802 
803 		newaddr = tee_mm_get_smem(mm);
804 		res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf,
805 				     newsize, fh->fat_entry.fek);
806 		if (res != TEE_SUCCESS)
807 			goto out;
808 
809 		fh->fat_entry.data_size = newsize;
810 		fh->fat_entry.start_address = newaddr;
811 		res = write_fat_entry(fh, true);
812 		if (res != TEE_SUCCESS)
813 			goto out;
814 	}
815 
816 	fh->pos += size;
817 out:
818 	if (pool_result)
819 		tee_mm_final(&p);
820 	if (newbuf)
821 		free(newbuf);
822 
823 	if (res == TEE_SUCCESS)
824 		return size;
825 
826 	return -1;
827 }
828 
829 tee_fs_off_t tee_rpmb_fs_lseek(int fd, tee_fs_off_t offset, int whence)
830 {
831 	struct rpmb_file_handle *fh;
832 	TEE_Result res;
833 	tee_fs_off_t ret = -1;
834 	tee_fs_off_t new_pos;
835 
836 	fh = handle_lookup(&fs_handle_db, fd);
837 	if (!fh)
838 		return TEE_ERROR_BAD_PARAMETERS;
839 
840 	res = read_fat(fh, NULL);
841 	if (res != TEE_SUCCESS)
842 		return -1;
843 
844 	switch (whence) {
845 	case TEE_FS_SEEK_SET:
846 		new_pos = offset;
847 		break;
848 
849 	case TEE_FS_SEEK_CUR:
850 		new_pos = fh->pos + offset;
851 		break;
852 
853 	case TEE_FS_SEEK_END:
854 		new_pos = fh->fat_entry.data_size + offset;
855 		break;
856 
857 	default:
858 		goto exit;
859 	}
860 
861 	if (new_pos < 0)
862 		new_pos = 0;
863 
864 	if (new_pos > TEE_DATA_MAX_POSITION) {
865 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
866 		goto exit;
867 	}
868 
869 	ret = fh->pos = new_pos;
870 exit:
871 	return ret;
872 }
873 
874 TEE_Result tee_rpmb_fs_rm(const char *filename)
875 {
876 	TEE_Result res = TEE_ERROR_GENERIC;
877 	struct rpmb_file_handle *fh = NULL;
878 
879 	if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) {
880 		res = TEE_ERROR_BAD_PARAMETERS;
881 		goto out;
882 	}
883 
884 	fh = alloc_file_handle(filename);
885 	if (!fh) {
886 		res = TEE_ERROR_OUT_OF_MEMORY;
887 		goto out;
888 	}
889 
890 	res = read_fat(fh, NULL);
891 	if (res != TEE_SUCCESS)
892 		goto out;
893 
894 	/* Clear this file entry. */
895 	memset(&fh->fat_entry, 0, sizeof(struct rpmb_fat_entry));
896 	res = write_fat_entry(fh, false);
897 
898 out:
899 	free(fh);
900 	return res;
901 }
902 
903 TEE_Result tee_rpmb_fs_rename(const char *old_name, const char *new_name)
904 {
905 	TEE_Result res = TEE_ERROR_GENERIC;
906 	struct rpmb_file_handle *fh_old = NULL;
907 	struct rpmb_file_handle *fh_new = NULL;
908 	uint32_t old_len;
909 	uint32_t new_len;
910 
911 	if (!old_name || !new_name) {
912 		res = TEE_ERROR_BAD_PARAMETERS;
913 		goto out;
914 	}
915 
916 	old_len = strlen(old_name);
917 	new_len = strlen(new_name);
918 
919 	if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) ||
920 	    (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) {
921 
922 		res = TEE_ERROR_BAD_PARAMETERS;
923 		goto out;
924 	}
925 
926 	fh_old = alloc_file_handle(old_name);
927 	if (!fh_old) {
928 		res = TEE_ERROR_OUT_OF_MEMORY;
929 		goto out;
930 	}
931 
932 	fh_new = alloc_file_handle(new_name);
933 	if (!fh_new) {
934 		res = TEE_ERROR_OUT_OF_MEMORY;
935 		goto out;
936 	}
937 
938 	res = read_fat(fh_old, NULL);
939 	if (res != TEE_SUCCESS)
940 		goto out;
941 
942 	res = read_fat(fh_new, NULL);
943 	if (res == TEE_SUCCESS) {
944 		res = TEE_ERROR_BAD_PARAMETERS;
945 		goto out;
946 	}
947 
948 	memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH);
949 	memcpy(fh_old->fat_entry.filename, new_name, new_len);
950 
951 	res = write_fat_entry(fh_old, false);
952 
953 out:
954 	free(fh_old);
955 	free(fh_new);
956 
957 	return res;
958 }
959 
960 int tee_rpmb_fs_mkdir(const char *path __unused, tee_fs_mode_t mode __unused)
961 {
962 	/*
963 	 * FIXME: mkdir() should really create some entry in the FAT so that
964 	 * access() would return success when the directory exists but is
965 	 * empty. This does not matter for the current use cases.
966 	 */
967 	return 0;
968 }
969 
970 int tee_rpmb_fs_ftruncate(int fd, tee_fs_off_t length)
971 {
972 	struct rpmb_file_handle *fh;
973 	tee_mm_pool_t p;
974 	bool pool_result = false;
975 	tee_mm_entry_t *mm;
976 	uint32_t newsize;
977 	uint8_t *newbuf = NULL;
978 	uintptr_t newaddr;
979 	TEE_Result res = TEE_ERROR_GENERIC;
980 
981 	if (length < 0 || length > INT32_MAX) {
982 		res = TEE_ERROR_BAD_PARAMETERS;
983 		goto out;
984 	}
985 	newsize = length;
986 
987 	fh = handle_lookup(&fs_handle_db, fd);
988 	if (!fh) {
989 		res = TEE_ERROR_BAD_PARAMETERS;
990 		goto out;
991 	}
992 
993 	res = read_fat(fh, NULL);
994 	if (res != TEE_SUCCESS)
995 		goto out;
996 
997 	if (newsize > fh->fat_entry.data_size) {
998 		/* Extend file */
999 
1000 		pool_result = tee_mm_init(&p,
1001 					  RPMB_STORAGE_START_ADDRESS,
1002 					  fs_par->max_rpmb_address,
1003 					  RPMB_BLOCK_SIZE_SHIFT,
1004 					  TEE_MM_POOL_HI_ALLOC);
1005 		if (!pool_result) {
1006 			res = TEE_ERROR_OUT_OF_MEMORY;
1007 			goto out;
1008 		}
1009 		res = read_fat(fh, &p);
1010 		if (res != TEE_SUCCESS)
1011 			goto out;
1012 
1013 		mm = tee_mm_alloc(&p, newsize);
1014 		newbuf = calloc(newsize, 1);
1015 		if (!mm || !newbuf) {
1016 			res = TEE_ERROR_OUT_OF_MEMORY;
1017 			goto out;
1018 		}
1019 
1020 		if (fh->fat_entry.data_size) {
1021 			res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID,
1022 					    fh->fat_entry.start_address,
1023 					    newbuf, fh->fat_entry.data_size,
1024 					    fh->fat_entry.fek);
1025 			if (res != TEE_SUCCESS)
1026 				goto out;
1027 		}
1028 
1029 		newaddr = tee_mm_get_smem(mm);
1030 		res = tee_rpmb_write(CFG_RPMB_FS_DEV_ID, newaddr, newbuf,
1031 				     newsize, fh->fat_entry.fek);
1032 		if (res != TEE_SUCCESS)
1033 			goto out;
1034 
1035 	} else {
1036 		/* Don't change file location */
1037 		newaddr = fh->fat_entry.start_address;
1038 	}
1039 
1040 	/* fh->pos is unchanged */
1041 	fh->fat_entry.data_size = newsize;
1042 	fh->fat_entry.start_address = newaddr;
1043 	res = write_fat_entry(fh, true);
1044 
1045 out:
1046 	if (pool_result)
1047 		tee_mm_final(&p);
1048 	if (newbuf)
1049 		free(newbuf);
1050 
1051 	if (res == TEE_SUCCESS)
1052 		return 0;
1053 
1054 	return -1;
1055 }
1056 
1057 static void tee_rpmb_fs_dir_free(tee_fs_dir *dir)
1058 {
1059 	struct tee_rpmb_fs_dirent *e;
1060 
1061 	if (!dir)
1062 		return;
1063 
1064 	free(dir->current);
1065 
1066 	while ((e = SIMPLEQ_FIRST(&dir->next))) {
1067 		SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1068 		free(e);
1069 	}
1070 }
1071 
1072 static TEE_Result tee_rpmb_fs_dir_populate(const char *path, tee_fs_dir *dir)
1073 {
1074 	struct tee_rpmb_fs_dirent *current = NULL;
1075 	struct rpmb_fat_entry *fat_entries = NULL;
1076 	uint32_t fat_address;
1077 	uint32_t filelen;
1078 	char *filename;
1079 	int i;
1080 	bool last_entry_found = false;
1081 	bool matched;
1082 	struct tee_rpmb_fs_dirent *next = NULL;
1083 	uint32_t pathlen;
1084 	TEE_Result res = TEE_ERROR_GENERIC;
1085 	uint32_t size;
1086 	char temp;
1087 
1088 	res = rpmb_fs_setup();
1089 	if (res != TEE_SUCCESS)
1090 		goto out;
1091 
1092 	res = get_fat_start_address(&fat_address);
1093 	if (res != TEE_SUCCESS)
1094 		goto out;
1095 
1096 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
1097 	fat_entries = malloc(size);
1098 	if (!fat_entries) {
1099 		res = TEE_ERROR_OUT_OF_MEMORY;
1100 		goto out;
1101 	}
1102 
1103 	pathlen = strlen(path);
1104 	while (!last_entry_found) {
1105 		res = tee_rpmb_read(CFG_RPMB_FS_DEV_ID, fat_address,
1106 				    (uint8_t *)fat_entries, size, NULL);
1107 		if (res != TEE_SUCCESS)
1108 			goto out;
1109 
1110 		for (i = 0; i < N_ENTRIES; i++) {
1111 			filename = fat_entries[i].filename;
1112 			if (fat_entries[i].flags & FILE_IS_ACTIVE) {
1113 				matched = false;
1114 				filelen = strlen(filename);
1115 				if (filelen > pathlen) {
1116 					temp = filename[pathlen];
1117 					filename[pathlen] = '\0';
1118 					if (strcmp(filename, path) == 0)
1119 						matched = true;
1120 
1121 					filename[pathlen] = temp;
1122 				}
1123 
1124 				if (matched) {
1125 					next = malloc(sizeof(*next));
1126 					if (!next) {
1127 						res = TEE_ERROR_OUT_OF_MEMORY;
1128 						goto out;
1129 					}
1130 
1131 					memset(next, 0, sizeof(*next));
1132 					next->entry.d_name = next->name;
1133 					memcpy(next->name,
1134 						&filename[pathlen],
1135 						filelen - pathlen);
1136 
1137 					SIMPLEQ_INSERT_TAIL(&dir->next, next,
1138 							    link);
1139 					current = next;
1140 				}
1141 			}
1142 
1143 			if (fat_entries[i].flags & FILE_IS_LAST_ENTRY) {
1144 				last_entry_found = true;
1145 				break;
1146 			}
1147 
1148 			/* Move to next fat_entry. */
1149 			fat_address += sizeof(struct rpmb_fat_entry);
1150 		}
1151 	}
1152 
1153 	/* No directories were found. */
1154 	if (!current) {
1155 		res = TEE_ERROR_NO_DATA;
1156 		goto out;
1157 	}
1158 
1159 	res = TEE_SUCCESS;
1160 
1161 out:
1162 	if (res != TEE_SUCCESS)
1163 		tee_rpmb_fs_dir_free(dir);
1164 	if (fat_entries)
1165 		free(fat_entries);
1166 
1167 	return res;
1168 }
1169 
1170 static TEE_Result tee_rpmb_fs_opendir_internal(const char *path,
1171 						tee_fs_dir **dir)
1172 {
1173 	uint32_t len;
1174 	uint32_t max_size;
1175 	char path_local[TEE_RPMB_FS_FILENAME_LENGTH];
1176 	TEE_Result res = TEE_ERROR_GENERIC;
1177 	tee_fs_dir *rpmb_dir = NULL;
1178 
1179 	if (!path || !dir) {
1180 		res = TEE_ERROR_BAD_PARAMETERS;
1181 		goto out;
1182 	}
1183 
1184 	/*
1185 	 * There must be room for at least the NULL char and a char for the
1186 	 * filename after the path.
1187 	 */
1188 	max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2;
1189 	len = strlen(path);
1190 	if (len > max_size || len == 0) {
1191 		res = TEE_ERROR_BAD_PARAMETERS;
1192 		goto out;
1193 	}
1194 
1195 	memset(path_local, 0, sizeof(path_local));
1196 	memcpy(path_local, path, len);
1197 
1198 	/* Add a slash to correctly match the full directory name. */
1199 	if (path_local[len - 1] != '/')
1200 		path_local[len] = '/';
1201 
1202 	rpmb_dir = calloc(1, sizeof(tee_fs_dir));
1203 	if (!rpmb_dir) {
1204 		res = TEE_ERROR_OUT_OF_MEMORY;
1205 		goto out;
1206 	}
1207 	SIMPLEQ_INIT(&rpmb_dir->next);
1208 
1209 	res = tee_rpmb_fs_dir_populate(path_local, rpmb_dir);
1210 	if (res != TEE_SUCCESS) {
1211 		free(rpmb_dir);
1212 		rpmb_dir = NULL;
1213 		goto out;
1214 	}
1215 
1216 	*dir = rpmb_dir;
1217 
1218 out:
1219 	return res;
1220 }
1221 
1222 tee_fs_dir *tee_rpmb_fs_opendir(const char *path)
1223 {
1224 	tee_fs_dir *dir = NULL;
1225 	TEE_Result res = TEE_ERROR_GENERIC;
1226 
1227 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1228 	if (res != TEE_SUCCESS)
1229 		dir = NULL;
1230 
1231 	return dir;
1232 }
1233 
1234 
1235 struct tee_fs_dirent *tee_rpmb_fs_readdir(tee_fs_dir *dir)
1236 {
1237 	if (!dir)
1238 		return NULL;
1239 
1240 	free(dir->current);
1241 
1242 	dir->current = SIMPLEQ_FIRST(&dir->next);
1243 	if (!dir->current)
1244 		return NULL;
1245 
1246 	SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1247 
1248 	return &dir->current->entry;
1249 }
1250 
1251 int tee_rpmb_fs_closedir(tee_fs_dir *dir)
1252 {
1253 	TEE_Result res = TEE_ERROR_GENERIC;
1254 
1255 	if (!dir) {
1256 		res = TEE_SUCCESS;
1257 		goto out;
1258 	}
1259 
1260 	tee_rpmb_fs_dir_free(dir);
1261 	free(dir);
1262 	res = TEE_SUCCESS;
1263 out:
1264 	if (res == TEE_SUCCESS)
1265 		return 0;
1266 
1267 	return -1;
1268 }
1269 
1270 int tee_rpmb_fs_rmdir(const char *path)
1271 {
1272 	tee_fs_dir *dir = NULL;
1273 	TEE_Result res = TEE_ERROR_GENERIC;
1274 	int ret = -1;
1275 
1276 	/* Open the directory anyting other than NO_DATA is a failure */
1277 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1278 	if (res == TEE_SUCCESS) {
1279 		tee_rpmb_fs_closedir(dir);
1280 		ret = -1;
1281 
1282 	} else if (res == TEE_ERROR_NO_DATA) {
1283 		ret = 0;
1284 
1285 	} else {
1286 		/* The case any other failure is returned */
1287 		ret = -1;
1288 	}
1289 
1290 
1291 	return ret;
1292 }
1293 
1294 TEE_Result tee_rpmb_fs_stat(const char *filename,
1295 			    struct tee_rpmb_fs_stat *stat)
1296 {
1297 	TEE_Result res = TEE_ERROR_GENERIC;
1298 	struct rpmb_file_handle *fh = NULL;
1299 
1300 	if (!stat || !filename) {
1301 		res = TEE_ERROR_BAD_PARAMETERS;
1302 		goto out;
1303 	}
1304 
1305 	fh = alloc_file_handle(filename);
1306 	if (!fh) {
1307 		res = TEE_ERROR_OUT_OF_MEMORY;
1308 		goto out;
1309 	}
1310 
1311 	res = read_fat(fh, NULL);
1312 	if (res != TEE_SUCCESS)
1313 		goto out;
1314 
1315 	stat->size = (size_t)fh->fat_entry.data_size;
1316 	stat->reserved = 0;
1317 
1318 out:
1319 	free(fh);
1320 	return res;
1321 }
1322 
1323 int tee_rpmb_fs_access(const char *filename, int mode)
1324 {
1325 	struct tee_rpmb_fs_stat stat;
1326 	TEE_Result res;
1327 
1328 	/* Mode is currently ignored, this only checks for existence */
1329 	(void)mode;
1330 
1331 	res = tee_rpmb_fs_stat(filename, &stat);
1332 
1333 	if (res == TEE_SUCCESS)
1334 		return 0;
1335 
1336 	return -1;
1337 }
1338 
1339 static struct tee_fs_fd *tee_fs_fd_lookup(int fd)
1340 {
1341 	return handle_lookup(&fs_handle_db, fd);
1342 }
1343 
1344 static int tee_fs_close(int fd)
1345 {
1346 	struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd);
1347 
1348 	return tee_fs_common_close(fdp);
1349 }
1350 
1351 static int tee_fs_read(TEE_Result *errno, int fd, void *buf, size_t len)
1352 {
1353 	struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd);
1354 
1355 	return tee_fs_common_read(errno, fdp, buf, len);
1356 }
1357 
1358 static int tee_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len)
1359 {
1360 	struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd);
1361 
1362 	return tee_fs_common_write(errno, fdp, buf, len);
1363 }
1364 
1365 static tee_fs_off_t tee_fs_lseek(TEE_Result *errno,
1366 				 int fd, tee_fs_off_t offset, int whence)
1367 {
1368 	struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd);
1369 
1370 	return tee_fs_common_lseek(errno, fdp, offset, whence);
1371 }
1372 
1373 static int tee_fs_ftruncate(TEE_Result *errno, int fd, tee_fs_off_t length)
1374 {
1375 	struct tee_fs_fd *fdp = tee_fs_fd_lookup(fd);
1376 
1377 	return tee_fs_common_ftruncate(errno, fdp, length);
1378 }
1379 
1380 struct tee_file_operations tee_file_ops = {
1381 	.open = tee_fs_common_open,
1382 	.close = tee_fs_close,
1383 	.read = tee_fs_read,
1384 	.write = tee_fs_write,
1385 	.lseek = tee_fs_lseek,
1386 	.ftruncate = tee_fs_ftruncate,
1387 	.rename = tee_fs_common_rename,
1388 	.unlink = tee_fs_common_unlink,
1389 	.mkdir = tee_fs_common_mkdir,
1390 	.opendir = tee_fs_common_opendir,
1391 	.closedir = tee_fs_common_closedir,
1392 	.readdir = tee_fs_common_readdir,
1393 	.rmdir = tee_fs_common_rmdir,
1394 	.access = tee_fs_common_access
1395 };
1396