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 <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} 265