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 /* no-execute for user, no access for group and other */
108 umask(S_IXUSR | S_IRWXG | S_IRWXO);
109
110 return 0;
111 }
112
handle_req(struct storage_msg * msg,const void * req,size_t req_len)113 static int handle_req(struct storage_msg* msg, const void* req, size_t req_len) {
114 int rc;
115
116 if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) && (msg->cmd != STORAGE_RPMB_SEND)) {
117 /*
118 * handling post commit messages on non rpmb commands are not
119 * implemented as there is no use case for this yet.
120 */
121 ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
122 msg->result = STORAGE_ERR_UNIMPLEMENTED;
123 return ipc_respond(msg, NULL, 0);
124 }
125
126 if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
127 rc = storage_sync_checkpoint();
128 if (rc < 0) {
129 msg->result = STORAGE_ERR_GENERIC;
130 return ipc_respond(msg, NULL, 0);
131 }
132 }
133
134 if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT) {
135 bool is_checkpoint_active = false;
136
137 rc = is_data_checkpoint_active(&is_checkpoint_active);
138 if (rc != 0) {
139 ALOGE("is_data_checkpoint_active failed in an unexpected way. Aborting.\n");
140 msg->result = STORAGE_ERR_GENERIC;
141 return ipc_respond(msg, NULL, 0);
142 } else if (is_checkpoint_active) {
143 ALOGE("Checkpoint in progress, dropping write ...\n");
144 msg->result = STORAGE_ERR_GENERIC;
145 return ipc_respond(msg, NULL, 0);
146 }
147 }
148
149 switch (msg->cmd) {
150 case STORAGE_FILE_DELETE:
151 rc = storage_file_delete(msg, req, req_len);
152 break;
153
154 case STORAGE_FILE_OPEN:
155 rc = storage_file_open(msg, req, req_len);
156 break;
157
158 case STORAGE_FILE_CLOSE:
159 rc = storage_file_close(msg, req, req_len);
160 break;
161
162 case STORAGE_FILE_WRITE:
163 rc = storage_file_write(msg, req, req_len);
164 break;
165
166 case STORAGE_FILE_READ:
167 rc = storage_file_read(msg, req, req_len);
168 break;
169
170 case STORAGE_FILE_GET_SIZE:
171 rc = storage_file_get_size(msg, req, req_len);
172 break;
173
174 case STORAGE_FILE_SET_SIZE:
175 rc = storage_file_set_size(msg, req, req_len);
176 break;
177
178 case STORAGE_RPMB_SEND:
179 rc = rpmb_send(msg, req, req_len);
180 break;
181
182 default:
183 ALOGE("unhandled command 0x%x\n", msg->cmd);
184 msg->result = STORAGE_ERR_UNIMPLEMENTED;
185 rc = 1;
186 }
187
188 if (rc > 0) {
189 /* still need to send response */
190 rc = ipc_respond(msg, NULL, 0);
191 }
192 return rc;
193 }
194
proxy_loop(void)195 static int proxy_loop(void) {
196 ssize_t rc;
197 struct storage_msg msg;
198
199 /* enter main message handling loop */
200 while (true) {
201 /* get incoming message */
202 rc = ipc_get_msg(&msg, req_buffer, REQ_BUFFER_SIZE);
203 if (rc < 0) return rc;
204
205 /* handle request */
206 req_buffer[rc] = 0; /* force zero termination */
207 rc = handle_req(&msg, req_buffer, rc);
208 if (rc) return rc;
209 }
210
211 return 0;
212 }
213
parse_args(int argc,char * argv[])214 static void parse_args(int argc, char* argv[]) {
215 int opt;
216 int oidx = 0;
217
218 while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
219 switch (opt) {
220 case 'd':
221 trusty_devname = strdup(optarg);
222 break;
223
224 case 'p':
225 ss_data_root = strdup(optarg);
226 break;
227
228 case 'r':
229 rpmb_devname = strdup(optarg);
230 break;
231
232 case 't':
233 dev_type = parse_dev_type(optarg);
234 if (dev_type == UNKNOWN_RPMB) {
235 ALOGE("Unrecognized dev type: %s\n", optarg);
236 show_usage_and_exit(EXIT_FAILURE);
237 }
238 break;
239
240 default:
241 ALOGE("unrecognized option (%c):\n", opt);
242 show_usage_and_exit(EXIT_FAILURE);
243 }
244 }
245
246 if (ss_data_root == NULL || trusty_devname == NULL || rpmb_devname == NULL) {
247 ALOGE("missing required argument(s)\n");
248 show_usage_and_exit(EXIT_FAILURE);
249 }
250
251 ALOGI("starting storageproxyd\n");
252 ALOGI("storage data root: %s\n", ss_data_root);
253 ALOGI("trusty dev: %s\n", trusty_devname);
254 ALOGI("rpmb dev: %s\n", rpmb_devname);
255 }
256
main(int argc,char * argv[])257 int main(int argc, char* argv[]) {
258 int rc;
259
260 /* drop privileges */
261 if (drop_privs() < 0) return EXIT_FAILURE;
262
263 /* parse arguments */
264 parse_args(argc, argv);
265
266 /* initialize secure storage directory */
267 rc = storage_init(ss_data_root);
268 if (rc < 0) return EXIT_FAILURE;
269
270 /* open rpmb device */
271 rc = rpmb_open(rpmb_devname, dev_type);
272 if (rc < 0) return EXIT_FAILURE;
273
274 /* connect to Trusty secure storage server */
275 rc = ipc_connect(trusty_devname, ss_srv_name);
276 if (rc < 0) return EXIT_FAILURE;
277
278 /* enter main loop */
279 rc = proxy_loop();
280 ALOGE("exiting proxy loop with status (%d)\n", rc);
281
282 ipc_disconnect();
283 rpmb_close();
284
285 return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
286 }
287