logd: enforce policy integrity
If a SELinux policy change or a switch to permissive mode is detected on a user build, restart the device into safe mode, and keep it there until an OTA is applied or user data is wiped. This change deprecates the ro.logd.auditd property. Needs matching changes from I781c3059ea8d4fb2f0c923e4488b1932d69678d3 Ica825cf2af74f5624cf4091544bd24bb5482dbe7 Id3ca7889ede30b54b7af73dd50653ca1a20d59aa Bug: 26902605 Change-Id: Idcdc5bff133f13c1267f0ec0a75cc8cf1ddbda0d
This commit is contained in:
parent
06bfaa7078
commit
d122ee65b6
|
@ -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))
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <sys/uio.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <log/logger.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
#include <private/android_logger.h>
|
||||
|
@ -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) };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue