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