1 /*
2 * Copyright (C) 2021 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 "storageproxy_shim.h"
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <interface/storage/storage.h>
22 #include <limits.h>
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <trusty_log.h>
30 #include <uapi/err.h>
31 #include <unistd.h>
32
33 #include "block_device_tipc.h"
34 #include "rpmb.h"
35 #include "rpmb_dev/rpmb_dev.h"
36
37 #define TLOG_TAG "ss-test"
38
39 #define DATA_DIRECTORY "rpmb_host_test_data"
40 #define PERSIST_DIRECTORY "persist"
41 #define RPMB_FILENAME "RPMB_DATA"
42 #define HOST_TEST_RPMB_SIZE 1024
43
44 static char data_directory[PATH_MAX];
45 static struct rpmb_dev_state rpmb_state = {
46 .data_fd = -1,
47 };
48
49 /* If >0 silently ignore writes to NS backing data files. */
50 static int ignore_next_ns_write_count = 0;
ignore_next_ns_writes(int count)51 void ignore_next_ns_writes(int count) {
52 ignore_next_ns_write_count = count;
53 }
54
init_rpmb_state(const char * base_directory)55 bool init_rpmb_state(const char* base_directory) {
56 int rc;
57 bool res = false;
58 rc = snprintf(data_directory, PATH_MAX - 1, "%s/%s", base_directory,
59 DATA_DIRECTORY);
60 if (rc < 0) {
61 goto err_mkdir;
62 }
63 data_directory[PATH_MAX - 1] = '\0';
64 rc = mkdir(data_directory, S_IWUSR | S_IRUSR | S_IXUSR);
65 if (rc < 0) {
66 if (errno != EEXIST) {
67 goto err_mkdir;
68 }
69 }
70
71 #if HAS_FS_TDP
72 char* tdp_directory =
73 malloc(strlen(data_directory) + sizeof(PERSIST_DIRECTORY) + 2);
74 if (!tdp_directory) {
75 goto err_alloc_tdp;
76 }
77 rc = sprintf(tdp_directory, "%s/%s", data_directory, PERSIST_DIRECTORY);
78 if (rc < 0) {
79 goto err_tdp_dirname;
80 }
81 rc = mkdir(tdp_directory, S_IWUSR | S_IRUSR | S_IXUSR);
82 if (rc < 0) {
83 if (errno != EEXIST) {
84 goto err_tdp_mkdir;
85 }
86 }
87 #endif
88
89 char* rpmb_filename =
90 malloc(strlen(data_directory) + sizeof(RPMB_FILENAME) + 2);
91 if (!rpmb_filename) {
92 goto err_alloc_rpmb;
93 }
94 rc = sprintf(rpmb_filename, "%s/%s", data_directory, RPMB_FILENAME);
95 if (rc < 0) {
96 goto err_rpmb_filename;
97 }
98 rpmb_state.data_fd =
99 open(rpmb_filename, O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR);
100 if (rpmb_state.data_fd < 0) {
101 fprintf(stderr, "storageproxy_shim: Could not open backing file\n");
102 goto err_open_rpmb;
103 }
104
105 /* Create new rpmb data file */
106 if (rpmb_state.header.max_block == 0) {
107 rpmb_state.header.max_block = HOST_TEST_RPMB_SIZE - 1;
108 }
109 rc = write(rpmb_state.data_fd, &rpmb_state.header,
110 sizeof(rpmb_state.header));
111 if (rc != sizeof(rpmb_state.header)) {
112 fprintf(stderr,
113 "storageproxy_shim: Failed to write rpmb data file: %d, %s\n",
114 rc, strerror(errno));
115 goto err_write_rpmb;
116 }
117
118 res = true;
119
120 err_write_rpmb:
121 err_open_rpmb:
122 err_rpmb_filename:
123 free(rpmb_filename);
124 err_alloc_rpmb:
125 #if HAS_FS_TDP
126 err_tdp_mkdir:
127 err_tdp_dirname:
128 free(tdp_directory);
129 err_alloc_tdp:
130 #endif
131 err_mkdir:
132 return res;
133 }
134
destroy_rpmb_state()135 void destroy_rpmb_state() {
136 if (rpmb_state.data_fd >= 0) {
137 close(rpmb_state.data_fd);
138 rpmb_state.data_fd = -1;
139 }
140 }
141
fail_next_rpmb_writes(int count,bool commit_writes)142 void fail_next_rpmb_writes(int count, bool commit_writes) {
143 rpmb_state.fail_next_writes = count;
144 rpmb_state.commit_failed_writes = commit_writes;
145 }
146
fail_next_rpmb_reads(int count)147 void fail_next_rpmb_reads(int count) {
148 rpmb_state.fail_next_reads = count;
149 }
150
fail_next_rpmb_get_counters(int count)151 void fail_next_rpmb_get_counters(int count) {
152 rpmb_state.fail_next_get_counters = count;
153 }
154
rpmb_send(void * mmc_handle,void * reliable_write_buf,size_t reliable_write_size,void * write_buf,size_t write_buf_size,void * read_buf,size_t read_buf_size,bool sync,bool sync_checkpoint)155 int rpmb_send(void* mmc_handle,
156 void* reliable_write_buf,
157 size_t reliable_write_size,
158 void* write_buf,
159 size_t write_buf_size,
160 void* read_buf,
161 size_t read_buf_size,
162 bool sync,
163 bool sync_checkpoint) {
164 rpmb_state.res_count = read_buf_size / sizeof(struct rpmb_packet);
165 assert(rpmb_state.res_count <= MAX_PACKET_COUNT);
166 rpmb_state.cmd_count =
167 (reliable_write_size + write_buf_size) / sizeof(struct rpmb_packet);
168 assert(rpmb_state.cmd_count <= MAX_PACKET_COUNT);
169
170 size_t cmd_index = reliable_write_size / sizeof(struct rpmb_packet);
171 memcpy(&rpmb_state.cmd[0], reliable_write_buf, reliable_write_size);
172 memcpy(&rpmb_state.cmd[cmd_index], write_buf, write_buf_size);
173
174 rpmb_dev_process_cmd(&rpmb_state);
175
176 memcpy(read_buf, rpmb_state.res, read_buf_size);
177 return NO_ERROR;
178 }
179
ns_open_file(handle_t ipc_handle,const char * fname,ns_handle_t * handlep,bool create)180 int ns_open_file(handle_t ipc_handle,
181 const char* fname,
182 ns_handle_t* handlep,
183 bool create) {
184 int rc;
185 char* path = malloc(strlen(data_directory) + strlen(fname) + 2);
186 if (!path) {
187 rc = ERR_NO_MEMORY;
188 goto err;
189 }
190 rc = sprintf(path, "%s/%s", data_directory, fname);
191 if (rc < 0) {
192 TLOGE("%s: asprintf failed\n", __func__);
193 rc = ERR_GENERIC;
194 goto err;
195 }
196
197 int flags = O_RDWR;
198 rc = open(path, flags, S_IWUSR | S_IRUSR);
199 if (create && rc == -1 && errno == ENOENT) {
200 flags |= O_CREAT;
201 rc = open(path, flags, S_IWUSR | S_IRUSR);
202 }
203 if (rc < 0) {
204 fprintf(stderr, "shim %s: open of file %s failed: %s\n", __func__, path,
205 strerror(errno));
206 goto err;
207 }
208 *handlep = rc;
209 rc = 0;
210
211 err:
212 if (path) {
213 free(path);
214 }
215 return rc;
216 }
217
ns_close_file(handle_t ipc_handle,ns_handle_t handle)218 void ns_close_file(handle_t ipc_handle, ns_handle_t handle) {
219 int fd = handle;
220 close(fd);
221 }
222
223 /* Helpers from storageproxyd */
write_with_retry(int fd,const void * buf_,size_t size,off_t offset)224 static ssize_t write_with_retry(int fd,
225 const void* buf_,
226 size_t size,
227 off_t offset) {
228 ssize_t rc;
229 const uint8_t* buf = buf_;
230
231 while (size > 0) {
232 rc = pwrite(fd, buf, size, offset);
233 if (rc < 0)
234 return rc;
235 size -= rc;
236 buf += rc;
237 offset += rc;
238 }
239 return 0;
240 }
241
read_with_retry(int fd,void * buf_,size_t size,off_t offset)242 static ssize_t read_with_retry(int fd, void* buf_, size_t size, off_t offset) {
243 ssize_t rc;
244 size_t rcnt = 0;
245 uint8_t* buf = buf_;
246
247 while (size > 0) {
248 rc = pread(fd, buf, size, offset);
249 if (rc < 0)
250 return rc;
251 if (rc == 0)
252 break;
253 size -= rc;
254 buf += rc;
255 offset += rc;
256 rcnt += rc;
257 }
258 return rcnt;
259 }
260
translate_errno(int error)261 static enum storage_err translate_errno(int error) {
262 enum storage_err result;
263 switch (error) {
264 case 0:
265 result = NO_ERROR;
266 break;
267 case EBADF:
268 case EINVAL:
269 case ENOTDIR:
270 case EISDIR:
271 case ENAMETOOLONG:
272 result = ERR_NOT_VALID;
273 break;
274 default:
275 result = ERR_GENERIC;
276 break;
277 }
278
279 return result;
280 }
281
ns_get_max_size(handle_t ipc_handle,ns_handle_t handle,data_block_t * size)282 int ns_get_max_size(handle_t ipc_handle,
283 ns_handle_t handle,
284 data_block_t* size) {
285 assert(size != NULL);
286 *size = 0x10000000000;
287 return 0;
288 }
289
ns_read_pos(handle_t ipc_handle,ns_handle_t handle,ns_off_t pos,void * data,int data_size)290 int ns_read_pos(handle_t ipc_handle,
291 ns_handle_t handle,
292 ns_off_t pos,
293 void* data,
294 int data_size) {
295 if (read_with_retry(handle, data, data_size, pos) != data_size) {
296 fprintf(stderr, "shim %s: read failed: %s\n", __func__,
297 strerror(errno));
298 return translate_errno(errno);
299 }
300 return data_size;
301 }
302
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)303 int ns_write_pos(handle_t ipc_handle,
304 ns_handle_t handle,
305 ns_off_t pos,
306 const void* data,
307 int data_size,
308 bool is_userdata,
309 bool sync) {
310 if (ignore_next_ns_write_count > 0) {
311 if (ignore_next_ns_write_count != INT_MAX) {
312 ignore_next_ns_write_count--;
313 }
314 return data_size;
315 }
316 if (write_with_retry(handle, data, data_size, pos)) {
317 fprintf(stderr, "shim %s: write failed: %s\n", __func__,
318 strerror(errno));
319 return translate_errno(errno);
320 }
321 return data_size;
322 }
323