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
};
-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) {
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;
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);
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;
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);