xref: /optee_os/core/tee/tee_ree_fs.c (revision 36d5a31387f01357077ca74444f3fd5ce1fcc690)
1 /*
2  * Copyright (c) 2015, Linaro Limited
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 <assert.h>
29 #include <kernel/thread.h>
30 #include <kernel/mutex.h>
31 #include <kernel/panic.h>
32 #include <mm/core_memprot.h>
33 #include <optee_msg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <string_ext.h>
38 #include <sys/queue.h>
39 #include <tee/tee_cryp_provider.h>
40 #include <tee/tee_fs.h>
41 #include <tee/tee_fs_defs.h>
42 #include <tee/tee_fs_rpc.h>
43 #include <tee/tee_fs_key_manager.h>
44 #include <trace.h>
45 #include <utee_defines.h>
46 #include <util.h>
47 
48 /*
49  * This file implements the tee_file_operations structure for a secure
50  * filesystem based on single file in normal world.
51  *
52  * All fields in the REE file are duplicated with two versions 0 and 1. The
53  * active meta-data block is selected by the lowest bit in the
54  * meta-counter.  The active file block is selected by corresponding bit
55  * number in struct tee_fs_file_info.backup_version_table.
56  *
57  * The atomicity of each operation is ensured by updating meta-counter when
58  * everything in the secondary blocks (both meta-data and file-data blocks)
59  * are successfully written.  The main purpose of the code below is to
60  * perform block encryption and authentication of the file data, and
61  * properly handle seeking through the file. One file (in the sense of
62  * struct tee_file_operations) maps to one file in the REE filesystem, and
63  * has the following structure:
64  *
65  * [ 4 bytes meta-counter]
66  * [ meta-data version 0][ meta-data version 1 ]
67  * [ Block 0 version 0 ][ Block 0 version 1 ]
68  * [ Block 1 version 0 ][ Block 1 version 1 ]
69  * ...
70  * [ Block n version 0 ][ Block n version 1 ]
71  *
72  * One meta-data block is built up as:
73  * [ struct meta_header | struct tee_fs_get_header_size ]
74  *
75  * One data block is built up as:
76  * [ struct block_header | BLOCK_FILE_SIZE bytes ]
77  *
78  * struct meta_header and struct block_header are defined in
79  * tee_fs_key_manager.h.
80  *
81  */
82 
83 #define MAX_NUM_CACHED_BLOCKS	1
84 
85 
86 #define MAX_FILE_SIZE	(BLOCK_FILE_SIZE * NUM_BLOCKS_PER_FILE)
87 
88 TAILQ_HEAD(block_head, block);
89 
90 struct block {
91 	TAILQ_ENTRY(block) list;
92 	int block_num;
93 	uint8_t *data;
94 };
95 
96 struct block_cache {
97 	struct block_head block_lru;
98 	uint8_t cached_block_num;
99 };
100 
101 struct tee_fs_fd {
102 	uint32_t meta_counter;
103 	struct tee_fs_file_meta meta;
104 	tee_fs_off_t pos;
105 	uint32_t flags;
106 	bool is_new_file;
107 	int fd;
108 	struct block_cache block_cache;
109 };
110 
111 static inline int pos_to_block_num(int position)
112 {
113 	return position >> BLOCK_FILE_SHIFT;
114 }
115 
116 static inline int get_last_block_num(size_t size)
117 {
118 	return pos_to_block_num(size - 1);
119 }
120 
121 static bool get_backup_version_of_block(struct tee_fs_file_meta *meta,
122 					size_t block_num)
123 {
124 	uint32_t index = (block_num / 32);
125 	uint32_t block_mask = 1 << (block_num % 32);
126 
127 	return !!(meta->info.backup_version_table[index] & block_mask);
128 }
129 
130 static inline void toggle_backup_version_of_block(
131 		struct tee_fs_file_meta *meta,
132 		size_t block_num)
133 {
134 	uint32_t index = (block_num / 32);
135 	uint32_t block_mask = 1 << (block_num % 32);
136 
137 	meta->info.backup_version_table[index] ^= block_mask;
138 }
139 
140 struct block_operations {
141 
142 	/*
143 	 * Read a block from REE File System which is corresponding
144 	 * to the given block_num.
145 	 */
146 	struct block *(*read)(struct tee_fs_fd *fdp, int block_num);
147 
148 	/*
149 	 * Write the given block to REE File System
150 	 */
151 	int (*write)(struct tee_fs_fd *fdp, struct block *b,
152 			struct tee_fs_file_meta *new_meta);
153 };
154 
155 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
156 
157 static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d)
158 
159 {
160 	return tee_fs_rpc_new_opendir(OPTEE_MSG_RPC_CMD_FS, name, d);
161 }
162 
163 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
164 {
165 	if (d)
166 		tee_fs_rpc_new_closedir(OPTEE_MSG_RPC_CMD_FS, d);
167 }
168 
169 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
170 				     struct tee_fs_dirent **ent)
171 {
172 	return tee_fs_rpc_new_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent);
173 }
174 
175 static size_t meta_size(void)
176 {
177 	return tee_fs_get_header_size(META_FILE) +
178 	       sizeof(struct tee_fs_file_meta);
179 }
180 
181 static size_t meta_pos_raw(struct tee_fs_fd *fdp, bool active)
182 {
183 	size_t offs = sizeof(uint32_t);
184 
185 	if ((fdp->meta_counter & 1) == active)
186 		offs += meta_size();
187 	return offs;
188 }
189 
190 static size_t block_size_raw(void)
191 {
192 	return tee_fs_get_header_size(BLOCK_FILE) + BLOCK_FILE_SIZE;
193 }
194 
195 static size_t block_pos_raw(struct tee_fs_file_meta *meta, size_t block_num,
196 			    bool active)
197 {
198 	size_t n = block_num * 2;
199 
200 	if (active == get_backup_version_of_block(meta, block_num))
201 		n++;
202 
203 	return sizeof(uint32_t) + meta_size() * 2 + n * block_size_raw();
204 }
205 
206 /*
207  * encrypted_fek: as input for META_FILE and BLOCK_FILE
208  */
209 static TEE_Result encrypt_and_write_file(struct tee_fs_fd *fdp,
210 		enum tee_fs_file_type file_type, size_t offs,
211 		void *data_in, size_t data_in_size,
212 		uint8_t *encrypted_fek)
213 {
214 	TEE_Result res;
215 	struct tee_fs_rpc_operation op;
216 	void *ciphertext;
217 	size_t header_size = tee_fs_get_header_size(file_type);
218 	size_t ciphertext_size = header_size + data_in_size;
219 
220 
221 	res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
222 					offs, ciphertext_size, &ciphertext);
223 	if (res != TEE_SUCCESS)
224 		return res;
225 
226 	res = tee_fs_encrypt_file(file_type, data_in, data_in_size,
227 				  ciphertext, &ciphertext_size, encrypted_fek);
228 	if (res != TEE_SUCCESS)
229 		return res;
230 
231 	return tee_fs_rpc_new_write_final(&op);
232 }
233 
234 /*
235  * encrypted_fek: as output for META_FILE
236  *                as input for BLOCK_FILE
237  */
238 static TEE_Result read_and_decrypt_file(struct tee_fs_fd *fdp,
239 		enum tee_fs_file_type file_type, size_t offs,
240 		void *data_out, size_t *data_out_size,
241 		uint8_t *encrypted_fek)
242 {
243 	TEE_Result res;
244 	struct tee_fs_rpc_operation op;
245 	size_t bytes;
246 	void *ciphertext;
247 
248 	bytes = *data_out_size + tee_fs_get_header_size(file_type);
249 	res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, offs,
250 				       bytes, &ciphertext);
251 	if (res != TEE_SUCCESS)
252 		return res;
253 
254 	res = tee_fs_rpc_new_read_final(&op, &bytes);
255 	if (res != TEE_SUCCESS)
256 		return res;
257 
258 	if (!bytes) {
259 		*data_out_size = 0;
260 		return TEE_SUCCESS;
261 	}
262 
263 	res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out,
264 				  data_out_size, encrypted_fek);
265 	if (res != TEE_SUCCESS)
266 		return TEE_ERROR_CORRUPT_OBJECT;
267 	return TEE_SUCCESS;
268 }
269 
270 static TEE_Result write_meta_file(struct tee_fs_fd *fdp,
271 		struct tee_fs_file_meta *meta)
272 {
273 	size_t offs = meta_pos_raw(fdp, false);
274 
275 	return encrypt_and_write_file(fdp, META_FILE, offs,
276 			(void *)&meta->info, sizeof(meta->info),
277 			meta->encrypted_fek);
278 }
279 
280 static TEE_Result write_meta_counter(struct tee_fs_fd *fdp)
281 {
282 	TEE_Result res;
283 	struct tee_fs_rpc_operation op;
284 	size_t bytes = sizeof(uint32_t);
285 	void *data;
286 
287 	res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS,
288 					fdp->fd, 0, bytes, &data);
289 	if (res != TEE_SUCCESS)
290 		return res;
291 
292 	memcpy(data, &fdp->meta_counter, bytes);
293 
294 	return tee_fs_rpc_new_write_final(&op);
295 }
296 
297 static TEE_Result create_meta(struct tee_fs_fd *fdp, const char *fname)
298 {
299 	TEE_Result res;
300 
301 	memset(fdp->meta.info.backup_version_table, 0xff,
302 		sizeof(fdp->meta.info.backup_version_table));
303 	fdp->meta.info.length = 0;
304 
305 	res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE);
306 	if (res != TEE_SUCCESS)
307 		return res;
308 
309 	res = tee_fs_rpc_new_create(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd);
310 	if (res != TEE_SUCCESS)
311 		return res;
312 
313 	fdp->meta.counter = fdp->meta_counter;
314 
315 	res = write_meta_file(fdp, &fdp->meta);
316 	if (res != TEE_SUCCESS)
317 		return res;
318 	return write_meta_counter(fdp);
319 }
320 
321 static TEE_Result commit_meta_file(struct tee_fs_fd *fdp,
322 				   struct tee_fs_file_meta *new_meta)
323 {
324 	TEE_Result res;
325 
326 	new_meta->counter = fdp->meta_counter + 1;
327 
328 	res = write_meta_file(fdp, new_meta);
329 	if (res != TEE_SUCCESS)
330 		return res;
331 
332 	/*
333 	 * From now on the new meta is successfully committed,
334 	 * change tee_fs_fd accordingly
335 	 */
336 	fdp->meta = *new_meta;
337 	fdp->meta_counter = fdp->meta.counter;
338 
339 	return write_meta_counter(fdp);
340 }
341 
342 static TEE_Result read_meta_file(struct tee_fs_fd *fdp,
343 		struct tee_fs_file_meta *meta)
344 {
345 	size_t meta_info_size = sizeof(struct tee_fs_file_info);
346 	size_t offs = meta_pos_raw(fdp, true);
347 
348 	return read_and_decrypt_file(fdp, META_FILE, offs,
349 				     &meta->info, &meta_info_size,
350 				     meta->encrypted_fek);
351 }
352 
353 static TEE_Result read_meta_counter(struct tee_fs_fd *fdp)
354 {
355 	TEE_Result res;
356 	struct tee_fs_rpc_operation op;
357 	void *data;
358 	size_t bytes = sizeof(uint32_t);
359 
360 	res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS,
361 				       fdp->fd, 0, bytes, &data);
362 	if (res != TEE_SUCCESS)
363 		return res;
364 
365 	res = tee_fs_rpc_new_read_final(&op, &bytes);
366 	if (res != TEE_SUCCESS)
367 		return res;
368 
369 	if (bytes != sizeof(uint32_t))
370 		return TEE_ERROR_CORRUPT_OBJECT;
371 
372 	memcpy(&fdp->meta_counter, data, bytes);
373 
374 	return TEE_SUCCESS;
375 }
376 
377 static TEE_Result read_meta(struct tee_fs_fd *fdp, const char *fname)
378 {
379 	TEE_Result res;
380 
381 	res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd);
382 	if (res != TEE_SUCCESS)
383 		return res;
384 
385 	res = read_meta_counter(fdp);
386 	if (res != TEE_SUCCESS)
387 		return res;
388 
389 	return read_meta_file(fdp, &fdp->meta);
390 }
391 
392 static bool is_block_file_exist(struct tee_fs_file_meta *meta,
393 					size_t block_num)
394 {
395 	size_t file_size = meta->info.length;
396 
397 	if (file_size == 0)
398 		return false;
399 
400 	return (block_num <= (size_t)get_last_block_num(file_size));
401 }
402 
403 static TEE_Result read_block_from_storage(struct tee_fs_fd *fdp,
404 					  struct block *b)
405 {
406 	TEE_Result res = TEE_SUCCESS;
407 	uint8_t *plaintext = b->data;
408 	size_t block_file_size = BLOCK_FILE_SIZE;
409 	size_t offs = block_pos_raw(&fdp->meta, b->block_num, true);
410 
411 	if (!is_block_file_exist(&fdp->meta, b->block_num))
412 		goto exit;
413 
414 	res = read_and_decrypt_file(fdp, BLOCK_FILE, offs, plaintext,
415 				    &block_file_size, fdp->meta.encrypted_fek);
416 	if (res != TEE_SUCCESS) {
417 		EMSG("Failed to read and decrypt file");
418 		goto exit;
419 	}
420 	if (block_file_size != BLOCK_FILE_SIZE)
421 		return TEE_ERROR_GENERIC;
422 	DMSG("Successfully read and decrypt block%d from storage",
423 	     b->block_num);
424 exit:
425 	return res;
426 }
427 
428 static int flush_block_to_storage(struct tee_fs_fd *fdp, struct block *b,
429 					 struct tee_fs_file_meta *new_meta)
430 {
431 	TEE_Result res;
432 	size_t block_num = b->block_num;
433 	size_t offs = block_pos_raw(&fdp->meta, b->block_num, false);
434 
435 	res = encrypt_and_write_file(fdp, BLOCK_FILE, offs, b->data,
436 				     BLOCK_FILE_SIZE, new_meta->encrypted_fek);
437 	if (res != TEE_SUCCESS) {
438 		EMSG("Failed to encrypt and write block file");
439 		goto fail;
440 	}
441 
442 	DMSG("Successfully encrypt and write block%d to storage",
443 	     b->block_num);
444 	toggle_backup_version_of_block(new_meta, block_num);
445 
446 	return 0;
447 fail:
448 	return -1;
449 }
450 
451 static struct block *alloc_block(void)
452 {
453 	struct block *c;
454 
455 	c = malloc(sizeof(struct block));
456 	if (!c)
457 		return NULL;
458 
459 	c->data = malloc(BLOCK_FILE_SIZE);
460 	if (!c->data) {
461 		EMSG("unable to alloc memory for block data");
462 		goto exit;
463 	}
464 
465 	c->block_num = -1;
466 
467 	return c;
468 
469 exit:
470 	free(c);
471 	return NULL;
472 }
473 
474 #ifdef CFG_FS_BLOCK_CACHE
475 static void free_block(struct block *b)
476 {
477 	if (b) {
478 		free(b->data);
479 		free(b);
480 	}
481 }
482 
483 static inline bool is_block_data_invalid(struct block *b)
484 {
485 	return (b->data_size == 0);
486 }
487 
488 static void get_block_from_cache(struct block_cache *cache,
489 			int block_num, struct block **out_block)
490 {
491 	struct block *b, *found = NULL;
492 
493 	DMSG("Try to find block%d in cache", block_num);
494 	TAILQ_FOREACH(b, &cache->block_lru, list) {
495 		if (b->block_num == block_num) {
496 			DMSG("Found in cache");
497 			found = b;
498 			break;
499 		}
500 	}
501 
502 	if (found) {
503 		TAILQ_REMOVE(&cache->block_lru, found, list);
504 		TAILQ_INSERT_HEAD(&cache->block_lru, found, list);
505 		*out_block = found;
506 		return;
507 	}
508 
509 	DMSG("Not found, reuse oldest block on LRU list");
510 	b = TAILQ_LAST(&cache->block_lru, block_head);
511 	TAILQ_REMOVE(&cache->block_lru, b, list);
512 	TAILQ_INSERT_HEAD(&cache->block_lru, b, list);
513 	b->block_num = block_num;
514 	b->data_size = 0;
515 	*out_block = b;
516 }
517 
518 static int init_block_cache(struct block_cache *cache)
519 {
520 	struct block *b;
521 
522 	TAILQ_INIT(&cache->block_lru);
523 	cache->cached_block_num = 0;
524 
525 	while (cache->cached_block_num < MAX_NUM_CACHED_BLOCKS) {
526 
527 		b = alloc_block();
528 		if (!b) {
529 			EMSG("Failed to alloc block");
530 			goto fail;
531 		} else {
532 			TAILQ_INSERT_HEAD(&cache->block_lru, b, list);
533 			cache->cached_block_num++;
534 		}
535 	}
536 	return 0;
537 
538 fail:
539 	TAILQ_FOREACH(b, &cache->block_lru, list)
540 		free_block(b);
541 	return -1;
542 }
543 
544 static void destroy_block_cache(struct block_cache *cache)
545 {
546 	struct block *b, *next;
547 
548 	TAILQ_FOREACH_SAFE(b, &cache->block_lru, list, next) {
549 		TAILQ_REMOVE(&cache->block_lru, b, list);
550 		free_block(b);
551 	}
552 }
553 #else
554 static int init_block_cache(struct block_cache *cache __unused)
555 {
556 	return 0;
557 }
558 
559 static void destroy_block_cache(struct block_cache *cache __unused)
560 {
561 }
562 #endif
563 
564 static void write_data_to_block(struct block *b, int offset,
565 				void *buf, size_t len)
566 {
567 	DMSG("Write %zd bytes to block%d", len, b->block_num);
568 	memcpy(b->data + offset, buf, len);
569 }
570 
571 static void read_data_from_block(struct block *b, int offset,
572 				void *buf, size_t len)
573 {
574 	DMSG("Read %zd bytes from block%d", len, b->block_num);
575 	memcpy(buf, b->data + offset, len);
576 }
577 
578 #ifdef CFG_FS_BLOCK_CACHE
579 static struct block *read_block_with_cache(struct tee_fs_fd *fdp, int block_num)
580 {
581 	struct block *b;
582 
583 	get_block_from_cache(&fdp->block_cache, block_num, &b);
584 	if (is_block_data_invalid(b))
585 		if (read_block_from_storage(fdp, b)) {
586 			EMSG("Unable to read block%d from storage",
587 					block_num);
588 			return NULL;
589 		}
590 
591 	return b;
592 }
593 #else
594 
595 static struct block *read_block_no_cache(struct tee_fs_fd *fdp, int block_num)
596 {
597 	static struct block *b;
598 	TEE_Result res;
599 
600 	if (!b)
601 		b = alloc_block();
602 	b->block_num = block_num;
603 
604 	res = read_block_from_storage(fdp, b);
605 	if (res != TEE_SUCCESS)
606 		EMSG("Unable to read block%d from storage",
607 				block_num);
608 
609 	return res != TEE_SUCCESS ? NULL : b;
610 }
611 #endif
612 
613 static struct block_operations block_ops = {
614 #ifdef CFG_FS_BLOCK_CACHE
615 	.read = read_block_with_cache,
616 #else
617 	.read = read_block_no_cache,
618 #endif
619 	.write = flush_block_to_storage,
620 };
621 
622 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, const void *buf,
623 		size_t len, struct tee_fs_file_meta *new_meta)
624 {
625 	int start_block_num = pos_to_block_num(fdp->pos);
626 	int end_block_num = pos_to_block_num(fdp->pos + len - 1);
627 	size_t remain_bytes = len;
628 	uint8_t *data_ptr = (uint8_t *)buf;
629 	int orig_pos = fdp->pos;
630 
631 	while (start_block_num <= end_block_num) {
632 		int offset = fdp->pos % BLOCK_FILE_SIZE;
633 		struct block *b;
634 		size_t size_to_write = (remain_bytes > BLOCK_FILE_SIZE) ?
635 			BLOCK_FILE_SIZE : remain_bytes;
636 
637 		if (size_to_write + offset > BLOCK_FILE_SIZE)
638 			size_to_write = BLOCK_FILE_SIZE - offset;
639 
640 		b = block_ops.read(fdp, start_block_num);
641 		if (!b)
642 			goto failed;
643 
644 		DMSG("Write data, offset: %d, size_to_write: %zd",
645 			offset, size_to_write);
646 		write_data_to_block(b, offset, data_ptr, size_to_write);
647 
648 		if (block_ops.write(fdp, b, new_meta)) {
649 			EMSG("Unable to wrtie block%d to storage",
650 					b->block_num);
651 			goto failed;
652 		}
653 
654 		data_ptr += size_to_write;
655 		remain_bytes -= size_to_write;
656 		start_block_num++;
657 		fdp->pos += size_to_write;
658 	}
659 
660 	if (fdp->pos > (tee_fs_off_t)new_meta->info.length)
661 		new_meta->info.length = fdp->pos;
662 
663 	return TEE_SUCCESS;
664 failed:
665 	fdp->pos = orig_pos;
666 	return TEE_ERROR_GENERIC;
667 }
668 
669 static TEE_Result open_internal(const char *file, bool create, bool overwrite,
670 				struct tee_file_handle **fh)
671 {
672 	TEE_Result res;
673 	size_t len;
674 	struct tee_fs_fd *fdp = NULL;
675 
676 	if (!file)
677 		return TEE_ERROR_BAD_PARAMETERS;
678 
679 	len = strlen(file) + 1;
680 	if (len > TEE_FS_NAME_MAX)
681 		return TEE_ERROR_BAD_PARAMETERS;
682 
683 	fdp = calloc(1, sizeof(struct tee_fs_fd));
684 	if (!fdp)
685 		return TEE_ERROR_OUT_OF_MEMORY;
686 	fdp->fd = -1;
687 
688 	mutex_lock(&ree_fs_mutex);
689 
690 	/* init internal status */
691 	if (init_block_cache(&fdp->block_cache)) {
692 		res = TEE_ERROR_OUT_OF_MEMORY;
693 		goto exit_free_fd;
694 	}
695 
696 	res = read_meta(fdp, file);
697 	if (res == TEE_SUCCESS) {
698 		if (overwrite) {
699 			res = TEE_ERROR_ACCESS_CONFLICT;
700 			goto exit_close_file;
701 		}
702 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
703 		if (!create)
704 			goto exit_destroy_block_cache;
705 		res = create_meta(fdp, file);
706 		if (res != TEE_SUCCESS)
707 			goto exit_close_file;
708 	} else {
709 		goto exit_destroy_block_cache;
710 	}
711 
712 	*fh = (struct tee_file_handle *)fdp;
713 	goto exit;
714 
715 exit_close_file:
716 	if (fdp->fd != -1)
717 		tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
718 	if (create)
719 		tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, file);
720 exit_destroy_block_cache:
721 	destroy_block_cache(&fdp->block_cache);
722 exit_free_fd:
723 	free(fdp);
724 exit:
725 	mutex_unlock(&ree_fs_mutex);
726 	return res;
727 }
728 
729 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh)
730 {
731 	return open_internal(file, false, false, fh);
732 }
733 
734 static TEE_Result ree_fs_create(const char *file, bool overwrite,
735 				struct tee_file_handle **fh)
736 {
737 	return open_internal(file, true, overwrite, fh);
738 }
739 
740 static void ree_fs_close(struct tee_file_handle **fh)
741 {
742 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
743 
744 	if (fdp) {
745 		destroy_block_cache(&fdp->block_cache);
746 		tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
747 		free(fdp);
748 		*fh = NULL;
749 	}
750 }
751 
752 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset,
753 			      TEE_Whence whence, int32_t *new_offs)
754 {
755 	TEE_Result res;
756 	tee_fs_off_t new_pos;
757 	size_t filelen;
758 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
759 
760 	mutex_lock(&ree_fs_mutex);
761 
762 	DMSG("offset=%d, whence=%d", (int)offset, whence);
763 
764 	filelen = fdp->meta.info.length;
765 
766 	switch (whence) {
767 	case TEE_DATA_SEEK_SET:
768 		new_pos = offset;
769 		break;
770 
771 	case TEE_DATA_SEEK_CUR:
772 		new_pos = fdp->pos + offset;
773 		break;
774 
775 	case TEE_DATA_SEEK_END:
776 		new_pos = filelen + offset;
777 		break;
778 
779 	default:
780 		res = TEE_ERROR_BAD_PARAMETERS;
781 		goto exit;
782 	}
783 
784 	if (new_pos < 0)
785 		new_pos = 0;
786 
787 	if (new_pos > TEE_DATA_MAX_POSITION) {
788 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
789 		res = TEE_ERROR_BAD_PARAMETERS;
790 		goto exit;
791 	}
792 
793 	fdp->pos = new_pos;
794 	if (new_offs)
795 		*new_offs = new_pos;
796 	res = TEE_SUCCESS;
797 exit:
798 	mutex_unlock(&ree_fs_mutex);
799 	return res;
800 }
801 
802 /*
803  * To ensure atomic truncate operation, we can:
804  *
805  *  - update file length to new length
806  *  - commit new meta
807  *
808  * To ensure atomic extend operation, we can:
809  *
810  *  - update file length to new length
811  *  - allocate and fill zero data to new blocks
812  *  - commit new meta
813  *
814  * Any failure before committing new meta is considered as
815  * update failed, and the file content will not be updated
816  */
817 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
818 					    tee_fs_off_t new_file_len)
819 {
820 	TEE_Result res;
821 	size_t old_file_len = fdp->meta.info.length;
822 	struct tee_fs_file_meta new_meta;
823 
824 	if ((size_t)new_file_len == old_file_len) {
825 		DMSG("Ignore due to file length does not changed");
826 		return TEE_SUCCESS;
827 	}
828 
829 	if (new_file_len > MAX_FILE_SIZE) {
830 		EMSG("Over maximum file size(%d)", MAX_FILE_SIZE);
831 		return TEE_ERROR_BAD_PARAMETERS;
832 	}
833 
834 	new_meta = fdp->meta;
835 	new_meta.info.length = new_file_len;
836 
837 	if ((size_t)new_file_len < old_file_len) {
838 		DMSG("Truncate file length to %zu", (size_t)new_file_len);
839 
840 		res = commit_meta_file(fdp, &new_meta);
841 		if (res != TEE_SUCCESS)
842 			return res;
843 	} else {
844 		size_t ext_len = new_file_len - old_file_len;
845 		int orig_pos = fdp->pos;
846 		uint8_t *buf;
847 
848 		buf = calloc(1, BLOCK_FILE_SIZE);
849 		if (!buf) {
850 			EMSG("Failed to allocate buffer, size=%d",
851 					BLOCK_FILE_SIZE);
852 			return TEE_ERROR_OUT_OF_MEMORY;
853 		}
854 
855 		DMSG("Extend file length to %zu", (size_t)new_file_len);
856 
857 		fdp->pos = old_file_len;
858 
859 		res = TEE_SUCCESS;
860 		while (ext_len > 0) {
861 			size_t data_len = (ext_len > BLOCK_FILE_SIZE) ?
862 					BLOCK_FILE_SIZE : ext_len;
863 
864 			DMSG("fill len=%zu", data_len);
865 			res = out_of_place_write(fdp, buf, data_len, &new_meta);
866 			if (res != TEE_SUCCESS) {
867 				EMSG("Failed to fill data");
868 				break;
869 			}
870 
871 			ext_len -= data_len;
872 		}
873 
874 		free(buf);
875 		fdp->pos = orig_pos;
876 
877 		if (res == TEE_SUCCESS) {
878 			res = commit_meta_file(fdp, &new_meta);
879 			if (res != TEE_SUCCESS)
880 				EMSG("Failed to commit meta file");
881 		}
882 	}
883 
884 	return res;
885 }
886 
887 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf,
888 			      size_t *len)
889 {
890 	TEE_Result res;
891 	int start_block_num;
892 	int end_block_num;
893 	size_t remain_bytes;
894 	uint8_t *data_ptr = buf;
895 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
896 
897 	mutex_lock(&ree_fs_mutex);
898 
899 	remain_bytes = *len;
900 	if ((fdp->pos + remain_bytes) < remain_bytes ||
901 	    fdp->pos > (tee_fs_off_t)fdp->meta.info.length)
902 		remain_bytes = 0;
903 	else if (fdp->pos + remain_bytes > fdp->meta.info.length)
904 		remain_bytes = fdp->meta.info.length - fdp->pos;
905 
906 	*len = remain_bytes;
907 
908 	if (!remain_bytes) {
909 		res = TEE_SUCCESS;
910 		goto exit;
911 	}
912 
913 	start_block_num = pos_to_block_num(fdp->pos);
914 	end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1);
915 
916 	while (start_block_num <= end_block_num) {
917 		struct block *b;
918 		int offset = fdp->pos % BLOCK_FILE_SIZE;
919 		size_t size_to_read = remain_bytes > BLOCK_FILE_SIZE ?
920 			BLOCK_FILE_SIZE : remain_bytes;
921 
922 		if (size_to_read + offset > BLOCK_FILE_SIZE)
923 			size_to_read = BLOCK_FILE_SIZE - offset;
924 
925 		b = block_ops.read(fdp, start_block_num);
926 		if (!b) {
927 			res = TEE_ERROR_CORRUPT_OBJECT;
928 			goto exit;
929 		}
930 
931 		read_data_from_block(b, offset, data_ptr, size_to_read);
932 		data_ptr += size_to_read;
933 		remain_bytes -= size_to_read;
934 		fdp->pos += size_to_read;
935 
936 		start_block_num++;
937 	}
938 	res = TEE_SUCCESS;
939 exit:
940 	mutex_unlock(&ree_fs_mutex);
941 	return res;
942 }
943 
944 /*
945  * To ensure atomicity of write operation, we need to
946  * do the following steps:
947  * (The sequence of operations is very important)
948  *
949  *  - Create a new backup version of meta file as a copy
950  *    of current meta file.
951  *  - For each blocks to write:
952  *    - Create new backup version for current block.
953  *    - Write data to new backup version.
954  *    - Update the new meta file accordingly.
955  *  - Write the new meta file.
956  *
957  * (Any failure in above steps is considered as update failed,
958  *  and the file content will not be updated)
959  */
960 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf,
961 			       size_t len)
962 {
963 	TEE_Result res;
964 	struct tee_fs_file_meta new_meta;
965 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
966 	size_t file_size;
967 
968 
969 	if (!len)
970 		return TEE_SUCCESS;
971 
972 	mutex_lock(&ree_fs_mutex);
973 
974 	file_size = fdp->meta.info.length;
975 
976 	if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) {
977 		res = TEE_ERROR_BAD_PARAMETERS;
978 		goto exit;
979 	}
980 
981 	if (file_size < (size_t)fdp->pos) {
982 		res = ree_fs_ftruncate_internal(fdp, fdp->pos);
983 		if (res != TEE_SUCCESS)
984 			goto exit;
985 	}
986 
987 	new_meta = fdp->meta;
988 	res = out_of_place_write(fdp, buf, len, &new_meta);
989 	if (res != TEE_SUCCESS)
990 		goto exit;
991 
992 	res = commit_meta_file(fdp, &new_meta);
993 exit:
994 	mutex_unlock(&ree_fs_mutex);
995 	return res;
996 }
997 
998 static TEE_Result ree_fs_rename_internal(const char *old, const char *new,
999 					 bool overwrite)
1000 {
1001 	size_t old_len;
1002 	size_t new_len;
1003 
1004 	DMSG("old=%s, new=%s", old, new);
1005 
1006 	old_len = strlen(old) + 1;
1007 	new_len = strlen(new) + 1;
1008 
1009 	if (old_len > TEE_FS_NAME_MAX || new_len > TEE_FS_NAME_MAX)
1010 		return TEE_ERROR_BAD_PARAMETERS;
1011 
1012 	return tee_fs_rpc_new_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite);
1013 }
1014 
1015 static TEE_Result ree_fs_rename(const char *old, const char *new,
1016 				bool overwrite)
1017 {
1018 	TEE_Result res;
1019 
1020 	mutex_lock(&ree_fs_mutex);
1021 	res = ree_fs_rename_internal(old, new, overwrite);
1022 	mutex_unlock(&ree_fs_mutex);
1023 
1024 	return res;
1025 }
1026 
1027 static TEE_Result ree_fs_remove(const char *file)
1028 {
1029 	TEE_Result res;
1030 
1031 	mutex_lock(&ree_fs_mutex);
1032 	res = tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, file);
1033 	mutex_unlock(&ree_fs_mutex);
1034 
1035 	return res;
1036 }
1037 
1038 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
1039 {
1040 	TEE_Result res;
1041 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
1042 
1043 	mutex_lock(&ree_fs_mutex);
1044 	res = ree_fs_ftruncate_internal(fdp, len);
1045 	mutex_unlock(&ree_fs_mutex);
1046 
1047 	return res;
1048 }
1049 
1050 const struct tee_file_operations ree_fs_ops = {
1051 	.open = ree_fs_open,
1052 	.create = ree_fs_create,
1053 	.close = ree_fs_close,
1054 	.read = ree_fs_read,
1055 	.write = ree_fs_write,
1056 	.seek = ree_fs_seek,
1057 	.truncate = ree_fs_truncate,
1058 	.rename = ree_fs_rename,
1059 	.remove = ree_fs_remove,
1060 	.opendir = ree_fs_opendir_rpc,
1061 	.closedir = ree_fs_closedir_rpc,
1062 	.readdir = ree_fs_readdir_rpc,
1063 };
1064