1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
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 #include <assert.h>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <handle.h>
32 #include <libgen.h>
33 #include <optee_msg_supplicant.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <teec_trace.h>
41 #include <tee_supp_fs.h>
42 #include <tee_supplicant.h>
43 #include <unistd.h>
44 
45 #ifndef __aligned
46 #define __aligned(x) __attribute__((__aligned__(x)))
47 #endif
48 #include <linux/tee.h>
49 
50 #ifndef PATH_MAX
51 #define PATH_MAX 255
52 #endif
53 
54 /* Path to all secure storage files. */
55 static char tee_fs_root[PATH_MAX];
56 
57 #define TEE_FS_FILENAME_MAX_LENGTH 150
58 
59 static pthread_mutex_t dir_handle_db_mutex = PTHREAD_MUTEX_INITIALIZER;
60 static struct handle_db dir_handle_db =
61 		HANDLE_DB_INITIALIZER_WITH_MUTEX(&dir_handle_db_mutex);
62 
tee_fs_get_absolute_filename(char * file,char * out,size_t out_size)63 static size_t tee_fs_get_absolute_filename(char *file, char *out,
64 					   size_t out_size)
65 {
66 	int s = 0;
67 
68 	if (!file || !out || (out_size <= strlen(tee_fs_root) + 1))
69 		return 0;
70 
71 	s = snprintf(out, out_size, "%s%s", tee_fs_root, file);
72 	if (s < 0 || (size_t)s >= out_size)
73 		return 0;
74 
75 	/* Safe to cast since we have checked that sizes are OK */
76 	return (size_t)s;
77 }
78 
do_mkdir(const char * path,mode_t mode)79 static int do_mkdir(const char *path, mode_t mode)
80 {
81 	struct stat st;
82 
83 	memset(&st, 0, sizeof(st));
84 
85 	if (mkdir(path, mode) != 0 && errno != EEXIST)
86 		return -1;
87 
88 	if (stat(path, &st) != 0 && !S_ISDIR(st.st_mode))
89 		return -1;
90 
91 	return 0;
92 }
93 
mkpath(const char * path,mode_t mode)94 static int mkpath(const char *path, mode_t mode)
95 {
96 	int status = 0;
97 	char *subpath = strdup(path);
98 	char *prev = subpath;
99 	char *curr = NULL;
100 
101 	while (status == 0 && (curr = strchr(prev, '/')) != 0) {
102 		/*
103 		 * Check for root or double slash
104 		 */
105 		if (curr != prev) {
106 			*curr = '\0';
107 			status = do_mkdir(subpath, mode);
108 			*curr = '/';
109 		}
110 		prev = curr + 1;
111 	}
112 	if (status == 0)
113 		status = do_mkdir(path, mode);
114 
115 	free(subpath);
116 	return status;
117 }
118 
tee_supp_fs_init(void)119 static int tee_supp_fs_init(void)
120 {
121 	size_t n = 0;
122 	mode_t mode = 0700;
123 
124 	n = snprintf(tee_fs_root, sizeof(tee_fs_root), "%s/", TEE_FS_PARENT_PATH);
125 	if (n >= sizeof(tee_fs_root))
126 		return -1;
127 
128 	if (mkpath(tee_fs_root, mode) != 0)
129 		return -1;
130 
131 	return 0;
132 }
133 
open_wrapper(const char * fname,int flags)134 static int open_wrapper(const char *fname, int flags)
135 {
136 	int fd = 0;
137 
138 	while (true) {
139 		fd = open(fname, flags | O_SYNC, 0600);
140 		if (fd >= 0 || errno != EINTR)
141 			return fd;
142 	}
143 }
144 
ree_fs_new_open(size_t num_params,struct tee_ioctl_param * params)145 static TEEC_Result ree_fs_new_open(size_t num_params,
146 				   struct tee_ioctl_param *params)
147 {
148 	char abs_filename[PATH_MAX] = { 0 };
149 	char *fname = NULL;
150 	int fd = 0;
151 
152 	if (num_params != 3 ||
153 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
154 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
155 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
156 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
157 	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
158 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
159 		return TEEC_ERROR_BAD_PARAMETERS;
160 
161 	fname = tee_supp_param_to_va(params + 1);
162 	if (!fname)
163 		return TEEC_ERROR_BAD_PARAMETERS;
164 
165 	if (!tee_fs_get_absolute_filename(fname, abs_filename,
166 					  sizeof(abs_filename)))
167 		return TEEC_ERROR_BAD_PARAMETERS;
168 
169 	fd = open_wrapper(abs_filename, O_RDWR);
170 	if (fd < 0) {
171 		/*
172 		 * In case the problem is the filesystem is RO, retry with the
173 		 * open flags restricted to RO.
174 		 */
175 		fd = open_wrapper(abs_filename, O_RDONLY);
176 		if (fd < 0)
177 			return TEEC_ERROR_ITEM_NOT_FOUND;
178 	}
179 
180 	params[2].a = fd;
181 	return TEEC_SUCCESS;
182 }
183 
ree_fs_new_create(size_t num_params,struct tee_ioctl_param * params)184 static TEEC_Result ree_fs_new_create(size_t num_params,
185 				     struct tee_ioctl_param *params)
186 {
187 	char abs_filename[PATH_MAX] = { 0 };
188 	char abs_dir[PATH_MAX] = { 0 };
189 	char *fname = NULL;
190 	char *d = NULL;
191 	int fd = 0;
192 	const int flags = O_RDWR | O_CREAT | O_TRUNC;
193 
194 	if (num_params != 3 ||
195 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
196 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
197 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
198 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
199 	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
200 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
201 		return TEEC_ERROR_BAD_PARAMETERS;
202 
203 	fname = tee_supp_param_to_va(params + 1);
204 	if (!fname)
205 		return TEEC_ERROR_BAD_PARAMETERS;
206 
207 	if (!tee_fs_get_absolute_filename(fname, abs_filename,
208 					  sizeof(abs_filename)))
209 		return TEEC_ERROR_BAD_PARAMETERS;
210 
211 	fd = open_wrapper(abs_filename, flags);
212 	if (fd >= 0)
213 		goto out;
214 	if (errno != ENOENT)
215 		return TEEC_ERROR_GENERIC;
216 
217 	/* Directory for file missing, try make to it */
218 	strncpy(abs_dir, abs_filename, sizeof(abs_dir));
219 	abs_dir[sizeof(abs_dir) - 1] = '\0';
220 	d = dirname(abs_dir);
221 	if (!mkdir(d, 0700)) {
222 		fd = open_wrapper(abs_filename, flags);
223 		if (fd >= 0)
224 			goto out;
225 		/*
226 		 * The directory was made but the file could still not be
227 		 * created.
228 		 */
229 		rmdir(d);
230 		return TEEC_ERROR_GENERIC;
231 	}
232 	if (errno != ENOENT)
233 		return TEEC_ERROR_GENERIC;
234 
235 	/* Parent directory for file missing, try to make it */
236 	d = dirname(d);
237 	if (mkdir(d, 0700))
238 		return TEEC_ERROR_GENERIC;
239 
240 	/* Try to make directory for file again */
241 	strncpy(abs_dir, abs_filename, sizeof(abs_dir));
242 	abs_dir[sizeof(abs_dir) - 1] = '\0';
243 	d = dirname(abs_dir);
244 	if (mkdir(d, 0700)) {
245 		d = dirname(d);
246 		rmdir(d);
247 		return TEEC_ERROR_GENERIC;
248 	}
249 
250 	fd = open_wrapper(abs_filename, flags);
251 	if (fd < 0) {
252 		rmdir(d);
253 		d = dirname(d);
254 		rmdir(d);
255 		return TEEC_ERROR_GENERIC;
256 	}
257 
258 out:
259 	params[2].a = fd;
260 	return TEEC_SUCCESS;
261 }
262 
ree_fs_new_close(size_t num_params,struct tee_ioctl_param * params)263 static TEEC_Result ree_fs_new_close(size_t num_params,
264 				    struct tee_ioctl_param *params)
265 {
266 	int fd = 0;
267 
268 	if (num_params != 1 ||
269 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
270 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
271 		return TEEC_ERROR_BAD_PARAMETERS;
272 
273 	fd = params[0].b;
274 	while (close(fd)) {
275 		if (errno != EINTR)
276 			return TEEC_ERROR_GENERIC;
277 	}
278 	return TEEC_SUCCESS;
279 }
280 
ree_fs_new_read(size_t num_params,struct tee_ioctl_param * params)281 static TEEC_Result ree_fs_new_read(size_t num_params,
282 				   struct tee_ioctl_param *params)
283 {
284 	uint8_t *buf = NULL;
285 	size_t len = 0;
286 	off_t offs = 0;
287 	int fd = 0;
288 	ssize_t r = 0;
289 	size_t s = 0;
290 
291 	if (num_params != 2 ||
292 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
293 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
294 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
295 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
296 		return TEEC_ERROR_BAD_PARAMETERS;
297 
298 	fd = params[0].b;
299 	offs = params[0].c;
300 
301 	buf = tee_supp_param_to_va(params + 1);
302 	if (!buf)
303 		return TEEC_ERROR_BAD_PARAMETERS;
304 	len = MEMREF_SIZE(params + 1);
305 
306 	s = 0;
307 	r = -1;
308 	while (r && len) {
309 		r = pread(fd, buf, len, offs);
310 		if (r < 0) {
311 			if (errno == EINTR)
312 				continue;
313 			return TEEC_ERROR_GENERIC;
314 		}
315 		assert((size_t)r <= len);
316 		buf += r;
317 		len -= r;
318 		offs += r;
319 		s += r;
320 	}
321 
322 	MEMREF_SIZE(params + 1) = s;
323 	return TEEC_SUCCESS;
324 }
325 
ree_fs_new_write(size_t num_params,struct tee_ioctl_param * params)326 static TEEC_Result ree_fs_new_write(size_t num_params,
327 				    struct tee_ioctl_param *params)
328 {
329 	uint8_t *buf = NULL;
330 	size_t len = 0;
331 	off_t offs = 0;
332 	int fd = 0;
333 	ssize_t r = 0;
334 
335 	if (num_params != 2 ||
336 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
337 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
338 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
339 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
340 		return TEEC_ERROR_BAD_PARAMETERS;
341 
342 	fd = params[0].b;
343 	offs = params[0].c;
344 
345 	buf = tee_supp_param_to_va(params + 1);
346 	if (!buf)
347 		return TEEC_ERROR_BAD_PARAMETERS;
348 	len = MEMREF_SIZE(params + 1);
349 
350 	while (len) {
351 		r = pwrite(fd, buf, len, offs);
352 		if (r < 0) {
353 			if (errno == EINTR)
354 				continue;
355 			return TEEC_ERROR_GENERIC;
356 		}
357 		assert((size_t)r <= len);
358 		buf += r;
359 		len -= r;
360 		offs += r;
361 	}
362 
363 	return TEEC_SUCCESS;
364 }
365 
ree_fs_new_truncate(size_t num_params,struct tee_ioctl_param * params)366 static TEEC_Result ree_fs_new_truncate(size_t num_params,
367 				       struct tee_ioctl_param *params)
368 {
369 	size_t len = 0;
370 	int fd = 0;
371 
372 	if (num_params != 1 ||
373 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
374 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
375 		return TEEC_ERROR_BAD_PARAMETERS;
376 
377 	fd = params[0].b;
378 	len = params[0].c;
379 
380 	while (ftruncate(fd, len)) {
381 		if (errno != EINTR)
382 			return TEEC_ERROR_GENERIC;
383 	}
384 
385 	return TEEC_SUCCESS;
386 }
387 
ree_fs_new_remove(size_t num_params,struct tee_ioctl_param * params)388 static TEEC_Result ree_fs_new_remove(size_t num_params,
389 				     struct tee_ioctl_param *params)
390 {
391 	char abs_filename[PATH_MAX] = { 0 };
392 	char *fname = NULL;
393 	char *d = NULL;
394 
395 	if (num_params != 2 ||
396 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
397 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
398 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
399 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
400 		return TEEC_ERROR_BAD_PARAMETERS;
401 
402 	fname = tee_supp_param_to_va(params + 1);
403 	if (!fname)
404 		return TEEC_ERROR_BAD_PARAMETERS;
405 
406 	if (!tee_fs_get_absolute_filename(fname, abs_filename,
407 					  sizeof(abs_filename)))
408 		return TEEC_ERROR_BAD_PARAMETERS;
409 
410 	if (unlink(abs_filename)) {
411 		if (errno == ENOENT)
412 			return TEEC_ERROR_ITEM_NOT_FOUND;
413 		return TEEC_ERROR_GENERIC;
414 	}
415 
416 	/* If a file is removed, maybe the directory can be removed to? */
417 	d = dirname(abs_filename);
418 	if (!rmdir(d)) {
419 		/*
420 		 * If the directory was removed, maybe the parent directory
421 		 * can be removed too?
422 		 */
423 		d = dirname(d);
424 		rmdir(d);
425 	}
426 
427 	return TEEC_SUCCESS;
428 }
429 
ree_fs_new_rename(size_t num_params,struct tee_ioctl_param * params)430 static TEEC_Result ree_fs_new_rename(size_t num_params,
431 				     struct tee_ioctl_param *params)
432 {
433 	char old_abs_filename[PATH_MAX] = { 0 };
434 	char new_abs_filename[PATH_MAX] = { 0 };
435 	char *old_fname = NULL;
436 	char *new_fname = NULL;
437 	bool overwrite = false;
438 
439 	if (num_params != 3 ||
440 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
441 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
442 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
443 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
444 	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
445 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
446 		return TEEC_ERROR_BAD_PARAMETERS;
447 
448 	overwrite = !!params[0].b;
449 
450 	old_fname = tee_supp_param_to_va(params + 1);
451 	if (!old_fname)
452 		return TEEC_ERROR_BAD_PARAMETERS;
453 
454 	new_fname = tee_supp_param_to_va(params + 2);
455 	if (!new_fname)
456 		return TEEC_ERROR_BAD_PARAMETERS;
457 
458 	if (!tee_fs_get_absolute_filename(old_fname, old_abs_filename,
459 					  sizeof(old_abs_filename)))
460 		return TEEC_ERROR_BAD_PARAMETERS;
461 
462 	if (!tee_fs_get_absolute_filename(new_fname, new_abs_filename,
463 					  sizeof(new_abs_filename)))
464 		return TEEC_ERROR_BAD_PARAMETERS;
465 
466 	if (!overwrite) {
467 		struct stat st;
468 
469 		if (!stat(new_abs_filename, &st))
470 			return TEEC_ERROR_ACCESS_CONFLICT;
471 	}
472 	if (rename(old_abs_filename, new_abs_filename)) {
473 		if (errno == ENOENT)
474 			return TEEC_ERROR_ITEM_NOT_FOUND;
475 	}
476 	return TEEC_SUCCESS;
477 }
478 
ree_fs_new_opendir(size_t num_params,struct tee_ioctl_param * params)479 static TEEC_Result ree_fs_new_opendir(size_t num_params,
480 				      struct tee_ioctl_param *params)
481 {
482 	char abs_filename[PATH_MAX] = { 0 };
483 	char *fname = NULL;
484 	DIR *dir = NULL;
485 	int handle = 0;
486 	struct dirent *dent = NULL;
487 	bool empty = true;
488 
489 	if (num_params != 3 ||
490 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
491 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
492 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
493 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
494 	    (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
495 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
496 		return TEEC_ERROR_BAD_PARAMETERS;
497 
498 	fname = tee_supp_param_to_va(params + 1);
499 	if (!fname)
500 		return TEEC_ERROR_BAD_PARAMETERS;
501 
502 	if (!tee_fs_get_absolute_filename(fname, abs_filename,
503 					  sizeof(abs_filename)))
504 		return TEEC_ERROR_BAD_PARAMETERS;
505 
506 	dir = opendir(abs_filename);
507 	if (!dir)
508 		return TEEC_ERROR_ITEM_NOT_FOUND;
509 
510 	/*
511 	 * Ignore empty directories. Works around an issue when the
512 	 * data path is mounted over NFS. Due to the way OP-TEE implements
513 	 * TEE_CloseAndDeletePersistentObject1() currently, tee-supplicant
514 	 * still has a file descriptor open to the file when it's removed in
515 	 * ree_fs_new_remove(). In this case the NFS server may create a
516 	 * temporary reference called .nfs????, and the rmdir() call fails
517 	 * so that the TA directory is left over. Checking this special case
518 	 * here avoids that TEE_StartPersistentObjectEnumerator() returns
519 	 * TEE_SUCCESS when it should return TEEC_ERROR_ITEM_NOT_FOUND.
520 	 * Test case: "xtest 6009 6010".
521 	 */
522 	while ((dent = readdir(dir))) {
523 		if (dent->d_name[0] == '.')
524 			continue;
525 		empty = false;
526 		break;
527 	}
528 	if (empty) {
529 		closedir(dir);
530 		return TEEC_ERROR_ITEM_NOT_FOUND;
531 	}
532 	rewinddir(dir);
533 
534 	handle = handle_get(&dir_handle_db, dir);
535 	if (handle < 0) {
536 		closedir(dir);
537 		return TEEC_ERROR_OUT_OF_MEMORY;
538 	}
539 
540 	params[2].a = handle;
541 	return TEEC_SUCCESS;
542 }
543 
ree_fs_new_closedir(size_t num_params,struct tee_ioctl_param * params)544 static TEEC_Result ree_fs_new_closedir(size_t num_params,
545 				       struct tee_ioctl_param *params)
546 {
547 	DIR *dir = NULL;
548 
549 	if (num_params != 1 ||
550 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
551 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
552 		return TEEC_ERROR_BAD_PARAMETERS;
553 
554 	dir = handle_put(&dir_handle_db, params[0].b);
555 	if (!dir)
556 		return TEEC_ERROR_BAD_PARAMETERS;
557 
558 	closedir(dir);
559 
560 	return TEEC_SUCCESS;
561 }
562 
ree_fs_new_readdir(size_t num_params,struct tee_ioctl_param * params)563 static TEEC_Result ree_fs_new_readdir(size_t num_params,
564 				      struct tee_ioctl_param *params)
565 {
566 	DIR *dir = NULL;
567 	struct dirent *dirent = NULL;
568 	char *buf = NULL;
569 	size_t len = 0;
570 	size_t fname_len = 0;
571 
572 	if (num_params != 2 ||
573 	    (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
574 			TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
575 	    (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
576 			TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
577 		return TEEC_ERROR_BAD_PARAMETERS;
578 
579 
580 	buf = tee_supp_param_to_va(params + 1);
581 	if (!buf)
582 		return TEEC_ERROR_BAD_PARAMETERS;
583 	len = MEMREF_SIZE(params + 1);
584 
585 	dir = handle_lookup(&dir_handle_db, params[0].b);
586 	if (!dir)
587 		return TEEC_ERROR_BAD_PARAMETERS;
588 
589 	while (true) {
590 		dirent = readdir(dir);
591 		if (!dirent)
592 			return TEEC_ERROR_ITEM_NOT_FOUND;
593 		if (dirent->d_name[0] != '.')
594 			break;
595 	}
596 
597 	fname_len = strlen(dirent->d_name) + 1;
598 	MEMREF_SIZE(params + 1) = fname_len;
599 	if (fname_len > len)
600 		return TEEC_ERROR_SHORT_BUFFER;
601 
602 	memcpy(buf, dirent->d_name, fname_len);
603 
604 	return TEEC_SUCCESS;
605 }
606 
tee_supp_fs_process(size_t num_params,struct tee_ioctl_param * params)607 TEEC_Result tee_supp_fs_process(size_t num_params,
608 				struct tee_ioctl_param *params)
609 {
610 	if (!num_params || !tee_supp_param_is_value(params))
611 		return TEEC_ERROR_BAD_PARAMETERS;
612 
613 	if (strlen(tee_fs_root) == 0) {
614 		if (tee_supp_fs_init() != 0) {
615 			EMSG("error tee_supp_fs_init: failed to create %s/",
616 				TEE_FS_PARENT_PATH);
617 			memset(tee_fs_root, 0, sizeof(tee_fs_root));
618 			return TEEC_ERROR_STORAGE_NOT_AVAILABLE;
619 		}
620 	}
621 
622 	switch (params->a) {
623 	case OPTEE_MRF_OPEN:
624 		return ree_fs_new_open(num_params, params);
625 	case OPTEE_MRF_CREATE:
626 		return ree_fs_new_create(num_params, params);
627 	case OPTEE_MRF_CLOSE:
628 		return ree_fs_new_close(num_params, params);
629 	case OPTEE_MRF_READ:
630 		return ree_fs_new_read(num_params, params);
631 	case OPTEE_MRF_WRITE:
632 		return ree_fs_new_write(num_params, params);
633 	case OPTEE_MRF_TRUNCATE:
634 		return ree_fs_new_truncate(num_params, params);
635 	case OPTEE_MRF_REMOVE:
636 		return ree_fs_new_remove(num_params, params);
637 	case OPTEE_MRF_RENAME:
638 		return ree_fs_new_rename(num_params, params);
639 	case OPTEE_MRF_OPENDIR:
640 		return ree_fs_new_opendir(num_params, params);
641 	case OPTEE_MRF_CLOSEDIR:
642 		return ree_fs_new_closedir(num_params, params);
643 	case OPTEE_MRF_READDIR:
644 		return ree_fs_new_readdir(num_params, params);
645 	default:
646 		return TEEC_ERROR_BAD_PARAMETERS;
647 	}
648 }
649