Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 721fdd3a authored by Nick Kralevich's avatar Nick Kralevich Committed by Gerrit Code Review
Browse files

Merge "Add MAC for remaining service_manager functionality."

parents 71139783 c67e6307
Loading
Loading
Loading
Loading
+75 −35
Original line number Diff line number Diff line
@@ -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;
    }
    char *sctx = NULL;
    const char *class = "service_manager";
    bool allowed;

    bool allowed = false;
    if (getpidcon(spid, &sctx) < 0) {
        ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
        return false;
    }

    const char *class = "service_manager";
    const char *perm = "add";
    int result = selinux_check_access(sctx, tctx, class, perm, (void *) name);
    allowed = (result == 0);

    char *tctx = NULL;
    char *sctx = NULL;
    freecon(sctx);
    return allowed;
}

    if (!sehandle) {
        ALOGE("SELinux: Failed to find sehandle %s.\n", name);
        return false;
static bool check_mac_perms_from_getcon(pid_t spid, const char *perm)
{
    if (selinux_enabled <= 0) {
        return true;
    }

    if (getpidcon(spid, &sctx) < 0) {
        ALOGE("SELinux: getpidcon failed to retrieve pid context.\n");
        return false;
    return check_mac_perms(spid, service_manager_context, perm, NULL);
}

    if (!sctx) {
        ALOGE("SELinux: Failed to find sctx for %s.\n", name);
        return false;
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);