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