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