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/include/log/log.h b/include/log/log.h
index 619bf23..3d9240d 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -604,7 +604,8 @@
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
-    LOG_ID_KERNEL = 5,
+    LOG_ID_SECURITY = 5,
+    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
 #endif
 
     LOG_ID_MAX
diff --git a/include/log/logd.h b/include/log/logd.h
index 0fe515f..b7aedaf 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -44,6 +44,8 @@
     size_t len);
 int __android_log_bswrite(int32_t tag, const char *payload);
 
+int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/liblog/log_read.c b/liblog/log_read.c
index fb86757..179f611 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -208,6 +208,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
     [LOG_ID_KERNEL] = "kernel",
 };
 
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 11c6d9c..c2b0ec2 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -84,7 +84,7 @@
 #endif  /* !defined(_WIN32) */
 
 #if FAKE_LOG_DEVICE
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
 #else
 static int logd_fd = -1;
 static int pstore_fd = -1;
@@ -181,6 +181,7 @@
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
     static pid_t last_pid = (pid_t) -1;
     static atomic_int_fast32_t dropped;
+    static atomic_int_fast32_t dropped_security;
 
     if (!nr) {
         return -EINVAL;
@@ -192,6 +193,23 @@
     if (last_pid == (pid_t) -1) {
         last_pid = getpid();
     }
+    if (log_id == LOG_ID_SECURITY) {
+        if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT)) {
+            uid_t uid = geteuid();
+            if ((uid != AID_SYSTEM) && (uid != AID_ROOT)) {
+                gid_t gid = getgid();
+                if ((gid != AID_SYSTEM) && (gid != AID_ROOT)) {
+                    gid = getegid();
+                    if ((gid != AID_SYSTEM) && (gid != AID_ROOT)) {
+                        return -EPERM;
+                    }
+                }
+            }
+        }
+        if (!__android_log_security()) {
+            return -EPERM;
+        }
+    }
     /*
      *  struct {
      *      // what we provide to pstore
@@ -229,7 +247,26 @@
     newVec[1].iov_len    = sizeof(header);
 
     if (logd_fd > 0) {
-        int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0,
+                                                    memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_SECURITY;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[2].iov_base = &buffer;
+            newVec[2].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped_security, snapshot,
+                                          memory_order_relaxed);
+            }
+        }
+        snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
         if (snapshot) {
             android_log_event_int_t buffer;
 
@@ -243,7 +280,8 @@
 
             ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-                atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+                atomic_fetch_add_explicit(&dropped, snapshot,
+                                          memory_order_relaxed);
             }
         }
     }
@@ -315,6 +353,10 @@
         ret -= sizeof(header);
     } else if (ret == -EAGAIN) {
         atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+        if (log_id == LOG_ID_SECURITY) {
+            atomic_fetch_add_explicit(&dropped_security, 1,
+                                      memory_order_relaxed);
+        }
     }
 #endif
 
@@ -328,6 +370,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
     [LOG_ID_KERNEL] = "kernel",
 };
 
@@ -483,6 +526,18 @@
     return write_to_log(LOG_ID_EVENTS, vec, 2);
 }
 
+int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_SECURITY, vec, 2);
+}
+
 /*
  * Like __android_log_bwrite, but takes the type as well.  Doesn't work
  * for the general case where we're generating lists of stuff, but very
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 597d8f6..1046d25 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -25,6 +25,7 @@
 #include <log/logger.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
+#include <private/android_logger.h>
 
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
@@ -201,6 +202,96 @@
     property_set(persist_key, persist);
 }
 
+TEST(liblog, __security_buffer) {
+    struct logger_list *logger_list;
+    android_event_long_t buffer;
+
+    static const char persist_key[] = "persist.logd.security";
+    char persist[PROP_VALUE_MAX];
+    bool set_persist = false;
+    bool allow_security = false;
+
+    if (__android_log_security()) {
+        allow_security = true;
+    } else {
+        property_get(persist_key, persist, "");
+        if (strcasecmp(persist, "true")) {
+            property_set(persist_key, "TRUE");
+            if (__android_log_security()) {
+                allow_security = true;
+                set_persist = true;
+            } else {
+                property_set(persist_key, persist);
+            }
+        }
+    }
+
+    if (!allow_security) {
+        fprintf(stderr, "WARNING: "
+                "security buffer disabled, bypassing end-to-end test\n");
+
+        log_time ts(CLOCK_MONOTONIC);
+
+        buffer.type = EVENT_TYPE_LONG;
+        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+        // expect failure!
+        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+        return;
+    }
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+        1000, pid)));
+
+    log_time ts(CLOCK_MONOTONIC);
+
+    buffer.type = EVENT_TYPE_LONG;
+    buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+    ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != (4 + 1 + 8))
+         || (log_msg.id() != LOG_ID_SECURITY)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        if (eventData[4] != EVENT_TYPE_LONG) {
+            continue;
+        }
+
+        log_time tx(eventData + 4 + 1);
+        if (ts == tx) {
+            ++count;
+        }
+    }
+
+    if (set_persist) {
+        property_set(persist_key, persist);
+    }
+
+    android_logger_list_close(logger_list);
+
+    EXPECT_EQ(1, count);
+
+}
+
 static unsigned signaled;
 log_time signal_time;
 
@@ -650,7 +741,8 @@
         EXPECT_EQ(id, android_logger_get_id(logger));
         EXPECT_LT(0, android_logger_get_log_size(logger));
         /* crash buffer is allowed to be empty, that is actually healthy! */
