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