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