diff options
author | Riley Spahn <rileyspahn@google.com> | 2014-07-08 09:03:00 -0700 |
---|---|---|
committer | Nick Kralevich <nnk@google.com> | 2014-07-15 10:11:33 -0700 |
commit | 2a0e40945b5f7adf2055b2f439b3ba4c6389ddc3 (patch) | |
tree | 7f8f187610f899ee914cc7e63ce2f2c19e3e4ed0 /cmds | |
parent | 2ad9d8a6e71f80b373c3ed0fece26b286d846292 (diff) | |
download | frameworks_native-2a0e40945b5f7adf2055b2f439b3ba4c6389ddc3.zip frameworks_native-2a0e40945b5f7adf2055b2f439b3ba4c6389ddc3.tar.gz frameworks_native-2a0e40945b5f7adf2055b2f439b3ba4c6389ddc3.tar.bz2 |
Add MAC for remaining service_manager functionality.
Add SELinux MAC for the list and find functionality
to service_manager. By default the list action uses
the service_manager_type attribute as its target
object.
(cherry picked from commit c67e6307cadb1f2cd876907c42d39b8374b93acd)
Change-Id: Iaf14b21346822a6b544091a0f4a9949117934b9a
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/servicemanager/service_manager.c | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 44f4f6d..f37427a 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -52,60 +52,77 @@ 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; + const char *class = "service_manager"; + bool allowed; - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle %s.\n", name); + if (getpidcon(spid, &sctx) < 0) { + ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); return false; } - if (getpidcon(spid, &sctx) < 0) { - ALOGE("SELinux: getpidcon failed to retrieve pid context.\n"); - return false; + int result = selinux_check_access(sctx, tctx, class, perm, (void *) name); + 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; } - if (!sctx) { - ALOGE("SELinux: Failed to find sctx for %s.\n", name); - return false; + 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 (selabel_lookup(sehandle, &tctx, name, 1) != 0) { - ALOGE("SELinux: selabel_lookup failed to set tctx for %s.\n", name); - freecon(sctx); - return false; + if (!sehandle) { + ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); + abort(); } - if (!tctx) { - ALOGE("SELinux: Failed to find tctx for %s.\n", name); - freecon(sctx); + if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { + ALOGE("SELinux: No match for %s in service_contexts.\n", name); return false; } - int result = selinux_check_access(sctx, tctx, class, perm, (void *) name); - allowed = (result == 0); - - freecon(sctx); + 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) +{ + 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) { - return check_mac_perms(str8(name, name_len), spid) ? 1 : 0; + 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); |