2 * Copyright (c) 2016, 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 * This file implements the tee_file_operations structure for a secure
30 * filesystem based on an SQLite database in normal world.
31 * The atomicity of each operation is ensured by using SQL transactions.
35 #include <kernel/mutex.h>
36 #include <optee_msg_supplicant.h>
39 #include <string_ext.h>
41 #include <sys/queue.h>
42 #include <tee/fs_htree.h>
43 #include <tee/tee_cryp_provider.h>
44 #include <tee/tee_fs.h>
45 #include <tee/tee_fs_rpc.h>
47 #include <utee_defines.h>
50 /* Block size for encryption */
51 #define BLOCK_SHIFT 12
52 #define BLOCK_SIZE (1 << BLOCK_SHIFT)
56 struct tee_fs_htree *ht;
57 int fd; /* returned by normal world */
60 static struct mutex sql_fs_mutex = MUTEX_INITIALIZER;
63 * Interface with tee-supplicant
66 static TEE_Result sql_fs_begin_transaction_rpc(void)
68 return tee_fs_rpc_begin_transaction(OPTEE_MSG_RPC_CMD_SQL_FS);
71 static TEE_Result sql_fs_end_transaction_rpc(bool rollback)
73 return tee_fs_rpc_end_transaction(OPTEE_MSG_RPC_CMD_SQL_FS,
77 static TEE_Result sql_fs_opendir_rpc(const TEE_UUID *uuid,
78 struct tee_fs_dir **d)
80 return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_SQL_FS, uuid, d);
83 static TEE_Result sql_fs_readdir_rpc(struct tee_fs_dir *d,
84 struct tee_fs_dirent **ent)
86 return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_SQL_FS, d, ent);
89 static TEE_Result sql_fs_remove_rpc(struct tee_pobj *po)
91 return tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, po);
94 static TEE_Result sql_fs_rename_rpc(struct tee_pobj *old, struct tee_pobj *new,
97 return tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_SQL_FS, old, new, overwrite);
100 static void sql_fs_closedir_rpc(struct tee_fs_dir *d)
103 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_SQL_FS, d);
107 * End of interface with tee-supplicant
111 /* Return the block number from a position in the user data */
112 static ssize_t block_num(tee_fs_off_t pos)
114 return pos / BLOCK_SIZE;
117 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
118 size_t *offs, size_t *size)
120 const size_t node_size = sizeof(struct tee_fs_htree_node_image);
121 const size_t block_nodes = BLOCK_SIZE / node_size;
130 * tee_fs_htree_image @ offs = 0
133 * tee_fs_htree_node_image 0 @ offs = 0
134 * tee_fs_htree_node_image 1 @ offs = node_size * 2
136 * tee_fs_htree_node_image 61 @ offs = node_size * 122
147 * tee_fs_htree_node_image 62 @ offs = 0
148 * tee_fs_htree_node_image 63 @ offs = node_size * 2
150 * tee_fs_htree_node_image 121 @ offs = node_size * 123
156 case TEE_FS_HTREE_TYPE_HEAD:
158 *size = sizeof(struct tee_fs_htree_image);
160 case TEE_FS_HTREE_TYPE_NODE:
161 pbn = 1 + ((idx / block_nodes) * block_nodes);
162 *offs = pbn * BLOCK_SIZE + node_size * (idx % block_nodes);
165 case TEE_FS_HTREE_TYPE_BLOCK:
167 pbn = 2 + bidx + bidx / (block_nodes - 1);
168 *offs = pbn * BLOCK_SIZE;
172 return TEE_ERROR_GENERIC;
176 static TEE_Result sql_fs_rpc_read_init(void *aux,
177 struct tee_fs_rpc_operation *op,
178 enum tee_fs_htree_type type, size_t idx,
179 uint8_t vers __unused, void **data)
181 struct sql_fs_fd *fdp = aux;
186 res = get_offs_size(type, idx, &offs, &size);
187 if (res != TEE_SUCCESS)
190 return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd,
194 static TEE_Result sql_fs_rpc_write_init(void *aux,
195 struct tee_fs_rpc_operation *op,
196 enum tee_fs_htree_type type, size_t idx,
197 uint8_t vers __unused, void **data)
199 struct sql_fs_fd *fdp = aux;
204 res = get_offs_size(type, idx, &offs, &size);
205 if (res != TEE_SUCCESS)
208 return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd,
212 static const struct tee_fs_htree_storage sql_fs_storage_ops = {
213 .block_size = BLOCK_SIZE,
214 .rpc_read_init = sql_fs_rpc_read_init,
215 .rpc_read_final = tee_fs_rpc_read_final,
216 .rpc_write_init = sql_fs_rpc_write_init,
217 .rpc_write_final = tee_fs_rpc_write_final,
221 * Partial write (< BLOCK_SIZE) into a block: read/update/write
222 * To save memory, passing data == NULL is equivalent to passing a buffer
223 * filled with zeroes.
225 static TEE_Result write_block_partial(struct sql_fs_fd *fdp, size_t bnum,
226 const uint8_t *data, size_t len,
230 size_t buf_size = BLOCK_SIZE;
233 if ((offset >= buf_size) || (offset + len > buf_size))
234 return TEE_ERROR_BAD_PARAMETERS;
236 buf = malloc(buf_size);
238 return TEE_ERROR_OUT_OF_MEMORY;
240 if (bnum * BLOCK_SIZE <
241 ROUNDUP(tee_fs_htree_get_meta(fdp->ht)->length, BLOCK_SIZE)) {
242 res = tee_fs_htree_read_block(&fdp->ht, bnum, buf);
243 if (res != TEE_SUCCESS)
246 memset(buf, 0, BLOCK_SIZE);
250 memcpy(buf + offset, data, len);
252 memset(buf + offset, 0, len);
254 res = tee_fs_htree_write_block(&fdp->ht, bnum, buf);
260 static TEE_Result sql_fs_ftruncate_internal(struct sql_fs_fd *fdp,
261 tee_fs_off_t new_length)
264 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
266 if ((size_t)new_length == meta->length)
269 sql_fs_begin_transaction_rpc();
271 if ((size_t)new_length < meta->length) {
272 /* Trim unused blocks */
273 int old_last_block = block_num(meta->length);
274 int last_block = block_num(new_length);
276 if (last_block < old_last_block) {
280 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
281 ROUNDUP(new_length, BLOCK_SIZE) /
282 BLOCK_SIZE, &offs, &sz);
283 if (res != TEE_SUCCESS)
286 res = tee_fs_htree_truncate(&fdp->ht,
287 new_length / BLOCK_SIZE);
288 if (res != TEE_SUCCESS)
291 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_SQL_FS,
293 if (res != TEE_SUCCESS)
297 /* Extend file with zeroes */
298 tee_fs_off_t off = meta->length % BLOCK_SIZE;
299 size_t bnum = block_num(meta->length);
300 size_t end_bnum = block_num(new_length);
302 while (bnum <= end_bnum) {
303 size_t len = (size_t)BLOCK_SIZE - (size_t)off;
305 res = write_block_partial(fdp, bnum, NULL, len, off);
306 if (res != TEE_SUCCESS)
313 meta->length = new_length;
316 if (res == TEE_SUCCESS)
317 res = tee_fs_htree_sync_to_storage(&fdp->ht);
318 sql_fs_end_transaction_rpc(res != TEE_SUCCESS);
322 static void sql_fs_close(struct tee_file_handle **fh)
324 struct sql_fs_fd *fdp = (struct sql_fs_fd *)*fh;
327 tee_fs_htree_close(&fdp->ht);
328 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
334 static TEE_Result open_internal(struct tee_pobj *po, bool create,
335 struct tee_file_handle **fh)
338 struct sql_fs_fd *fdp;
339 bool created = false;
341 fdp = calloc(1, sizeof(*fdp));
343 return TEE_ERROR_OUT_OF_MEMORY;
346 mutex_lock(&sql_fs_mutex);
349 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_SQL_FS, po, &fdp->fd);
351 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_SQL_FS, po, &fdp->fd);
352 if (res != TEE_SUCCESS)
355 res = tee_fs_htree_open(create, &sql_fs_storage_ops, fdp, &fdp->ht);
357 if (res == TEE_SUCCESS) {
358 *fh = (struct tee_file_handle *)fdp;
360 if (fdp && fdp->fd != -1)
361 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
363 tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, po);
366 mutex_unlock(&sql_fs_mutex);
370 static TEE_Result sql_fs_open(struct tee_pobj *po, struct tee_file_handle **fh)
372 return open_internal(po, false, fh);
375 static TEE_Result sql_fs_create(struct tee_pobj *po,
376 struct tee_file_handle **fh)
378 return open_internal(po, true, fh);
382 static TEE_Result sql_fs_read(struct tee_file_handle *fh, size_t pos,
383 void *buf, size_t *len)
386 struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
387 size_t remain_bytes = *len;
388 uint8_t *data_ptr = buf;
389 uint8_t *block = NULL;
394 mutex_lock(&sql_fs_mutex);
396 file_size = tee_fs_htree_get_meta(fdp->ht)->length;
397 if ((pos + remain_bytes) < remain_bytes || pos > file_size)
399 else if (pos + remain_bytes > file_size)
400 remain_bytes = file_size - pos;
409 start_block_num = block_num(pos);
410 end_block_num = block_num(pos + remain_bytes - 1);
412 block = malloc(BLOCK_SIZE);
414 res = TEE_ERROR_OUT_OF_MEMORY;
418 while (start_block_num <= end_block_num) {
419 size_t offset = pos % BLOCK_SIZE;
420 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
422 if (size_to_read + offset > BLOCK_SIZE)
423 size_to_read = BLOCK_SIZE - offset;
425 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
426 if (res != TEE_SUCCESS)
429 memcpy(data_ptr, block + offset, size_to_read);
431 data_ptr += size_to_read;
432 remain_bytes -= size_to_read;
440 mutex_unlock(&sql_fs_mutex);
444 static TEE_Result sql_fs_write(struct tee_file_handle *fh, size_t pos,
445 const void *buf, size_t len)
448 struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
449 struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
450 size_t remain_bytes = len;
451 const uint8_t *data_ptr = buf;
458 mutex_lock(&sql_fs_mutex);
460 sql_fs_begin_transaction_rpc();
462 if (meta->length < pos) {
464 res = sql_fs_ftruncate_internal(fdp, pos);
465 if (res != TEE_SUCCESS)
469 start_block_num = block_num(pos);
470 end_block_num = block_num(pos + len - 1);
472 while (start_block_num <= end_block_num) {
473 size_t offset = pos % BLOCK_SIZE;
474 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
476 if (size_to_write + offset > BLOCK_SIZE)
477 size_to_write = BLOCK_SIZE - offset;
479 res = write_block_partial(fdp, start_block_num, data_ptr,
480 size_to_write, offset);
481 if (res != TEE_SUCCESS)
484 data_ptr += size_to_write;
485 remain_bytes -= size_to_write;
486 pos += size_to_write;
491 if (pos > meta->length)
495 if (res == TEE_SUCCESS)
496 res = tee_fs_htree_sync_to_storage(&fdp->ht);
497 sql_fs_end_transaction_rpc(res != TEE_SUCCESS);
498 mutex_unlock(&sql_fs_mutex);
502 static TEE_Result sql_fs_truncate(struct tee_file_handle *fh, size_t len)
505 struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
507 mutex_lock(&sql_fs_mutex);
508 res = sql_fs_ftruncate_internal(fdp, len);
509 mutex_unlock(&sql_fs_mutex);
514 const struct tee_file_operations sql_fs_ops = {
516 .create = sql_fs_create,
517 .close = sql_fs_close,
519 .write = sql_fs_write,
520 .truncate = sql_fs_truncate,
522 .opendir = sql_fs_opendir_rpc,
523 .closedir = sql_fs_closedir_rpc,
524 .readdir = sql_fs_readdir_rpc,
525 .rename = sql_fs_rename_rpc,
526 .remove = sql_fs_remove_rpc,