xref: /optee_os/core/tee/tee_ree_fs.c (revision eaf1547cbd2cb77e0a7996c01a26ca528a32180f)
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_supplicant.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_rpc.h>
42 #include <tee/tee_fs_key_manager.h>
43 #include <trace.h>
44 #include <utee_defines.h>
45 #include <util.h>
46 
47 /*
48  * This file implements the tee_file_operations structure for a secure
49  * filesystem based on single file in normal world.
50  *
51  * All fields in the REE file are duplicated with two versions 0 and 1. The
52  * active meta-data block is selected by the lowest bit in the
53  * meta-counter.  The active file block is selected by corresponding bit
54  * number in struct tee_fs_file_info.backup_version_table.
55  *
56  * The atomicity of each operation is ensured by updating meta-counter when
57  * everything in the secondary blocks (both meta-data and file-data blocks)
58  * are successfully written.  The main purpose of the code below is to
59  * perform block encryption and authentication of the file data, and
60  * properly handle seeking through the file. One file (in the sense of
61  * struct tee_file_operations) maps to one file in the REE filesystem, and
62  * has the following structure:
63  *
64  * [ 4 bytes meta-counter]
65  * [ meta-data version 0][ meta-data version 1 ]
66  * [ Block 0 version 0 ][ Block 0 version 1 ]
67  * [ Block 1 version 0 ][ Block 1 version 1 ]
68  * ...
69  * [ Block n version 0 ][ Block n version 1 ]
70  *
71  * One meta-data block is built up as:
72  * [ struct meta_header | struct tee_fs_get_header_size ]
73  *
74  * One data block is built up as:
75  * [ struct block_header | BLOCK_FILE_SIZE bytes ]
76  *
77  * struct meta_header and struct block_header are defined in
78  * tee_fs_key_manager.h.
79  *
80  */
81 
82 #define BLOCK_SHIFT	12
83 
84 #define BLOCK_SIZE	(1 << BLOCK_SHIFT)
85 
86 #define MAX_FILE_SIZE	(BLOCK_SIZE * NUM_BLOCKS_PER_FILE)
87 
88 struct tee_fs_fd {
89 	uint32_t meta_counter;
90 	struct tee_fs_file_meta meta;
91 	tee_fs_off_t pos;
92 	uint32_t flags;
93 	bool is_new_file;
94 	int fd;
95 };
96 
97 static inline int pos_to_block_num(int position)
98 {
99 	return position >> BLOCK_SHIFT;
100 }
101 
102 static inline int get_last_block_num(size_t size)
103 {
104 	return pos_to_block_num(size - 1);
105 }
106 
107 static bool get_backup_version_of_block(struct tee_fs_file_meta *meta,
108 					size_t block_num)
109 {
110 	uint32_t index = (block_num / 32);
111 	uint32_t block_mask = 1 << (block_num % 32);
112 
113 	return !!(meta->info.backup_version_table[index] & block_mask);
114 }
115 
116 static inline void toggle_backup_version_of_block(
117 		struct tee_fs_file_meta *meta,
118 		size_t block_num)
119 {
120 	uint32_t index = (block_num / 32);
121 	uint32_t block_mask = 1 << (block_num % 32);
122 
123 	meta->info.backup_version_table[index] ^= block_mask;
124 }
125 
126 struct block_operations {
127 
128 	/*
129 	 * Read a block from REE File System which is corresponding
130 	 * to the given block_num.
131 	 */
132 	struct block *(*read)(struct tee_fs_fd *fdp, int block_num);
133 
134 	/*
135 	 * Write the given block to REE File System
136 	 */
137 	int (*write)(struct tee_fs_fd *fdp, struct block *b,
138 			struct tee_fs_file_meta *new_meta);
139 };
140 
141 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
142 
143 static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d)
144 
145 {
146 	return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name, d);
147 }
148 
149 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
150 {
151 	if (d)
152 		tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d);
153 }
154 
155 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
156 				     struct tee_fs_dirent **ent)
157 {
158 	return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent);
159 }
160 
161 static size_t meta_size(void)
162 {
163 	return tee_fs_get_header_size(META_FILE) +
164 	       sizeof(struct tee_fs_file_meta);
165 }
166 
167 static size_t meta_pos_raw(struct tee_fs_fd *fdp, bool active)
168 {
169 	size_t offs = sizeof(uint32_t);
170 
171 	if ((fdp->meta_counter & 1) == active)
172 		offs += meta_size();
173 	return offs;
174 }
175 
176 static size_t block_size_raw(void)
177 {
178 	return tee_fs_get_header_size(BLOCK_FILE) + BLOCK_SIZE;
179 }
180 
181 static size_t block_pos_raw(struct tee_fs_file_meta *meta, size_t block_num,
182 			    bool active)
183 {
184 	size_t n = block_num * 2;
185 
186 	if (active == get_backup_version_of_block(meta, block_num))
187 		n++;
188 
189 	return sizeof(uint32_t) + meta_size() * 2 + n * block_size_raw();
190 }
191 
192 /*
193  * encrypted_fek: as input for META_FILE and BLOCK_FILE
194  */
195 static TEE_Result encrypt_and_write_file(struct tee_fs_fd *fdp,
196 		enum tee_fs_file_type file_type, size_t offs,
197 		void *data_in, size_t data_in_size,
198 		uint8_t *encrypted_fek)
199 {
200 	TEE_Result res;
201 	struct tee_fs_rpc_operation op;
202 	void *ciphertext;
203 	size_t header_size = tee_fs_get_header_size(file_type);
204 	size_t ciphertext_size = header_size + data_in_size;
205 
206 
207 	res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
208 				    offs, ciphertext_size, &ciphertext);
209 	if (res != TEE_SUCCESS)
210 		return res;
211 
212 	res = tee_fs_encrypt_file(file_type, data_in, data_in_size,
213 				  ciphertext, &ciphertext_size, encrypted_fek);
214 	if (res != TEE_SUCCESS)
215 		return res;
216 
217 	return tee_fs_rpc_write_final(&op);
218 }
219 
220 /*
221  * encrypted_fek: as output for META_FILE
222  *                as input for BLOCK_FILE
223  */
224 static TEE_Result read_and_decrypt_file(struct tee_fs_fd *fdp,
225 		enum tee_fs_file_type file_type, size_t offs,
226 		void *data_out, size_t *data_out_size,
227 		uint8_t *encrypted_fek)
228 {
229 	TEE_Result res;
230 	struct tee_fs_rpc_operation op;
231 	size_t bytes;
232 	void *ciphertext;
233 
234 	bytes = *data_out_size + tee_fs_get_header_size(file_type);
235 	res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, offs,
236 				   bytes, &ciphertext);
237 	if (res != TEE_SUCCESS)
238 		return res;
239 
240 	res = tee_fs_rpc_read_final(&op, &bytes);
241 	if (res != TEE_SUCCESS)
242 		return res;
243 
244 	if (!bytes) {
245 		*data_out_size = 0;
246 		return TEE_SUCCESS;
247 	}
248 
249 	res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out,
250 				  data_out_size, encrypted_fek);
251 	if (res != TEE_SUCCESS)
252 		return TEE_ERROR_CORRUPT_OBJECT;
253 	return TEE_SUCCESS;
254 }
255 
256 static TEE_Result write_meta_file(struct tee_fs_fd *fdp,
257 		struct tee_fs_file_meta *meta)
258 {
259 	size_t offs = meta_pos_raw(fdp, false);
260 
261 	return encrypt_and_write_file(fdp, META_FILE, offs,
262 			(void *)&meta->info, sizeof(meta->info),
263 			meta->encrypted_fek);
264 }
265 
266 static TEE_Result write_meta_counter(struct tee_fs_fd *fdp)
267 {
268 	TEE_Result res;
269 	struct tee_fs_rpc_operation op;
270 	size_t bytes = sizeof(uint32_t);
271 	void *data;
272 
273 	res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0,
274 				    bytes, &data);
275 	if (res != TEE_SUCCESS)
276 		return res;
277 
278 	memcpy(data, &fdp->meta_counter, bytes);
279 
280 	return tee_fs_rpc_write_final(&op);
281 }
282 
283 static TEE_Result create_meta(struct tee_fs_fd *fdp, const char *fname)
284 {
285 	TEE_Result res;
286 
287 	memset(fdp->meta.info.backup_version_table, 0xff,
288 		sizeof(fdp->meta.info.backup_version_table));
289 	fdp->meta.info.length = 0;
290 
291 	res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE);
292 	if (res != TEE_SUCCESS)
293 		return res;
294 
295 	res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd);
296 	if (res != TEE_SUCCESS)
297 		return res;
298 
299 	fdp->meta.counter = fdp->meta_counter;
300 
301 	res = write_meta_file(fdp, &fdp->meta);
302 	if (res != TEE_SUCCESS)
303 		return res;
304 	return write_meta_counter(fdp);
305 }
306 
307 static TEE_Result commit_meta_file(struct tee_fs_fd *fdp,
308 				   struct tee_fs_file_meta *new_meta)
309 {
310 	TEE_Result res;
311 
312 	new_meta->counter = fdp->meta_counter + 1;
313 
314 	res = write_meta_file(fdp, new_meta);
315 	if (res != TEE_SUCCESS)
316 		return res;
317 
318 	/*
319 	 * From now on the new meta is successfully committed,
320 	 * change tee_fs_fd accordingly
321 	 */
322 	fdp->meta = *new_meta;
323 	fdp->meta_counter = fdp->meta.counter;
324 
325 	return write_meta_counter(fdp);
326 }
327 
328 static TEE_Result read_meta_file(struct tee_fs_fd *fdp,
329 		struct tee_fs_file_meta *meta)
330 {
331 	size_t meta_info_size = sizeof(struct tee_fs_file_info);
332 	size_t offs = meta_pos_raw(fdp, true);
333 
334 	return read_and_decrypt_file(fdp, META_FILE, offs,
335 				     &meta->info, &meta_info_size,
336 				     meta->encrypted_fek);
337 }
338 
339 static TEE_Result read_meta_counter(struct tee_fs_fd *fdp)
340 {
341 	TEE_Result res;
342 	struct tee_fs_rpc_operation op;
343 	void *data;
344 	size_t bytes = sizeof(uint32_t);
345 
346 	res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0,
347 				   bytes, &data);
348 	if (res != TEE_SUCCESS)
349 		return res;
350 
351 	res = tee_fs_rpc_read_final(&op, &bytes);
352 	if (res != TEE_SUCCESS)
353 		return res;
354 
355 	if (bytes != sizeof(uint32_t))
356 		return TEE_ERROR_CORRUPT_OBJECT;
357 
358 	memcpy(&fdp->meta_counter, data, bytes);
359 
360 	return TEE_SUCCESS;
361 }
362 
363 static TEE_Result read_meta(struct tee_fs_fd *fdp, const char *fname)
364 {
365 	TEE_Result res;
366 
367 	res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd);
368 	if (res != TEE_SUCCESS)
369 		return res;
370 
371 	res = read_meta_counter(fdp);
372 	if (res != TEE_SUCCESS)
373 		return res;
374 
375 	return read_meta_file(fdp, &fdp->meta);
376 }
377 
378 static TEE_Result read_block(struct tee_fs_fd *fdp, int bnum, uint8_t *data)
379 {
380 	TEE_Result res;
381 	size_t ct_size = block_size_raw();
382 	size_t out_size = BLOCK_SIZE;
383 	ssize_t pos = block_pos_raw(&fdp->meta, bnum, true);
384 	size_t bytes;
385 	void *ct;
386 	struct tee_fs_rpc_operation op;
387 
388 	res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, pos,
389 				   ct_size, &ct);
390 	if (res != TEE_SUCCESS)
391 		return res;
392 	res = tee_fs_rpc_read_final(&op, &bytes);
393 	if (res != TEE_SUCCESS)
394 		return res;
395 	if (!bytes) {
396 		memset(data, 0, BLOCK_SIZE);
397 		return TEE_SUCCESS; /* Block does not exist */
398 	}
399 
400 	return tee_fs_decrypt_file(BLOCK_FILE, ct, bytes, data,
401 				   &out_size, fdp->meta.encrypted_fek);
402 }
403 
404 static TEE_Result write_block(struct tee_fs_fd *fdp, size_t bnum, uint8_t *data,
405 			      struct tee_fs_file_meta *new_meta)
406 {
407 	TEE_Result res;
408 	size_t offs = block_pos_raw(new_meta, bnum, false);
409 
410 	res = encrypt_and_write_file(fdp, BLOCK_FILE, offs, data,
411 				     BLOCK_SIZE, new_meta->encrypted_fek);
412 	if (res == TEE_SUCCESS)
413 		toggle_backup_version_of_block(new_meta, bnum);
414 	return res;
415 }
416 
417 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, const void *buf,
418 		size_t len, struct tee_fs_file_meta *new_meta)
419 {
420 	TEE_Result res;
421 	int start_block_num = pos_to_block_num(fdp->pos);
422 	int end_block_num = pos_to_block_num(fdp->pos + len - 1);
423 	size_t remain_bytes = len;
424 	uint8_t *data_ptr = (uint8_t *)buf;
425 	uint8_t *block;
426 	int orig_pos = fdp->pos;
427 
428 	block = malloc(BLOCK_SIZE);
429 	if (!block)
430 		return TEE_ERROR_OUT_OF_MEMORY;
431 
432 	while (start_block_num <= end_block_num) {
433 		int offset = fdp->pos % BLOCK_SIZE;
434 		size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
435 
436 		if (size_to_write + offset > BLOCK_SIZE)
437 			size_to_write = BLOCK_SIZE - offset;
438 
439 		res = read_block(fdp, start_block_num, block);
440 		if (res == TEE_ERROR_ITEM_NOT_FOUND)
441 			memset(block, 0, BLOCK_SIZE);
442 		else if (res != TEE_SUCCESS)
443 			goto exit;
444 
445 		if (data_ptr)
446 			memcpy(block + offset, data_ptr, size_to_write);
447 		else
448 			memset(block + offset, 0, size_to_write);
449 
450 		res = write_block(fdp, start_block_num, block, new_meta);
451 		if (res != TEE_SUCCESS)
452 			goto exit;
453 
454 		if (data_ptr)
455 			data_ptr += size_to_write;
456 		remain_bytes -= size_to_write;
457 		start_block_num++;
458 		fdp->pos += size_to_write;
459 	}
460 
461 	if (fdp->pos > (tee_fs_off_t)new_meta->info.length)
462 		new_meta->info.length = fdp->pos;
463 
464 exit:
465 	free(block);
466 	if (res != TEE_SUCCESS)
467 		fdp->pos = orig_pos;
468 	return res;
469 }
470 
471 static TEE_Result open_internal(const char *file, bool create,
472 				struct tee_file_handle **fh)
473 {
474 	TEE_Result res;
475 	size_t len;
476 	struct tee_fs_fd *fdp = NULL;
477 
478 	if (!file)
479 		return TEE_ERROR_BAD_PARAMETERS;
480 
481 	len = strlen(file) + 1;
482 	if (len > TEE_FS_NAME_MAX)
483 		return TEE_ERROR_BAD_PARAMETERS;
484 
485 	fdp = calloc(1, sizeof(struct tee_fs_fd));
486 	if (!fdp)
487 		return TEE_ERROR_OUT_OF_MEMORY;
488 	fdp->fd = -1;
489 
490 	mutex_lock(&ree_fs_mutex);
491 
492 	if (create)
493 		res = create_meta(fdp, file);
494 	else
495 		res = read_meta(fdp, file);
496 
497 	if (res == TEE_SUCCESS) {
498 		*fh = (struct tee_file_handle *)fdp;
499 	} else {
500 		if (fdp->fd != -1)
501 			tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
502 		if (create)
503 			tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file);
504 		free(fdp);
505 	}
506 
507 	mutex_unlock(&ree_fs_mutex);
508 	return res;
509 }
510 
511 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh)
512 {
513 	return open_internal(file, false, fh);
514 }
515 
516 static TEE_Result ree_fs_create(const char *file, struct tee_file_handle **fh)
517 {
518 	return open_internal(file, true, fh);
519 }
520 
521 static void ree_fs_close(struct tee_file_handle **fh)
522 {
523 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
524 
525 	if (fdp) {
526 		tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
527 		free(fdp);
528 		*fh = NULL;
529 	}
530 }
531 
532 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset,
533 			      TEE_Whence whence, int32_t *new_offs)
534 {
535 	TEE_Result res;
536 	tee_fs_off_t new_pos;
537 	size_t filelen;
538 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
539 
540 	mutex_lock(&ree_fs_mutex);
541 
542 	DMSG("offset=%d, whence=%d", (int)offset, whence);
543 
544 	filelen = fdp->meta.info.length;
545 
546 	switch (whence) {
547 	case TEE_DATA_SEEK_SET:
548 		new_pos = offset;
549 		break;
550 
551 	case TEE_DATA_SEEK_CUR:
552 		new_pos = fdp->pos + offset;
553 		break;
554 
555 	case TEE_DATA_SEEK_END:
556 		new_pos = filelen + offset;
557 		break;
558 
559 	default:
560 		res = TEE_ERROR_BAD_PARAMETERS;
561 		goto exit;
562 	}
563 
564 	if (new_pos < 0)
565 		new_pos = 0;
566 
567 	if (new_pos > TEE_DATA_MAX_POSITION) {
568 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
569 		res = TEE_ERROR_BAD_PARAMETERS;
570 		goto exit;
571 	}
572 
573 	fdp->pos = new_pos;
574 	if (new_offs)
575 		*new_offs = new_pos;
576 	res = TEE_SUCCESS;
577 exit:
578 	mutex_unlock(&ree_fs_mutex);
579 	return res;
580 }
581 
582 /*
583  * To ensure atomic truncate operation, we can:
584  *
585  *  - update file length to new length
586  *  - commit new meta
587  *
588  * To ensure atomic extend operation, we can:
589  *
590  *  - update file length to new length
591  *  - allocate and fill zero data to new blocks
592  *  - commit new meta
593  *
594  * Any failure before committing new meta is considered as
595  * update failed, and the file content will not be updated
596  */
597 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
598 					    tee_fs_off_t new_file_len)
599 {
600 	TEE_Result res;
601 	size_t old_file_len = fdp->meta.info.length;
602 	struct tee_fs_file_meta new_meta;
603 
604 	if (new_file_len > MAX_FILE_SIZE)
605 		return TEE_ERROR_BAD_PARAMETERS;
606 
607 	new_meta = fdp->meta;
608 	new_meta.info.length = new_file_len;
609 
610 	if ((size_t)new_file_len > old_file_len) {
611 		size_t ext_len = new_file_len - old_file_len;
612 		int orig_pos = fdp->pos;
613 
614 		fdp->pos = old_file_len;
615 		res = out_of_place_write(fdp, NULL, ext_len, &new_meta);
616 		fdp->pos = orig_pos;
617 		if (res != TEE_SUCCESS)
618 			return res;
619 	}
620 
621 	return commit_meta_file(fdp, &new_meta);
622 }
623 
624 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf,
625 			      size_t *len)
626 {
627 	TEE_Result res;
628 	int start_block_num;
629 	int end_block_num;
630 	size_t remain_bytes;
631 	uint8_t *data_ptr = buf;
632 	uint8_t *block = NULL;
633 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
634 
635 	mutex_lock(&ree_fs_mutex);
636 
637 	remain_bytes = *len;
638 	if ((fdp->pos + remain_bytes) < remain_bytes ||
639 	    fdp->pos > (tee_fs_off_t)fdp->meta.info.length)
640 		remain_bytes = 0;
641 	else if (fdp->pos + (tee_fs_off_t)remain_bytes >
642 		(tee_fs_off_t)fdp->meta.info.length)
643 		remain_bytes = fdp->meta.info.length - fdp->pos;
644 
645 	*len = remain_bytes;
646 
647 	if (!remain_bytes) {
648 		res = TEE_SUCCESS;
649 		goto exit;
650 	}
651 
652 	start_block_num = pos_to_block_num(fdp->pos);
653 	end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1);
654 
655 	block = malloc(BLOCK_SIZE);
656 	if (!block) {
657 		res = TEE_ERROR_OUT_OF_MEMORY;
658 		goto exit;
659 	}
660 
661 	while (start_block_num <= end_block_num) {
662 		tee_fs_off_t offset = fdp->pos % BLOCK_SIZE;
663 		size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
664 
665 		if (size_to_read + offset > BLOCK_SIZE)
666 			size_to_read = BLOCK_SIZE - offset;
667 
668 		res = read_block(fdp, start_block_num, block);
669 		if (res != TEE_SUCCESS) {
670 			if (res == TEE_ERROR_MAC_INVALID)
671 				res = TEE_ERROR_CORRUPT_OBJECT;
672 			goto exit;
673 		}
674 
675 		memcpy(data_ptr, block + offset, size_to_read);
676 
677 		data_ptr += size_to_read;
678 		remain_bytes -= size_to_read;
679 		fdp->pos += size_to_read;
680 
681 		start_block_num++;
682 	}
683 	res = TEE_SUCCESS;
684 exit:
685 	mutex_unlock(&ree_fs_mutex);
686 	free(block);
687 	return res;
688 }
689 
690 /*
691  * To ensure atomicity of write operation, we need to
692  * do the following steps:
693  * (The sequence of operations is very important)
694  *
695  *  - Create a new backup version of meta file as a copy
696  *    of current meta file.
697  *  - For each blocks to write:
698  *    - Create new backup version for current block.
699  *    - Write data to new backup version.
700  *    - Update the new meta file accordingly.
701  *  - Write the new meta file.
702  *
703  * (Any failure in above steps is considered as update failed,
704  *  and the file content will not be updated)
705  */
706 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf,
707 			       size_t len)
708 {
709 	TEE_Result res;
710 	struct tee_fs_file_meta new_meta;
711 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
712 	size_t file_size;
713 
714 	if (!len)
715 		return TEE_SUCCESS;
716 
717 	mutex_lock(&ree_fs_mutex);
718 
719 	file_size = fdp->meta.info.length;
720 
721 	if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) {
722 		res = TEE_ERROR_BAD_PARAMETERS;
723 		goto exit;
724 	}
725 
726 	if (file_size < (size_t)fdp->pos) {
727 		res = ree_fs_ftruncate_internal(fdp, fdp->pos);
728 		if (res != TEE_SUCCESS)
729 			goto exit;
730 	}
731 
732 	new_meta = fdp->meta;
733 	res = out_of_place_write(fdp, buf, len, &new_meta);
734 	if (res != TEE_SUCCESS)
735 		goto exit;
736 
737 	res = commit_meta_file(fdp, &new_meta);
738 exit:
739 	mutex_unlock(&ree_fs_mutex);
740 	return res;
741 }
742 
743 static TEE_Result ree_fs_rename(const char *old, const char *new,
744 				bool overwrite)
745 {
746 	TEE_Result res;
747 
748 	mutex_lock(&ree_fs_mutex);
749 	res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite);
750 	mutex_unlock(&ree_fs_mutex);
751 
752 	return res;
753 }
754 
755 static TEE_Result ree_fs_remove(const char *file)
756 {
757 	TEE_Result res;
758 
759 	mutex_lock(&ree_fs_mutex);
760 	res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file);
761 	mutex_unlock(&ree_fs_mutex);
762 
763 	return res;
764 }
765 
766 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
767 {
768 	TEE_Result res;
769 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
770 
771 	mutex_lock(&ree_fs_mutex);
772 	res = ree_fs_ftruncate_internal(fdp, len);
773 	mutex_unlock(&ree_fs_mutex);
774 
775 	return res;
776 }
777 
778 const struct tee_file_operations ree_fs_ops = {
779 	.open = ree_fs_open,
780 	.create = ree_fs_create,
781 	.close = ree_fs_close,
782 	.read = ree_fs_read,
783 	.write = ree_fs_write,
784 	.seek = ree_fs_seek,
785 	.truncate = ree_fs_truncate,
786 	.rename = ree_fs_rename,
787 	.remove = ree_fs_remove,
788 	.opendir = ree_fs_opendir_rpc,
789 	.closedir = ree_fs_closedir_rpc,
790 	.readdir = ree_fs_readdir_rpc,
791 };
792