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
This commit is contained in:
parent
44cabca1ef
commit
0b2a011cc4
2 changed files with 27 additions and 111 deletions
|
@ -6,7 +6,8 @@ service logd /system/bin/logd
|
|||
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
|
||||
|
|
135
logd/main.cpp
135
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 @@ static int drop_privs(bool klogd, bool auditd) {
|
|||
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 @@ static int drop_privs(bool klogd, bool auditd) {
|
|||
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 bool package_list_parser_cb(pkg_info* info, void* /* userdata */) {
|
|||
|
||||
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 void readDmesg(LogAudit* al, LogKlog* kl) {
|
|||
}
|
||||
|
||||
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 @@ int main(int argc, char* argv[]) {
|
|||
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 @@ int main(int argc, char* argv[]) {
|
|||
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.
|
||||
|
|
Loading…
Reference in a new issue