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

Commit 0b2a011c authored by Tom Cherry's avatar Tom Cherry
Browse files

logd: don't drop user/groups/capabilities/priority in drop_privs()

On Android, unlike POSIX, groups and capabilities are able to be set
per thread.  This is useless however, since threads are not a security
boundary.  This change drops the logic to set groups and capabilities
per thread and instead leaves all threads running with the initial
user and groups.

This does still drop some capabilities if they're unneeded due to
features being disabled.

This also moves the setpriority() call from code into the init script.

Test: logd runs with the expected user/groups and with the expected
      capabilities and priority without any errors

Change-Id: Ibb0e529ea1574a2b8ec391a2678504ca9fbe19be
parent 44cabca1
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -6,7 +6,8 @@ service logd /system/bin/logd
    file /dev/kmsg w
    file /dev/kmsg w
    user logd
    user logd
    group logd system package_info readproc
    group logd system package_info readproc
    capabilities SYSLOG AUDIT_CONTROL SETGID
    capabilities SYSLOG AUDIT_CONTROL
    priority 10
    writepid /dev/cpuset/system-background/tasks
    writepid /dev/cpuset/system-background/tasks


service logd-reinit /system/bin/logd --reinit
service logd-reinit /system/bin/logd --reinit
+20 −105
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#include <dirent.h>
#include <dirent.h>
#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <fcntl.h>
#include <linux/capability.h>
#include <poll.h>
#include <poll.h>
#include <sched.h>
#include <sched.h>
#include <semaphore.h>
#include <semaphore.h>
@@ -57,35 +58,10 @@
    '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
    '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
        '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, '>'
        '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, '>'


//
// The service is designed to be run by init, it does not respond well to starting up manually. Init
// The service is designed to be run by init, it does not respond well
// has a 'sigstop' feature that sends SIGSTOP to a service immediately before calling exec().  This
// to starting up manually. When starting up manually the sockets will
// allows debuggers, etc to be attached to logd at the very beginning, while still having init
// fail to open typically for one of the following reasons:
// handle the user, groups, capabilities, files, etc setup.
//     EADDRINUSE if logger is running.
//     EACCESS if started without precautions (below)
//
// Here is a cookbook procedure for starting up logd manually assuming
// init is out of the way, pedantically all permissions and SELinux
// security is put back in place:
//
//    setenforce 0
//    rm /dev/socket/logd*
//    chmod 777 /dev/socket
//        # here is where you would attach the debugger or valgrind for example
//    runcon u:r:logd:s0 /system/bin/logd </dev/null >/dev/null 2>&1 &
//    sleep 1
//    chmod 755 /dev/socket
//    chown logd.logd /dev/socket/logd*
//    restorecon /dev/socket/logd*
//    setenforce 1
//
// If minimalism prevails, typical for debugging and security is not a concern:
//
//    setenforce 0
//    chmod 777 /dev/socket
//    logd
//

static int drop_privs(bool klogd, bool auditd) {
static int drop_privs(bool klogd, bool auditd) {
    sched_param param = {};
    sched_param param = {};


@@ -99,11 +75,6 @@ static int drop_privs(bool klogd, bool auditd) {
        return -1;
        return -1;
    }
    }


    if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
        android::prdebug("failed to set background cgroup");
        return -1;
    }

    if (!__android_logger_property_get_bool("ro.debuggable",
    if (!__android_logger_property_get_bool("ro.debuggable",
                                            BOOL_DEFAULT_FALSE) &&
                                            BOOL_DEFAULT_FALSE) &&
        prctl(PR_SET_DUMPABLE, 0) == -1) {
        prctl(PR_SET_DUMPABLE, 0) == -1) {
@@ -111,52 +82,26 @@ static int drop_privs(bool klogd, bool auditd) {
        return -1;
        return -1;
    }
    }


    std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(),
    std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free);
                                                             cap_free);
    if (cap_clear(caps.get()) < 0) {
    if (cap_clear(caps.get()) < 0) return -1;
    cap_value_t cap_value[] = { CAP_SETGID,  // must be first for below
                                klogd ? CAP_SYSLOG : CAP_SETGID,
                                auditd ? CAP_AUDIT_CONTROL : CAP_SETGID };
    if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(cap_value), cap_value,
                     CAP_SET) < 0) {
        return -1;
    }
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(cap_value), cap_value,
                     CAP_SET) < 0) {
        return -1;
    }
    if (cap_set_proc(caps.get()) < 0) {
        android::prdebug(
            "failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)",
            errno);
        return -1;
        return -1;
    }
    }

    std::vector<cap_value_t> cap_value;
    gid_t groups[] = { AID_READPROC };
    if (klogd) {

        cap_value.emplace_back(CAP_SYSLOG);
    if (setgroups(arraysize(groups), groups) == -1) {
        android::prdebug("failed to set AID_READPROC groups");
        return -1;
    }

    if (setgid(AID_LOGD) != 0) {
        android::prdebug("failed to set AID_LOGD gid");
        return -1;
    }
    }

    if (auditd) {
    if (setuid(AID_LOGD) != 0) {
        cap_value.emplace_back(CAP_AUDIT_CONTROL);
        android::prdebug("failed to set AID_LOGD uid");
        return -1;
    }
    }


    if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) {
    if (cap_set_flag(caps.get(), CAP_PERMITTED, cap_value.size(), cap_value.data(), CAP_SET) < 0) {
        return -1;
        return -1;
    }
    }
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) {
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, cap_value.size(), cap_value.data(), CAP_SET) < 0) {
        return -1;
        return -1;
    }
    }
    if (cap_set_proc(caps.get()) < 0) {
    if (cap_set_proc(caps.get()) < 0) {
        android::prdebug("failed to clear CAP_SETGID (%d)", errno);
        android::prdebug("failed to set CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)", errno);
        return -1;
        return -1;
    }
    }


