xref: /optee_os/core/tee/tee_ree_fs.c (revision 63988d7cb5d649265ec68a2887296e63503da579)
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_dirfile.h>
40 #include <tee/fs_htree.h>
41 #include <tee/tee_cryp_provider.h>
42 #include <tee/tee_fs.h>
43 #include <tee/tee_fs_rpc.h>
44 #include <tee/tee_pobj.h>
45 #include <trace.h>
46 #include <utee_defines.h>
47 #include <util.h>
48 
49 #define BLOCK_SHIFT	12
50 
51 #define BLOCK_SIZE	(1 << BLOCK_SHIFT)
52 
53 struct tee_fs_fd {
54 	struct tee_fs_htree *ht;
55 	int fd;
56 	struct tee_fs_dirfile_fileh dfh;
57 	const TEE_UUID *uuid;
58 };
59 
60 struct tee_fs_dir {
61 	struct tee_fs_dirfile_dirh *dirh;
62 	int idx;
63 	struct tee_fs_dirent d;
64 };
65 
66 static int pos_to_block_num(int position)
67 {
68 	return position >> BLOCK_SHIFT;
69 }
70 
71 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
72 
73 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos,
74 				     const void *buf, size_t len)
75 {
76 	TEE_Result res;
77 	size_t start_block_num = pos_to_block_num(pos);
78 	size_t end_block_num = pos_to_block_num(pos + len - 1);
79 	size_t remain_bytes = len;
80 	uint8_t *data_ptr = (uint8_t *)buf;
81 	uint8_t *block;
82 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
83 
84 	block = malloc(BLOCK_SIZE);
85 	if (!block)
86 		return TEE_ERROR_OUT_OF_MEMORY;
87 
88 	while (start_block_num <= end_block_num) {
89 		size_t offset = pos % BLOCK_SIZE;
90 		size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
91 
92 		if (size_to_write + offset > BLOCK_SIZE)
93 			size_to_write = BLOCK_SIZE - offset;
94 
95 		if (start_block_num * BLOCK_SIZE <
96 		    ROUNDUP(meta->length, BLOCK_SIZE)) {
97 			res = tee_fs_htree_read_block(&fdp->ht,
98 						      start_block_num, block);
99 			if (res != TEE_SUCCESS)
100 				goto exit;
101 		} else {
102 			memset(block, 0, BLOCK_SIZE);
103 		}
104 
105 		if (data_ptr)
106 			memcpy(block + offset, data_ptr, size_to_write);
107 		else
108 			memset(block + offset, 0, size_to_write);
109 
110 		res = tee_fs_htree_write_block(&fdp->ht, start_block_num,
111 					       block);
112 		if (res != TEE_SUCCESS)
113 			goto exit;
114 
115 		if (data_ptr)
116 			data_ptr += size_to_write;
117 		remain_bytes -= size_to_write;
118 		start_block_num++;
119 		pos += size_to_write;
120 	}
121 
122 	if (pos > meta->length)
123 		meta->length = pos;
124 
125 exit:
126 	free(block);
127 	return res;
128 }
129 
130 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
131 				uint8_t vers, size_t *offs, size_t *size)
132 {
133 	const size_t node_size = sizeof(struct tee_fs_htree_node_image);
134 	const size_t block_nodes = BLOCK_SIZE / (node_size * 2);
135 	size_t pbn;
136 	size_t bidx;
137 
138 	assert(vers == 0 || vers == 1);
139 
140 	/*
141 	 * File layout
142 	 *
143 	 * phys block 0:
144 	 * tee_fs_htree_image vers 0 @ offs = 0
145 	 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
146 	 *
147 	 * phys block 1:
148 	 * tee_fs_htree_node_image 0  vers 0 @ offs = 0
149 	 * tee_fs_htree_node_image 0  vers 1 @ offs = node_size
150 	 * tee_fs_htree_node_image 1  vers 0 @ offs = node_size * 2
151 	 * tee_fs_htree_node_image 1  vers 1 @ offs = node_size * 3
152 	 * ...
153 	 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122
154 	 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123
155 	 *
156 	 * phys block 2:
157 	 * data block 0 vers 0
158 	 *
159 	 * phys block 3:
160 	 * data block 0 vers 1
161 	 *
162 	 * ...
163 	 * phys block 63:
164 	 * data block 61 vers 0
165 	 *
166 	 * phys block 64:
167 	 * data block 61 vers 1
168 	 *
169 	 * phys block 65:
170 	 * tee_fs_htree_node_image 62  vers 0 @ offs = 0
171 	 * tee_fs_htree_node_image 62  vers 1 @ offs = node_size
172 	 * tee_fs_htree_node_image 63  vers 0 @ offs = node_size * 2
173 	 * tee_fs_htree_node_image 63  vers 1 @ offs = node_size * 3
174 	 * ...
175 	 * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122
176 	 * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123
177 	 *
178 	 * ...
179 	 */
180 
181 	switch (type) {
182 	case TEE_FS_HTREE_TYPE_HEAD:
183 		*offs = sizeof(struct tee_fs_htree_image) * vers;
184 		*size = sizeof(struct tee_fs_htree_image);
185 		return TEE_SUCCESS;
186 	case TEE_FS_HTREE_TYPE_NODE:
187 		pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
188 		*offs = pbn * BLOCK_SIZE +
189 			2 * node_size * (idx % block_nodes) +
190 			node_size * vers;
191 		*size = node_size;
192 		return TEE_SUCCESS;
193 	case TEE_FS_HTREE_TYPE_BLOCK:
194 		bidx = 2 * idx + vers;
195 		pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
196 		*offs = pbn * BLOCK_SIZE;
197 		*size = BLOCK_SIZE;
198 		return TEE_SUCCESS;
199 	default:
200 		return TEE_ERROR_GENERIC;
201 	}
202 }
203 
204 static TEE_Result ree_fs_rpc_read_init(void *aux,
205 				       struct tee_fs_rpc_operation *op,
206 				       enum tee_fs_htree_type type, size_t idx,
207 				       uint8_t vers, void **data)
208 {
209 	struct tee_fs_fd *fdp = aux;
210 	TEE_Result res;
211 	size_t offs;
212 	size_t size;
213 
214 	res = get_offs_size(type, idx, vers, &offs, &size);
215 	if (res != TEE_SUCCESS)
216 		return res;
217 
218 	return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
219 				    offs, size, data);
220 }
221 
222 static TEE_Result ree_fs_rpc_write_init(void *aux,
223 					struct tee_fs_rpc_operation *op,
224 					enum tee_fs_htree_type type, size_t idx,
225 					uint8_t vers, void **data)
226 {
227 	struct tee_fs_fd *fdp = aux;
228 	TEE_Result res;
229 	size_t offs;
230 	size_t size;
231 
232 	res = get_offs_size(type, idx, vers, &offs, &size);
233 	if (res != TEE_SUCCESS)
234 		return res;
235 
236 	return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
237 				     offs, size, data);
238 }
239 
240 static const struct tee_fs_htree_storage ree_fs_storage_ops = {
241 	.block_size = BLOCK_SIZE,
242 	.rpc_read_init = ree_fs_rpc_read_init,
243 	.rpc_read_final = tee_fs_rpc_read_final,
244 	.rpc_write_init = ree_fs_rpc_write_init,
245 	.rpc_write_final = tee_fs_rpc_write_final,
246 };
247 
248 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
249 					    tee_fs_off_t new_file_len)
250 {
251 	TEE_Result res;
252 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
253 
254 	if ((size_t)new_file_len > meta->length) {
255 		size_t ext_len = new_file_len - meta->length;
256 
257 		res = out_of_place_write(fdp, meta->length, NULL, ext_len);
258 		if (res != TEE_SUCCESS)
259 			return res;
260 	} else {
261 		size_t offs;
262 		size_t sz;
263 
264 		res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
265 				    ROUNDUP(new_file_len, BLOCK_SIZE) /
266 					BLOCK_SIZE, 1, &offs, &sz);
267 		if (res != TEE_SUCCESS)
268 			return res;
269 
270 		res = tee_fs_htree_truncate(&fdp->ht,
271 					    new_file_len / BLOCK_SIZE);
272 		if (res != TEE_SUCCESS)
273 			return res;
274 
275 		res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd,
276 					  offs + sz);
277 		if (res != TEE_SUCCESS)
278 			return res;
279 
280 		meta->length = new_file_len;
281 	}
282 
283 	return TEE_SUCCESS;
284 }
285 
286 static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos,
287 					void *buf, size_t *len)
288 {
289 	TEE_Result res;
290 	int start_block_num;
291 	int end_block_num;
292 	size_t remain_bytes;
293 	uint8_t *data_ptr = buf;
294 	uint8_t *block = NULL;
295 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
296 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
297 
298 	remain_bytes = *len;
299 	if ((pos + remain_bytes) < remain_bytes || pos > meta->length)
300 		remain_bytes = 0;
301 	else if (pos + remain_bytes > meta->length)
302 		remain_bytes = meta->length - pos;
303 
304 	*len = remain_bytes;
305 
306 	if (!remain_bytes) {
307 		res = TEE_SUCCESS;
308 		goto exit;
309 	}
310 
311 	start_block_num = pos_to_block_num(pos);
312 	end_block_num = pos_to_block_num(pos + remain_bytes - 1);
313 
314 	block = malloc(BLOCK_SIZE);
315 	if (!block) {
316 		res = TEE_ERROR_OUT_OF_MEMORY;
317 		goto exit;
318 	}
319 
320 	while (start_block_num <= end_block_num) {
321 		size_t offset = pos % BLOCK_SIZE;
322 		size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
323 
324 		if (size_to_read + offset > BLOCK_SIZE)
325 			size_to_read = BLOCK_SIZE - offset;
326 
327 		res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
328 		if (res != TEE_SUCCESS)
329 			goto exit;
330 
331 		memcpy(data_ptr, block + offset, size_to_read);
332 
333 		data_ptr += size_to_read;
334 		remain_bytes -= size_to_read;
335 		pos += size_to_read;
336 
337 		start_block_num++;
338 	}
339 	res = TEE_SUCCESS;
340 exit:
341 	free(block);
342 	return res;
343 }
344 
345 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos,
346 			      void *buf, size_t *len)
347 {
348 	TEE_Result res;
349 
350 	mutex_lock(&ree_fs_mutex);
351 	res = ree_fs_read_primitive(fh, pos, buf, len);
352 	mutex_unlock(&ree_fs_mutex);
353 
354 	return res;
355 }
356 
357 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos,
358 					 const void *buf, size_t len)
359 {
360 	TEE_Result res;
361 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
362 	size_t file_size;
363 
364 	if (!len)
365 		return TEE_SUCCESS;
366 
367 	file_size = tee_fs_htree_get_meta(fdp->ht)->length;
368 
369 	if ((pos + len) < len)
370 		return TEE_ERROR_BAD_PARAMETERS;
371 
372 	if (file_size < pos) {
373 		res = ree_fs_ftruncate_internal(fdp, pos);
374 		if (res != TEE_SUCCESS)
375 			return res;
376 	}
377 
378 	return out_of_place_write(fdp, pos, buf, len);
379 }
380 
381 static TEE_Result ree_fs_open_primitive(bool create, const TEE_UUID *uuid,
382 					struct tee_fs_dirfile_fileh *dfh,
383 					struct tee_file_handle **fh)
384 {
385 	TEE_Result res;
386 	struct tee_fs_fd *fdp;
387 	uint8_t *hash = NULL;
388 
389 	fdp = calloc(1, sizeof(struct tee_fs_fd));
390 	if (!fdp)
391 		return TEE_ERROR_OUT_OF_MEMORY;
392 	fdp->fd = -1;
393 	fdp->uuid = uuid;
394 
395 	if (create)
396 		res = tee_fs_rpc_create_dfh(OPTEE_MSG_RPC_CMD_FS,
397 					    dfh, &fdp->fd);
398 	else
399 		res = tee_fs_rpc_open_dfh(OPTEE_MSG_RPC_CMD_FS, dfh, &fdp->fd);
400 
401 	if (res != TEE_SUCCESS)
402 		goto out;
403 
404 	if (dfh)
405 		hash = dfh->hash;
406 	res = tee_fs_htree_open(create, hash, uuid, &ree_fs_storage_ops,
407 				fdp, &fdp->ht);
408 out:
409 	if (res == TEE_SUCCESS) {
410 		if (dfh)
411 			fdp->dfh = *dfh;
412 		else
413 			fdp->dfh.idx = -1;
414 		*fh = (struct tee_file_handle *)fdp;
415 	} else {
416 		if (fdp->fd != -1)
417 			tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
418 		if (create)
419 			tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, dfh);
420 		free(fdp);
421 	}
422 
423 	return res;
424 }
425 
426 static void ree_fs_close_primitive(struct tee_file_handle *fh)
427 {
428 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
429 
430 	if (fdp) {
431 		tee_fs_htree_close(&fdp->ht);
432 		tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
433 		free(fdp);
434 	}
435 }
436 
437 static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh,
438 					 uint8_t *hash)
439 {
440 	TEE_Result res;
441 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
442 
443 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
444 
445 	if (!res && hash)
446 		memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash));
447 
448 	return res;
449 }
450 
451 static const struct tee_fs_dirfile_operations ree_dirf_ops = {
452 	.open = ree_fs_open_primitive,
453 	.close = ree_fs_close_primitive,
454 	.read = ree_fs_read_primitive,
455 	.write = ree_fs_write_primitive,
456 	.commit_writes = ree_dirf_commit_writes,
457 };
458 
459 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size,
460 			      struct tee_file_handle **fh)
461 {
462 	TEE_Result res;
463 	struct tee_fs_dirfile_dirh *dirh = NULL;
464 	struct tee_fs_dirfile_fileh dfh;
465 
466 	mutex_lock(&ree_fs_mutex);
467 
468 	res = tee_fs_dirfile_open(&po->uuid, &ree_dirf_ops, &dirh);
469 	if (res != TEE_SUCCESS)
470 		goto out;
471 
472 	res = tee_fs_dirfile_find(dirh, po->obj_id, po->obj_id_len, &dfh);
473 	if (res != TEE_SUCCESS)
474 		goto out;
475 
476 	res = ree_fs_open_primitive(false, &po->uuid, &dfh, fh);
477 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
478 		/*
479 		 * If the object isn't found someone has tampered with it,
480 		 * treat it as corrupt.
481 		 */
482 		res = TEE_ERROR_CORRUPT_OBJECT;
483 	} else if (!res && size) {
484 		struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
485 
486 		*size = tee_fs_htree_get_meta(fdp->ht)->length;
487 	}
488 
489 out:
490 	tee_fs_dirfile_close(dirh);
491 	mutex_unlock(&ree_fs_mutex);
492 
493 	return res;
494 }
495 
496 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh,
497 			   struct tee_fs_fd *fdp, struct tee_pobj *po,
498 			   bool overwrite)
499 {
500 	TEE_Result res;
501 	bool have_old_dfh = false;
502 	struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 };
503 
504 	res = tee_fs_dirfile_find(dirh, po->obj_id, po->obj_id_len, &old_dfh);
505 	if (!overwrite && !res)
506 		return TEE_ERROR_ACCESS_CONFLICT;
507 
508 	if (!res)
509 		have_old_dfh = true;
510 
511 	/*
512 	 * If old_dfh wasn't found, the idx will be -1 and
513 	 * tee_fs_dirfile_rename() will allocate a new index.
514 	 */
515 	fdp->dfh.idx = old_dfh.idx;
516 	old_dfh.idx = -1;
517 	res = tee_fs_dirfile_rename(dirh, &fdp->dfh,
518 				    po->obj_id, po->obj_id_len);
519 	if (res)
520 		return res;
521 
522 	res = tee_fs_dirfile_commit_writes(dirh);
523 	if (res)
524 		return res;
525 
526 	if (have_old_dfh)
527 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &old_dfh);
528 
529 	return TEE_SUCCESS;
530 }
531 
532 static void ree_fs_close(struct tee_file_handle **fh)
533 {
534 	ree_fs_close_primitive(*fh);
535 	*fh = NULL;
536 }
537 
538 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite,
539 				const void *head, size_t head_size,
540 				const void *attr, size_t attr_size,
541 				const void *data, size_t data_size,
542 				struct tee_file_handle **fh)
543 {
544 	struct tee_fs_fd *fdp;
545 	struct tee_fs_dirfile_dirh *dirh = NULL;
546 	struct tee_fs_dirfile_fileh dfh;
547 	TEE_Result res;
548 	size_t pos = 0;
549 
550 	*fh = NULL;
551 	mutex_lock(&ree_fs_mutex);
552 
553 	res = tee_fs_dirfile_open(&po->uuid, &ree_dirf_ops, &dirh);
554 	if (res)
555 		goto out;
556 
557 	res = tee_fs_dirfile_get_tmp(dirh, &dfh);
558 	if (res)
559 		goto out;
560 
561 	res = ree_fs_open_primitive(true, &po->uuid, &dfh, fh);
562 	if (res)
563 		goto out;
564 
565 	if (head && head_size) {
566 		res = ree_fs_write_primitive(*fh, pos, head, head_size);
567 		if (res)
568 			goto out;
569 		pos += head_size;
570 	}
571 
572 	if (attr && attr_size) {
573 		res = ree_fs_write_primitive(*fh, pos, attr, attr_size);
574 		if (res)
575 			goto out;
576 		pos += attr_size;
577 	}
578 
579 	if (data && data_size) {
580 		res = ree_fs_write_primitive(*fh, pos, data, data_size);
581 		if (res)
582 			goto out;
583 	}
584 
585 	fdp = (struct tee_fs_fd *)*fh;
586 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
587 	if (res)
588 		goto out;
589 
590 	res = set_name(dirh, fdp, po, overwrite);
591 out:
592 	if (res && *fh) {
593 		ree_fs_close(fh);
594 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh);
595 	}
596 	tee_fs_dirfile_close(dirh);
597 	mutex_unlock(&ree_fs_mutex);
598 
599 	return res;
600 }
601 
602 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos,
603 			       const void *buf, size_t len)
604 {
605 	TEE_Result res;
606 	struct tee_fs_dirfile_dirh *dirh = NULL;
607 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
608 
609 	mutex_lock(&ree_fs_mutex);
610 
611 	res = tee_fs_dirfile_open(fdp->uuid, &ree_dirf_ops, &dirh);
612 	if (res)
613 		goto out;
614 
615 	res = ree_fs_write_primitive(fh, pos, buf, len);
616 	if (res)
617 		goto out;
618 
619 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
620 	if (res)
621 		goto out;
622 
623 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
624 	if (res)
625 		goto out;
626 	res = tee_fs_dirfile_commit_writes(dirh);
627 out:
628 	tee_fs_dirfile_close(dirh);
629 	mutex_unlock(&ree_fs_mutex);
630 
631 	return res;
632 }
633 
634 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
635 				bool overwrite)
636 {
637 	TEE_Result res;
638 	struct tee_fs_dirfile_dirh *dirh = NULL;
639 	struct tee_fs_dirfile_fileh dfh;
640 	struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 };
641 
642 	if (!new)
643 		return TEE_ERROR_BAD_PARAMETERS;
644 
645 	mutex_lock(&ree_fs_mutex);
646 	res = tee_fs_dirfile_open(&old->uuid, &ree_dirf_ops, &dirh);
647 	if (res)
648 		goto out;
649 
650 	res = tee_fs_dirfile_find(dirh, new->obj_id, new->obj_id_len,
651 				  &remove_dfh);
652 	if (!res && !overwrite) {
653 		res = TEE_ERROR_ACCESS_CONFLICT;
654 		goto out;
655 	}
656 
657 	res = tee_fs_dirfile_find(dirh, old->obj_id, old->obj_id_len, &dfh);
658 	if (res)
659 		goto out;
660 
661 	res = tee_fs_dirfile_rename(dirh, &dfh, new->obj_id, new->obj_id_len);
662 	if (res)
663 		goto out;
664 
665 	if (remove_dfh.idx != -1) {
666 		res = tee_fs_dirfile_remove(dirh, &remove_dfh);
667 		if (res)
668 			goto out;
669 	}
670 
671 	res = tee_fs_dirfile_commit_writes(dirh);
672 	if (res)
673 		goto out;
674 
675 	if (remove_dfh.idx != -1)
676 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &remove_dfh);
677 
678 out:
679 	tee_fs_dirfile_close(dirh);
680 	mutex_unlock(&ree_fs_mutex);
681 
682 	return res;
683 
684 }
685 
686 static TEE_Result ree_fs_remove(struct tee_pobj *po)
687 {
688 	TEE_Result res;
689 	struct tee_fs_dirfile_dirh *dirh = NULL;
690 	struct tee_fs_dirfile_fileh dfh;
691 
692 	mutex_lock(&ree_fs_mutex);
693 	res = tee_fs_dirfile_open(&po->uuid, &ree_dirf_ops, &dirh);
694 	if (res)
695 		goto out;
696 
697 	res = tee_fs_dirfile_find(dirh, po->obj_id, po->obj_id_len, &dfh);
698 	if (res)
699 		goto out;
700 
701 	res = tee_fs_dirfile_remove(dirh, &dfh);
702 	if (res)
703 		goto out;
704 
705 	res = tee_fs_dirfile_commit_writes(dirh);
706 	if (res)
707 		goto out;
708 
709 	tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh);
710 
711 	assert(tee_fs_dirfile_find(dirh, po->obj_id, po->obj_id_len, &dfh));
712 out:
713 	tee_fs_dirfile_close(dirh);
714 	mutex_unlock(&ree_fs_mutex);
715 
716 	return res;
717 }
718 
719 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
720 {
721 	TEE_Result res;
722 	struct tee_fs_dirfile_dirh *dirh = NULL;
723 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
724 
725 	mutex_lock(&ree_fs_mutex);
726 
727 	res = tee_fs_dirfile_open(fdp->uuid, &ree_dirf_ops, &dirh);
728 	if (res != TEE_SUCCESS)
729 		goto out;
730 
731 	res = ree_fs_ftruncate_internal(fdp, len);
732 	if (!res)
733 		goto out;
734 
735 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
736 	if (!res)
737 		goto out;
738 
739 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
740 
741 out:
742 	tee_fs_dirfile_close(dirh);
743 	mutex_unlock(&ree_fs_mutex);
744 
745 	return res;
746 }
747 
748 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid,
749 				     struct tee_fs_dir **dir)
750 
751 {
752 	TEE_Result res;
753 	struct tee_fs_dir *d = calloc(1, sizeof(*d));
754 
755 	if (!d)
756 		return TEE_ERROR_OUT_OF_MEMORY;
757 
758 	mutex_lock(&ree_fs_mutex);
759 
760 	res = tee_fs_dirfile_open(uuid, &ree_dirf_ops, &d->dirh);
761 	if (res)
762 		goto out;
763 
764 	/* See that there's at least one file */
765 	d->idx = -1;
766 	d->d.oidlen = sizeof(d->d.oid);
767 	res = tee_fs_dirfile_get_next(d->dirh, &d->idx, d->d.oid, &d->d.oidlen);
768 	d->idx = -1;
769 
770 out:
771 	if (!res) {
772 		*dir = d;
773 	} else {
774 		if (d)
775 			tee_fs_dirfile_close(d->dirh);
776 		free(d);
777 	}
778 	mutex_unlock(&ree_fs_mutex);
779 
780 	return res;
781 }
782 
783 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
784 {
785 	if (d) {
786 		mutex_lock(&ree_fs_mutex);
787 
788 		tee_fs_dirfile_close(d->dirh);
789 		free(d);
790 
791 		mutex_unlock(&ree_fs_mutex);
792 	}
793 }
794 
795 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
796 				     struct tee_fs_dirent **ent)
797 {
798 	TEE_Result res;
799 
800 	mutex_lock(&ree_fs_mutex);
801 
802 	d->d.oidlen = sizeof(d->d.oid);
803 	res = tee_fs_dirfile_get_next(d->dirh, &d->idx, d->d.oid, &d->d.oidlen);
804 	if (res == TEE_SUCCESS)
805 		*ent = &d->d;
806 
807 	mutex_unlock(&ree_fs_mutex);
808 
809 	return res;
810 }
811 
812 const struct tee_file_operations ree_fs_ops = {
813 	.open = ree_fs_open,
814 	.create = ree_fs_create,
815 	.close = ree_fs_close,
816 	.read = ree_fs_read,
817 	.write = ree_fs_write,
818 	.truncate = ree_fs_truncate,
819 	.rename = ree_fs_rename,
820 	.remove = ree_fs_remove,
821 	.opendir = ree_fs_opendir_rpc,
822 	.closedir = ree_fs_closedir_rpc,
823 	.readdir = ree_fs_readdir_rpc,
824 };
825