service_manager.c revision 2a0e40945b5f7adf2055b2f439b3ba4c6389ddc3
1/* Copyright 2008 The Android Open Source Project 2 */ 3 4#include <stdio.h> 5#include <stdlib.h> 6#include <errno.h> 7#include <fcntl.h> 8 9#include <private/android_filesystem_config.h> 10 11#include <selinux/android.h> 12#include <selinux/avc.h> 13 14#include "binder.h" 15 16#if 0 17#define ALOGI(x...) fprintf(stderr, "svcmgr: " x) 18#define ALOGE(x...) fprintf(stderr, "svcmgr: " x) 19#else 20#define LOG_TAG "ServiceManager" 21#include <cutils/log.h> 22#endif 23 24uint32_t svcmgr_handle; 25 26const char *str8(const uint16_t *x, size_t x_len) 27{ 28 static char buf[128]; 29 size_t max = 127; 30 char *p = buf; 31 32 if (x_len < max) { 33 max = x_len; 34 } 35 36 if (x) { 37 while ((max > 0) && (*x != '\0')) { 38 *p++ = *x++; 39 max--; 40 } 41 } 42 *p++ = 0; 43 return buf; 44} 45 46int str16eq(const uint16_t *a, const char *b) 47{ 48 while (*a && *b) 49 if (*a++ != *b++) return 0; 50 if (*a || *b) 51 return 0; 52 return 1; 53} 54 55static int selinux_enabled; 56static char *service_manager_context; 57static struct selabel_handle* sehandle; 58 59static bool check_mac_perms(pid_t spid, const char *tctx, const char *perm, const char *name) 60{ 61 char *sctx = NULL; 62 const char *class = "service_manager"; 63 bool allowed; 64 65 if (getpidcon(spid, &sctx) < 0) { 66 ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); 67 return false; 68 } 69 70 int result = selinux_check_access(sctx, tctx, class, perm, (void *) name); 71 allowed = (result == 0); 72 73 freecon(sctx); 74 return allowed; 75} 76 77static bool check_mac_perms_from_getcon(pid_t spid, const char *perm) 78{ 79 if (selinux_enabled <= 0) { 80 return true; 81 } 82 83 return check_mac_perms(spid, service_manager_context, perm, NULL); 84} 85 86static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char *name) 87{ 88 bool allowed; 89 char *tctx = NULL; 90 91 if (selinux_enabled <= 0) { 92 return true; 93 } 94 95 if (!sehandle) { 96 ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); 97 abort(); 98 } 99 100 if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { 101 ALOGE("SELinux: No match for %s in service_contexts.\n", name); 102 return false; 103 } 104 105 allowed = check_mac_perms(spid, tctx, perm, name); 106 freecon(tctx); 107 return allowed; 108} 109 110static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid) 111{ 112 const char *perm = "add"; 113 return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0; 114} 115 116static int svc_can_list(pid_t spid) 117{ 118 const char *perm = "list"; 119 return check_mac_perms_from_getcon(spid, perm) ? 1 : 0; 120} 121 122static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid) 123{ 124 const char *perm = "find"; 125 return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0; 126} 127 128struct svcinfo 129{ 130 struct svcinfo *next; 131 uint32_t handle; 132 struct binder_death death; 133 int allow_isolated; 134 size_t len; 135 uint16_t name[0]; 136}; 137 138struct svcinfo *svclist = NULL; 139 140struct svcinfo *find_svc(const uint16_t *s16, size_t len) 141{ 142 struct svcinfo *si; 143 144 for (si = svclist; si; si = si->next) { 145 if ((len == si->len) && 146 !memcmp(s16, si->name, len * sizeof(uint16_t))) { 147 return si; 148 } 149 } 150 return NULL; 151} 152 153void svcinfo_death(struct binder_state *bs, void *ptr) 154{ 155 struct svcinfo *si = (struct svcinfo* ) ptr; 156 157 ALOGI("service '%s' died\n", str8(si->name, si->len)); 158 if (si->handle) { 159 binder_release(bs, si->handle); 160 si->handle = 0; 161 } 162} 163 164uint16_t svcmgr_id[] = { 165 'a','n','d','r','o','i','d','.','o','s','.', 166 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' 167}; 168 169 170uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid) 171{ 172 struct svcinfo *si; 173 174 if (!svc_can_find(s, len, spid)) { 175 ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n", 176 str8(s, len), uid); 177 return 0; 178 } 179 si = find_svc(s, len); 180 //ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0); 181 if (si && si->handle) { 182 if (!si->allow_isolated) { 183 // If this service doesn't allow access from isolated processes, 184 // then check the uid to see if it is isolated. 185 uid_t appid = uid % AID_USER; 186 if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { 187 return 0; 188 } 189 } 190 return si->handle; 191 } else { 192 return 0; 193 } 194} 195 196int do_add_service(struct binder_state *bs, 197 const uint16_t *s, size_t len, 198 uint32_t handle, uid_t uid, int allow_isolated, 199 pid_t spid) 200{ 201 struct svcinfo *si; 202 203 //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, 204 // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); 205 206 if (!handle || (len == 0) || (len > 127)) 207 return -1; 208 209 if (!svc_can_register(s, len, spid)) { 210 ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", 211 str8(s, len), handle, uid); 212 return -1; 213 } 214 215 si = find_svc(s, len); 216 if (si) { 217 if (si->handle) { 218 ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", 219 str8(s, len), handle, uid); 220 svcinfo_death(bs, si); 221 } 222 si->handle = handle; 223 } else { 224 si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); 225 if (!si) { 226 ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", 227 str8(s, len), handle, uid); 228 return -1; 229 } 230 si->handle = handle; 231 si->len = len; 232 memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); 233 si->name[len] = '\0'; 234 si->death.func = (void*) svcinfo_death; 235 si->death.ptr = si; 236 si->allow_isolated = allow_isolated; 237 si->next = svclist; 238 svclist = si; 239 } 240 241 binder_acquire(bs, handle); 242 binder_link_to_death(bs, handle, &si->death); 243 return 0; 244} 245 246int svcmgr_handler(struct binder_state *bs, 247 struct binder_transaction_data *txn, 248 struct binder_io *msg, 249 struct binder_io *reply) 250{ 251 struct svcinfo *si; 252 uint16_t *s; 253 size_t len; 254 uint32_t handle; 255 uint32_t strict_policy; 256 int allow_isolated; 257 258 //ALOGI("target=%x code=%d pid=%d uid=%d\n", 259 // txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid); 260 261 if (txn->target.handle != svcmgr_handle) 262 return -1; 263 264 if (txn->code == PING_TRANSACTION) 265 return 0; 266 267 // Equivalent to Parcel::enforceInterface(), reading the RPC 268 // header with the strict mode policy mask and the interface name. 269 // Note that we ignore the strict_policy and don't propagate it 270 // further (since we do no outbound RPCs anyway). 271 strict_policy = bio_get_uint32(msg); 272 s = bio_get_string16(msg, &len); 273 if (s == NULL) { 274 return -1; 275 } 276 277 if ((len != (sizeof(svcmgr_id) / 2)) || 278 memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { 279 fprintf(stderr,"invalid id %s\n", str8(s, len)); 280 return -1; 281 } 282 283 if (sehandle && selinux_status_updated() > 0) { 284 struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); 285 if (tmp_sehandle) { 286 selabel_close(sehandle); 287 sehandle = tmp_sehandle; 288 } 289 } 290 291 switch(txn->code) { 292 case SVC_MGR_GET_SERVICE: 293 case SVC_MGR_CHECK_SERVICE: 294 s = bio_get_string16(msg, &len); 295 if (s == NULL) { 296 return -1; 297 } 298 handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid); 299 if (!handle) 300 break; 301 bio_put_ref(reply, handle); 302 return 0; 303 304 case SVC_MGR_ADD_SERVICE: 305 s = bio_get_string16(msg, &len); 306 if (s == NULL) { 307 return -1; 308 } 309 handle = bio_get_ref(msg); 310 allow_isolated = bio_get_uint32(msg) ? 1 : 0; 311 if (do_add_service(bs, s, len, handle, txn->sender_euid, 312 allow_isolated, txn->sender_pid)) 313 return -1; 314 break; 315 316 case SVC_MGR_LIST_SERVICES: { 317 uint32_t n = bio_get_uint32(msg); 318 319 if (!svc_can_list(txn->sender_pid)) { 320 ALOGE("list_service() uid=%d - PERMISSION DENIED\n", 321 txn->sender_euid); 322 return -1; 323 } 324 si = svclist; 325 while ((n-- > 0) && si) 326 si = si->next; 327 if (si) { 328 bio_put_string16(reply, si->name); 329 return 0; 330 } 331 return -1; 332 } 333 default: 334 ALOGE("unknown code %d\n", txn->code); 335 return -1; 336 } 337 338 bio_put_uint32(reply, 0); 339 return 0; 340} 341 342 343static int audit_callback(void *data, security_class_t cls, char *buf, size_t len) 344{ 345 snprintf(buf, len, "service=%s", !data ? "NULL" : (char *)data); 346 return 0; 347} 348 349int main(int argc, char **argv) 350{ 351 struct binder_state *bs; 352 353 bs = binder_open(128*1024); 354 if (!bs) { 355 ALOGE("failed to open binder driver\n"); 356 return -1; 357 } 358 359 if (binder_become_context_manager(bs)) { 360 ALOGE("cannot become context manager (%s)\n", strerror(errno)); 361 return -1; 362 } 363 364 selinux_enabled = is_selinux_enabled(); 365 sehandle = selinux_android_service_context_handle(); 366 367 if (selinux_enabled > 0) { 368 if (sehandle == NULL) { 369 ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); 370 abort(); 371 } 372 373 if (getcon(&service_manager_context) != 0) { 374 ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); 375 abort(); 376 } 377 } 378 379 union selinux_callback cb; 380 cb.func_audit = audit_callback; 381 selinux_set_callback(SELINUX_CB_AUDIT, cb); 382 cb.func_log = selinux_log_callback; 383 selinux_set_callback(SELINUX_CB_LOG, cb); 384 385 svcmgr_handle = BINDER_SERVICE_MANAGER; 386 binder_loop(bs, svcmgr_handler); 387 388 return 0; 389} 390