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