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