logd: liblog: logcat: Add LOG_ID_SECURITY

- Largish commit, buffer and access controls done together
- Add LOG_ID_SECURITY binary content log
- Add "default" meta buffer
- allow LOG_ID_SECURITY only from AID_SYSTEM and AID_ROOT UID & GID
- Use __android_log_security() to gate logging
- Add __android_log_security_bwrite() native access to security
  logging.
- Add liblog.__security_buffer end-to-end gTest

Bug: 26029733
Change-Id: Ibcf5b4660c17c1aa6902c0d93f8ffd29c93d9a93
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index c45111a..e103359 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -34,6 +34,7 @@
 
 #include "CommandListener.h"
 #include "LogCommand.h"
+#include "LogUtils.h"
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
                                  LogListener * /*swl*/) :
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index bf650cd..cb3d1c2 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -21,6 +21,7 @@
 #include "LogCommand.h"
 #include "LogReader.h"
 #include "LogTimes.h"
+#include "LogUtils.h"
 
 FlushCommand::FlushCommand(LogReader &reader,
                            bool nonBlock,
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 6770bb7..3ce6b61 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -199,22 +199,24 @@
 
     LogBufferElement *elem = new LogBufferElement(log_id, realtime,
                                                   uid, pid, tid, msg, len);
-    int prio = ANDROID_LOG_INFO;
-    const char *tag = NULL;
-    if (log_id == LOG_ID_EVENTS) {
-        tag = android::tagToName(elem->getTag());
-    } else {
-        prio = *msg;
-        tag = msg + 1;
-    }
-    if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-        // Log traffic received to total
-        pthread_mutex_lock(&mLogElementsLock);
-        stats.add(elem);
-        stats.subtract(elem);
-        pthread_mutex_unlock(&mLogElementsLock);
-        delete elem;
-        return -EACCES;
+    if (log_id != LOG_ID_SECURITY) {
+        int prio = ANDROID_LOG_INFO;
+        const char *tag = NULL;
+        if (log_id == LOG_ID_EVENTS) {
+            tag = android::tagToName(elem->getTag());
+        } else {
+            prio = *msg;
+            tag = msg + 1;
+        }
+        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+            // Log traffic received to total
+            pthread_mutex_lock(&mLogElementsLock);
+            stats.add(elem);
+            stats.subtract(elem);
+            pthread_mutex_unlock(&mLogElementsLock);
+            delete elem;
+            return -EACCES;
+        }
     }
 
     pthread_mutex_lock(&mLogElementsLock);
@@ -484,7 +486,7 @@
     }
 
     // prune by worst offender by uid
-    bool hasBlacklist = mPrune.naughty();
+    bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
     while (!clearAll && (pruneRows > 0)) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
@@ -654,7 +656,7 @@
     }
 
     bool whitelist = false;
-    bool hasWhitelist = mPrune.nice() && !clearAll;
+    bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index c4c302b..f92a085 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -51,7 +51,8 @@
 }
 
 uint32_t LogBufferElement::getTag() const {
-    if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+    if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
+            !mMsg || (mMsgLen < sizeof(uint32_t))) {
         return 0;
     }
     return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
@@ -158,7 +159,9 @@
                           mDropped, (mDropped > 1) ? "s" : "");
 
     size_t hdrLen;
-    if (mLogId == LOG_ID_EVENTS) {
+    // LOG_ID_SECURITY not strictly needed since spam filter not activated,
+    // but required for accuracy.
+    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -172,7 +175,7 @@
     }
 
     size_t retval = hdrLen + len;
-    if (mLogId == LOG_ID_EVENTS) {
+    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
         android_log_event_string_t *event =
             reinterpret_cast<android_log_event_string_t *>(buffer);
 
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 6d0e92e..3b17576 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -22,6 +22,7 @@
 #include <private/android_filesystem_config.h>
 
 #include "LogCommand.h"
+#include "LogUtils.h"
 
 LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
 }
@@ -56,20 +57,18 @@
     return false;
 }
 
-bool clientHasLogCredentials(SocketClient * cli) {
-    uid_t uid = cli->getUid();
-    if (uid == AID_ROOT) {
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
+    if ((uid == AID_ROOT) || (uid == AID_SYSTEM) || (uid == AID_LOG)) {
         return true;
     }
 
-    gid_t gid = cli->getGid();
     if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
         return true;
     }
 
     // FYI We will typically be here for 'adb logcat'
     char filename[256];
-    snprintf(filename, sizeof(filename), "/proc/%u/status", cli->getPid());
+    snprintf(filename, sizeof(filename), "/proc/%u/status", pid);
 
     bool ret;
     bool foundLog = false;
@@ -145,3 +144,7 @@
 
     return ret;
 }
+
+bool clientHasLogCredentials(SocketClient *cli) {
+    return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
+}
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
index e3b96a2..c944478 100644
--- a/logd/LogCommand.h
+++ b/logd/LogCommand.h
@@ -26,6 +26,4 @@
     virtual ~LogCommand() {}
 };
 
-bool clientHasLogCredentials(SocketClient * cli);
-
 #endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index b29f5ab..9bbf9e8 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -27,6 +27,7 @@
 #include <private/android_logger.h>
 
 #include "LogListener.h"
+#include "LogUtils.h"
 
 LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
         SocketListener(getLogSocket(), false),
@@ -92,6 +93,12 @@
         return false;
     }
 
+    if ((header->id == LOG_ID_SECURITY) &&
+            (!__android_log_security() ||
+             !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
+        return false;
+    }
+
     char *msg = ((char *)buffer) + sizeof(android_log_header_t);
     n -= sizeof(android_log_header_t);
 
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 416edd8..bf0e30b 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -85,7 +85,11 @@
 
     uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.add(tag, element);
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.add(tag, element);
+        } else {
+            tagTable.add(tag, element);
+        }
     }
 }
 
@@ -113,7 +117,11 @@
 
     uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.subtract(tag, element);
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.subtract(tag, element);
+        } else {
+            tagTable.subtract(tag, element);
+        }
     }
 }
 
@@ -468,6 +476,11 @@
         output += tagTable.format(*this, uid, name, LOG_ID_EVENTS);
     }
 
+    if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
+        name = "Chattiest security log buffer TAGs:";
+        output += securityTagTable.format(*this, uid, name, LOG_ID_SECURITY);
+    }
+
     return output;
 }
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 28810d9..8558b06 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -397,6 +397,9 @@
     typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
     tagTable_t tagTable;
 
+    // security tag list
+    tagTable_t securityTagTable;
+
 public:
     LogStatistics();
 
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 533eb1c..b591f28 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <log/log.h>
+#include <sysutils/SocketClient.h>
 
 // Hijack this header as a common include file used by most all sources
 // to report some utilities defined here and there.
@@ -38,8 +39,12 @@
 
 }
 
+// Furnished in LogCommand.cpp
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
+bool clientHasLogCredentials(SocketClient *cli);
+
 static inline bool worstUidEnabledForLogid(log_id_t id) {
-    return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
+    return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) || (id == LOG_ID_RADIO);
 }
 
 template <int (*cmp)(const char *l, const char *r, const size_t s)>