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