Update from upstream to 2.4.0 version
[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/mutex.h>
30 #include <kernel/panic.h>
31 #include <kernel/thread.h>
32 #include <mm/core_memprot.h>
33 #include <optee_msg_supplicant.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string_ext.h>
37 #include <string.h>
38 #include <sys/queue.h>
39 #include <tee/fs_htree.h>
40 #include <tee/tee_cryp_provider.h>
41 #include <tee/tee_fs.h>
42 #include <tee/tee_fs_rpc.h>
43 #include <trace.h>
44 #include <utee_defines.h>
45 #include <util.h>
46
47 #define BLOCK_SHIFT     12
48
49 #define BLOCK_SIZE      (1 << BLOCK_SHIFT)
50
51 struct tee_fs_fd {
52         struct tee_fs_htree *ht;
53         int fd;
54 };
55
56 static int pos_to_block_num(int position)
57 {
58         return position >> BLOCK_SHIFT;
59 }
60
61 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
62
63 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid,
64                                      struct tee_fs_dir **d)
65
66 {
67         return tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, uuid, d);
68 }
69
70 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
71 {
72         if (d)
73                 tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d);
74 }
75
76 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
77                                      struct tee_fs_dirent **ent)
78 {
79         return tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d, ent);
80 }
81
82 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos,
83                                      const void *buf, size_t len)
84 {
85         TEE_Result res;
86         size_t start_block_num = pos_to_block_num(pos);
87         size_t end_block_num = pos_to_block_num(pos + len - 1);
88         size_t remain_bytes = len;
89         uint8_t *data_ptr = (uint8_t *)buf;
90         uint8_t *block;
91         struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
92
93         block = malloc(BLOCK_SIZE);
94         if (!block)
95                 return TEE_ERROR_OUT_OF_MEMORY;
96
97         while (start_block_num <= end_block_num) {
98                 size_t offset = pos % BLOCK_SIZE;
99                 size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
100
101                 if (size_to_write + offset > BLOCK_SIZE)
102                         size_to_write = BLOCK_SIZE - offset;
103
104                 if (start_block_num * BLOCK_SIZE <
105                     ROUNDUP(meta->length, BLOCK_SIZE)) {
106                         res = tee_fs_htree_read_block(&fdp->ht,
107                                                       start_block_num, block);
108                         if (res != TEE_SUCCESS)
109                                 goto exit;
110                 } else {
111                         memset(block, 0, BLOCK_SIZE);
112                 }
113
114                 if (data_ptr)
115                         memcpy(block + offset, data_ptr, size_to_write);
116                 else
117                         memset(block + offset, 0, size_to_write);
118
119                 res = tee_fs_htree_write_block(&fdp->ht, start_block_num,
120                                                block);
121                 if (res != TEE_SUCCESS)
122                         goto exit;
123
124                 if (data_ptr)
125                         data_ptr += size_to_write;
126                 remain_bytes -= size_to_write;
127                 start_block_num++;
128                 pos += size_to_write;
129         }
130
131         if (pos > meta->length)
132                 meta->length = pos;
133
134 exit:
135         free(block);
136         return res;
137 }
138
139 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
140                                 uint8_t vers, size_t *offs, size_t *size)
141 {
142         const size_t node_size = sizeof(struct tee_fs_htree_node_image);
143         const size_t block_nodes = BLOCK_SIZE / (node_size * 2);
144         size_t pbn;
145         size_t bidx;
146
147         assert(vers == 0 || vers == 1);
148
149         /*
150          * File layout
151          *
152          * phys block 0:
153          * tee_fs_htree_image vers 0 @ offs = 0
154          * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
155          *
156          * phys block 1:
157          * tee_fs_htree_node_image 0  vers 0 @ offs = 0
158          * tee_fs_htree_node_image 0  vers 1 @ offs = node_size
159          * tee_fs_htree_node_image 1  vers 0 @ offs = node_size * 2
160          * tee_fs_htree_node_image 1  vers 1 @ offs = node_size * 3
161          * ...
162          * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122
163          * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123
164          *
165          * phys block 2:
166          * data block 0 vers 0
167          *
168          * phys block 3:
169          * data block 0 vers 1
170          *
171          * ...
172          * phys block 63:
173          * data block 61 vers 0
174          *
175          * phys block 64:
176          * data block 61 vers 1
177          *
178          * phys block 65:
179          * tee_fs_htree_node_image 62  vers 0 @ offs = 0
180          * tee_fs_htree_node_image 62  vers 1 @ offs = node_size
181          * tee_fs_htree_node_image 63  vers 0 @ offs = node_size * 2
182          * tee_fs_htree_node_image 63  vers 1 @ offs = node_size * 3
183          * ...
184          * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122
185          * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123
186          *
187          * ...
188          */
189
190         switch (type) {
191         case TEE_FS_HTREE_TYPE_HEAD:
192                 *offs = sizeof(struct tee_fs_htree_image) * vers;
193                 *size = sizeof(struct tee_fs_htree_image);
194                 return TEE_SUCCESS;
195         case TEE_FS_HTREE_TYPE_NODE:
196                 pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
197                 *offs = pbn * BLOCK_SIZE +
198                         2 * node_size * (idx % block_nodes) +
199                         node_size * vers;
200                 *size = node_size;
201                 return TEE_SUCCESS;
202         case TEE_FS_HTREE_TYPE_BLOCK:
203                 bidx = 2 * idx + vers;
204                 pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
205                 *offs = pbn * BLOCK_SIZE;
206                 *size = BLOCK_SIZE;
207                 return TEE_SUCCESS;
208         default:
209                 return TEE_ERROR_GENERIC;
210         }
211 }
212
213 static TEE_Result ree_fs_rpc_read_init(void *aux,
214                                        struct tee_fs_rpc_operation *op,
215                                        enum tee_fs_htree_type type, size_t idx,
216                                        uint8_t vers, void **data)
217 {
218         struct tee_fs_fd *fdp = aux;
219         TEE_Result res;
220         size_t offs;
221         size_t size;
222
223         res = get_offs_size(type, idx, vers, &offs, &size);
224         if (res != TEE_SUCCESS)
225                 return res;
226
227         return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
228                                     offs, size, data);
229 }
230
231 static TEE_Result ree_fs_rpc_write_init(void *aux,
232                                         struct tee_fs_rpc_operation *op,
233                                         enum tee_fs_htree_type type, size_t idx,
234                                         uint8_t vers, void **data)
235 {
236         struct tee_fs_fd *fdp = aux;
237         TEE_Result res;
238         size_t offs;
239         size_t size;
240
241         res = get_offs_size(type, idx, vers, &offs, &size);
242         if (res != TEE_SUCCESS)
243                 return res;
244
245         return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
246                                      offs, size, data);
247 }
248
249 static const struct tee_fs_htree_storage ree_fs_storage_ops = {
250         .block_size = BLOCK_SIZE,
251         .rpc_read_init = ree_fs_rpc_read_init,
252         .rpc_read_final = tee_fs_rpc_read_final,
253         .rpc_write_init = ree_fs_rpc_write_init,
254         .rpc_write_final = tee_fs_rpc_write_final,
255 };
256
257 static TEE_Result open_internal(struct tee_pobj *po, bool create,
258                                 struct tee_file_handle **fh)
259 {
260         TEE_Result res;
261         struct tee_fs_fd *fdp = NULL;
262
263         fdp = calloc(1, sizeof(struct tee_fs_fd));
264         if (!fdp)
265                 return TEE_ERROR_OUT_OF_MEMORY;
266         fdp->fd = -1;
267
268         mutex_lock(&ree_fs_mutex);
269
270         if (create)
271                 res = tee_fs_rpc_create(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd);
272         else
273                 res = tee_fs_rpc_open(OPTEE_MSG_RPC_CMD_FS, po, &fdp->fd);
274
275         if (res != TEE_SUCCESS)
276                 goto out;
277
278         res = tee_fs_htree_open(create, &ree_fs_storage_ops, fdp, &fdp->ht);
279 out:
280         if (res == TEE_SUCCESS) {
281                 *fh = (struct tee_file_handle *)fdp;
282         } else {
283                 if (fdp->fd != -1)
284                         tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
285                 if (create)
286                         tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po);
287                 free(fdp);
288         }
289
290         mutex_unlock(&ree_fs_mutex);
291         return res;
292 }
293
294 static TEE_Result ree_fs_open(struct tee_pobj *po, struct tee_file_handle **fh)
295 {
296         return open_internal(po, false, fh);
297 }
298
299 static TEE_Result ree_fs_create(struct tee_pobj *po,
300                                 struct tee_file_handle **fh)
301 {
302         return open_internal(po, true, fh);
303 }
304
305 static void ree_fs_close(struct tee_file_handle **fh)
306 {
307         struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
308
309         if (fdp) {
310                 tee_fs_htree_close(&fdp->ht);
311                 tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
312                 free(fdp);
313                 *fh = NULL;
314         }
315 }
316
317 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
318                                             tee_fs_off_t new_file_len)
319 {
320         TEE_Result res;
321         struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
322
323         if ((size_t)new_file_len > meta->length) {
324                 size_t ext_len = new_file_len - meta->length;
325
326                 res = out_of_place_write(fdp, meta->length, NULL, ext_len);
327                 if (res != TEE_SUCCESS)
328                         return res;
329         } else {
330                 size_t offs;
331                 size_t sz;
332
333                 res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
334                                     ROUNDUP(new_file_len, BLOCK_SIZE) /
335                                         BLOCK_SIZE, 1, &offs, &sz);
336                 if (res != TEE_SUCCESS)
337                         return res;
338
339                 res = tee_fs_htree_truncate(&fdp->ht,
340                                             new_file_len / BLOCK_SIZE);
341                 if (res != TEE_SUCCESS)
342                         return res;
343
344                 res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd,
345                                           offs + sz);
346                 if (res != TEE_SUCCESS)
347                         return res;
348
349                 meta->length = new_file_len;
350         }
351
352         return tee_fs_htree_sync_to_storage(&fdp->ht);
353 }
354
355 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos,
356                               void *buf, size_t *len)
357 {
358         TEE_Result res;
359         int start_block_num;
360         int end_block_num;
361         size_t remain_bytes;
362         uint8_t *data_ptr = buf;
363         uint8_t *block = NULL;
364         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
365         struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
366
367         mutex_lock(&ree_fs_mutex);
368
369         remain_bytes = *len;
370         if ((pos + remain_bytes) < remain_bytes || pos > meta->length)
371                 remain_bytes = 0;
372         else if (pos + remain_bytes > meta->length)
373                 remain_bytes = meta->length - pos;
374
375         *len = remain_bytes;
376
377         if (!remain_bytes) {
378                 res = TEE_SUCCESS;
379                 goto exit;
380         }
381
382         start_block_num = pos_to_block_num(pos);
383         end_block_num = pos_to_block_num(pos + remain_bytes - 1);
384
385         block = malloc(BLOCK_SIZE);
386         if (!block) {
387                 res = TEE_ERROR_OUT_OF_MEMORY;
388                 goto exit;
389         }
390
391         while (start_block_num <= end_block_num) {
392                 size_t offset = pos % BLOCK_SIZE;
393                 size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
394
395                 if (size_to_read + offset > BLOCK_SIZE)
396                         size_to_read = BLOCK_SIZE - offset;
397
398                 res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
399                 if (res != TEE_SUCCESS)
400                         goto exit;
401
402                 memcpy(data_ptr, block + offset, size_to_read);
403
404                 data_ptr += size_to_read;
405                 remain_bytes -= size_to_read;
406                 pos += size_to_read;
407
408                 start_block_num++;
409         }
410         res = TEE_SUCCESS;
411 exit:
412         mutex_unlock(&ree_fs_mutex);
413         free(block);
414         return res;
415 }
416
417 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos,
418                                const void *buf, size_t len)
419 {
420         TEE_Result res;
421         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
422         size_t file_size;
423
424         if (!len)
425                 return TEE_SUCCESS;
426
427         mutex_lock(&ree_fs_mutex);
428
429         file_size = tee_fs_htree_get_meta(fdp->ht)->length;
430
431         if ((pos + len) < len) {
432                 res = TEE_ERROR_BAD_PARAMETERS;
433                 goto exit;
434         }
435
436         if (file_size < pos) {
437                 res = ree_fs_ftruncate_internal(fdp, pos);
438                 if (res != TEE_SUCCESS)
439                         goto exit;
440         }
441
442         res = out_of_place_write(fdp, pos, buf, len);
443         if (res != TEE_SUCCESS)
444                 goto exit;
445
446 exit:
447         if (res == TEE_SUCCESS)
448                 res = tee_fs_htree_sync_to_storage(&fdp->ht);
449         mutex_unlock(&ree_fs_mutex);
450         return res;
451 }
452
453 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
454                                 bool overwrite)
455 {
456         TEE_Result res;
457
458         mutex_lock(&ree_fs_mutex);
459         res = tee_fs_rpc_rename(OPTEE_MSG_RPC_CMD_FS, old, new, overwrite);
460         mutex_unlock(&ree_fs_mutex);
461
462         return res;
463 }
464
465 static TEE_Result ree_fs_remove(struct tee_pobj *po)
466 {
467         TEE_Result res;
468
469         mutex_lock(&ree_fs_mutex);
470         res = tee_fs_rpc_remove(OPTEE_MSG_RPC_CMD_FS, po);
471         mutex_unlock(&ree_fs_mutex);
472
473         return res;
474 }
475
476 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
477 {
478         TEE_Result res;
479         struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
480
481         mutex_lock(&ree_fs_mutex);
482         res = ree_fs_ftruncate_internal(fdp, len);
483         mutex_unlock(&ree_fs_mutex);
484
485         return res;
486 }
487
488 const struct tee_file_operations ree_fs_ops = {
489         .open = ree_fs_open,
490         .create = ree_fs_create,
491         .close = ree_fs_close,
492         .read = ree_fs_read,
493         .write = ree_fs_write,
494         .truncate = ree_fs_truncate,
495         .rename = ree_fs_rename,
496         .remove = ree_fs_remove,
497         .opendir = ree_fs_opendir_rpc,
498         .closedir = ree_fs_closedir_rpc,
499         .readdir = ree_fs_readdir_rpc,
500 };