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

Commit 11c783f1 authored by Kenny Root's avatar Kenny Root Committed by Android Git Automerger
Browse files

am 9494f297: Merge "Implement SELinux/MAC checks for property service."

* commit '9494f297':
  Implement SELinux/MAC checks for property service.
parents 4dcd52ab 9494f297
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@

#ifdef HAVE_SELINUX
struct selabel_handle *sehandle;
struct selabel_handle *sehandle_prop;
#endif

static int property_triggers_enabled = 0;
@@ -755,9 +756,34 @@ static int bootchart_init_action(int nargs, char **args)
#endif

#ifdef HAVE_SELINUX
static const struct selinux_opt seopts_prop[] = {
        { SELABEL_OPT_PATH, "/data/system/property_contexts" },
        { SELABEL_OPT_PATH, "/property_contexts" },
        { 0, NULL }
};

struct selabel_handle* selinux_android_prop_context_handle(void)
{
    int i = 0;
    struct selabel_handle* sehandle = NULL;
    while ((sehandle == NULL) && seopts_prop[i].value) {
        sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);
        i++;
    }

    if (!sehandle) {
        ERROR("SELinux:  Could not load property_contexts:  %s\n",
              strerror(errno));
        return NULL;
    }
    INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[i - 1].value);
    return sehandle;
}

void selinux_init_all_handles(void)
{
    sehandle = selinux_android_file_context_handle();
    sehandle_prop = selinux_android_prop_context_handle();
}

int selinux_reload_policy(void)
@@ -775,9 +801,19 @@ int selinux_reload_policy(void)
    if (sehandle)
        selabel_close(sehandle);

    if (sehandle_prop)
        selabel_close(sehandle_prop);

    selinux_init_all_handles();
    return 0;
}

int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
{
    snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
    return 0;
}

#endif

int main(int argc, char **argv)
@@ -831,6 +867,13 @@ int main(int argc, char **argv)
    process_kernel_cmdline();

#ifdef HAVE_SELINUX
    union selinux_callback cb;
    cb.func_log = klog_write;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);

    INFO("loading selinux policy\n");
    if (selinux_enabled) {
        if (selinux_android_load_policy() < 0) {
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ int load_565rle_image( char *file_name );

#ifdef HAVE_SELINUX
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
extern int selinux_reload_policy(void);
#endif

+79 −11
Original line number Diff line number Diff line
@@ -40,6 +40,11 @@
#include <sys/atomics.h>
#include <private/android_filesystem_config.h>

#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
#endif

#include "property_service.h"
#include "init.h"
#include "util.h"
@@ -192,23 +197,77 @@ static void update_prop_info(prop_info *pi, const char *value, unsigned len)
    __futex_wake(&pi->serial, INT32_MAX);
}

static int check_mac_perms(const char *name, char *sctx)
{
#ifdef HAVE_SELINUX
    if (is_selinux_enabled() <= 0)
        return 1;

    char *tctx = NULL;
    const char *class = "property_service";
    const char *perm = "set";
    int result = 0;

    if (!sctx)
        goto err;

    if (!sehandle_prop)
        goto err;

    if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
        goto err;

    if (selinux_check_access(sctx, tctx, class, perm, name) == 0)
        result = 1;

    freecon(tctx);
 err:
    return result;

#endif
    return 1;
}

static int check_control_mac_perms(const char *name, char *sctx)
{
#ifdef HAVE_SELINUX

    /*
     *  Create a name prefix out of ctl.<service name>
     *  The new prefix allows the use of the existing
     *  property service backend labeling while avoiding
     *  mislabels based on true property prefixes.
     */
    char ctl_name[PROP_VALUE_MAX+4];
    int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);

    if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
        return 0;

    return check_mac_perms(ctl_name, sctx);

#endif
    return 1;
}

/*
 * Checks permissions for starting/stoping system services.
 * AID_SYSTEM and AID_ROOT are always allowed.
 *
 * Returns 1 if uid allowed, 0 otherwise.
 */
static int check_control_perms(const char *name, unsigned int uid, unsigned int gid) {
static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {

    int i;
    if (uid == AID_SYSTEM || uid == AID_ROOT)
        return 1;
      return check_control_mac_perms(name, sctx);

    /* Search the ACL */
    for (i = 0; control_perms[i].service; i++) {
        if (strcmp(control_perms[i].service, name) == 0) {
            if ((uid && control_perms[i].uid == uid) ||
                (gid && control_perms[i].gid == gid)) {
                return 1;
                return check_control_mac_perms(name, sctx);
            }
        }
    }
@@ -219,22 +278,22 @@ static int check_control_perms(const char *name, unsigned int uid, unsigned int
 * Checks permissions for setting system properties.
 * Returns 1 if uid allowed, 0 otherwise.
 */
static int check_perms(const char *name, unsigned int uid, unsigned int gid)
static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
{
    int i;
    if (uid == 0)
        return 1;

    if(!strncmp(name, "ro.", 3))
        name +=3;

    if (uid == 0)
        return check_mac_perms(name, sctx);

    for (i = 0; property_perms[i].prefix; i++) {
        int tmp;
        if (strncmp(property_perms[i].prefix, name,
                    strlen(property_perms[i].prefix)) == 0) {
            if ((uid && property_perms[i].uid == uid) ||
                (gid && property_perms[i].gid == gid)) {
                return 1;

                return check_mac_perms(name, sctx);
            }
        }
    }
@@ -355,6 +414,7 @@ void handle_property_set_fd()
    struct sockaddr_un addr;
    socklen_t addr_size = sizeof(addr);
    socklen_t cr_size = sizeof(cr);
    char * source_ctx = NULL;

    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
        return;
@@ -380,18 +440,22 @@ void handle_property_set_fd()
        msg.name[PROP_NAME_MAX-1] = 0;
        msg.value[PROP_VALUE_MAX-1] = 0;

#ifdef HAVE_SELINUX
        getpeercon(s, &source_ctx);
#endif

        if(memcmp(msg.name,"ctl.",4) == 0) {
            // Keep the old close-socket-early behavior when handling
            // ctl.* properties.
            close(s);
            if (check_control_perms(msg.value, cr.uid, cr.gid)) {
            if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
                handle_control_message((char*) msg.name + 4, (char*) msg.value);
            } else {
                ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
                        msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
            }
        } else {
            if (check_perms(msg.name, cr.uid, cr.gid)) {
            if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
                property_set((char*) msg.name, (char*) msg.value);
            } else {
                ERROR("sys_prop: permission denied uid:%d  name:%s\n",
@@ -403,6 +467,10 @@ void handle_property_set_fd()
            // the property is written to memory.
            close(s);
        }
#ifdef HAVE_SELINUX
        freecon(source_ctx);
#endif

        break;

    default: