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