Update from upstream to 2.4.0 version
[platform/core/security/tef-optee_os.git] / core / tee / tee_sql_fs.c
1 /*
2  * Copyright (c) 2016, 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 /*
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.
32  */
33
34 #include <assert.h>
35 #include <kernel/mutex.h>
36 #include <optee_msg_supplicant.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string_ext.h>
40 #include <string.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>
46 #include <trace.h>
47 #include <utee_defines.h>
48 #include <util.h>
49
50 /* Block size for encryption */
51 #define BLOCK_SHIFT 12
52 #define BLOCK_SIZE (1 << BLOCK_SHIFT)
53
54 /* File descriptor */
55 struct sql_fs_fd {
56         struct tee_fs_htree *ht;
57         int fd; /* returned by normal world */
58 };
59
60 static struct mutex sql_fs_mutex = MUTEX_INITIALIZER;
61
62 /*
63  * Interface with tee-supplicant
64  */
65
66 static TEE_Result sql_fs_begin_transaction_rpc(void)
67 {
68         return tee_fs_rpc_begin_transaction(OPTEE_MSG_RPC_CMD_SQL_FS);
69 }
70
71 static TEE_Result sql_fs_end_transaction_rpc(bool rollback)
72 {
73         return tee_fs_rpc_end_transaction(OPTEE_MSG_RPC_CMD_SQL_FS,
74                                              rollback);
75 }
76
77 static TEE_Result sql_fs_opendir_rpc(const TEE_UUID *uuid,
78                                      struct tee_fs_dir **d)
79 {
80         return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_SQL_FS, uuid, d);
81 }
82
83 static TEE_Result sql_fs_readdir_rpc(struct tee_fs_dir *d,
84                                      struct tee_fs_dirent **ent)
85 {
86         return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_SQL_FS, d, ent);
87 }
88
89 static TEE_Result sql_fs_remove_rpc(struct tee_pobj *po)
90 {
91         return tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, po);
92 }
93
94 static TEE_Result sql_fs_rename_rpc(struct tee_pobj *old, struct tee_pobj *new,
95                                     bool overwrite)
96 {
97         return tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_SQL_FS, old, new, overwrite);
98 }
99
100 static void sql_fs_closedir_rpc(struct tee_fs_dir *d)
101 {
102         if (d)
103                 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_SQL_FS, d);
104 }
105
106 /*
107  * End of interface with tee-supplicant
108  */
109
110
111 /* Return the block number from a position in the user data */
112 static ssize_t block_num(tee_fs_off_t pos)
113 {
114         return pos / BLOCK_SIZE;
115 }
116
117 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
118                                 size_t *offs, size_t *size)
119 {
120         const size_t node_size = sizeof(struct tee_fs_htree_node_image);
121         const size_t block_nodes = BLOCK_SIZE / node_size;
122         size_t pbn;
123         size_t bidx;
124
125
126         /*
127          * File layout
128          *
129          * phys block 0:
130          * tee_fs_htree_image @ offs = 0
131          *
132          * phys block 1:
133          * tee_fs_htree_node_image 0  @ offs = 0
134          * tee_fs_htree_node_image 1  @ offs = node_size * 2
135          * ...
136          * tee_fs_htree_node_image 61 @ offs = node_size * 122
137          *
138          * phys block 2:
139          * data block 0
140          *
141          * ...
142          *
143          * phys block 64:
144          * data block 61
145          *
146          * phys block 65:
147          * tee_fs_htree_node_image 62  @ offs = 0
148          * tee_fs_htree_node_image 63  @ offs = node_size * 2
149          * ...
150          * tee_fs_htree_node_image 121 @ offs = node_size * 123
151          *
152          * ...
153          */
154
155         switch (type) {
156         case TEE_FS_HTREE_TYPE_HEAD:
157                 *offs = 0;
158                 *size = sizeof(struct tee_fs_htree_image);
159                 return TEE_SUCCESS;
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);
163                 *size = node_size;
164                 return TEE_SUCCESS;
165         case TEE_FS_HTREE_TYPE_BLOCK:
166                 bidx = idx;
167                 pbn = 2 + bidx + bidx / (block_nodes - 1);
168                 *offs = pbn * BLOCK_SIZE;
169                 *size = BLOCK_SIZE;
170                 return TEE_SUCCESS;
171         default:
172                 return TEE_ERROR_GENERIC;
173         }
174 }
175
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)
180 {
181         struct sql_fs_fd *fdp = aux;
182         TEE_Result res;
183         size_t offs;
184         size_t size;
185
186         res = get_offs_size(type, idx, &offs, &size);
187         if (res != TEE_SUCCESS)
188                 return res;
189
190         return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd,
191                                     offs, size, data);
192 }
193
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)
198 {
199         struct sql_fs_fd *fdp = aux;
200         TEE_Result res;
201         size_t offs;
202         size_t size;
203
204         res = get_offs_size(type, idx, &offs, &size);
205         if (res != TEE_SUCCESS)
206                 return res;
207
208         return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd,
209                                      offs, size, data);
210 }
211
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,
218 };
219
220 /*
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.
224  */
225 static TEE_Result write_block_partial(struct sql_fs_fd *fdp, size_t bnum,
226                                       const uint8_t *data, size_t len,
227                                       size_t offset)
228 {
229         TEE_Result res;
230         size_t buf_size = BLOCK_SIZE;
231         uint8_t *buf = NULL;
232
233         if ((offset >= buf_size) || (offset + len > buf_size))
234                 return TEE_ERROR_BAD_PARAMETERS;
235
236         buf = malloc(buf_size);
237         if (!buf)
238                 return TEE_ERROR_OUT_OF_MEMORY;
239
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)
244                         goto exit;
245         } else {
246                 memset(buf, 0, BLOCK_SIZE);
247         }
248
249         if (data)
250                 memcpy(buf + offset, data, len);
251         else
252                 memset(buf + offset, 0, len);
253
254         res = tee_fs_htree_write_block(&fdp->ht, bnum, buf);
255 exit:
256         free(buf);
257         return res;
258 }
259
260 static TEE_Result sql_fs_ftruncate_internal(struct sql_fs_fd *fdp,
261                                             tee_fs_off_t new_length)
262 {
263         TEE_Result res;
264         struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
265
266         if ((size_t)new_length == meta->length)
267                 return TEE_SUCCESS;
268
269         sql_fs_begin_transaction_rpc();
270
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);
275
276                 if (last_block < old_last_block) {
277                         size_t offs;
278                         size_t sz;
279
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)
284                                 goto exit;
285
286                         res = tee_fs_htree_truncate(&fdp->ht,
287                                                     new_length / BLOCK_SIZE);
288                         if (res != TEE_SUCCESS)
289                                 goto exit;
290
291                         res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_SQL_FS,
292                                                   fdp->fd, offs + sz);
293                         if (res != TEE_SUCCESS)
294                                 goto exit;
295                 }
296         } else {
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);
301
302                 while (bnum <= end_bnum) {
303                         size_t len = (size_t)BLOCK_SIZE - (size_t)off;
304
305                         res = write_block_partial(fdp, bnum, NULL, len, off);
306                         if (res != TEE_SUCCESS)
307                                 goto exit;
308                         off = 0;
309                         bnum++;
310                 }
311         }
312
313         meta->length = new_length;
314         res = TEE_SUCCESS;
315 exit:
316         if (res == TEE_SUCCESS)
317                 res = tee_fs_htree_sync_to_storage(&fdp->ht);
318         sql_fs_end_transaction_rpc(res != TEE_SUCCESS);
319         return res;
320 }
321
322 static void sql_fs_close(struct tee_file_handle **fh)
323 {
324         struct sql_fs_fd *fdp = (struct sql_fs_fd *)*fh;
325
326         if (fdp) {
327                 tee_fs_htree_close(&fdp->ht);
328                 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
329                 free(fdp);
330                 *fh = NULL;
331         }
332 }
333
334 static TEE_Result open_internal(struct tee_pobj *po, bool create,
335                                 struct tee_file_handle **fh)
336 {
337         TEE_Result res;
338         struct sql_fs_fd *fdp;
339         bool created = false;
340
341         fdp = calloc(1, sizeof(*fdp));
342         if (!fdp)
343                 return TEE_ERROR_OUT_OF_MEMORY;
344         fdp->fd = -1;
345
346         mutex_lock(&sql_fs_mutex);
347
348         if (create)
349                 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_SQL_FS, po, &fdp->fd);
350         else
351                 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_SQL_FS, po, &fdp->fd);
352         if (res != TEE_SUCCESS)
353                 goto out;
354
355         res = tee_fs_htree_open(create, &sql_fs_storage_ops, fdp, &fdp->ht);
356 out:
357         if (res == TEE_SUCCESS) {
358                 *fh = (struct tee_file_handle *)fdp;
359         } else {
360                 if (fdp && fdp->fd != -1)
361                         tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fdp->fd);
362                 if (created)
363                         tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_SQL_FS, po);
364                 free(fdp);
365         }
366         mutex_unlock(&sql_fs_mutex);
367         return res;
368 }
369
370 static TEE_Result sql_fs_open(struct tee_pobj *po, struct tee_file_handle **fh)
371 {
372         return open_internal(po, false, fh);
373 }
374
375 static TEE_Result sql_fs_create(struct tee_pobj *po,
376                                 struct tee_file_handle **fh)
377 {
378         return open_internal(po, true, fh);
379 }
380
381
382 static TEE_Result sql_fs_read(struct tee_file_handle *fh, size_t pos,
383                               void *buf, size_t *len)
384 {
385         TEE_Result res;
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;
390         int start_block_num;
391         int end_block_num;
392         size_t file_size;
393
394         mutex_lock(&sql_fs_mutex);
395
396         file_size = tee_fs_htree_get_meta(fdp->ht)->length;
397         if ((pos + remain_bytes) < remain_bytes || pos > file_size)
398                 remain_bytes = 0;
399         else if (pos + remain_bytes > file_size)
400                 remain_bytes = file_size - pos;
401
402         *len = remain_bytes;
403
404         if (!remain_bytes) {
405                 res = TEE_SUCCESS;
406                 goto exit;
407         }
408
409         start_block_num = block_num(pos);
410         end_block_num = block_num(pos + remain_bytes - 1);
411
412         block = malloc(BLOCK_SIZE);
413         if (!block) {
414                 res = TEE_ERROR_OUT_OF_MEMORY;
415                 goto exit;
416         }
417
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);
421
422                 if (size_to_read + offset > BLOCK_SIZE)
423                         size_to_read = BLOCK_SIZE - offset;
424
425                 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
426                 if (res != TEE_SUCCESS)
427                         goto exit;
428
429                 memcpy(data_ptr, block + offset, size_to_read);
430
431                 data_ptr += size_to_read;
432                 remain_bytes -= size_to_read;
433                 pos += size_to_read;
434
435                 start_block_num++;
436         }
437         res = TEE_SUCCESS;
438 exit:
439         free(block);
440         mutex_unlock(&sql_fs_mutex);
441         return res;
442 }
443
444 static TEE_Result sql_fs_write(struct tee_file_handle *fh, size_t pos,
445                                const void *buf, size_t len)
446 {
447         TEE_Result res;
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;
452         int start_block_num;
453         int end_block_num;
454
455         if (!len)
456                 return TEE_SUCCESS;
457
458         mutex_lock(&sql_fs_mutex);
459
460         sql_fs_begin_transaction_rpc();
461
462         if (meta->length < pos) {
463                 /* Fill hole */
464                 res = sql_fs_ftruncate_internal(fdp, pos);
465                 if (res != TEE_SUCCESS)
466                         goto exit;
467         }
468
469         start_block_num = block_num(pos);
470         end_block_num = block_num(pos + len - 1);
471
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);
475
476                 if (size_to_write + offset > BLOCK_SIZE)
477                         size_to_write = BLOCK_SIZE - offset;
478
479                 res = write_block_partial(fdp, start_block_num, data_ptr,
480                                           size_to_write, offset);
481                 if (res != TEE_SUCCESS)
482                         goto exit;
483
484                 data_ptr += size_to_write;
485                 remain_bytes -= size_to_write;
486                 pos += size_to_write;
487
488                 start_block_num++;
489         }
490
491         if (pos > meta->length)
492                 meta->length = pos;
493
494 exit:
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);
499         return res;
500 }
501
502 static TEE_Result sql_fs_truncate(struct tee_file_handle *fh, size_t len)
503 {
504         TEE_Result res;
505         struct sql_fs_fd *fdp = (struct sql_fs_fd *)fh;
506
507         mutex_lock(&sql_fs_mutex);
508         res = sql_fs_ftruncate_internal(fdp, len);
509         mutex_unlock(&sql_fs_mutex);
510
511         return res;
512 }
513
514 const struct tee_file_operations sql_fs_ops = {
515         .open = sql_fs_open,
516         .create = sql_fs_create,
517         .close = sql_fs_close,
518         .read = sql_fs_read,
519         .write = sql_fs_write,
520         .truncate = sql_fs_truncate,
521
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,
527 };