diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 44f4f6dac..f37427a0b 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -52,46 +52,18 @@ int str16eq(const uint16_t *a, const char *b) return 1; } +static int selinux_enabled; +static char *service_manager_context; static struct selabel_handle* sehandle; -static bool check_mac_perms(const char *name, pid_t spid) +static bool check_mac_perms(pid_t spid, const char *tctx, const char *perm, const char *name) { - if (is_selinux_enabled() <= 0) { - return true; - } - - bool allowed = false; - - const char *class = "service_manager"; - const char *perm = "add"; - - char *tctx = NULL; char *sctx = NULL; - - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle %s.\n", name); - return false; - } + const char *class = "service_manager"; + bool allowed; if (getpidcon(spid, &sctx) < 0) { - ALOGE("SELinux: getpidcon failed to retrieve pid context.\n"); - return false; - } - - if (!sctx) { - ALOGE("SELinux: Failed to find sctx for %s.\n", name); - return false; - } - - if (selabel_lookup(sehandle, &tctx, name, 1) != 0) { - ALOGE("SELinux: selabel_lookup failed to set tctx for %s.\n", name); - freecon(sctx); - return false; - } - - if (!tctx) { - ALOGE("SELinux: Failed to find tctx for %s.\n", name); - freecon(sctx); + ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); return false; } @@ -99,13 +71,58 @@ static bool check_mac_perms(const char *name, pid_t spid) allowed = (result == 0); freecon(sctx); + return allowed; +} + +static bool check_mac_perms_from_getcon(pid_t spid, const char *perm) +{ + if (selinux_enabled <= 0) { + return true; + } + + return check_mac_perms(spid, service_manager_context, perm, NULL); +} + +static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char *name) +{ + bool allowed; + char *tctx = NULL; + + if (selinux_enabled <= 0) { + return true; + } + + if (!sehandle) { + ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); + abort(); + } + + if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { + ALOGE("SELinux: No match for %s in service_contexts.\n", name); + return false; + } + + allowed = check_mac_perms(spid, tctx, perm, name); freecon(tctx); return allowed; } -static int svc_can_register(uid_t uid, const uint16_t *name, size_t name_len, pid_t spid) +static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid) { - return check_mac_perms(str8(name, name_len), spid) ? 1 : 0; + const char *perm = "add"; + return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0; +} + +static int svc_can_list(pid_t spid) +{ + const char *perm = "list"; + return check_mac_perms_from_getcon(spid, perm) ? 1 : 0; +} + +static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid) +{ + const char *perm = "find"; + return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0; } struct svcinfo @@ -150,10 +167,15 @@ uint16_t svcmgr_id[] = { }; -uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid) +uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid) { struct svcinfo *si; + if (!svc_can_find(s, len, spid)) { + ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n", + str8(s, len), uid); + return 0; + } si = find_svc(s, len); //ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0); if (si && si->handle) { @@ -184,7 +206,7 @@ int do_add_service(struct binder_state *bs, if (!handle || (len == 0) || (len > 127)) return -1; - if (!svc_can_register(uid, s, len, spid)) { + if (!svc_can_register(s, len, spid)) { ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid); return -1; @@ -273,7 +295,7 @@ int svcmgr_handler(struct binder_state *bs, if (s == NULL) { return -1; } - handle = do_find_service(bs, s, len, txn->sender_euid); + handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid); if (!handle) break; bio_put_ref(reply, handle); @@ -294,6 +316,11 @@ int svcmgr_handler(struct binder_state *bs, case SVC_MGR_LIST_SERVICES: { uint32_t n = bio_get_uint32(msg); + if (!svc_can_list(txn->sender_pid)) { + ALOGE("list_service() uid=%d - PERMISSION DENIED\n", + txn->sender_euid); + return -1; + } si = svclist; while ((n-- > 0) && si) si = si->next; @@ -334,8 +361,21 @@ int main(int argc, char **argv) return -1; } + selinux_enabled = is_selinux_enabled(); sehandle = selinux_android_service_context_handle(); + if (selinux_enabled > 0) { + if (sehandle == NULL) { + ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); + abort(); + } + + if (getcon(&service_manager_context) != 0) { + ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); + abort(); + } + } + union selinux_callback cb; cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb);