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