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