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