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