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