xref: /optee_os/core/tee/tee_fs_rpc.c (revision c84eee6397bb8ae0745d9aa24b5228a58793378b)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <kernel/tee_misc.h>
8 #include <kernel/thread.h>
9 #include <mm/core_memprot.h>
10 #include <optee_rpc_cmd.h>
11 #include <stdlib.h>
12 #include <string_ext.h>
13 #include <string.h>
14 #include <tee/tee_fs.h>
15 #include <tee/tee_fs_rpc.h>
16 #include <tee/tee_pobj.h>
17 #include <tee/tee_svc_storage.h>
18 #include <trace.h>
19 #include <util.h>
20 
21 struct tee_fs_dir {
22 	int nw_dir;
23 	struct tee_fs_dirent d;
24 };
25 
26 static TEE_Result operation_commit(struct tee_fs_rpc_operation *op)
27 {
28 	return thread_rpc_cmd(op->id, op->num_params, op->params);
29 }
30 
31 static TEE_Result operation_open(uint32_t id, unsigned int cmd,
32 				 struct tee_pobj *po, int *fd)
33 {
34 	struct mobj *mobj;
35 	TEE_Result res;
36 	void *va;
37 
38 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
39 					THREAD_SHM_TYPE_APPLICATION,
40 					TEE_FS_NAME_MAX, &mobj);
41 	if (!va)
42 		return TEE_ERROR_OUT_OF_MEMORY;
43 
44 	res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX,
45 					      po, po->temporary);
46 	if (res != TEE_SUCCESS)
47 		return res;
48 
49 	struct tee_fs_rpc_operation op = {
50 		.id = id, .num_params = 3, .params = {
51 			[0] = THREAD_PARAM_VALUE(IN, cmd, 0, 0),
52 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
53 			[2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0),
54 	} };
55 
56 	res = operation_commit(&op);
57 	if (res == TEE_SUCCESS)
58 		*fd = op.params[2].u.value.a;
59 
60 	return res;
61 }
62 
63 TEE_Result tee_fs_rpc_open(uint32_t id, struct tee_pobj *po, int *fd)
64 {
65 	return operation_open(id, OPTEE_RPC_FS_OPEN, po, fd);
66 }
67 
68 TEE_Result tee_fs_rpc_create(uint32_t id, struct tee_pobj *po, int *fd)
69 {
70 	return operation_open(id, OPTEE_RPC_FS_CREATE, po, fd);
71 }
72 
73 static TEE_Result operation_open_dfh(uint32_t id, unsigned int cmd,
74 				 const struct tee_fs_dirfile_fileh *dfh,
75 				 int *fd)
76 {
77 	struct mobj *mobj;
78 	TEE_Result res;
79 	void *va;
80 
81 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
82 					THREAD_SHM_TYPE_APPLICATION,
83 					TEE_FS_NAME_MAX, &mobj);
84 	if (!va)
85 		return TEE_ERROR_OUT_OF_MEMORY;
86 
87 	res = tee_svc_storage_create_filename_dfh(va, TEE_FS_NAME_MAX, dfh);
88 	if (res != TEE_SUCCESS)
89 		return res;
90 
91 	struct tee_fs_rpc_operation op = {
92 		.id = id, .num_params = 3, .params = {
93 			[0] = THREAD_PARAM_VALUE(IN, cmd, 0, 0),
94 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
95 			[2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0),
96 	} };
97 
98 	res = operation_commit(&op);
99 	if (res == TEE_SUCCESS)
100 		*fd = op.params[2].u.value.a;
101 
102 	return res;
103 }
104 
105 
106 
107 TEE_Result tee_fs_rpc_open_dfh(uint32_t id,
108 			       const struct tee_fs_dirfile_fileh *dfh, int *fd)
109 {
110 	return operation_open_dfh(id, OPTEE_RPC_FS_OPEN, dfh, fd);
111 }
112 
113 TEE_Result tee_fs_rpc_create_dfh(uint32_t id,
114 				 const struct tee_fs_dirfile_fileh *dfh,
115 				 int *fd)
116 {
117 	return operation_open_dfh(id, OPTEE_RPC_FS_CREATE, dfh, fd);
118 }
119 
120 TEE_Result tee_fs_rpc_close(uint32_t id, int fd)
121 {
122 	struct tee_fs_rpc_operation op = {
123 		.id = id, .num_params = 1, .params = {
124 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_CLOSE, fd, 0),
125 		},
126 	};
127 
128 	return operation_commit(&op);
129 }
130 
131 TEE_Result tee_fs_rpc_read_init(struct tee_fs_rpc_operation *op,
132 				uint32_t id, int fd, tee_fs_off_t offset,
133 				size_t data_len, void **out_data)
134 {
135 	struct mobj *mobj;
136 	uint8_t *va;
137 
138 	if (offset < 0)
139 		return TEE_ERROR_BAD_PARAMETERS;
140 
141 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
142 					THREAD_SHM_TYPE_APPLICATION,
143 					data_len, &mobj);
144 	if (!va)
145 		return TEE_ERROR_OUT_OF_MEMORY;
146 
147 	*op = (struct tee_fs_rpc_operation){
148 		.id = id, .num_params = 2, .params = {
149 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READ, fd,
150 						 offset),
151 			[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, data_len),
152 		},
153 	};
154 
155 	*out_data = va;
156 
157 	return TEE_SUCCESS;
158 }
159 
160 TEE_Result tee_fs_rpc_read_final(struct tee_fs_rpc_operation *op,
161 				 size_t *data_len)
162 {
163 	TEE_Result res = operation_commit(op);
164 
165 	if (res == TEE_SUCCESS)
166 		*data_len = op->params[1].u.memref.size;
167 	return res;
168 }
169 
170 TEE_Result tee_fs_rpc_write_init(struct tee_fs_rpc_operation *op,
171 				 uint32_t id, int fd, tee_fs_off_t offset,
172 				 size_t data_len, void **data)
173 {
174 	struct mobj *mobj;
175 	uint8_t *va;
176 
177 	if (offset < 0)
178 		return TEE_ERROR_BAD_PARAMETERS;
179 
180 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
181 					THREAD_SHM_TYPE_APPLICATION,
182 					data_len, &mobj);
183 	if (!va)
184 		return TEE_ERROR_OUT_OF_MEMORY;
185 
186 	*op = (struct tee_fs_rpc_operation){
187 		.id = id, .num_params = 2, .params = {
188 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_WRITE, fd,
189 						 offset),
190 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, data_len),
191 		},
192 	};
193 
194 	*data = va;
195 
196 	return TEE_SUCCESS;
197 }
198 
199 TEE_Result tee_fs_rpc_write_final(struct tee_fs_rpc_operation *op)
200 {
201 	return operation_commit(op);
202 }
203 
204 TEE_Result tee_fs_rpc_truncate(uint32_t id, int fd, size_t len)
205 {
206 	struct tee_fs_rpc_operation op = {
207 		.id = id, .num_params = 1, .params = {
208 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_TRUNCATE, fd,
209 						 len),
210 		}
211 	};
212 
213 	return operation_commit(&op);
214 }
215 
216 TEE_Result tee_fs_rpc_remove(uint32_t id, struct tee_pobj *po)
217 {
218 	TEE_Result res;
219 	struct mobj *mobj;
220 	void *va;
221 
222 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
223 					THREAD_SHM_TYPE_APPLICATION,
224 					TEE_FS_NAME_MAX, &mobj);
225 	if (!va)
226 		return TEE_ERROR_OUT_OF_MEMORY;
227 
228 	res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX,
229 					      po, po->temporary);
230 	if (res != TEE_SUCCESS)
231 		return res;
232 
233 	struct tee_fs_rpc_operation op = {
234 		.id = id, .num_params = 2, .params = {
235 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_REMOVE, 0, 0),
236 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
237 		},
238 	};
239 
240 	return operation_commit(&op);
241 }
242 
243 TEE_Result tee_fs_rpc_remove_dfh(uint32_t id,
244 				 const struct tee_fs_dirfile_fileh *dfh)
245 {
246 	TEE_Result res;
247 	struct mobj *mobj;
248 	void *va;
249 
250 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
251 					THREAD_SHM_TYPE_APPLICATION,
252 					TEE_FS_NAME_MAX, &mobj);
253 	if (!va)
254 		return TEE_ERROR_OUT_OF_MEMORY;
255 
256 
257 	res = tee_svc_storage_create_filename_dfh(va, TEE_FS_NAME_MAX, dfh);
258 	if (res != TEE_SUCCESS)
259 		return res;
260 
261 	struct tee_fs_rpc_operation op = {
262 		.id = id, .num_params = 2, .params = {
263 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_REMOVE, 0, 0),
264 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
265 		}
266 	};
267 
268 	return operation_commit(&op);
269 }
270 
271 TEE_Result tee_fs_rpc_rename(uint32_t id, struct tee_pobj *old,
272 			     struct tee_pobj *new, bool overwrite)
273 {
274 	TEE_Result res;
275 	struct mobj *mobj;
276 	char *va;
277 	bool temp;
278 
279 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
280 					THREAD_SHM_TYPE_APPLICATION,
281 					TEE_FS_NAME_MAX * 2, &mobj);
282 	if (!va)
283 		return TEE_ERROR_OUT_OF_MEMORY;
284 
285 
286 	if (new)
287 		temp = old->temporary;
288 	else
289 		temp = true;
290 	res = tee_svc_storage_create_filename(va, TEE_FS_NAME_MAX,
291 					      old, temp);
292 	if (res != TEE_SUCCESS)
293 		return res;
294 
295 	if (new) {
296 		res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX,
297 						      TEE_FS_NAME_MAX,
298 						      new, new->temporary);
299 	} else {
300 		res = tee_svc_storage_create_filename(va + TEE_FS_NAME_MAX,
301 						      TEE_FS_NAME_MAX,
302 						      old, false);
303 	}
304 	if (res != TEE_SUCCESS)
305 		return res;
306 
307 	struct tee_fs_rpc_operation op = {
308 		.id = id, .num_params = 3, .params = {
309 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_RENAME,
310 						 overwrite, 0),
311 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
312 			[2] = THREAD_PARAM_MEMREF(IN, mobj, TEE_FS_NAME_MAX,
313 						  TEE_FS_NAME_MAX),
314 		}
315 	};
316 
317 	return operation_commit(&op);
318 }
319 
320 TEE_Result tee_fs_rpc_opendir(uint32_t id, const TEE_UUID *uuid,
321 			      struct tee_fs_dir **d)
322 {
323 	TEE_Result res;
324 	struct mobj *mobj;
325 	void *va;
326 	struct tee_fs_dir *dir = calloc(1, sizeof(*dir));
327 
328 	if (!dir)
329 		return TEE_ERROR_OUT_OF_MEMORY;
330 
331 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
332 					THREAD_SHM_TYPE_APPLICATION,
333 					TEE_FS_NAME_MAX, &mobj);
334 	if (!va) {
335 		res = TEE_ERROR_OUT_OF_MEMORY;
336 		goto err_exit;
337 	}
338 
339 
340 	res = tee_svc_storage_create_dirname(va, TEE_FS_NAME_MAX, uuid);
341 	if (res != TEE_SUCCESS)
342 		goto err_exit;
343 
344 	struct tee_fs_rpc_operation op = {
345 		.id = id, .num_params = 3, .params = {
346 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_OPENDIR,
347 						 0, 0),
348 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
349 			[2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0),
350 		}
351 	};
352 
353 	res = operation_commit(&op);
354 
355 	if (res != TEE_SUCCESS)
356 		goto err_exit;
357 
358 	dir->nw_dir = op.params[2].u.value.a;
359 	*d = dir;
360 
361 	return TEE_SUCCESS;
362 err_exit:
363 	free(dir);
364 
365 	return res;
366 }
367 
368 TEE_Result tee_fs_rpc_closedir(uint32_t id, struct tee_fs_dir *d)
369 {
370 	struct tee_fs_rpc_operation op = {
371 		.id = id, .num_params = 1, .params = {
372 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_CLOSEDIR,
373 						 d->nw_dir, 0),
374 		}
375 	};
376 
377 	free(d);
378 	return operation_commit(&op);
379 }
380 
381 TEE_Result tee_fs_rpc_readdir(uint32_t id, struct tee_fs_dir *d,
382 			      struct tee_fs_dirent **ent)
383 {
384 	TEE_Result res;
385 	struct mobj *mobj;
386 	void *va;
387 	const size_t max_name_len = TEE_FS_NAME_MAX + 1;
388 
389 	if (!d)
390 		return TEE_ERROR_ITEM_NOT_FOUND;
391 
392 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
393 					THREAD_SHM_TYPE_APPLICATION,
394 					max_name_len, &mobj);
395 	if (!va)
396 		return TEE_ERROR_OUT_OF_MEMORY;
397 
398 	struct tee_fs_rpc_operation op = {
399 		.id = id, .num_params = 2, .params = {
400 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READDIR,
401 						 d->nw_dir, 0),
402 			[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, max_name_len),
403 		}
404 	};
405 
406 	res = operation_commit(&op);
407 	if (res != TEE_SUCCESS)
408 		return res;
409 
410 	d->d.oidlen = tee_hs2b(va, d->d.oid, strnlen(va, max_name_len),
411 			       sizeof(d->d.oid));
412 	if (!d->d.oidlen)
413 		return TEE_ERROR_OUT_OF_MEMORY;
414 
415 	*ent = &d->d;
416 	return TEE_SUCCESS;
417 }
418