xref: /optee_os/core/tee/tee_ree_fs.c (revision 40ea51dee3aa8ae6f07ff8bf1299bfe7799a4db5)
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 };
501