7a82acbe7c65cdfb98ba16037e95d426832a2450
[platform/core/security/tef-optee_os.git] / core / tee / tee_ree_fs.c
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_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_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_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_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_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_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_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_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_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0,
275                                     bytes, &data);
276         if (res != TEE_SUCCESS)
277                 return res;
278
279         memcpy(data, &fdp->meta_counter, bytes);
280
281         return tee_fs_rpc_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_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_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0,
348                                    bytes, &data);
349         if (res != TEE_SUCCESS)
350                 return res;
351
352         res = tee_fs_rpc_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_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_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, pos,
390                                    ct_size, &ct);
391         if (res != TEE_SUCCESS)
392                 return res;
393         res = tee_fs_rpc_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,
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         if (create)
494                 res = create_meta(fdp, file);
495         else
496                 res = read_meta(fdp, file);
497
498         if (res == TEE_SUCCESS) {
499                 *fh = (struct tee_file_handle *)fdp;
500         } else {
501                 if (fdp->fd != -1)
502                         tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
503                 if (create)
504                         tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file);
505                 free(fdp);
506         }
507
508         mutex_unlock(&ree_fs_mutex);
509         return res;
510 }
511
512 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh)
513 {
514         return open_internal(file, false, fh);
515 }
516
517 static TEE_Result ree_fs_create(const char *file, struct tee_file_handle **fh)
518 {
519         return open_internal(file, true, fh);
520 }
521
522 static void ree_fs_close(struct tee_file_handle **fh)
523 {
524         struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
525
526         if (fdp) {
527                 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
528                 free(fdp);
529                 *fh = NULL;
530         }
531 }
532
533 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset,
534                               TEE_Whence whence, int32_t *new_offs)
535 {
536         TEE_Result res;
537         tee_fs_off_t new_pos;
538         size_t filelen;
539         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
540
541         mutex_lock(&ree_fs_mutex);
542
543         DMSG("offset=%d, whence=%d", (int)offset, whence);
544
545         filelen = fdp->meta.info.length;
546
547         switch (whence) {
548         case TEE_DATA_SEEK_SET:
549                 new_pos = offset;
550                 break;
551
552         case TEE_DATA_SEEK_CUR:
553                 new_pos = fdp->pos + offset;
554                 break;
555
556         case TEE_DATA_SEEK_END:
557                 new_pos = filelen + offset;
558                 break;
559
560         default:
561                 res = TEE_ERROR_BAD_PARAMETERS;
562                 goto exit;
563         }
564
565         if (new_pos < 0)
566                 new_pos = 0;
567
568         if (new_pos > TEE_DATA_MAX_POSITION) {
569                 EMSG("Position is beyond TEE_DATA_MAX_POSITION");
570                 res = TEE_ERROR_BAD_PARAMETERS;
571                 goto exit;
572         }
573
574         fdp->pos = new_pos;
575         if (new_offs)
576                 *new_offs = new_pos;
577         res = TEE_SUCCESS;
578 exit:
579         mutex_unlock(&ree_fs_mutex);
580         return res;
581 }
582
583 /*
584  * To ensure atomic truncate operation, we can:
585  *
586  *  - update file length to new length
587  *  - commit new meta
588  *
589  * To ensure atomic extend operation, we can:
590  *
591  *  - update file length to new length
592  *  - allocate and fill zero data to new blocks
593  *  - commit new meta
594  *
595  * Any failure before committing new meta is considered as
596  * update failed, and the file content will not be updated
597  */
598 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
599                                             tee_fs_off_t new_file_len)
600 {
601         TEE_Result res;
602         size_t old_file_len = fdp->meta.info.length;
603         struct tee_fs_file_meta new_meta;
604
605         if (new_file_len > MAX_FILE_SIZE)
606                 return TEE_ERROR_BAD_PARAMETERS;
607
608         new_meta = fdp->meta;
609         new_meta.info.length = new_file_len;
610
611         if ((size_t)new_file_len > old_file_len) {
612                 size_t ext_len = new_file_len - old_file_len;
613                 int orig_pos = fdp->pos;
614
615                 fdp->pos = old_file_len;
616                 res = out_of_place_write(fdp, NULL, ext_len, &new_meta);
617                 fdp->pos = orig_pos;
618                 if (res != TEE_SUCCESS)
619                         return res;
620         }
621
622         return commit_meta_file(fdp, &new_meta);
623 }
624
625 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf,
626                               size_t *len)
627 {
628         TEE_Result res;
629         int start_block_num;
630         int end_block_num;
631         size_t remain_bytes;
632         uint8_t *data_ptr = buf;
633         uint8_t *block = NULL;
634         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
635
636         mutex_lock(&ree_fs_mutex);
637
638         remain_bytes = *len;
639         if ((fdp->pos + remain_bytes) < remain_bytes ||
640             fdp->pos > (tee_fs_off_t)fdp->meta.info.length)
641                 remain_bytes = 0;
642         else if (fdp->pos + (tee_fs_off_t)remain_bytes >
643                 (tee_fs_off_t)fdp->meta.info.length)
644                 remain_bytes = fdp->meta.info.length - fdp->pos;
645
646         *len = remain_bytes;
647
648         if (!remain_bytes) {
649                 res = TEE_SUCCESS;
650                 goto exit;
651         }
652
653         start_block_num = pos_to_block_num(fdp->pos);
654         end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1);
655
656         block = malloc(BLOCK_SIZE);
657         if (!block) {
658                 res = TEE_ERROR_OUT_OF_MEMORY;
659                 goto exit;
660         }
661
662         while (start_block_num <= end_block_num) {
663                 tee_fs_off_t offset = fdp->pos % BLOCK_SIZE;
664                 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
665
666                 if (size_to_read + offset > BLOCK_SIZE)
667                         size_to_read = BLOCK_SIZE - offset;
668
669                 res = read_block(fdp, start_block_num, block);
670                 if (res != TEE_SUCCESS) {
671                         if (res == TEE_ERROR_MAC_INVALID)
672                                 res = TEE_ERROR_CORRUPT_OBJECT;
673                         goto exit;
674                 }
675
676                 memcpy(data_ptr, block + offset, size_to_read);
677
678                 data_ptr += size_to_read;
679                 remain_bytes -= size_to_read;
680                 fdp->pos += size_to_read;
681
682                 start_block_num++;
683         }
684         res = TEE_SUCCESS;
685 exit:
686         mutex_unlock(&ree_fs_mutex);
687         free(block);
688         return res;
689 }
690
691 /*
692  * To ensure atomicity of write operation, we need to
693  * do the following steps:
694  * (The sequence of operations is very important)
695  *
696  *  - Create a new backup version of meta file as a copy
697  *    of current meta file.
698  *  - For each blocks to write:
699  *    - Create new backup version for current block.
700  *    - Write data to new backup version.
701  *    - Update the new meta file accordingly.
702  *  - Write the new meta file.
703  *
704  * (Any failure in above steps is considered as update failed,
705  *  and the file content will not be updated)
706  */
707 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf,
708                                size_t len)
709 {
710         TEE_Result res;
711         struct tee_fs_file_meta new_meta;
712         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
713         size_t file_size;
714
715         if (!len)
716                 return TEE_SUCCESS;
717
718         mutex_lock(&ree_fs_mutex);
719
720         file_size = fdp->meta.info.length;
721
722         if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) {
723                 res = TEE_ERROR_BAD_PARAMETERS;
724                 goto exit;
725         }
726
727         if (file_size < (size_t)fdp->pos) {
728                 res = ree_fs_ftruncate_internal(fdp, fdp->pos);
729                 if (res != TEE_SUCCESS)
730                         goto exit;
731         }
732
733         new_meta = fdp->meta;
734         res = out_of_place_write(fdp, buf, len, &new_meta);
735         if (res != TEE_SUCCESS)
736                 goto exit;
737
738         res = commit_meta_file(fdp, &new_meta);
739 exit:
740         mutex_unlock(&ree_fs_mutex);
741         return res;
742 }
743
744 static TEE_Result ree_fs_rename(const char *old, const char *new,
745                                 bool overwrite)
746 {
747         TEE_Result res;
748
749         mutex_lock(&ree_fs_mutex);
750         res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite);
751         mutex_unlock(&ree_fs_mutex);
752
753         return res;
754 }
755
756 static TEE_Result ree_fs_remove(const char *file)
757 {
758         TEE_Result res;
759
760         mutex_lock(&ree_fs_mutex);
761         res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file);
762         mutex_unlock(&ree_fs_mutex);
763
764         return res;
765 }
766
767 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
768 {
769         TEE_Result res;
770         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
771
772         mutex_lock(&ree_fs_mutex);
773         res = ree_fs_ftruncate_internal(fdp, len);
774         mutex_unlock(&ree_fs_mutex);
775
776         return res;
777 }
778
779 const struct tee_file_operations ree_fs_ops = {
780         .open = ree_fs_open,
781         .create = ree_fs_create,
782         .close = ree_fs_close,
783         .read = ree_fs_read,
784         .write = ree_fs_write,
785         .seek = ree_fs_seek,
786         .truncate = ree_fs_truncate,
787         .rename = ree_fs_rename,
788         .remove = ree_fs_remove,
789         .opendir = ree_fs_opendir_rpc,
790         .closedir = ree_fs_closedir_rpc,
791         .readdir = ree_fs_readdir_rpc,
792 };