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
diff --git a/logd/logd.rc b/logd/logd.rc
index 438419a..530f342 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -6,7 +6,8 @@
     file /dev/kmsg w
     user logd
     group logd system package_info readproc
-    capabilities SYSLOG AUDIT_CONTROL SETGID
+    capabilities SYSLOG AUDIT_CONTROL
+    priority 10
     writepid /dev/cpuset/system-background/tasks
 
 service logd-reinit /system/bin/logd --reinit
diff --git a/logd/main.cpp b/logd/main.cpp
index fd3cdf8..28dcc5a 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -17,6 +17,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/capability.h>
 #include <poll.h>
 #include <sched.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, '>'
 
-//
-// The service is designed to be run by init, it does not respond well
-// to starting up manually. When starting up manually the sockets will
-// fail to open typically for one of the following reasons:
-//     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
-//
-
+// The service is designed to be run by init, it does not respond well to starting up manually. Init
+// has a 'sigstop' feature that sends SIGSTOP to a service immediately before calling exec().  This
+// allows debuggers, etc to be attached to logd at the very beginning, while still having init
+// handle the user, groups, capabilities, files, etc setup.
 static int drop_privs(bool klogd, bool auditd) {
     sched_param param = {};
 
@@ -99,11 +75,6 @@
         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",
                                             BOOL_DEFAULT_FALSE) &&
         prctl(PR_SET_DUMPABLE, 0) == -1) {
@@ -111,52 +82,26 @@
         return -1;
     }
 
-    std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(),
-                                                             cap_free);
-    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) {
+    std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free);
+    if (cap_clear(caps.get()) < 0) {
         return -1;
     }
-    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(cap_value), cap_value,
-                     CAP_SET) < 0) {
+    std::vector<cap_value_t> cap_value;
+    if (klogd) {
+        cap_value.emplace_back(CAP_SYSLOG);
+    }
+    if (auditd) {
+        cap_value.emplace_back(CAP_AUDIT_CONTROL);
+    }
+
+    if (cap_set_flag(caps.get(), CAP_PERMITTED, cap_value.size(), cap_value.data(), CAP_SET) < 0) {
+        return -1;
+    }
+    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, cap_value.size(), cap_value.data(), 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;
-    }
-
-    gid_t groups[] = { AID_READPROC };
-
-    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 (setuid(AID_LOGD) != 0) {
-        android::prdebug("failed to set AID_LOGD uid");
-        return -1;
-    }
-
-    if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) {
-        return -1;
-    }
-    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) {
-        return -1;
-    }
-    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;
     }
 
@@ -227,30 +172,6 @@
 
 static void* reinit_thread_start(void* /*obj*/) {
     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) {
         // uidToName Privileged Worker
@@ -373,11 +294,6 @@
 }
 
 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(
         "logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
     if (sock < 0) return -errno;
@@ -440,6 +356,11 @@
         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
     sem_init(&reinit, 0, 0);
     sem_init(&uidName, 0, 0);
@@ -461,12 +382,6 @@
         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
     // socket connection, and as a reader lock on a range of log
     // entries.