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