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