• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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