blob: 187a1dbbfabbdf5f560f7d293b0f1183ac268853 [file] [log] [blame]
Pascal Brand04ac4652014-06-03 16:12:38 +02001/*
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 */
Pierre Ducroquete3148e32025-06-23 12:41:00 +020027
28#define _GNU_SOURCE
29
Jens Wiklander1472d0e2016-09-09 10:41:15 +020030#include <assert.h>
Pascal Brand04ac4652014-06-03 16:12:38 +020031#include <dirent.h>
Jens Wiklander1472d0e2016-09-09 10:41:15 +020032#include <errno.h>
33#include <fcntl.h>
Pascal Brand73531b92015-03-06 11:16:31 +010034#include <handle.h>
Jens Wiklander1472d0e2016-09-09 10:41:15 +020035#include <libgen.h>
Jerome Forissiera1df0732016-10-26 13:45:45 +020036#include <optee_msg_supplicant.h>
Jens Wiklander1472d0e2016-09-09 10:41:15 +020037#include <stdbool.h>
38#include <stdint.h>
39#include <stdio.h>
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +030040#include <stdlib.h>
Jens Wiklander1472d0e2016-09-09 10:41:15 +020041#include <string.h>
42#include <sys/stat.h>
43#include <teec_trace.h>
Jens Wiklander1472d0e2016-09-09 10:41:15 +020044#include <tee_supp_fs.h>
45#include <tee_supplicant.h>
46#include <unistd.h>
47
48#ifndef __aligned
49#define __aligned(x) __attribute__((__aligned__(x)))
50#endif
51#include <linux/tee.h>
Pascal Brand04ac4652014-06-03 16:12:38 +020052
Pascal Brand04ac4652014-06-03 16:12:38 +020053#ifndef PATH_MAX
54#define PATH_MAX 255
55#endif
56
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +030057/* Path to all secure storage files. */
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +020058static int tee_fs_fd = -1;
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +030059
Jens Wiklander955e1252014-06-04 10:45:51 +020060static pthread_mutex_t dir_handle_db_mutex = PTHREAD_MUTEX_INITIALIZER;
61static struct handle_db dir_handle_db =
62 HANDLE_DB_INITIALIZER_WITH_MUTEX(&dir_handle_db_mutex);
63
Jerome Forissiere7cba712022-07-04 16:34:40 +020064static TEEC_Result errno_to_teec(int err)
65{
66 switch (err) {
67 case ENOSPC:
68 return TEEC_ERROR_STORAGE_NO_SPACE;
69 case ENOENT:
70 return TEEC_ERROR_ITEM_NOT_FOUND;
71 default:
72 break;
73 }
74 return TEEC_ERROR_GENERIC;
75}
76
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +020077static size_t tee_fs_get_relative_filename(char *file, char *out,
78 size_t out_size)
79{
80 int s = 0;
81
82 if (!file || !out || (out_size <= strlen(file) + 3))
83 return 0;
84
85 s = snprintf(out, out_size, "./%s", file);
86 if (s < 0 || (size_t)s >= out_size)
87 return 0;
88
89 /* Safe to cast since we have checked that sizes are OK */
90 return (size_t)s;
91}
92
Joakim Nordellcb3842c2022-10-21 13:27:33 +020093static void fs_fsync(void)
94{
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +020095 if (tee_fs_fd > 0)
96 fsync(tee_fs_fd);
Joakim Nordellcb3842c2022-10-21 13:27:33 +020097}
98
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +030099static int do_mkdir(const char *path, mode_t mode)
Pascal Brand04ac4652014-06-03 16:12:38 +0200100{
101 struct stat st;
102
Etienne Carriere924a4742019-03-21 09:43:35 +0100103 memset(&st, 0, sizeof(st));
104
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +0300105 if (mkdir(path, mode) != 0 && errno != EEXIST)
Pascal Brand04ac4652014-06-03 16:12:38 +0200106 return -1;
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +0300107
108 if (stat(path, &st) != 0 && !S_ISDIR(st.st_mode))
109 return -1;
110
111 return 0;
112}
113
114static int mkpath(const char *path, mode_t mode)
115{
116 int status = 0;
117 char *subpath = strdup(path);
118 char *prev = subpath;
Etienne Carriere924a4742019-03-21 09:43:35 +0100119 char *curr = NULL;
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +0300120
121 while (status == 0 && (curr = strchr(prev, '/')) != 0) {
122 /*
123 * Check for root or double slash
124 */
125 if (curr != prev) {
126 *curr = '\0';
127 status = do_mkdir(subpath, mode);
128 *curr = '/';
129 }
130 prev = curr + 1;
131 }
132 if (status == 0)
133 status = do_mkdir(path, mode);
134
135 free(subpath);
136 return status;
137}
138
Victor Chongcb716672019-04-26 16:41:55 +0900139static int tee_supp_fs_init(void)
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +0300140{
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +0300141 mode_t mode = 0700;
142
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200143 if (mkpath(supplicant_params.fs_parent_path, mode) != 0)
Ruslan Piasetskyi48aed6e2017-06-01 09:36:21 +0300144 return -1;
145
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200146 tee_fs_fd = open(supplicant_params.fs_parent_path, O_RDONLY);
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200147 if (tee_fs_fd < 0)
148 return -1;
Pierre Ducroquet84557a22025-06-23 12:41:00 +0200149 fs_fsync();
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200150
Pascal Brand04ac4652014-06-03 16:12:38 +0200151 return 0;
152}
153
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200154static int openat_wrapper(const char *fname, int flags)
155{
156 int fd = 0;
157
158 while (true) {
159 fd = openat(tee_fs_fd, fname, flags | O_SYNC, 0600);
160 if (fd >= 0 || errno != EINTR)
161 return fd;
162 }
163}
164
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200165static TEEC_Result ree_fs_new_open(size_t num_params,
166 struct tee_ioctl_param *params)
167{
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200168 char rel_filename[PATH_MAX] = { 0 };
Etienne Carriere924a4742019-03-21 09:43:35 +0100169 char *fname = NULL;
170 int fd = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200171
172 if (num_params != 3 ||
173 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
174 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
175 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
176 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
177 (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
178 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
179 return TEEC_ERROR_BAD_PARAMETERS;
180
181 fname = tee_supp_param_to_va(params + 1);
182 if (!fname)
183 return TEEC_ERROR_BAD_PARAMETERS;
184
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200185 if (!tee_fs_get_relative_filename(fname, rel_filename,
186 sizeof(rel_filename)))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200187 return TEEC_ERROR_BAD_PARAMETERS;
188
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200189 fd = openat_wrapper(rel_filename, O_RDWR);
Andy Green7f161072017-01-31 09:35:52 +0800190 if (fd < 0) {
191 /*
192 * In case the problem is the filesystem is RO, retry with the
193 * open flags restricted to RO.
194 */
Pierre Ducroquetb7f589a2025-06-23 12:41:00 +0200195 fd = openat_wrapper(rel_filename, O_RDONLY);
Andy Green7f161072017-01-31 09:35:52 +0800196 if (fd < 0)
197 return TEEC_ERROR_ITEM_NOT_FOUND;
198 }
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200199
Jens Wiklander342acae2020-04-17 14:29:38 +0200200 params[2].a = fd;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200201 return TEEC_SUCCESS;
202}
203
204static TEEC_Result ree_fs_new_create(size_t num_params,
205 struct tee_ioctl_param *params)
206{
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200207 char rel_filename[PATH_MAX] = { 0 };
208 char rel_dir[PATH_MAX] = { 0 };
Etienne Carriere924a4742019-03-21 09:43:35 +0100209 char *fname = NULL;
210 char *d = NULL;
211 int fd = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200212 const int flags = O_RDWR | O_CREAT | O_TRUNC;
213
214 if (num_params != 3 ||
215 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
216 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
217 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
218 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
219 (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
220 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
221 return TEEC_ERROR_BAD_PARAMETERS;
222
223 fname = tee_supp_param_to_va(params + 1);
224 if (!fname)
225 return TEEC_ERROR_BAD_PARAMETERS;
226
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200227 if (!tee_fs_get_relative_filename(fname, rel_filename,
228 sizeof(rel_filename)))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200229 return TEEC_ERROR_BAD_PARAMETERS;
230
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200231 fd = openat_wrapper(rel_filename, flags);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200232 if (fd >= 0)
233 goto out;
234 if (errno != ENOENT)
Jerome Forissiere7cba712022-07-04 16:34:40 +0200235 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200236
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200237 /* Directory for file missing, try to make it */
238 strncpy(rel_dir, rel_filename, sizeof(rel_dir));
239 rel_dir[sizeof(rel_dir) - 1] = '\0';
240 d = dirname(rel_dir);
241 if (!mkdirat(tee_fs_fd, d, 0700)) {
Jerome Forissiere7cba712022-07-04 16:34:40 +0200242 int err = 0;
243
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200244 fd = openat_wrapper(rel_filename, flags);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200245 if (fd >= 0)
246 goto out;
247 /*
248 * The directory was made but the file could still not be
249 * created.
250 */
Jerome Forissiere7cba712022-07-04 16:34:40 +0200251 err = errno;
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200252 unlinkat(tee_fs_fd, d, AT_REMOVEDIR);
Jerome Forissiere7cba712022-07-04 16:34:40 +0200253 return errno_to_teec(err);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200254 }
255 if (errno != ENOENT)
Jerome Forissiere7cba712022-07-04 16:34:40 +0200256 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200257
258 /* Parent directory for file missing, try to make it */
259 d = dirname(d);
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200260 if (mkdirat(tee_fs_fd, d, 0700))
Jerome Forissiere7cba712022-07-04 16:34:40 +0200261 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200262
263 /* Try to make directory for file again */
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200264 d = dirname(rel_dir);
265 if (mkdirat(tee_fs_fd, d, 0700)) {
Jerome Forissiere7cba712022-07-04 16:34:40 +0200266 int err = errno;
267
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200268 d = dirname(d);
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200269 unlinkat(tee_fs_fd, d, AT_REMOVEDIR);
Jerome Forissiere7cba712022-07-04 16:34:40 +0200270 return errno_to_teec(err);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200271 }
272
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200273 fd = openat_wrapper(rel_filename, flags);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200274 if (fd < 0) {
Jerome Forissiere7cba712022-07-04 16:34:40 +0200275 int err = errno;
276
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200277 unlinkat(tee_fs_fd, d, AT_REMOVEDIR);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200278 d = dirname(d);
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200279 unlinkat(tee_fs_fd, d, AT_REMOVEDIR);
Jerome Forissiere7cba712022-07-04 16:34:40 +0200280 return errno_to_teec(err);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200281 }
282
283out:
Joakim Nordellcb3842c2022-10-21 13:27:33 +0200284 fs_fsync();
Jens Wiklander342acae2020-04-17 14:29:38 +0200285 params[2].a = fd;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200286 return TEEC_SUCCESS;
287}
288
289static TEEC_Result ree_fs_new_close(size_t num_params,
290 struct tee_ioctl_param *params)
291{
Etienne Carriere924a4742019-03-21 09:43:35 +0100292 int fd = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200293
294 if (num_params != 1 ||
295 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
296 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
297 return TEEC_ERROR_BAD_PARAMETERS;
298
Jens Wiklander342acae2020-04-17 14:29:38 +0200299 fd = params[0].b;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200300 while (close(fd)) {
301 if (errno != EINTR)
Jerome Forissiere7cba712022-07-04 16:34:40 +0200302 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200303 }
304 return TEEC_SUCCESS;
305}
306
307static TEEC_Result ree_fs_new_read(size_t num_params,
308 struct tee_ioctl_param *params)
309{
Etienne Carriere924a4742019-03-21 09:43:35 +0100310 uint8_t *buf = NULL;
311 size_t len = 0;
312 off_t offs = 0;
313 int fd = 0;
314 ssize_t r = 0;
315 size_t s = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200316
317 if (num_params != 2 ||
318 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
319 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
320 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
321 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
322 return TEEC_ERROR_BAD_PARAMETERS;
323
Jens Wiklander342acae2020-04-17 14:29:38 +0200324 fd = params[0].b;
325 offs = params[0].c;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200326
327 buf = tee_supp_param_to_va(params + 1);
328 if (!buf)
329 return TEEC_ERROR_BAD_PARAMETERS;
Jens Wiklander342acae2020-04-17 14:29:38 +0200330 len = MEMREF_SIZE(params + 1);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200331
332 s = 0;
333 r = -1;
334 while (r && len) {
335 r = pread(fd, buf, len, offs);
336 if (r < 0) {
337 if (errno == EINTR)
338 continue;
Jerome Forissiere7cba712022-07-04 16:34:40 +0200339 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200340 }
341 assert((size_t)r <= len);
342 buf += r;
343 len -= r;
344 offs += r;
345 s += r;
346 }
347
Jens Wiklander342acae2020-04-17 14:29:38 +0200348 MEMREF_SIZE(params + 1) = s;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200349 return TEEC_SUCCESS;
350}
351
352static TEEC_Result ree_fs_new_write(size_t num_params,
353 struct tee_ioctl_param *params)
354{
Etienne Carriere924a4742019-03-21 09:43:35 +0100355 uint8_t *buf = NULL;
356 size_t len = 0;
357 off_t offs = 0;
358 int fd = 0;
359 ssize_t r = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200360
361 if (num_params != 2 ||
362 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
363 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
364 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
365 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
366 return TEEC_ERROR_BAD_PARAMETERS;
367
Jens Wiklander342acae2020-04-17 14:29:38 +0200368 fd = params[0].b;
369 offs = params[0].c;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200370
371 buf = tee_supp_param_to_va(params + 1);
372 if (!buf)
373 return TEEC_ERROR_BAD_PARAMETERS;
Jens Wiklander342acae2020-04-17 14:29:38 +0200374 len = MEMREF_SIZE(params + 1);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200375
376 while (len) {
377 r = pwrite(fd, buf, len, offs);
378 if (r < 0) {
379 if (errno == EINTR)
380 continue;
Jerome Forissiere7cba712022-07-04 16:34:40 +0200381 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200382 }
383 assert((size_t)r <= len);
384 buf += r;
385 len -= r;
386 offs += r;
387 }
388
389 return TEEC_SUCCESS;
390}
391
392static TEEC_Result ree_fs_new_truncate(size_t num_params,
393 struct tee_ioctl_param *params)
394{
Etienne Carriere924a4742019-03-21 09:43:35 +0100395 size_t len = 0;
396 int fd = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200397
398 if (num_params != 1 ||
399 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
400 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
401 return TEEC_ERROR_BAD_PARAMETERS;
402
Jens Wiklander342acae2020-04-17 14:29:38 +0200403 fd = params[0].b;
404 len = params[0].c;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200405
406 while (ftruncate(fd, len)) {
407 if (errno != EINTR)
Jerome Forissiere7cba712022-07-04 16:34:40 +0200408 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200409 }
410
411 return TEEC_SUCCESS;
412}
413
414static TEEC_Result ree_fs_new_remove(size_t num_params,
415 struct tee_ioctl_param *params)
416{
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200417 char rel_filename[PATH_MAX] = { 0 };
Etienne Carriere924a4742019-03-21 09:43:35 +0100418 char *fname = NULL;
419 char *d = NULL;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200420
421 if (num_params != 2 ||
422 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
423 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
424 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
425 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
426 return TEEC_ERROR_BAD_PARAMETERS;
427
428 fname = tee_supp_param_to_va(params + 1);
429 if (!fname)
430 return TEEC_ERROR_BAD_PARAMETERS;
431
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200432 if (!tee_fs_get_relative_filename(fname, rel_filename,
433 sizeof(rel_filename)))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200434 return TEEC_ERROR_BAD_PARAMETERS;
435
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200436 if (unlinkat(tee_fs_fd, rel_filename, 0))
Jerome Forissiere7cba712022-07-04 16:34:40 +0200437 return errno_to_teec(errno);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200438
439 /* If a file is removed, maybe the directory can be removed to? */
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200440 d = dirname(rel_filename);
441 if (!unlinkat(tee_fs_fd, d, AT_REMOVEDIR)) {
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200442 /*
443 * If the directory was removed, maybe the parent directory
444 * can be removed too?
445 */
446 d = dirname(d);
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200447 unlinkat(tee_fs_fd, d, AT_REMOVEDIR);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200448 }
449
450 return TEEC_SUCCESS;
451}
452
453static TEEC_Result ree_fs_new_rename(size_t num_params,
454 struct tee_ioctl_param *params)
455{
Pierre Ducroquet8ec14392025-06-23 12:41:00 +0200456 char old_rel_filename[PATH_MAX] = { 0 };
457 char new_rel_filename[PATH_MAX] = { 0 };
Etienne Carriere924a4742019-03-21 09:43:35 +0100458 char *old_fname = NULL;
459 char *new_fname = NULL;
460 bool overwrite = false;
Pierre Ducroquete3148e32025-06-23 12:41:00 +0200461 int flags = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200462
463 if (num_params != 3 ||
464 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
465 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
466 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
467 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
468 (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
469 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT)
470 return TEEC_ERROR_BAD_PARAMETERS;
471
Jens Wiklander342acae2020-04-17 14:29:38 +0200472 overwrite = !!params[0].b;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200473
474 old_fname = tee_supp_param_to_va(params + 1);
475 if (!old_fname)
476 return TEEC_ERROR_BAD_PARAMETERS;
477
478 new_fname = tee_supp_param_to_va(params + 2);
479 if (!new_fname)
480 return TEEC_ERROR_BAD_PARAMETERS;
481
Pierre Ducroquet8ec14392025-06-23 12:41:00 +0200482 if (!tee_fs_get_relative_filename(old_fname, old_rel_filename,
483 sizeof(old_rel_filename)))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200484 return TEEC_ERROR_BAD_PARAMETERS;
485
Pierre Ducroquet8ec14392025-06-23 12:41:00 +0200486 if (!tee_fs_get_relative_filename(new_fname, new_rel_filename,
487 sizeof(new_rel_filename)))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200488 return TEEC_ERROR_BAD_PARAMETERS;
489
Pierre Ducroquete3148e32025-06-23 12:41:00 +0200490 if (!overwrite)
491 flags = RENAME_NOREPLACE;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200492
Pierre Ducroquete3148e32025-06-23 12:41:00 +0200493 if (renameat2(tee_fs_fd, old_rel_filename, tee_fs_fd, new_rel_filename, flags)) {
494 if (errno == EEXIST)
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200495 return TEEC_ERROR_ACCESS_CONFLICT;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200496 if (errno == ENOENT)
497 return TEEC_ERROR_ITEM_NOT_FOUND;
498 }
Joakim Nordellcb3842c2022-10-21 13:27:33 +0200499
500 fs_fsync();
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200501 return TEEC_SUCCESS;
502}
503
504static TEEC_Result ree_fs_new_opendir(size_t num_params,
505 struct tee_ioctl_param *params)
506{
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200507 char rel_filename[PATH_MAX] = { 0 };
Etienne Carriere924a4742019-03-21 09:43:35 +0100508 char *fname = NULL;
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200509 int dir_fd = -1;
Etienne Carriere924a4742019-03-21 09:43:35 +0100510 DIR *dir = NULL;
511 int handle = 0;
512 struct dirent *dent = NULL;
Jerome Forissier1df40462017-03-23 11:30:08 +0100513 bool empty = true;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200514
515 if (num_params != 3 ||
516 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
517 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
518 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
519 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
520 (params[2].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
521 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT)
522 return TEEC_ERROR_BAD_PARAMETERS;
523
524 fname = tee_supp_param_to_va(params + 1);
525 if (!fname)
526 return TEEC_ERROR_BAD_PARAMETERS;
527
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200528 if (!tee_fs_get_relative_filename(fname, rel_filename,
529 sizeof(rel_filename)))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200530 return TEEC_ERROR_BAD_PARAMETERS;
531
Pierre Ducroquet9a791ba2025-06-23 12:41:00 +0200532 dir_fd = openat_wrapper(rel_filename, O_DIRECTORY);
533 if (dir_fd < 0)
534 return TEEC_ERROR_ITEM_NOT_FOUND;
535 dir = fdopendir(dir_fd);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200536 if (!dir)
537 return TEEC_ERROR_ITEM_NOT_FOUND;
538
Jerome Forissier1df40462017-03-23 11:30:08 +0100539 /*
540 * Ignore empty directories. Works around an issue when the
541 * data path is mounted over NFS. Due to the way OP-TEE implements
542 * TEE_CloseAndDeletePersistentObject1() currently, tee-supplicant
543 * still has a file descriptor open to the file when it's removed in
544 * ree_fs_new_remove(). In this case the NFS server may create a
545 * temporary reference called .nfs????, and the rmdir() call fails
546 * so that the TA directory is left over. Checking this special case
547 * here avoids that TEE_StartPersistentObjectEnumerator() returns
548 * TEE_SUCCESS when it should return TEEC_ERROR_ITEM_NOT_FOUND.
549 * Test case: "xtest 6009 6010".
550 */
551 while ((dent = readdir(dir))) {
552 if (dent->d_name[0] == '.')
553 continue;
554 empty = false;
555 break;
556 }
557 if (empty) {
558 closedir(dir);
559 return TEEC_ERROR_ITEM_NOT_FOUND;
560 }
561 rewinddir(dir);
562
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200563 handle = handle_get(&dir_handle_db, dir);
564 if (handle < 0) {
565 closedir(dir);
566 return TEEC_ERROR_OUT_OF_MEMORY;
567 }
568
Jens Wiklander342acae2020-04-17 14:29:38 +0200569 params[2].a = handle;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200570 return TEEC_SUCCESS;
571}
572
573static TEEC_Result ree_fs_new_closedir(size_t num_params,
574 struct tee_ioctl_param *params)
575{
Etienne Carriere924a4742019-03-21 09:43:35 +0100576 DIR *dir = NULL;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200577
578 if (num_params != 1 ||
579 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
580 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT)
581 return TEEC_ERROR_BAD_PARAMETERS;
582
Jens Wiklander342acae2020-04-17 14:29:38 +0200583 dir = handle_put(&dir_handle_db, params[0].b);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200584 if (!dir)
585 return TEEC_ERROR_BAD_PARAMETERS;
586
587 closedir(dir);
588
589 return TEEC_SUCCESS;
590}
591
592static TEEC_Result ree_fs_new_readdir(size_t num_params,
593 struct tee_ioctl_param *params)
594{
Etienne Carriere924a4742019-03-21 09:43:35 +0100595 DIR *dir = NULL;
596 struct dirent *dirent = NULL;
597 char *buf = NULL;
598 size_t len = 0;
599 size_t fname_len = 0;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200600
601 if (num_params != 2 ||
602 (params[0].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
603 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT ||
604 (params[1].attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) !=
605 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT)
606 return TEEC_ERROR_BAD_PARAMETERS;
607
608
609 buf = tee_supp_param_to_va(params + 1);
610 if (!buf)
611 return TEEC_ERROR_BAD_PARAMETERS;
Jens Wiklander342acae2020-04-17 14:29:38 +0200612 len = MEMREF_SIZE(params + 1);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200613
Jens Wiklander342acae2020-04-17 14:29:38 +0200614 dir = handle_lookup(&dir_handle_db, params[0].b);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200615 if (!dir)
616 return TEEC_ERROR_BAD_PARAMETERS;
617
618 while (true) {
619 dirent = readdir(dir);
620 if (!dirent)
621 return TEEC_ERROR_ITEM_NOT_FOUND;
622 if (dirent->d_name[0] != '.')
623 break;
624 }
625
626 fname_len = strlen(dirent->d_name) + 1;
Jens Wiklander342acae2020-04-17 14:29:38 +0200627 MEMREF_SIZE(params + 1) = fname_len;
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200628 if (fname_len > len)
629 return TEEC_ERROR_SHORT_BUFFER;
630
631 memcpy(buf, dirent->d_name, fname_len);
632
633 return TEEC_SUCCESS;
634}
635
Jens Wiklander5229afd2016-12-12 12:38:28 +0100636TEEC_Result tee_supp_fs_process(size_t num_params,
637 struct tee_ioctl_param *params)
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200638{
Jens Wiklander5229afd2016-12-12 12:38:28 +0100639 if (!num_params || !tee_supp_param_is_value(params))
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200640 return TEEC_ERROR_BAD_PARAMETERS;
641
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200642 if (tee_fs_fd == -1) {
Victor Chongcb716672019-04-26 16:41:55 +0900643 if (tee_supp_fs_init() != 0) {
Victor Chong83c7bcf2019-05-10 17:40:15 +0900644 EMSG("error tee_supp_fs_init: failed to create %s/",
Pierre Ducroquet0abffbf2025-06-23 12:41:00 +0200645 supplicant_params.fs_parent_path);
646 tee_fs_fd = -1;
Victor Chongcb716672019-04-26 16:41:55 +0900647 return TEEC_ERROR_STORAGE_NOT_AVAILABLE;
648 }
649 }
650
Jens Wiklander342acae2020-04-17 14:29:38 +0200651 switch (params->a) {
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200652 case OPTEE_MRF_OPEN:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100653 return ree_fs_new_open(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200654 case OPTEE_MRF_CREATE:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100655 return ree_fs_new_create(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200656 case OPTEE_MRF_CLOSE:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100657 return ree_fs_new_close(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200658 case OPTEE_MRF_READ:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100659 return ree_fs_new_read(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200660 case OPTEE_MRF_WRITE:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100661 return ree_fs_new_write(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200662 case OPTEE_MRF_TRUNCATE:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100663 return ree_fs_new_truncate(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200664 case OPTEE_MRF_REMOVE:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100665 return ree_fs_new_remove(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200666 case OPTEE_MRF_RENAME:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100667 return ree_fs_new_rename(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200668 case OPTEE_MRF_OPENDIR:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100669 return ree_fs_new_opendir(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200670 case OPTEE_MRF_CLOSEDIR:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100671 return ree_fs_new_closedir(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200672 case OPTEE_MRF_READDIR:
Jens Wiklander5229afd2016-12-12 12:38:28 +0100673 return ree_fs_new_readdir(num_params, params);
Jens Wiklander1472d0e2016-09-09 10:41:15 +0200674 default:
675 return TEEC_ERROR_BAD_PARAMETERS;
676 }
Pascal Brand04ac4652014-06-03 16:12:38 +0200677}