blob: d645ac01c95886c02df80f812977eec22c974919 [file] [log] [blame]
Michael Ryleev7a2bc372016-03-08 15:16:11 -08001/*
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 <private/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
35static uint8_t req_buffer[REQ_BUFFER_SIZE + 1];
36
37static const char *ss_data_root;
38static const char *trusty_devname;
39static const char *rpmb_devname;
40static const char *ss_srv_name = STORAGE_DISK_PROXY_PORT;
41
42static const char *_sopts = "hp:d:r:";
43static 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
51static 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
57static 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
98static 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
167static 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
190static 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
229int main(int argc, char *argv[])
230{
231 int rc;
232 uint retry_cnt;
233
234 /* drop privileges */
235 if (drop_privs() < 0)
236 return EXIT_FAILURE;
237
238 /* parse arguments */
239 parse_args(argc, argv);
240
241 /* initialize secure storage directory */
242 rc = storage_init(ss_data_root);
243 if (rc < 0)
244 return EXIT_FAILURE;
245
246 /* open rpmb device */
247 rc = rpmb_open(rpmb_devname);
248 if (rc < 0)
249 return EXIT_FAILURE;
250
251 /* connect to Trusty secure storage server */
252 rc = ipc_connect(trusty_devname, ss_srv_name);
253 if (rc < 0)
254 return EXIT_FAILURE;
255
256 /* enter main loop */
257 rc = proxy_loop();
258 ALOGE("exiting proxy loop with status (%d)\n", rc);
259
260 ipc_disconnect();
261 rpmb_close();
262
263 return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
264}