1 /*
2 * Copyright (C) 2016 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 #include <errno.h>
17 #include <getopt.h>
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/capability.h>
23 #include <sys/prctl.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 #include <cutils/android_filesystem_config.h>
28
29 #include "checkpoint_handling.h"
30 #include "ipc.h"
31 #include "log.h"
32 #include "rpmb.h"
33 #include "storage.h"
34
35 #define REQ_BUFFER_SIZE 4096
36 static uint8_t req_buffer[REQ_BUFFER_SIZE + 1];
37
38 static const char* ss_data_root;
39 static const char* trusty_devname;
40 static const char* rpmb_devname;
41 static const char* ss_srv_name = STORAGE_DISK_PROXY_PORT;
42
43 static enum dev_type dev_type = MMC_RPMB;
44
parse_dev_type(const char * dev_type_name)45 static enum dev_type parse_dev_type(const char* dev_type_name) {
46 if (!strcmp(dev_type_name, "mmc")) {
47 return MMC_RPMB;
48 } else if (!strcmp(dev_type_name, "virt")) {
49 return VIRT_RPMB;
50 } else if (!strcmp(dev_type_name, "sock")) {
51 return SOCK_RPMB;
52 } else if (!strcmp(dev_type_name, "ufs")) {
53 return UFS_RPMB;
54 } else {
55 return UNKNOWN_RPMB;
56 }
57 }
58
59 static const char* _sopts = "hp:d:r:t:";
60 static const struct option _lopts[] = {{"help", no_argument, NULL, 'h'},
61 {"trusty_dev", required_argument, NULL, 'd'},
62 {"data_path", required_argument, NULL, 'p'},
63 {"rpmb_dev", required_argument, NULL, 'r'},
64 {"dev_type", required_argument, NULL, 't'},
65 {0, 0, 0, 0}};
66
show_usage_and_exit(int code)67 static void show_usage_and_exit(int code) {
68 ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type>\n");
69 ALOGE("Available dev types: mmc, virt\n");
70 exit(code);
71 }
72
drop_privs(void)73 static int drop_privs(void) {
74 struct __user_cap_header_struct capheader;
75 struct __user_cap_data_struct capdata[2];
76
77 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
78 return -1;
79 }
80
81 /*
82 * ensure we're running as the system user
83 */
84 if (setgid(AID_SYSTEM) != 0) {
85 return -1;
86 }
87
88 if (setuid(AID_SYSTEM) != 0) {
89 return -1;
90 }
91
92 /*
93 * drop all capabilities except SYS_RAWIO
94 */
95 memset(&capheader, 0, sizeof(capheader));
96 memset(&capdata, 0, sizeof(capdata));
97 capheader.version = _LINUX_CAPABILITY_VERSION_3;
98 capheader.pid = 0;
99
100 capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted = CAP_TO_MASK(CAP_SYS_RAWIO);
101 capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective = CAP_TO_MASK(CAP_SYS_RAWIO);
102
103 if (capset(&capheader, &capdata[0]) < 0) {
104 return -1;
105 }
106
107 /*
108 * No access for group and other. We need execute access for user to create
109 * an accessible directory.
110 */
111 umask(S_IRWXG | S_IRWXO);
112
113 return 0;
114 }
115
handle_req(struct storage_msg * msg,const void * req,size_t req_len)116 static int handle_req(struct storage_msg* msg, const void* req, size_t req_len) {
117 int rc;
118
119 if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) && msg->cmd != STORAGE_RPMB_SEND &&
120 msg->cmd != STORAGE_FILE_WRITE) {
121 /*
122 * handling post commit messages on commands other than rpmb and write
123 * operations are not implemented as there is no use case for this yet.
124 */
125 ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
126 msg->result = STORAGE_ERR_UNIMPLEMENTED;
127 return ipc_respond(msg, NULL, 0);
128 }
129
130 if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
131 rc = storage_sync_checkpoint();
132 if (rc < 0) {
133 msg->result = STORAGE_ERR_SYNC_FAILURE;
134 return ipc_respond(msg, NULL, 0);
135 }
136 }
137
138 if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT) {
139 bool is_checkpoint_active = false;
140
141 rc = is_data_checkpoint_active(&is_checkpoint_active);
142 if (rc != 0) {
143 ALOGE("is_data_checkpoint_active failed in an unexpected way. Aborting.\n");
144 msg->result = STORAGE_ERR_GENERIC;
145 return ipc_respond(msg, NULL, 0);
146 } else if (is_checkpoint_active) {
147 ALOGE("Checkpoint in progress, dropping write ...\n");
148 msg->result = STORAGE_ERR_GENERIC;
149 return ipc_respond(msg, NULL, 0);
150 }
151 }
152
153 switch (msg->cmd) {
154 case STORAGE_FILE_DELETE:
155 rc = storage_file_delete(msg, req, req_len);
156 break;
157
158 case STORAGE_FILE_OPEN:
159 rc = storage_file_open(msg, req, req_len);
160 break;
161
162 case STORAGE_FILE_CLOSE:
163 rc = storage_file_close(msg, req, req_len);
164 break;
165
166 case STORAGE_FILE_WRITE:
167 rc = storage_file_write(msg, req, req_len);
168 break;
169
170 case STORAGE_FILE_READ:
171 rc = storage_file_read(msg, req, req_len);
172 break;
173
174 case STORAGE_FILE_GET_SIZE:
175 rc = storage_file_get_size(msg, req, req_len);
176 break;
177
178 case STORAGE_FILE_SET_SIZE:
179 rc = storage_file_set_size(msg, req, req_len);
180 break;
181
182 case STORAGE_RPMB_SEND:
183 rc = rpmb_send(msg, req, req_len);
184 break;
185
186 default:
187 ALOGE("unhandled command 0x%x\n", msg->cmd);
188 msg->result = STORAGE_ERR_UNIMPLEMENTED;
189 rc = 1;
190 }
191
192 if (rc > 0) {
193 /* still need to send response */
194 rc = ipc_respond(msg, NULL, 0);
195 }
196 return rc;
197 }
198
proxy_loop(void)199 static int proxy_loop(void) {
200 ssize_t rc;
201 struct storage_msg msg;
202
203 /* enter main message handling loop */
204 while (true) {
205 /* get incoming message */
206 rc = ipc_get_msg(&msg, req_buffer, REQ_BUFFER_SIZE);
207 if (rc < 0) return rc;
208
209 /* handle request */
210 req_buffer[rc] = 0; /* force zero termination */
211 rc = handle_req(&msg, req_buffer, rc);
212 if (rc) return rc;
213 }
214
215 return 0;
216 }
217
parse_args(int argc,char * argv[])218 static void parse_args(int argc, char* argv[]) {
219 int opt;
220 int oidx = 0;
221
222 while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
223 switch (opt) {
224 case 'd':
225 trusty_devname = strdup(optarg);
226 break;
227
228 case 'p':
229 ss_data_root = strdup(optarg);
230 break;
231
232 case 'r':
233 rpmb_devname = strdup(optarg);
234 break;
235
236 case 't':
237 dev_type = parse_dev_type(optarg);
238 if (dev_type == UNKNOWN_RPMB) {
239 ALOGE("Unrecognized dev type: %s\n", optarg);
240 show_usage_and_exit(EXIT_FAILURE);
241 }
242 break;
243
244 default:
245 ALOGE("unrecognized option (%c):\n", opt);
246 show_usage_and_exit(EXIT_FAILURE);
247 }
248 }
249
250 if (ss_data_root == NULL || trusty_devname == NULL || rpmb_devname == NULL) {
251 ALOGE("missing required argument(s)\n");
252 show_usage_and_exit(EXIT_FAILURE);
253 }
254
255 ALOGI("starting storageproxyd\n");
256 ALOGI("storage data root: %s\n", ss_data_root);
257 ALOGI("trusty dev: %s\n", trusty_devname);
258 ALOGI("rpmb dev: %s\n", rpmb_devname);
259 }
260
main(int argc,char * argv[])261 int main(int argc, char* argv[]) {
262 int rc;
263
264 /* drop privileges */
265 if (drop_privs() < 0) return EXIT_FAILURE;
266
267 /* parse arguments */
268 parse_args(argc, argv);
269
270 /* initialize secure storage directory */
271 rc = storage_init(ss_data_root);
272 if (rc < 0) return EXIT_FAILURE;
273
274 /* open rpmb device */
275 rc = rpmb_open(rpmb_devname, dev_type);
276 if (rc < 0) return EXIT_FAILURE;
277
278 /* connect to Trusty secure storage server */
279 rc = ipc_connect(trusty_devname, ss_srv_name);
280 if (rc < 0) return EXIT_FAILURE;
281
282 /* enter main loop */
283 rc = proxy_loop();
284 ALOGE("exiting proxy loop with status (%d)\n", rc);
285
286 ipc_disconnect();
287 rpmb_close();
288
289 return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
290 }
291