@@ -227,30 +172,6 @@ static bool package_list_parser_cb(pkg_info* info, void* /* userdata */) {


static void* reinit_thread_start(void* /*obj*/) {
static void* reinit_thread_start(void* /*obj*/) {
    prctl(PR_SET_NAME, "logd.daemon");
    prctl(PR_SET_NAME, "logd.daemon");
    set_sched_policy(0, SP_BACKGROUND);
    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);

    // We should drop to AID_LOGD, if we are anything else, we have
    // even lesser privileges and accept our fate.
    gid_t groups[] = {
        AID_SYSTEM,        // search access to /data/system path
        AID_PACKAGE_INFO,  // readonly access to /data/system/packages.list
    };
    if (setgroups(arraysize(groups), groups) == -1) {
        android::prdebug(
            "logd.daemon: failed to set AID_SYSTEM AID_PACKAGE_INFO groups");
    }
    if (setgid(AID_LOGD) != 0) {
        android::prdebug("logd.daemon: failed to set AID_LOGD gid");
    }
    if (setuid(AID_LOGD) != 0) {
        android::prdebug("logd.daemon: failed to set AID_LOGD uid");
    }

    cap_t caps = cap_init();
    (void)cap_clear(caps);
    (void)cap_set_proc(caps);
    (void)cap_free(caps);


    while (reinit_running && !sem_wait(&reinit) && reinit_running) {
    while (reinit_running && !sem_wait(&reinit) && reinit_running) {
        // uidToName Privileged Worker
        // uidToName Privileged Worker
@@ -373,11 +294,6 @@ static void readDmesg(LogAudit* al, LogKlog* kl) {
}
}


static int issueReinit() {
static int issueReinit() {
    cap_t caps = cap_init();
    (void)cap_clear(caps);
    (void)cap_set_proc(caps);
    (void)cap_free(caps);

    int sock = TEMP_FAILURE_RETRY(socket_local_client(
    int sock = TEMP_FAILURE_RETRY(socket_local_client(
        "logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
        "logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
    if (sock < 0) return -errno;
    if (sock < 0) return -errno;
@@ -440,6 +356,11 @@ int main(int argc, char* argv[]) {
        if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
        if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
    }
    }


    bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
    if (drop_privs(klogd, auditd) != 0) {
        return EXIT_FAILURE;
    }

    // Reinit Thread
    // Reinit Thread
    sem_init(&reinit, 0, 0);
    sem_init(&reinit, 0, 0);
    sem_init(&uidName, 0, 0);
    sem_init(&uidName, 0, 0);
@@ -461,12 +382,6 @@ int main(int argc, char* argv[]) {
        pthread_attr_destroy(&attr);
        pthread_attr_destroy(&attr);
    }
    }


    bool auditd =
        __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
    if (drop_privs(klogd, auditd) != 0) {
        return EXIT_FAILURE;
    }

    // Serves the purpose of managing the last logs times read on a
    // Serves the purpose of managing the last logs times read on a
    // socket connection, and as a reader lock on a range of log
    // socket connection, and as a reader lock on a range of log
    // entries.
    // entries.