diff --git a/logd/Android.mk b/logd/Android.mk index feca8d555..203943c31 100644 --- a/logd/Android.mk +++ b/logd/Android.mk @@ -42,6 +42,10 @@ event_flag := -DAUDITD_LOG_TAG=1003 -DLOGD_LOG_TAG=1004 LOCAL_CFLAGS := -Werror $(event_flag) +ifeq ($(TARGET_BUILD_VARIANT),user) +LOCAL_CFLAGS += -DAUDITD_ENFORCE_INTEGRITY=true +endif + include $(BUILD_EXECUTABLE) include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index 143fb0429..fffc9ba96 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,10 @@ #include "LogAudit.h" #include "LogKlog.h" +#ifndef AUDITD_ENFORCE_INTEGRITY +#define AUDITD_ENFORCE_INTEGRITY false +#endif + #define KMSG_PRIORITY(PRI) \ '<', \ '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \ @@ -43,11 +48,10 @@ LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) : logbuf(buf), reader(reader), fdDmesg(fdDmesg), + policyLoaded(false), + rebootToSafeMode(false), initialized(false) { - static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), - 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':', - ' ', 's', 't', 'a', 'r', 't', '\n' }; - write(fdDmesg, auditd_message, sizeof(auditd_message)); + logToDmesg("start"); } bool LogAudit::onDataAvailable(SocketClient *cli) { @@ -73,6 +77,46 @@ bool LogAudit::onDataAvailable(SocketClient *cli) { return true; } +void LogAudit::logToDmesg(const std::string& str) +{ + static const char prefix[] = { KMSG_PRIORITY(LOG_INFO), + 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':', + ' ', '\0' }; + std::string message = prefix + str + "\n"; + write(fdDmesg, message.c_str(), message.length()); +} + +std::string LogAudit::getProperty(const std::string& name) +{ + char value[PROP_VALUE_MAX] = {0}; + property_get(name.c_str(), value, ""); + return value; +} + +void LogAudit::enforceIntegrity() { + if (!AUDITD_ENFORCE_INTEGRITY) { + logToDmesg("integrity enforcement suppressed; not rebooting"); + } else if (rebootToSafeMode) { + if (getProperty("persist.sys.safemode") == "1") { + logToDmesg("integrity enforcement suppressed; in safe mode"); + return; + } + + logToDmesg("enforcing integrity; rebooting to safe mode"); + property_set("persist.sys.safemode", "1"); + + std::string buildDate = getProperty("ro.build.date.utc"); + if (!buildDate.empty()) { + property_set("persist.sys.audit_safemode", buildDate.c_str()); + } + + property_set("sys.powerctl", "reboot"); + } else { + logToDmesg("enforcing integrity: rebooting to recovery"); + property_set("sys.powerctl", "reboot,recovery"); + } +} + int LogAudit::logPrint(const char *fmt, ...) { if (fmt == NULL) { return -EINVAL; @@ -94,7 +138,27 @@ int LogAudit::logPrint(const char *fmt, ...) { memmove(cp, cp + 1, strlen(cp + 1) + 1); } - bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded "); + bool loaded = strstr(str, " policy loaded "); + + if (loaded) { + if (policyLoaded) { + // SELinux policy changes are not allowed + enforceIntegrity(); + } else { + logToDmesg("policy loaded"); + policyLoaded = true; + } + } + + bool permissive = strstr(str, " enforcing=0") || + strstr(str, " permissive=1"); + + if (permissive) { + // SELinux in permissive mode is not allowed + enforceIntegrity(); + } + + bool info = loaded || permissive; if ((fdDmesg >= 0) && initialized) { struct iovec iov[3]; static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) }; diff --git a/logd/LogAudit.h b/logd/LogAudit.h index 8a82630f5..455ed58c0 100644 --- a/logd/LogAudit.h +++ b/logd/LogAudit.h @@ -24,12 +24,15 @@ class LogAudit : public SocketListener { LogBuffer *logbuf; LogReader *reader; int fdDmesg; + bool policyLoaded; + bool rebootToSafeMode; bool initialized; public: LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg); int log(char *buf, size_t len); bool isMonotonic() { return logbuf->isMonotonic(); } + void allowSafeMode(bool allow = true) { rebootToSafeMode = allow; } protected: virtual bool onDataAvailable(SocketClient *cli); @@ -38,6 +41,9 @@ private: static int getLogSocket(); int logPrint(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); + void logToDmesg(const std::string& str); + std::string getProperty(const std::string& name); + void enforceIntegrity(); }; #endif diff --git a/logd/README.property b/logd/README.property index 6200d3ee5..4bc5541c0 100644 --- a/logd/README.property +++ b/logd/README.property @@ -1,7 +1,6 @@ The properties that logd responds to are: name type default description -ro.logd.auditd bool true Enable selinux audit daemon ro.logd.auditd.dmesg bool true selinux audit messages duplicated and sent on to dmesg log persist.logd.security bool false Enable security buffer. diff --git a/logd/main.cpp b/logd/main.cpp index bef40c7b0..f4d746416 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -245,6 +245,7 @@ static char *name; static sem_t reinit; static bool reinit_running = false; static LogBuffer *logBuf = NULL; +static LogAudit *logAudit = NULL; static bool package_list_parser_cb(pkg_info *info, void * /* userdata */) { @@ -292,6 +293,10 @@ static void *reinit_thread_start(void * /*obj*/) { logBuf->init(); logBuf->initPrune(NULL); } + + if (logAudit) { + logAudit->allowSafeMode(); + } } return NULL; @@ -512,25 +517,19 @@ int main(int argc, char *argv[]) { // initiated log messages. New log entries are added to LogBuffer // and LogReader is notified to send updates to connected clients. - bool auditd = property_get_bool("logd.auditd", - BOOL_DEFAULT_TRUE | - BOOL_DEFAULT_FLAG_PERSIST); - LogAudit *al = NULL; - if (auditd) { - al = new LogAudit(logBuf, reader, - property_get_bool("logd.auditd.dmesg", - BOOL_DEFAULT_TRUE | - BOOL_DEFAULT_FLAG_PERSIST) - ? fdDmesg - : -1); - } + logAudit = new LogAudit(logBuf, reader, + property_get_bool("logd.auditd.dmesg", + BOOL_DEFAULT_TRUE | + BOOL_DEFAULT_FLAG_PERSIST) + ? fdDmesg + : -1); LogKlog *kl = NULL; if (klogd) { - kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL); + kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, logAudit != NULL); } - readDmesg(al, kl); + readDmesg(logAudit, kl); // failure is an option ... messages are in dmesg (required by standard) @@ -538,8 +537,9 @@ int main(int argc, char *argv[]) { delete kl; } - if (al && al->startListener()) { - delete al; + if (logAudit && logAudit->startListener()) { + delete logAudit; + logAudit = NULL; } TEMP_FAILURE_RETRY(pause());