Merge "Don't use bare `noreturn` in log.h."
diff --git a/init/Android.mk b/init/Android.mk
index ecdf5db..111fe89 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -54,7 +54,7 @@
     service.cpp \
     util.cpp \
 
-LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup libnl
 LOCAL_WHOLE_STATIC_LIBRARIES := libcap
 LOCAL_MODULE := libinit
 LOCAL_SANITIZE := integer
@@ -103,7 +103,8 @@
     libdl \
     libsparse_static \
     libz \
-    libprocessgroup
+    libprocessgroup \
+    libnl \
 
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/log.cpp b/init/log.cpp
index 8618340..6b32526 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -19,6 +19,8 @@
 #include <fcntl.h>
 #include <string.h>
 
+#include <linux/audit.h>
+#include <netlink/netlink.h>
 #include <selinux/selinux.h>
 
 void InitKernelLogging(char* argv[]) {
@@ -38,6 +40,24 @@
     android::base::InitLogging(argv, &android::base::KernelLogger);
 }
 
+static void selinux_avc_log(char* buf, size_t buf_len) {
+    size_t str_len = strnlen(buf, buf_len);
+
+    // trim newline at end of string
+    buf[str_len - 1] = '\0';
+
+    struct nl_sock* sk = nl_socket_alloc();
+    if (sk == NULL) {
+        return;
+    }
+    nl_connect(sk, NETLINK_AUDIT);
+    int result;
+    do {
+        result = nl_send_simple(sk, AUDIT_USER_AVC, 0, buf, str_len);
+    } while (result == -NLE_INTR);
+    nl_socket_free(sk);
+}
+
 int selinux_klog_callback(int type, const char *fmt, ...) {
     android::base::LogSeverity severity = android::base::ERROR;
     if (type == SELINUX_WARNING) {
@@ -48,8 +68,15 @@
     char buf[1024];
     va_list ap;
     va_start(ap, fmt);
-    vsnprintf(buf, sizeof(buf), fmt, ap);
+    int res = vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
-    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+    if (res <= 0) {
+        return 0;
+    }
+    if (type == SELINUX_AVC) {
+        selinux_avc_log(buf, sizeof(buf));
+    } else {
+        android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+    }
     return 0;
 }
diff --git a/init/service.cpp b/init/service.cpp
index 7cff348..0f7f62f 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -582,12 +582,15 @@
             console_ = default_console;
         }
 
-        bool have_console = (access(console_.c_str(), R_OK | W_OK) != -1);
-        if (!have_console) {
-            PLOG(ERROR) << "service '" << name_ << "' cannot gain read/write access to console '" << console_ << "'";
+        // Make sure that open call succeeds to ensure a console driver is
+        // properly registered for the device node
+        int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
+        if (console_fd < 0) {
+            PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
             flags_ |= SVC_DISABLED;
             return false;
         }
+        close(console_fd);
     }
 
     struct stat sb;
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index aa05932..11ffcb7 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -47,6 +47,10 @@
         logbuf(buf),
         reader(reader),
         fdDmesg(fdDmesg),
+        main(__android_logger_property_get_bool("ro.logd.auditd.main",
+                                                BOOL_DEFAULT_TRUE)),
+        events(__android_logger_property_get_bool("ro.logd.auditd.events",
+                                                  BOOL_DEFAULT_TRUE)),
         initialized(false) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
         'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
@@ -94,6 +98,13 @@
     }
 
     char *cp;
+    // Work around kernels missing
+    // https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
+    // Such kernels improperly add newlines inside audit messages.
+    while ((cp = strchr(str, '\n'))) {
+        *cp = ' ';
+    }
+
     while ((cp = strstr(str, "  "))) {
         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     }
@@ -172,6 +183,11 @@
         }
     }
 
+    if (!main && !events) {
+        free(str);
+        return 0;
+    }
+
     pid_t pid = getpid();
     pid_t tid = gettid();
     uid_t uid = AID_LOGD;
@@ -222,7 +238,7 @@
 
     bool notify = false;
 
-    {   // begin scope for event buffer
+    if (events) {   // begin scope for event buffer
         uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
 
         android_log_event_string_t *event
@@ -277,7 +293,7 @@
     size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
     n = b + e + l + 2;
 
-    {   // begin scope for main buffer
+    if (main) {   // begin scope for main buffer
         char newstr[n];
 
         *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index ab30e28..844951d 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -26,7 +26,9 @@
 class LogAudit : public SocketListener {
     LogBuffer *logbuf;
     LogReader *reader;
-    int fdDmesg;
+    int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
+    bool main;
+    bool events;
     bool initialized;
 
 public:
diff --git a/logd/README.property b/logd/README.property
index 791b1d5..de6767a 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -2,8 +2,9 @@
 
 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
+ro.logd.auditd.dmesg       bool   true   selinux audit messages sent to dmesg.
+ro.logd.auditd.main        bool   true   selinux audit messages sent to main.
+ro.logd.auditd.events      bool   true   selinux audit messages sent to events.
 persist.logd.security      bool   false  Enable security buffer.
 ro.device_owner            bool   false  Override persist.logd.security to false
 ro.logd.kernel             bool+ svelte+ Enable klogd daemon
diff --git a/logd/main.cpp b/logd/main.cpp
index c3343d7..5878f15 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -451,9 +451,8 @@
         pthread_attr_destroy(&attr);
     }
 
-    bool auditd = __android_logger_property_get_bool("logd.auditd",
-                                                     BOOL_DEFAULT_TRUE |
-                                                     BOOL_DEFAULT_FLAG_PERSIST);
+    bool auditd = __android_logger_property_get_bool("ro.logd.auditd",
+                                                     BOOL_DEFAULT_TRUE);
     if (drop_privs(klogd, auditd) != 0) {
         return -1;
     }
@@ -513,8 +512,8 @@
     if (auditd) {
         al = new LogAudit(logBuf, reader,
                           __android_logger_property_get_bool(
-                              "logd.auditd.dmesg",
-                              BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST)
+                              "ro.logd.auditd.dmesg",
+                              BOOL_DEFAULT_TRUE)
                                   ? fdDmesg
                                   : -1);
     }