2 * Copyright (c) 2015, Linaro Limited
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
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>
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>
45 #include <utee_defines.h>
49 * This file implements the tee_file_operations structure for a secure
50 * filesystem based on single file in normal world.
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.
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:
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 ]
70 * [ Block n version 0 ][ Block n version 1 ]
72 * One meta-data block is built up as:
73 * [ struct meta_header | struct tee_fs_get_header_size ]
75 * One data block is built up as:
76 * [ struct block_header | BLOCK_FILE_SIZE bytes ]
78 * struct meta_header and struct block_header are defined in
79 * tee_fs_key_manager.h.
83 #define BLOCK_SHIFT 12
85 #define BLOCK_SIZE (1 << BLOCK_SHIFT)
87 #define MAX_FILE_SIZE (BLOCK_SIZE * NUM_BLOCKS_PER_FILE)
90 uint32_t meta_counter;
91 struct tee_fs_file_meta meta;
98 static inline int pos_to_block_num(int position)
100 return position >> BLOCK_SHIFT;
103 static inline int get_last_block_num(size_t size)
105 return pos_to_block_num(size - 1);
108 static bool get_backup_version_of_block(struct tee_fs_file_meta *meta,
111 uint32_t index = (block_num / 32);
112 uint32_t block_mask = 1 << (block_num % 32);
114 return !!(meta->info.backup_version_table[index] & block_mask);
117 static inline void toggle_backup_version_of_block(
118 struct tee_fs_file_meta *meta,
121 uint32_t index = (block_num / 32);
122 uint32_t block_mask = 1 << (block_num % 32);
124 meta->info.backup_version_table[index] ^= block_mask;
127 struct block_operations {
130 * Read a block from REE File System which is corresponding
131 * to the given block_num.
133 struct block *(*read)(struct tee_fs_fd *fdp, int block_num);
136 * Write the given block to REE File System
138 int (*write)(struct tee_fs_fd *fdp, struct block *b,
139 struct tee_fs_file_meta *new_meta);
142 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
144 static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d)
147 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name, d);
150 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
153 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d);
156 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
157 struct tee_fs_dirent **ent)
159 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent);
162 static size_t meta_size(void)
164 return tee_fs_get_header_size(META_FILE) +
165 sizeof(struct tee_fs_file_meta);
168 static size_t meta_pos_raw(struct tee_fs_fd *fdp, bool active)
170 size_t offs = sizeof(uint32_t);
172 if ((fdp->meta_counter & 1) == active)
177 static size_t block_size_raw(void)
179 return tee_fs_get_header_size(BLOCK_FILE) + BLOCK_SIZE;
182 static size_t block_pos_raw(struct tee_fs_file_meta *meta, size_t block_num,
185 size_t n = block_num * 2;
187 if (active == get_backup_version_of_block(meta, block_num))
190 return sizeof(uint32_t) + meta_size() * 2 + n * block_size_raw();
194 * encrypted_fek: as input for META_FILE and BLOCK_FILE
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)
202 struct tee_fs_rpc_operation op;
204 size_t header_size = tee_fs_get_header_size(file_type);
205 size_t ciphertext_size = header_size + data_in_size;
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)
213 res = tee_fs_encrypt_file(file_type, data_in, data_in_size,
214 ciphertext, &ciphertext_size, encrypted_fek);
215 if (res != TEE_SUCCESS)
218 return tee_fs_rpc_write_final(&op);
222 * encrypted_fek: as output for META_FILE
223 * as input for BLOCK_FILE
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)
231 struct tee_fs_rpc_operation op;
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,
238 if (res != TEE_SUCCESS)
241 res = tee_fs_rpc_read_final(&op, &bytes);
242 if (res != TEE_SUCCESS)
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;
257 static TEE_Result write_meta_file(struct tee_fs_fd *fdp,
258 struct tee_fs_file_meta *meta)
260 size_t offs = meta_pos_raw(fdp, false);
262 return encrypt_and_write_file(fdp, META_FILE, offs,
263 (void *)&meta->info, sizeof(meta->info),
264 meta->encrypted_fek);
267 static TEE_Result write_meta_counter(struct tee_fs_fd *fdp)
270 struct tee_fs_rpc_operation op;
271 size_t bytes = sizeof(uint32_t);
274 res = tee_fs_rpc_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0,
276 if (res != TEE_SUCCESS)
279 memcpy(data, &fdp->meta_counter, bytes);
281 return tee_fs_rpc_write_final(&op);
284 static TEE_Result create_meta(struct tee_fs_fd *fdp, const char *fname)
288 memset(fdp->meta.info.backup_version_table, 0xff,
289 sizeof(fdp->meta.info.backup_version_table));
290 fdp->meta.info.length = 0;
292 res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE);
293 if (res != TEE_SUCCESS)
296 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd);
297 if (res != TEE_SUCCESS)
300 fdp->meta.counter = fdp->meta_counter;
302 res = write_meta_file(fdp, &fdp->meta);
303 if (res != TEE_SUCCESS)
305 return write_meta_counter(fdp);
308 static TEE_Result commit_meta_file(struct tee_fs_fd *fdp,
309 struct tee_fs_file_meta *new_meta)
313 new_meta->counter = fdp->meta_counter + 1;
315 res = write_meta_file(fdp, new_meta);
316 if (res != TEE_SUCCESS)
320 * From now on the new meta is successfully committed,
321 * change tee_fs_fd accordingly
323 fdp->meta = *new_meta;
324 fdp->meta_counter = fdp->meta.counter;
326 return write_meta_counter(fdp);
329 static TEE_Result read_meta_file(struct tee_fs_fd *fdp,
330 struct tee_fs_file_meta *meta)
332 size_t meta_info_size = sizeof(struct tee_fs_file_info);
333 size_t offs = meta_pos_raw(fdp, true);
335 return read_and_decrypt_file(fdp, META_FILE, offs,
336 &meta->info, &meta_info_size,
337 meta->encrypted_fek);
340 static TEE_Result read_meta_counter(struct tee_fs_fd *fdp)
343 struct tee_fs_rpc_operation op;
345 size_t bytes = sizeof(uint32_t);
347 res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, 0,
349 if (res != TEE_SUCCESS)
352 res = tee_fs_rpc_read_final(&op, &bytes);
353 if (res != TEE_SUCCESS)
356 if (bytes != sizeof(uint32_t))
357 return TEE_ERROR_CORRUPT_OBJECT;
359 memcpy(&fdp->meta_counter, data, bytes);
364 static TEE_Result read_meta(struct tee_fs_fd *fdp, const char *fname)
368 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, fname, &fdp->fd);
369 if (res != TEE_SUCCESS)
372 res = read_meta_counter(fdp);
373 if (res != TEE_SUCCESS)
376 return read_meta_file(fdp, &fdp->meta);
379 static TEE_Result read_block(struct tee_fs_fd *fdp, int bnum, uint8_t *data)
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);
387 struct tee_fs_rpc_operation op;
389 res = tee_fs_rpc_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fdp->fd, pos,
391 if (res != TEE_SUCCESS)
393 res = tee_fs_rpc_read_final(&op, &bytes);
394 if (res != TEE_SUCCESS)
397 memset(data, 0, BLOCK_SIZE);
398 return TEE_SUCCESS; /* Block does not exist */
401 return tee_fs_decrypt_file(BLOCK_FILE, ct, bytes, data,
402 &out_size, fdp->meta.encrypted_fek);
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)
409 size_t offs = block_pos_raw(new_meta, bnum, false);
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);
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)
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;
427 int orig_pos = fdp->pos;
429 block = malloc(BLOCK_SIZE);
431 return TEE_ERROR_OUT_OF_MEMORY;
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);
437 if (size_to_write + offset > BLOCK_SIZE)
438 size_to_write = BLOCK_SIZE - offset;
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)
447 memcpy(block + offset, data_ptr, size_to_write);
449 memset(block + offset, 0, size_to_write);
451 res = write_block(fdp, start_block_num, block, new_meta);
452 if (res != TEE_SUCCESS)
456 data_ptr += size_to_write;
457 remain_bytes -= size_to_write;
459 fdp->pos += size_to_write;
462 if (fdp->pos > (tee_fs_off_t)new_meta->info.length)
463 new_meta->info.length = fdp->pos;
467 if (res != TEE_SUCCESS)
472 static TEE_Result open_internal(const char *file, bool create,
473 struct tee_file_handle **fh)
477 struct tee_fs_fd *fdp = NULL;
480 return TEE_ERROR_BAD_PARAMETERS;
482 len = strlen(file) + 1;
483 if (len > TEE_FS_NAME_MAX)
484 return TEE_ERROR_BAD_PARAMETERS;
486 fdp = calloc(1, sizeof(struct tee_fs_fd));
488 return TEE_ERROR_OUT_OF_MEMORY;
491 mutex_lock(&ree_fs_mutex);
494 res = create_meta(fdp, file);
496 res = read_meta(fdp, file);
498 if (res == TEE_SUCCESS) {
499 *fh = (struct tee_file_handle *)fdp;
502 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
504 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file);
508 mutex_unlock(&ree_fs_mutex);
512 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh)
514 return open_internal(file, false, fh);
517 static TEE_Result ree_fs_create(const char *file, struct tee_file_handle **fh)
519 return open_internal(file, true, fh);
522 static void ree_fs_close(struct tee_file_handle **fh)
524 struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
527 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
533 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset,
534 TEE_Whence whence, int32_t *new_offs)
537 tee_fs_off_t new_pos;
539 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
541 mutex_lock(&ree_fs_mutex);
543 DMSG("offset=%d, whence=%d", (int)offset, whence);
545 filelen = fdp->meta.info.length;
548 case TEE_DATA_SEEK_SET:
552 case TEE_DATA_SEEK_CUR:
553 new_pos = fdp->pos + offset;
556 case TEE_DATA_SEEK_END:
557 new_pos = filelen + offset;
561 res = TEE_ERROR_BAD_PARAMETERS;
568 if (new_pos > TEE_DATA_MAX_POSITION) {
569 EMSG("Position is beyond TEE_DATA_MAX_POSITION");
570 res = TEE_ERROR_BAD_PARAMETERS;
579 mutex_unlock(&ree_fs_mutex);
584 * To ensure atomic truncate operation, we can:
586 * - update file length to new length
589 * To ensure atomic extend operation, we can:
591 * - update file length to new length
592 * - allocate and fill zero data to new blocks
595 * Any failure before committing new meta is considered as
596 * update failed, and the file content will not be updated
598 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
599 tee_fs_off_t new_file_len)
602 size_t old_file_len = fdp->meta.info.length;
603 struct tee_fs_file_meta new_meta;
605 if (new_file_len > MAX_FILE_SIZE)
606 return TEE_ERROR_BAD_PARAMETERS;
608 new_meta = fdp->meta;
609 new_meta.info.length = new_file_len;
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;
615 fdp->pos = old_file_len;
616 res = out_of_place_write(fdp, NULL, ext_len, &new_meta);
618 if (res != TEE_SUCCESS)
622 return commit_meta_file(fdp, &new_meta);
625 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf,
632 uint8_t *data_ptr = buf;
633 uint8_t *block = NULL;
634 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
636 mutex_lock(&ree_fs_mutex);
639 if ((fdp->pos + remain_bytes) < remain_bytes ||
640 fdp->pos > (tee_fs_off_t)fdp->meta.info.length)
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;
653 start_block_num = pos_to_block_num(fdp->pos);
654 end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1);
656 block = malloc(BLOCK_SIZE);
658 res = TEE_ERROR_OUT_OF_MEMORY;
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);
666 if (size_to_read + offset > BLOCK_SIZE)
667 size_to_read = BLOCK_SIZE - offset;
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;
676 memcpy(data_ptr, block + offset, size_to_read);
678 data_ptr += size_to_read;
679 remain_bytes -= size_to_read;
680 fdp->pos += size_to_read;
686 mutex_unlock(&ree_fs_mutex);
692 * To ensure atomicity of write operation, we need to
693 * do the following steps:
694 * (The sequence of operations is very important)
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.
704 * (Any failure in above steps is considered as update failed,
705 * and the file content will not be updated)
707 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf,
711 struct tee_fs_file_meta new_meta;
712 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
718 mutex_lock(&ree_fs_mutex);
720 file_size = fdp->meta.info.length;
722 if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) {
723 res = TEE_ERROR_BAD_PARAMETERS;
727 if (file_size < (size_t)fdp->pos) {
728 res = ree_fs_ftruncate_internal(fdp, fdp->pos);
729 if (res != TEE_SUCCESS)
733 new_meta = fdp->meta;
734 res = out_of_place_write(fdp, buf, len, &new_meta);
735 if (res != TEE_SUCCESS)
738 res = commit_meta_file(fdp, &new_meta);
740 mutex_unlock(&ree_fs_mutex);
744 static TEE_Result ree_fs_rename(const char *old, const char *new,
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);
756 static TEE_Result ree_fs_remove(const char *file)
760 mutex_lock(&ree_fs_mutex);
761 res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, file);
762 mutex_unlock(&ree_fs_mutex);
767 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
770 struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
772 mutex_lock(&ree_fs_mutex);
773 res = ree_fs_ftruncate_internal(fdp, len);
774 mutex_unlock(&ree_fs_mutex);
779 const struct tee_file_operations ree_fs_ops = {
781 .create = ree_fs_create,
782 .close = ree_fs_close,
784 .write = ree_fs_write,
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,