1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <lk/compiler.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include <trusty_ipc.h>
22 #include <uapi/err.h>
23
24 #include <interface/storage/storage.h>
25
26 #include "ipc.h"
27 #include "rpmb.h"
28 #include "tipc_ns.h"
29
30 #define SS_ERR(args...) fprintf(stderr, "ss: " args)
31 #define SS_WARN(args...) fprintf(stderr, "ss: " args)
32 #define SS_DBG_IO(args...)
33
translate_error(enum storage_err err)34 static inline int translate_error(enum storage_err err) {
35 switch (err) {
36 case STORAGE_NO_ERROR:
37 return NO_ERROR;
38 case STORAGE_ERR_NOT_VALID:
39 return ERR_NOT_VALID;
40 case STORAGE_ERR_SYNC_FAILURE:
41 return ERR_IO;
42 case STORAGE_ERR_UNIMPLEMENTED:
43 return ERR_NOT_IMPLEMENTED;
44 case STORAGE_ERR_GENERIC:
45 default:
46 return ERR_GENERIC;
47 }
48 }
49
check_response(enum storage_cmd cmd,struct storage_msg * msg,size_t read_len)50 static inline int check_response(enum storage_cmd cmd,
51 struct storage_msg* msg,
52 size_t read_len) {
53 if (read_len < sizeof(*msg)) {
54 SS_ERR("%s: invalid response size %zu\n", __func__, read_len);
55 return ERR_IO;
56 }
57
58 if ((enum storage_cmd)msg->cmd != (cmd | STORAGE_RESP_BIT)) {
59 SS_ERR("%s: invalid response (%d) for cmd (%d)\n", __func__, msg->cmd,
60 cmd);
61 return ERR_IO;
62 }
63
64 return translate_error(msg->result);
65 }
66
rpmb_send(void * handle_,void * reliable_write_buf,size_t reliable_write_size,void * write_buf,size_t write_size,void * read_buf,size_t read_size,bool sync,bool sync_checkpoint)67 int rpmb_send(void* handle_,
68 void* reliable_write_buf,
69 size_t reliable_write_size,
70 void* write_buf,
71 size_t write_size,
72 void* read_buf,
73 size_t read_size,
74 bool sync,
75 bool sync_checkpoint) {
76 SS_DBG_IO(
77 "%s: handle %p, rel_write size %zu, write size %zu, read size %zu\n",
78 __func__, handle_, reliable_write_size, write_size, read_size);
79
80 int rc;
81 handle_t* handlep = handle_;
82 handle_t handle = *handlep;
83
84 struct storage_rpmb_send_req req = {
85 .read_size = read_size,
86 .reliable_write_size = reliable_write_size,
87 .write_size = write_size,
88 };
89
90 struct storage_msg msg = {
91 .cmd = STORAGE_RPMB_SEND,
92 .flags = sync ? (STORAGE_MSG_FLAG_PRE_COMMIT |
93 STORAGE_MSG_FLAG_POST_COMMIT)
94 : 0,
95 .size = sizeof(msg) + sizeof(req) + reliable_write_size +
96 write_size,
97 };
98
99 if (sync_checkpoint) {
100 msg.flags |= STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT;
101 }
102
103 struct iovec rx_iov[] = {
104 {.iov_base = &msg, .iov_len = sizeof(msg)},
105 {.iov_base = read_buf, .iov_len = read_size},
106 };
107
108 struct iovec tx_iov[] = {
109 {.iov_base = &msg, .iov_len = sizeof(msg)},
110 {.iov_base = &req, .iov_len = sizeof(req)},
111 {.iov_base = reliable_write_buf, .iov_len = reliable_write_size},
112 {.iov_base = write_buf, .iov_len = write_size},
113 };
114
115 rc = sync_ipc_send_msg(handle, tx_iov, countof(tx_iov), rx_iov,
116 countof(rx_iov));
117 if (rc < 0) {
118 SS_ERR("%s: rpmb send failed, ipc failure: %d\n", __func__, rc);
119 return rc;
120 }
121
122 size_t bytes_read = (size_t)rc;
123
124 rc = check_response(STORAGE_RPMB_SEND, &msg, bytes_read);
125 if (rc != NO_ERROR) {
126 return rc;
127 }
128
129 if (bytes_read != sizeof(msg) + read_size) {
130 SS_ERR("%s: rpmb send failed, invalid response size (%zu != %zu + %zu)\n",
131 __func__, bytes_read, sizeof(msg), read_size);
132 return ERR_NOT_VALID;
133 }
134
135 return NO_ERROR;
136 }
137
ns_open_file(handle_t ipc_handle,const char * fname,ns_handle_t * handlep,bool create)138 int ns_open_file(handle_t ipc_handle,
139 const char* fname,
140 ns_handle_t* handlep,
141 bool create) {
142 SS_DBG_IO("%s: open %s create: %d\n", __func__, fname, create);
143
144 size_t fname_size = strlen(fname);
145 struct storage_file_open_resp resp;
146
147 struct storage_file_open_req req = {
148 .flags = create ? STORAGE_FILE_OPEN_CREATE : 0,
149 };
150
151 struct storage_msg msg = {
152 .cmd = STORAGE_FILE_OPEN,
153 .size = sizeof(msg) + sizeof(req) + fname_size,
154 };
155
156 struct iovec tx_iov[] = {{.iov_base = &msg, .iov_len = sizeof(msg)},
157 {.iov_base = &req, .iov_len = sizeof(req)},
158 {.iov_base = (char*)fname, .iov_len = fname_size}};
159
160 struct iovec rx_iov[] = {{.iov_base = &msg, .iov_len = sizeof(msg)},
161 {.iov_base = &resp, .iov_len = sizeof(resp)}};
162
163 int rc = sync_ipc_send_msg(ipc_handle, tx_iov, countof(tx_iov), rx_iov,
164 countof(rx_iov));
165 if (rc < 0) {
166 SS_ERR("%s: open failed, %d\n", __func__, rc);
167 return rc;
168 }
169
170 size_t bytes_read = (size_t)rc;
171
172 rc = check_response(STORAGE_FILE_OPEN, &msg, bytes_read);
173 if (rc != NO_ERROR) {
174 return rc;
175 }
176
177 if (bytes_read != sizeof(msg) + sizeof(resp)) {
178 SS_ERR("%s: open failed, invalid response size (%zu != %zu)\n",
179 __func__, bytes_read, sizeof(resp));
180 return ERR_NOT_VALID;
181 }
182
183 *handlep = resp.handle;
184
185 return NO_ERROR;
186 }
187
ns_close_file(handle_t ipc_handle,ns_handle_t handle)188 void ns_close_file(handle_t ipc_handle, ns_handle_t handle) {
189 SS_DBG_IO("close handle: %llu\n", handle);
190 struct storage_file_close_req req = {
191 .handle = handle,
192 };
193
194 struct storage_msg msg = {
195 .cmd = STORAGE_FILE_CLOSE,
196 .size = sizeof(msg) + sizeof(req),
197 };
198
199 struct iovec iov[] = {
200 {.iov_base = &msg, .iov_len = sizeof(msg)},
201 {.iov_base = &req, .iov_len = sizeof(req)},
202 };
203
204 int rc = sync_ipc_send_msg(ipc_handle, iov, countof(iov), iov, 1);
205 if (rc < 0) {
206 SS_ERR("%s: close failed, %d\n", __func__, rc);
207 return;
208 }
209
210 rc = check_response(STORAGE_FILE_CLOSE, &msg, rc);
211 if (rc < 0) {
212 SS_ERR("%s: close failed, %d\n", __func__, rc);
213 }
214 }
215
ns_get_max_size(handle_t ipc_handle,ns_handle_t handle,data_block_t * size)216 int ns_get_max_size(handle_t ipc_handle,
217 ns_handle_t handle,
218 data_block_t* size) {
219 assert(size != NULL);
220
221 SS_DBG_IO("get max size: %llu\n", handle);
222 struct storage_file_get_max_size_req req = {
223 .handle = handle,
224 };
225
226 struct storage_file_get_max_size_resp resp = {0};
227
228 struct storage_msg msg = {
229 .cmd = STORAGE_FILE_GET_MAX_SIZE,
230 .size = sizeof(msg) + sizeof(req),
231 };
232
233 struct iovec tx_iov[] = {
234 {.iov_base = &msg, .iov_len = sizeof(msg)},
235 {.iov_base = &req, .iov_len = sizeof(req)},
236 };
237
238 struct iovec rx_iov[] = {{.iov_base = &msg, .iov_len = sizeof(msg)},
239 {.iov_base = &resp, .iov_len = sizeof(resp)}};
240
241 int rc = sync_ipc_send_msg(ipc_handle, tx_iov, countof(tx_iov), rx_iov,
242 countof(rx_iov));
243 if (rc < 0) {
244 SS_ERR("%s: read failed, %d\n", __func__, rc);
245 return rc;
246 }
247
248 size_t bytes_read = (size_t)rc;
249
250 rc = check_response(STORAGE_FILE_GET_MAX_SIZE, &msg, bytes_read);
251 if (rc != NO_ERROR) {
252 return rc;
253 }
254
255 if (bytes_read != sizeof(msg) + sizeof(resp)) {
256 SS_ERR("%s: get_max_size failed, invalid response size (%zu != %zu)\n",
257 __func__, bytes_read, sizeof(msg) + sizeof(resp));
258 return ERR_NOT_VALID;
259 }
260
261 *size = resp.max_size;
262 return rc;
263 }
264
265 /**
266 * ns_read_pos - Read a block of data from a non-secure file
267 * @ipc_handle: Handle of non-secure connection
268 * @handle: Handle of file to read from
269 * @pos: Offset to start reading at
270 * @data: Pointer to output buffer
271 * @data_size: Number of bytes to attempt to read
272 *
273 * Return value: Number of bytes read, or a negative error code if an error
274 * occurred. Note: zero is a valid number of bytes read to return if @pos is
275 * past the end of the file.
276 */
ns_read_pos(handle_t ipc_handle,ns_handle_t handle,ns_off_t pos,void * data,int data_size)277 int ns_read_pos(handle_t ipc_handle,
278 ns_handle_t handle,
279 ns_off_t pos,
280 void* data,
281 int data_size) {
282 SS_DBG_IO("%s: handle %llu, pos %llu, size %d\n", __func__, handle, pos,
283 data_size);
284
285 struct storage_file_read_req req = {
286 .handle = handle,
287 .offset = pos,
288 .size = data_size,
289 };
290
291 struct storage_msg msg = {
292 .cmd = STORAGE_FILE_READ,
293 .size = sizeof(msg) + sizeof(req),
294 };
295
296 struct iovec tx_iov[] = {
297 {.iov_base = &msg, .iov_len = sizeof(msg)},
298 {.iov_base = &req, .iov_len = sizeof(req)},
299 };
300
301 struct iovec rx_iov[] = {{.iov_base = &msg, .iov_len = sizeof(msg)},
302 {.iov_base = data, .iov_len = data_size}};
303
304 int rc = sync_ipc_send_msg(ipc_handle, tx_iov, countof(tx_iov), rx_iov,
305 countof(rx_iov));
306 if (rc < 0) {
307 SS_ERR("%s: read failed, %d\n", __func__, rc);
308 return rc;
309 }
310
311 size_t data_len = rc;
312 assert(data_len <= sizeof(msg) + data_size);
313
314 rc = check_response(STORAGE_FILE_READ, &msg, data_len);
315 if (rc != NO_ERROR) {
316 return rc;
317 }
318
319 assert(data_len >= sizeof(msg));
320 return data_len - sizeof(msg);
321 }
322
ns_write_pos(handle_t ipc_handle,ns_handle_t handle,ns_off_t pos,const void * data,int data_size,bool is_userdata,bool sync)323 int ns_write_pos(handle_t ipc_handle,
324 ns_handle_t handle,
325 ns_off_t pos,
326 const void* data,
327 int data_size,
328 bool is_userdata,
329 bool sync) {
330 uint32_t flags = 0;
331 SS_DBG_IO("%s: handle %llu, pos %llu, size %d\n", __func__, handle, pos,
332 data_size);
333
334 if (is_userdata) {
335 flags |= STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT;
336 }
337
338 if (sync) {
339 flags |= STORAGE_MSG_FLAG_PRE_COMMIT | STORAGE_MSG_FLAG_POST_COMMIT;
340 }
341
342 struct storage_file_write_req req = {
343 .handle = handle,
344 .offset = pos,
345 };
346
347 struct storage_msg msg = {
348 .cmd = STORAGE_FILE_WRITE,
349 .flags = flags,
350 .size = sizeof(msg) + sizeof(req) + data_size,
351 };
352
353 struct iovec iov[] = {{.iov_base = &msg, .iov_len = sizeof(msg)},
354 {.iov_base = &req, .iov_len = sizeof(req)},
355 {.iov_base = (void*)data, .iov_len = data_size}};
356
357 int rc = sync_ipc_send_msg(ipc_handle, iov, countof(iov), iov, 1);
358 if (rc < 0) {
359 SS_ERR("%s: write failed, %d\n", __func__, rc);
360 return rc;
361 }
362
363 rc = check_response(STORAGE_FILE_WRITE, &msg, rc);
364 if (rc != NO_ERROR) {
365 return rc;
366 }
367
368 return data_size;
369 }
370