-        if (android_logger_get_log_readable_size(logger) || strcmp("crash", name)) {
+        if (android_logger_get_log_readable_size(logger) ||
+                (strcmp("crash", name) && strcmp("security", name))) {
             EXPECT_LT(0, android_logger_get_log_readable_size(logger));
         }
         EXPECT_LT(0, android_logger_get_log_version(logger));
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 059916e..8ceeba5 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -283,10 +283,12 @@
                     "  --buffer_size=<size>\n"
                     "  -L              dump logs from prior to last reboot\n"
                     "  --last\n"
+                    // Leave security (Device Owner only installations) and
+                    // kernel (userdebug and eng) buffers undocumented.
                     "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
-                    "  --buffer=<buffer> 'events', 'crash' or 'all'. Multiple -b parameters are\n"
-                    "                  allowed and results are interleaved. The default is\n"
-                    "                  -b main -b system -b crash.\n"
+                    "  --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
+                    "                  parameters are allowed and results are interleaved. The\n"
+                    "                  default is -b main -b system -b crash.\n"
                     "  -B              output the log in binary.\n"
                     "  --binary\n"
                     "  -S              output statistics.\n"
@@ -696,16 +698,20 @@
             break;
 
             case 'b': {
-                if (strcmp(optarg, "all") == 0) {
-                    while (devices) {
-                        dev = devices;
-                        devices = dev->next;
-                        delete dev;
-                    }
+                if (strcmp(optarg, "default") == 0) {
+                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        switch (i) {
+                        case LOG_ID_SECURITY:
+                        case LOG_ID_EVENTS:
+                            continue;
+                        case LOG_ID_MAIN:
+                        case LOG_ID_SYSTEM:
+                        case LOG_ID_CRASH:
+                            break;
+                        default:
+                            continue;
+                        }
 
-                    devices = dev = NULL;
-                    g_devCount = 0;
-                    for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                         const char *name = android_log_id_to_name((log_id_t)i);
                         log_id_t log_id = android_name_to_log_id(name);
 
@@ -713,7 +719,58 @@
                             continue;
                         }
 
-                        bool binary = strcmp(name, "events") == 0;
+                        bool found = false;
+                        for (dev = devices; dev; dev = dev->next) {
+                            if (!strcmp(optarg, dev->device)) {
+                                found = true;
+                                break;
+                            }
+                            if (!dev->next) {
+                                break;
+                            }
+                        }
+                        if (found) {
+                            break;
+                        }
+
+                        log_device_t* d = new log_device_t(name, false);
+
+                        if (dev) {
+                            dev->next = d;
+                            dev = d;
+                        } else {
+                            devices = dev = d;
+                        }
+                        g_devCount++;
+                    }
+                    break;
+                }
+
+                if (strcmp(optarg, "all") == 0) {
+                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        const char *name = android_log_id_to_name((log_id_t)i);
+                        log_id_t log_id = android_name_to_log_id(name);
+
+                        if (log_id != (log_id_t)i) {
+                            continue;
+                        }
+
+                        bool found = false;
+                        for (dev = devices; dev; dev = dev->next) {
+                            if (!strcmp(optarg, dev->device)) {
+                                found = true;
+                                break;
+                            }
+                            if (!dev->next) {
+                                break;
+                            }
+                        }
+                        if (found) {
+                            break;
+                        }
+
+                        bool binary = !strcmp(name, "events") ||
+                                      !strcmp(name, "security");
                         log_device_t* d = new log_device_t(name, binary);
 
                         if (dev) {
@@ -727,14 +784,21 @@
                     break;
                 }
 
-                bool binary = strcmp(optarg, "events") == 0;
+                bool binary = !(strcmp(optarg, "events") &&
+                                strcmp(optarg, "security"));
 
                 if (devices) {
                     dev = devices;
                     while (dev->next) {
+                        if (!strcmp(optarg, dev->device)) {
+                            dev = NULL;
+                            break;
+                        }
                         dev = dev->next;
                     }
-                    dev->next = new log_device_t(optarg, binary);
+                    if (dev) {
+                        dev->next = new log_device_t(optarg, binary);
+                    }
                 } else {
                     devices = new log_device_t(optarg, binary);
                 }
@@ -1004,7 +1068,7 @@
         size_t len = 8192;
         char *buf;
 
-        for(int retry = 32;
+        for (int retry = 32;
                 (retry >= 0) && ((buf = new char [len]));
                 delete [] buf, buf = NULL, --retry) {
             if (getPruneList) {
@@ -1094,7 +1158,7 @@
             logcat_panic(false, "logcat read failure");
         }
 
-        for(d = devices; d; d = d->next) {
+        for (d = devices; d; d = d->next) {
             if (android_name_to_log_id(d->device) == log_msg.id()) {
                 break;
             }
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)>