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