xref: /optee_os/core/tee/tee_rpmb_fs.c (revision a0fdab653c2f0ea1f1c2b2fa8765f2e8a0df0474)
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 DEV_ID                          0
47 #define RPMB_FS_MAGIC                   0x52504D42
48 #define FS_VERSION                      2
49 #define N_ENTRIES                       8
50 
51 #define FILE_IS_ACTIVE                  (1u << 0)
52 #define FILE_IS_LAST_ENTRY              (1u << 1)
53 
54 /**
55  * FS parameters: Information often used by internal functions.
56  * fat_start_address will be set by rpmb_fs_setup().
57  * rpmb_fs_parameters can be read by any other function.
58  */
59 struct rpmb_fs_parameters {
60 	uint32_t fat_start_address;
61 	uint32_t max_rpmb_address;
62 };
63 
64 /**
65  * File entry for a single file in a RPMB_FS partition.
66  */
67 struct rpmb_fat_entry {
68 	uint32_t start_address;
69 	uint32_t data_size;
70 	uint32_t flags;
71 	uint32_t write_counter;
72 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
73 };
74 
75 /**
76  * FAT entry context with reference to a FAT entry and its
77  * location in RPMB.
78  */
79 struct rpmb_file_handle {
80 	/* Pointer to a fat_entry */
81 	struct rpmb_fat_entry fat_entry;
82 	/* Pointer to a filename */
83 	char filename[TEE_RPMB_FS_FILENAME_LENGTH];
84 	/* Adress for current entry in RPMB */
85 	uint32_t rpmb_fat_address;
86 	/* Current position */
87 	uint32_t pos;
88 };
89 
90 /**
91  * RPMB_FS partition data
92  */
93 struct rpmb_fs_partition {
94 	uint32_t rpmb_fs_magic;
95 	uint32_t fs_version;
96 	uint32_t write_counter;
97 	uint32_t fat_start_address;
98 	/* Do not use reserved[] for other purpose than partition data. */
99 	uint8_t reserved[112];
100 };
101 
102 /**
103  * A node in a list of directory entries. entry->name is a
104  * pointer to name here.
105  */
106 struct tee_rpmb_fs_dirent {
107 	struct tee_fs_dirent entry;
108 	char name[TEE_RPMB_FS_FILENAME_LENGTH];
109 	SIMPLEQ_ENTRY(tee_rpmb_fs_dirent) link;
110 };
111 
112 /**
113  * The RPMB directory representation. It contains a queue of
114  * RPMB directory entries: 'next'.
115  * The current pointer points to the last directory entry
116  * returned by readdir().
117  */
118 struct tee_fs_dir {
119 	struct tee_rpmb_fs_dirent *current;
120 	SIMPLEQ_HEAD(next_head, tee_rpmb_fs_dirent) next;
121 };
122 
123 static TEE_Result get_fat_start_address(uint32_t *addr);
124 
125 static struct rpmb_fs_parameters *fs_par;
126 
127 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER;
128 
129 static void dump_fat(void)
130 {
131 	TEE_Result res = TEE_ERROR_GENERIC;
132 	struct rpmb_fat_entry *fat_entries = NULL;
133 	uint32_t fat_address;
134 	size_t size;
135 	int i;
136 	bool last_entry_found = false;
137 
138 	res = get_fat_start_address(&fat_address);
139 	if (res != TEE_SUCCESS)
140 		goto out;
141 
142 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
143 	fat_entries = malloc(size);
144 	if (!fat_entries) {
145 		res = TEE_ERROR_OUT_OF_MEMORY;
146 		goto out;
147 	}
148 
149 	while (!last_entry_found) {
150 		res = tee_rpmb_read(DEV_ID, fat_address,
151 				    (uint8_t *)fat_entries, size);
152 		if (res != TEE_SUCCESS)
153 			goto out;
154 
155 		for (i = 0; i < N_ENTRIES; i++) {
156 
157 			FMSG("flags 0x%x, size %d, address 0x%x, filename '%s'",
158 				fat_entries[i].flags,
159 				fat_entries[i].data_size,
160 				fat_entries[i].start_address,
161 				fat_entries[i].filename);
162 
163 			if ((fat_entries[i].flags & FILE_IS_LAST_ENTRY) != 0) {
164 				last_entry_found = true;
165 				break;
166 			}
167 
168 			/* Move to next fat_entry. */
169 			fat_address += sizeof(struct rpmb_fat_entry);
170 		}
171 	}
172 
173 out:
174 	free(fat_entries);
175 }
176 
177 #if (TRACE_LEVEL >= TRACE_DEBUG)
178 static void dump_fh(struct rpmb_file_handle *fh)
179 {
180 	DMSG("fh->filename=%s", fh->filename);
181 	DMSG("fh->pos=%u", fh->pos);
182 	DMSG("fh->rpmb_fat_address=%u", fh->rpmb_fat_address);
183 	DMSG("fh->fat_entry.start_address=%u", fh->fat_entry.start_address);
184 	DMSG("fh->fat_entry.data_size=%u", fh->fat_entry.data_size);
185 }
186 #else
187 static void dump_fh(struct rpmb_file_handle *fh __unused)
188 {
189 }
190 #endif
191 
192 static struct rpmb_file_handle *alloc_file_handle(const char *filename)
193 {
194 	struct rpmb_file_handle *fh = NULL;
195 
196 	fh = calloc(1, sizeof(struct rpmb_file_handle));
197 	if (!fh)
198 		return NULL;
199 
200 	if (filename)
201 		strlcpy(fh->filename, filename, sizeof(fh->filename));
202 
203 	return fh;
204 }
205 
206 /**
207  * write_fat_entry: Store info in a fat_entry to RPMB.
208  */
209 static TEE_Result write_fat_entry(struct rpmb_file_handle *fh,
210 				  bool update_write_counter)
211 {
212 	TEE_Result res = TEE_ERROR_GENERIC;
213 
214 	/* Protect partition data. */
215 	if (fh->rpmb_fat_address < sizeof(struct rpmb_fs_partition)) {
216 		res = TEE_ERROR_ACCESS_CONFLICT;
217 		goto out;
218 	}
219 
220 	if (fh->rpmb_fat_address % sizeof(struct rpmb_fat_entry) != 0) {
221 		res = TEE_ERROR_BAD_PARAMETERS;
222 		goto out;
223 	}
224 
225 	if (update_write_counter) {
226 		res = tee_rpmb_get_write_counter(DEV_ID,
227 						 &fh->fat_entry.write_counter);
228 		if (res != TEE_SUCCESS)
229 			goto out;
230 	}
231 
232 	res = tee_rpmb_write(DEV_ID, fh->rpmb_fat_address,
233 			     (uint8_t *)&fh->fat_entry,
234 			     sizeof(struct rpmb_fat_entry));
235 
236 	dump_fat();
237 
238 out:
239 	return res;
240 }
241 
242 /**
243  * rpmb_fs_setup: Setup rpmb fs.
244  * Set initial partition and FS values and write to RPMB.
245  * Store frequently used data in RAM.
246  */
247 static TEE_Result rpmb_fs_setup(void)
248 {
249 	TEE_Result res = TEE_ERROR_GENERIC;
250 	struct rpmb_fs_partition *partition_data = NULL;
251 	struct rpmb_file_handle *fh = NULL;
252 	uint32_t max_rpmb_block = 0;
253 
254 	if (fs_par) {
255 		res = TEE_SUCCESS;
256 		goto out;
257 	}
258 
259 	res = tee_rpmb_get_max_block(DEV_ID, &max_rpmb_block);
260 	if (res != TEE_SUCCESS)
261 		goto out;
262 
263 	partition_data = calloc(1, sizeof(struct rpmb_fs_partition));
264 	if (!partition_data) {
265 		res = TEE_ERROR_OUT_OF_MEMORY;
266 		goto out;
267 	}
268 
269 	res = tee_rpmb_read(DEV_ID, RPMB_STORAGE_START_ADDRESS,
270 			    (uint8_t *)partition_data,
271 			    sizeof(struct rpmb_fs_partition));
272 	if (res != TEE_SUCCESS)
273 		goto out;
274 
275 #ifndef CFG_RPMB_RESET_FAT
276 	if (partition_data->rpmb_fs_magic == RPMB_FS_MAGIC) {
277 		if (partition_data->fs_version == FS_VERSION) {
278 			res = TEE_SUCCESS;
279 			goto store_fs_par;
280 		} else {
281 			/* Wrong software is in use. */
282 			res = TEE_ERROR_ACCESS_DENIED;
283 			goto out;
284 		}
285 	}
286 #else
287 	EMSG("**** Clearing Storage ****");
288 #endif
289 
290 	/* Setup new partition data. */
291 	partition_data->rpmb_fs_magic = RPMB_FS_MAGIC;
292 	partition_data->fs_version = FS_VERSION;
293 	partition_data->fat_start_address = RPMB_FS_FAT_START_ADDRESS;
294 
295 	/* Initial FAT entry with FILE_IS_LAST_ENTRY flag set. */
296 	fh = alloc_file_handle(NULL);
297 	if (!fh) {
298 		res = TEE_ERROR_OUT_OF_MEMORY;
299 		goto out;
300 	}
301 	fh->fat_entry.flags = FILE_IS_LAST_ENTRY;
302 	fh->rpmb_fat_address = partition_data->fat_start_address;
303 
304 	/* Write init FAT entry and partition data to RPMB. */
305 	res = write_fat_entry(fh, true);
306 	if (res != TEE_SUCCESS)
307 		goto out;
308 
309 	res =
310 	    tee_rpmb_get_write_counter(DEV_ID, &partition_data->write_counter);
311 	if (res != TEE_SUCCESS)
312 		goto out;
313 	res = tee_rpmb_write(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(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(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 newsize;
674 	uint8_t *newbuf = NULL;
675 	uintptr_t newaddr;
676 
677 	if (!size)
678 		return 0;
679 
680 	if (!buf) {
681 		res = TEE_ERROR_BAD_PARAMETERS;
682 		goto out;
683 	}
684 
685 	if (!fs_par) {
686 		res = TEE_ERROR_GENERIC;
687 		goto out;
688 	}
689 
690 	fh = handle_lookup(&fs_handle_db, fd);
691 	if (!fh) {
692 		res = TEE_ERROR_BAD_PARAMETERS;
693 		goto out;
694 	}
695 	dump_fh(fh);
696 
697 	/* Upper memory allocation must be used for RPMB_FS. */
698 	pool_result = tee_mm_init(&p,
699 				  RPMB_STORAGE_START_ADDRESS,
700 				  fs_par->max_rpmb_address,
701 				  RPMB_BLOCK_SIZE_SHIFT,
702 				  TEE_MM_POOL_HI_ALLOC);
703 	if (!pool_result) {
704 		res = TEE_ERROR_OUT_OF_MEMORY;
705 		goto out;
706 	}
707 
708 	res = read_fat(fh, &p);
709 	if (res != TEE_SUCCESS)
710 		goto out;
711 
712 	TEE_ASSERT(!(fh->fat_entry.flags & FILE_IS_LAST_ENTRY));
713 
714 	newsize = fh->pos + size;
715 	if (newsize <= fh->fat_entry.data_size) {
716 		/* Modifying file content */
717 
718 		res = tee_rpmb_write(DEV_ID,
719 				     fh->fat_entry.start_address + fh->pos,
720 				     buf, size);
721 		if (res != TEE_SUCCESS)
722 			goto out;
723 	} else {
724 		/* Extend file: allocate, read, update, write */
725 
726 		mm = tee_mm_alloc(&p, newsize);
727 		newbuf = calloc(newsize, 1);
728 		if (!mm || !newbuf) {
729 			res = TEE_ERROR_OUT_OF_MEMORY;
730 			goto out;
731 		}
732 
733 		if (fh->fat_entry.data_size) {
734 			res = tee_rpmb_read(DEV_ID,
735 					    fh->fat_entry.start_address,
736 					    newbuf, fh->fat_entry.data_size);
737 			if (res != TEE_SUCCESS)
738 				goto out;
739 		}
740 
741 		memcpy(newbuf + fh->pos, buf, size);
742 
743 		newaddr = tee_mm_get_smem(mm);
744 		res = tee_rpmb_write(DEV_ID, newaddr, newbuf, newsize);
745 		if (res != TEE_SUCCESS)
746 			goto out;
747 
748 		fh->fat_entry.data_size = newsize;
749 		fh->fat_entry.start_address = newaddr;
750 		res = write_fat_entry(fh, true);
751 		if (res != TEE_SUCCESS)
752 			goto out;
753 	}
754 
755 	fh->pos = newsize;
756 out:
757 	if (pool_result)
758 		tee_mm_final(&p);
759 	if (newbuf)
760 		free(newbuf);
761 
762 	if (res == TEE_SUCCESS)
763 		return size;
764 
765 	return -1;
766 }
767 
768 tee_fs_off_t tee_rpmb_fs_lseek(int fd, tee_fs_off_t offset, int whence)
769 {
770 	struct rpmb_file_handle *fh;
771 	TEE_Result res;
772 	tee_fs_off_t ret = -1;
773 	tee_fs_off_t new_pos;
774 
775 	fh = handle_lookup(&fs_handle_db, fd);
776 	if (!fh)
777 		return TEE_ERROR_BAD_PARAMETERS;
778 
779 	res = read_fat(fh, NULL);
780 	if (res != TEE_SUCCESS)
781 		return -1;
782 
783 	switch (whence) {
784 	case TEE_FS_SEEK_SET:
785 		new_pos = offset;
786 		break;
787 
788 	case TEE_FS_SEEK_CUR:
789 		new_pos = fh->pos + offset;
790 		break;
791 
792 	case TEE_FS_SEEK_END:
793 		new_pos = fh->fat_entry.data_size + offset;
794 		break;
795 
796 	default:
797 		goto exit;
798 	}
799 
800 	if (new_pos < 0)
801 		new_pos = 0;
802 
803 	if (new_pos > TEE_DATA_MAX_POSITION) {
804 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
805 		goto exit;
806 	}
807 
808 	ret = fh->pos = new_pos;
809 exit:
810 	return ret;
811 }
812 
813 TEE_Result tee_rpmb_fs_rm(const char *filename)
814 {
815 	TEE_Result res = TEE_ERROR_GENERIC;
816 	struct rpmb_file_handle *fh = NULL;
817 
818 	if (!filename || strlen(filename) >= TEE_RPMB_FS_FILENAME_LENGTH - 1) {
819 		res = TEE_ERROR_BAD_PARAMETERS;
820 		goto out;
821 	}
822 
823 	fh = alloc_file_handle(filename);
824 	if (!fh) {
825 		res = TEE_ERROR_OUT_OF_MEMORY;
826 		goto out;
827 	}
828 
829 	res = read_fat(fh, NULL);
830 	if (res != TEE_SUCCESS)
831 		goto out;
832 
833 	/* Clear this file entry. */
834 	memset(&fh->fat_entry, 0, sizeof(struct rpmb_fat_entry));
835 	res = write_fat_entry(fh, false);
836 
837 out:
838 	free(fh);
839 	IMSG("Deleting file %s returned 0x%x\n", filename, res);
840 	return res;
841 }
842 
843 TEE_Result tee_rpmb_fs_rename(const char *old_name, const char *new_name)
844 {
845 	TEE_Result res = TEE_ERROR_GENERIC;
846 	struct rpmb_file_handle *fh_old = NULL;
847 	struct rpmb_file_handle *fh_new = NULL;
848 	uint32_t old_len;
849 	uint32_t new_len;
850 
851 	if (!old_name || !new_name) {
852 		res = TEE_ERROR_BAD_PARAMETERS;
853 		goto out;
854 	}
855 
856 	old_len = strlen(old_name);
857 	new_len = strlen(new_name);
858 
859 	if ((old_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) ||
860 	    (new_len >= TEE_RPMB_FS_FILENAME_LENGTH - 1) || (new_len == 0)) {
861 
862 		res = TEE_ERROR_BAD_PARAMETERS;
863 		goto out;
864 	}
865 
866 	fh_old = alloc_file_handle(old_name);
867 	if (!fh_old) {
868 		res = TEE_ERROR_OUT_OF_MEMORY;
869 		goto out;
870 	}
871 
872 	fh_new = alloc_file_handle(new_name);
873 	if (!fh_new) {
874 		res = TEE_ERROR_OUT_OF_MEMORY;
875 		goto out;
876 	}
877 
878 	res = read_fat(fh_old, NULL);
879 	if (res != TEE_SUCCESS)
880 		goto out;
881 
882 	res = read_fat(fh_new, NULL);
883 	if (res == TEE_SUCCESS) {
884 		res = TEE_ERROR_BAD_PARAMETERS;
885 		goto out;
886 	}
887 
888 	memset(fh_old->fat_entry.filename, 0, TEE_RPMB_FS_FILENAME_LENGTH);
889 	memcpy(fh_old->fat_entry.filename, new_name, new_len);
890 
891 	res = write_fat_entry(fh_old, false);
892 
893 out:
894 	free(fh_old);
895 	free(fh_new);
896 
897 	return res;
898 }
899 
900 int tee_rpmb_fs_mkdir(const char *path __unused, tee_fs_mode_t mode __unused)
901 {
902 	/*
903 	 * FIXME: mkdir() should really create some entry in the FAT so that
904 	 * access() would return success when the directory exists but is
905 	 * empty. This does not matter for the current use cases.
906 	 */
907 	return 0;
908 }
909 
910 int tee_rpmb_fs_ftruncate(int fd, tee_fs_off_t length)
911 {
912 	struct rpmb_file_handle *fh;
913 	tee_mm_pool_t p;
914 	bool pool_result = false;
915 	tee_mm_entry_t *mm;
916 	uint32_t newsize;
917 	uint8_t *newbuf = NULL;
918 	uintptr_t newaddr;
919 	TEE_Result res = TEE_ERROR_GENERIC;
920 
921 	if (length < 0 || length > INT32_MAX) {
922 		res = TEE_ERROR_BAD_PARAMETERS;
923 		goto out;
924 	}
925 	newsize = length;
926 
927 	fh = handle_lookup(&fs_handle_db, fd);
928 	if (!fh) {
929 		res = TEE_ERROR_BAD_PARAMETERS;
930 		goto out;
931 	}
932 
933 	res = read_fat(fh, NULL);
934 	if (res != TEE_SUCCESS)
935 		goto out;
936 
937 	if (newsize > fh->fat_entry.data_size) {
938 		/* Extend file */
939 
940 		pool_result = tee_mm_init(&p,
941 					  RPMB_STORAGE_START_ADDRESS,
942 					  fs_par->max_rpmb_address,
943 					  RPMB_BLOCK_SIZE_SHIFT,
944 					  TEE_MM_POOL_HI_ALLOC);
945 		if (!pool_result) {
946 			res = TEE_ERROR_OUT_OF_MEMORY;
947 			goto out;
948 		}
949 		res = read_fat(fh, &p);
950 		if (res != TEE_SUCCESS)
951 			goto out;
952 
953 		mm = tee_mm_alloc(&p, newsize);
954 		newbuf = calloc(newsize, 1);
955 		if (!mm || !newbuf) {
956 			res = TEE_ERROR_OUT_OF_MEMORY;
957 			goto out;
958 		}
959 
960 		if (fh->fat_entry.data_size) {
961 			res = tee_rpmb_read(DEV_ID,
962 					    fh->fat_entry.start_address,
963 					    newbuf, fh->fat_entry.data_size);
964 			if (res != TEE_SUCCESS)
965 				goto out;
966 		}
967 
968 		newaddr = tee_mm_get_smem(mm);
969 		res = tee_rpmb_write(DEV_ID, newaddr, newbuf, newsize);
970 		if (res != TEE_SUCCESS)
971 			goto out;
972 
973 	} else {
974 		/* Don't change file location */
975 		newaddr = fh->fat_entry.start_address;
976 	}
977 
978 	/* fh->pos is unchanged */
979 	fh->fat_entry.data_size = newsize;
980 	fh->fat_entry.start_address = newaddr;
981 	res = write_fat_entry(fh, true);
982 
983 out:
984 	if (pool_result)
985 		tee_mm_final(&p);
986 	if (newbuf)
987 		free(newbuf);
988 
989 	if (res == TEE_SUCCESS)
990 		return 0;
991 
992 	return -1;
993 }
994 
995 static void tee_rpmb_fs_dir_free(tee_fs_dir *dir)
996 {
997 	struct tee_rpmb_fs_dirent *e;
998 
999 	if (!dir)
1000 		return;
1001 
1002 	free(dir->current);
1003 
1004 	while ((e = SIMPLEQ_FIRST(&dir->next))) {
1005 		SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1006 		free(e);
1007 	}
1008 }
1009 
1010 static TEE_Result tee_rpmb_fs_dir_populate(const char *path, tee_fs_dir *dir)
1011 {
1012 	struct tee_rpmb_fs_dirent *current = NULL;
1013 	struct rpmb_fat_entry *fat_entries = NULL;
1014 	uint32_t fat_address;
1015 	uint32_t filelen;
1016 	char *filename;
1017 	int i;
1018 	bool last_entry_found = false;
1019 	bool matched;
1020 	struct tee_rpmb_fs_dirent *next = NULL;
1021 	uint32_t pathlen;
1022 	TEE_Result res = TEE_ERROR_GENERIC;
1023 	uint32_t size;
1024 	char temp;
1025 
1026 	res = rpmb_fs_setup();
1027 	if (res != TEE_SUCCESS)
1028 		goto out;
1029 
1030 	res = get_fat_start_address(&fat_address);
1031 	if (res != TEE_SUCCESS)
1032 		goto out;
1033 
1034 	size = N_ENTRIES * sizeof(struct rpmb_fat_entry);
1035 	fat_entries = malloc(size);
1036 	if (!fat_entries) {
1037 		res = TEE_ERROR_OUT_OF_MEMORY;
1038 		goto out;
1039 	}
1040 
1041 	pathlen = strlen(path);
1042 	while (!last_entry_found) {
1043 		res = tee_rpmb_read(DEV_ID, fat_address,
1044 				    (uint8_t *)fat_entries, size);
1045 		if (res != TEE_SUCCESS)
1046 			goto out;
1047 
1048 		for (i = 0; i < N_ENTRIES; i++) {
1049 			filename = fat_entries[i].filename;
1050 			if (fat_entries[i].flags & FILE_IS_ACTIVE) {
1051 				matched = false;
1052 				filelen = strlen(filename);
1053 				if (filelen > pathlen) {
1054 					temp = filename[pathlen];
1055 					filename[pathlen] = '\0';
1056 					if (strcmp(filename, path) == 0)
1057 						matched = true;
1058 
1059 					filename[pathlen] = temp;
1060 				}
1061 
1062 				if (matched) {
1063 					next = malloc(sizeof(*next));
1064 					if (!next) {
1065 						res = TEE_ERROR_OUT_OF_MEMORY;
1066 						goto out;
1067 					}
1068 
1069 					memset(next, 0, sizeof(*next));
1070 					next->entry.d_name = next->name;
1071 					memcpy(next->name,
1072 						&filename[pathlen],
1073 						filelen - pathlen);
1074 
1075 					SIMPLEQ_INSERT_TAIL(&dir->next, next,
1076 							    link);
1077 					current = next;
1078 				}
1079 			}
1080 
1081 			if (fat_entries[i].flags & FILE_IS_LAST_ENTRY) {
1082 				last_entry_found = true;
1083 				break;
1084 			}
1085 
1086 			/* Move to next fat_entry. */
1087 			fat_address += sizeof(struct rpmb_fat_entry);
1088 		}
1089 	}
1090 
1091 	/* No directories were found. */
1092 	if (!current) {
1093 		res = TEE_ERROR_NO_DATA;
1094 		goto out;
1095 	}
1096 
1097 	res = TEE_SUCCESS;
1098 
1099 out:
1100 	if (res != TEE_SUCCESS)
1101 		tee_rpmb_fs_dir_free(dir);
1102 	if (fat_entries)
1103 		free(fat_entries);
1104 
1105 	return res;
1106 }
1107 
1108 static TEE_Result tee_rpmb_fs_opendir_internal(const char *path,
1109 						tee_fs_dir **dir)
1110 {
1111 	uint32_t len;
1112 	uint32_t max_size;
1113 	char path_local[TEE_RPMB_FS_FILENAME_LENGTH];
1114 	TEE_Result res = TEE_ERROR_GENERIC;
1115 	tee_fs_dir *rpmb_dir = NULL;
1116 
1117 	if (!path || !dir) {
1118 		res = TEE_ERROR_BAD_PARAMETERS;
1119 		goto out;
1120 	}
1121 
1122 	/*
1123 	 * There must be room for at least the NULL char and a char for the
1124 	 * filename after the path.
1125 	 */
1126 	max_size = TEE_RPMB_FS_FILENAME_LENGTH - 2;
1127 	len = strlen(path);
1128 	if (len > max_size || len == 0) {
1129 		res = TEE_ERROR_BAD_PARAMETERS;
1130 		goto out;
1131 	}
1132 
1133 	memset(path_local, 0, sizeof(path_local));
1134 	memcpy(path_local, path, len);
1135 
1136 	/* Add a slash to correctly match the full directory name. */
1137 	if (path_local[len - 1] != '/')
1138 		path_local[len] = '/';
1139 
1140 	rpmb_dir = calloc(1, sizeof(tee_fs_dir));
1141 	if (!rpmb_dir) {
1142 		res = TEE_ERROR_OUT_OF_MEMORY;
1143 		goto out;
1144 	}
1145 	SIMPLEQ_INIT(&rpmb_dir->next);
1146 
1147 	res = tee_rpmb_fs_dir_populate(path_local, rpmb_dir);
1148 	if (res != TEE_SUCCESS) {
1149 		free(rpmb_dir);
1150 		rpmb_dir = NULL;
1151 		goto out;
1152 	}
1153 
1154 	*dir = rpmb_dir;
1155 
1156 out:
1157 	return res;
1158 }
1159 
1160 tee_fs_dir *tee_rpmb_fs_opendir(const char *path)
1161 {
1162 	tee_fs_dir *dir = NULL;
1163 	TEE_Result res = TEE_ERROR_GENERIC;
1164 
1165 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1166 	if (res != TEE_SUCCESS)
1167 		dir = NULL;
1168 
1169 	return dir;
1170 }
1171 
1172 
1173 struct tee_fs_dirent *tee_rpmb_fs_readdir(tee_fs_dir *dir)
1174 {
1175 	if (!dir)
1176 		return NULL;
1177 
1178 	free(dir->current);
1179 
1180 	dir->current = SIMPLEQ_FIRST(&dir->next);
1181 	if (!dir->current)
1182 		return NULL;
1183 
1184 	SIMPLEQ_REMOVE_HEAD(&dir->next, link);
1185 
1186 	return &dir->current->entry;
1187 }
1188 
1189 int tee_rpmb_fs_closedir(tee_fs_dir *dir)
1190 {
1191 	TEE_Result res = TEE_ERROR_GENERIC;
1192 
1193 	if (!dir) {
1194 		res = TEE_SUCCESS;
1195 		goto out;
1196 	}
1197 
1198 	tee_rpmb_fs_dir_free(dir);
1199 	free(dir);
1200 	res = TEE_SUCCESS;
1201 out:
1202 	if (res == TEE_SUCCESS)
1203 		return 0;
1204 
1205 	return -1;
1206 }
1207 
1208 int tee_rpmb_fs_rmdir(const char *path)
1209 {
1210 	tee_fs_dir *dir = NULL;
1211 	TEE_Result res = TEE_ERROR_GENERIC;
1212 	int ret = -1;
1213 
1214 	/* Open the directory anyting other than NO_DATA is a failure */
1215 	res = tee_rpmb_fs_opendir_internal(path, &dir);
1216 	if (res == TEE_SUCCESS) {
1217 		tee_rpmb_fs_closedir(dir);
1218 		ret = -1;
1219 
1220 	} else if (res == TEE_ERROR_NO_DATA) {
1221 		ret = 0;
1222 
1223 	} else {
1224 		/* The case any other failure is returned */
1225 		ret = -1;
1226 	}
1227 
1228 
1229 	return ret;
1230 }
1231 
1232 TEE_Result tee_rpmb_fs_stat(const char *filename,
1233 			    struct tee_rpmb_fs_stat *stat)
1234 {
1235 	TEE_Result res = TEE_ERROR_GENERIC;
1236 	struct rpmb_file_handle *fh = NULL;
1237 
1238 	if (!stat || !filename) {
1239 		res = TEE_ERROR_BAD_PARAMETERS;
1240 		goto out;
1241 	}
1242 
1243 	fh = alloc_file_handle(filename);
1244 	if (!fh) {
1245 		res = TEE_ERROR_OUT_OF_MEMORY;
1246 		goto out;
1247 	}
1248 
1249 	res = read_fat(fh, NULL);
1250 	if (res != TEE_SUCCESS)
1251 		goto out;
1252 
1253 	stat->size = (size_t)fh->fat_entry.data_size;
1254 	stat->reserved = 0;
1255 
1256 out:
1257 	free(fh);
1258 	return res;
1259 }
1260 
1261 int tee_rpmb_fs_access(const char *filename, int mode)
1262 {
1263 	struct tee_rpmb_fs_stat stat;
1264 	TEE_Result res;
1265 
1266 	/* Mode is currently ignored, this only checks for existence */
1267 	(void)mode;
1268 
1269 	res = tee_rpmb_fs_stat(filename, &stat);
1270 
1271 	if (res == TEE_SUCCESS)
1272 		return 0;
1273 
1274 	return -1;
1275 }
1276 
1277