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 <tee/fs_dirfile.h>
13 #include <tee/tee_fs.h>
14 #include <tee/tee_fs_rpc.h>
15 #include <trace.h>
16 #include <util.h>
17 
18 struct tee_fs_dir {
19 	int nw_dir;
20 	struct tee_fs_dirent d;
21 };
22 
23 /* "/dirf.db" or "/<file number>" */
create_filename(void * buf,size_t blen,const struct tee_fs_dirfile_fileh * dfh)24 static TEE_Result create_filename(void *buf, size_t blen,
25 				  const struct tee_fs_dirfile_fileh *dfh)
26 {
27 	char *file = buf;
28 	size_t pos = 0;
29 	size_t l;
30 
31 	if (pos >= blen)
32 		return TEE_ERROR_SHORT_BUFFER;
33 
34 	file[pos] = '/';
35 	pos++;
36 	if (pos >= blen)
37 		return TEE_ERROR_SHORT_BUFFER;
38 
39 	l = blen - pos;
40 	return tee_fs_dirfile_fileh_to_fname(dfh, file + pos, &l);
41 }
42 
operation_commit(struct tee_fs_rpc_operation * op)43 static TEE_Result operation_commit(struct tee_fs_rpc_operation *op)
44 {
45 	return thread_rpc_cmd(op->id, op->num_params, op->params);
46 }
47 
operation_open_dfh(uint32_t id,unsigned int cmd,const struct tee_fs_dirfile_fileh * dfh,int * fd)48 static TEE_Result operation_open_dfh(uint32_t id, unsigned int cmd,
49 				 const struct tee_fs_dirfile_fileh *dfh,
50 				 int *fd)
51 {
52 	struct tee_fs_rpc_operation op = { };
53 	struct mobj *mobj = NULL;
54 	TEE_Result res = TEE_SUCCESS;
55 	void *va = NULL;
56 
57 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
58 					THREAD_SHM_TYPE_APPLICATION,
59 					TEE_FS_NAME_MAX, &mobj);
60 	if (!va)
61 		return TEE_ERROR_OUT_OF_MEMORY;
62 
63 	res = create_filename(va, TEE_FS_NAME_MAX, dfh);
64 	if (res != TEE_SUCCESS)
65 		return res;
66 
67 	op = (struct tee_fs_rpc_operation){
68 		.id = id, .num_params = 3, .params = {
69 			[0] = THREAD_PARAM_VALUE(IN, cmd, 0, 0),
70 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
71 			[2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0),
72 	} };
73 
74 	res = operation_commit(&op);
75 	if (res == TEE_SUCCESS)
76 		*fd = op.params[2].u.value.a;
77 
78 	return res;
79 }
80 
81 
82 
tee_fs_rpc_open_dfh(uint32_t id,const struct tee_fs_dirfile_fileh * dfh,int * fd)83 TEE_Result tee_fs_rpc_open_dfh(uint32_t id,
84 			       const struct tee_fs_dirfile_fileh *dfh, int *fd)
85 {
86 	return operation_open_dfh(id, OPTEE_RPC_FS_OPEN, dfh, fd);
87 }
88 
tee_fs_rpc_create_dfh(uint32_t id,const struct tee_fs_dirfile_fileh * dfh,int * fd)89 TEE_Result tee_fs_rpc_create_dfh(uint32_t id,
90 				 const struct tee_fs_dirfile_fileh *dfh,
91 				 int *fd)
92 {
93 	return operation_open_dfh(id, OPTEE_RPC_FS_CREATE, dfh, fd);
94 }
95 
tee_fs_rpc_close(uint32_t id,int fd)96 TEE_Result tee_fs_rpc_close(uint32_t id, int fd)
97 {
98 	struct tee_fs_rpc_operation op = {
99 		.id = id, .num_params = 1, .params = {
100 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_CLOSE, fd, 0),
101 		},
102 	};
103 
104 	return operation_commit(&op);
105 }
106 
tee_fs_rpc_read_init(struct tee_fs_rpc_operation * op,uint32_t id,int fd,tee_fs_off_t offset,size_t data_len,void ** out_data)107 TEE_Result tee_fs_rpc_read_init(struct tee_fs_rpc_operation *op,
108 				uint32_t id, int fd, tee_fs_off_t offset,
109 				size_t data_len, void **out_data)
110 {
111 	struct mobj *mobj;
112 	uint8_t *va;
113 
114 	if (offset < 0)
115 		return TEE_ERROR_BAD_PARAMETERS;
116 
117 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
118 					THREAD_SHM_TYPE_APPLICATION,
119 					data_len, &mobj);
120 	if (!va)
121 		return TEE_ERROR_OUT_OF_MEMORY;
122 
123 	*op = (struct tee_fs_rpc_operation){
124 		.id = id, .num_params = 2, .params = {
125 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READ, fd,
126 						 offset),
127 			[1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, data_len),
128 		},
129 	};
130 
131 	*out_data = va;
132 
133 	return TEE_SUCCESS;
134 }
135 
tee_fs_rpc_read_final(struct tee_fs_rpc_operation * op,size_t * data_len)136 TEE_Result tee_fs_rpc_read_final(struct tee_fs_rpc_operation *op,
137 				 size_t *data_len)
138 {
139 	TEE_Result res = operation_commit(op);
140 
141 	if (res == TEE_SUCCESS)
142 		*data_len = op->params[1].u.memref.size;
143 	return res;
144 }
145 
tee_fs_rpc_write_init(struct tee_fs_rpc_operation * op,uint32_t id,int fd,tee_fs_off_t offset,size_t data_len,void ** data)146 TEE_Result tee_fs_rpc_write_init(struct tee_fs_rpc_operation *op,
147 				 uint32_t id, int fd, tee_fs_off_t offset,
148 				 size_t data_len, void **data)
149 {
150 	struct mobj *mobj;
151 	uint8_t *va;
152 
153 	if (offset < 0)
154 		return TEE_ERROR_BAD_PARAMETERS;
155 
156 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
157 					THREAD_SHM_TYPE_APPLICATION,
158 					data_len, &mobj);
159 	if (!va)
160 		return TEE_ERROR_OUT_OF_MEMORY;
161 
162 	*op = (struct tee_fs_rpc_operation){
163 		.id = id, .num_params = 2, .params = {
164 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_WRITE, fd,
165 						 offset),
166 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, data_len),
167 		},
168 	};
169 
170 	*data = va;
171 
172 	return TEE_SUCCESS;
173 }
174 
tee_fs_rpc_write_final(struct tee_fs_rpc_operation * op)175 TEE_Result tee_fs_rpc_write_final(struct tee_fs_rpc_operation *op)
176 {
177 	return operation_commit(op);
178 }
179 
tee_fs_rpc_truncate(uint32_t id,int fd,size_t len)180 TEE_Result tee_fs_rpc_truncate(uint32_t id, int fd, size_t len)
181 {
182 	struct tee_fs_rpc_operation op = {
183 		.id = id, .num_params = 1, .params = {
184 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_TRUNCATE, fd,
185 						 len),
186 		}
187 	};
188 
189 	return operation_commit(&op);
190 }
191 
tee_fs_rpc_remove_dfh(uint32_t id,const struct tee_fs_dirfile_fileh * dfh)192 TEE_Result tee_fs_rpc_remove_dfh(uint32_t id,
193 				 const struct tee_fs_dirfile_fileh *dfh)
194 {
195 	struct tee_fs_rpc_operation op = { };
196 	TEE_Result res = TEE_SUCCESS;
197 	struct mobj *mobj = NULL;
198 	void *va = NULL;
199 
200 	va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS,
201 					THREAD_SHM_TYPE_APPLICATION,
202 					TEE_FS_NAME_MAX, &mobj);
203 	if (!va)
204 		return TEE_ERROR_OUT_OF_MEMORY;
205 
206 
207 	res = create_filename(va, TEE_FS_NAME_MAX, dfh);
208 	if (res != TEE_SUCCESS)
209 		return res;
210 
211 	op = (struct tee_fs_rpc_operation){
212 		.id = id, .num_params = 2, .params = {
213 			[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_REMOVE, 0, 0),
214 			[1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX),
215 		}
216 	};
217 
218 	return operation_commit(&op);
219 }
220