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