Merge "liblog: gate write on log id available" am: fbdbf10
am: f44cb4c

* commit 'f44cb4c6cb11a4a2cd6af8f72d84a092bcfcf513':
  liblog: gate write on log id available

Change-Id: Ida839dd23ea2b3b1b860c6e8e2b32af61b2fea29
diff --git a/liblog/logd_writer.c b/liblog/logd_writer.c
index 696237d..059f170 100644
--- a/liblog/logd_writer.c
+++ b/liblog/logd_writer.c
@@ -105,12 +105,6 @@
     if (logId > LOG_ID_SECURITY) {
         return -EINVAL;
     }
-    if (logId == LOG_ID_SECURITY) {
-        uid_t uid = __android_log_uid();
-        if ((uid != AID_LOG) && (uid != AID_ROOT) && (uid != AID_SYSTEM)) {
-            return -EPERM;
-        }
-    }
     if (logdLoggerWrite.context.sock < 0) {
         if (access("/dev/socket/logdw", W_OK) == 0) {
             return 0;
diff --git a/liblog/logger.h b/liblog/logger.h
index 61bc396..5d031d7 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -40,6 +40,7 @@
 struct android_log_transport_write {
   struct listnode node;
   const char *name;
+  unsigned logMask; /* cache of available success */
   union android_log_context context; /* Initialized by static allocation */
 
   int (*available)(log_id_t logId);
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index f15c7cd..0d6ba08 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -26,6 +26,7 @@
 #include <cutils/list.h>
 #include <log/log.h>
 #include <log/logger.h>
+#include <private/android_filesystem_config.h>
 
 #include "config_read.h"
 #include "log_portability.h"
@@ -91,6 +92,10 @@
         logger_for_each(logger, logger_list) {
             log_id_t logId = logger->logId;
 
+            if ((logId == LOG_ID_SECURITY) &&
+                    (__android_log_uid() != AID_SYSTEM)) {
+                continue;
+            }
             if (transport->read &&
                     (!transport->available ||
                         (transport->available(logId) >= 0))) {
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index a4155e9..b802ed7 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -49,20 +49,85 @@
     kLogUninitialized, kLogNotAvailable, kLogAvailable
 } g_log_status = kLogUninitialized;
 
+static int check_log_uid_permissions()
+{
+#if defined(__BIONIC__)
+    uid_t uid = __android_log_uid();
+
+    /* Matches clientHasLogCredentials() in logd */
+    if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+        uid = geteuid();
+        if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
+            gid_t gid = getgid();
+            if ((gid != AID_SYSTEM) &&
+                    (gid != AID_ROOT) &&
+                    (gid != AID_LOG)) {
+                gid = getegid();
+                if ((gid != AID_SYSTEM) &&
+                        (gid != AID_ROOT) &&
+                        (gid != AID_LOG)) {
+                    int num_groups;
+                    gid_t *groups;
+
+                    num_groups = getgroups(0, NULL);
+                    if (num_groups <= 0) {
+                        return -EPERM;
+                    }
+                    groups = calloc(num_groups, sizeof(gid_t));
+                    if (!groups) {
+                        return -ENOMEM;
+                    }
+                    num_groups = getgroups(num_groups, groups);
+                    while (num_groups > 0) {
+                        if (groups[num_groups - 1] == AID_LOG) {
+                            break;
+                        }
+                        --num_groups;
+                    }
+                    free(groups);
+                    if (num_groups <= 0) {
+                        return -EPERM;
+                    }
+                }
+            }
+        }
+    }
+#endif
+    return 0;
+}
+
+static void __android_log_cache_available(
+        struct android_log_transport_write *node)
+{
+    size_t i;
+
+    if (node->logMask) {
+        return;
+    }
+
+    for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+        if (node->write &&
+                (i != LOG_ID_KERNEL) &&
+                ((i != LOG_ID_SECURITY) ||
+                    (check_log_uid_permissions() == 0)) &&
+                (!node->available || ((*node->available)(i) >= 0))) {
+            node->logMask |= 1 << i;
+        }
+    }
+}
+
 LIBLOG_ABI_PUBLIC int __android_log_dev_available()
 {
     struct android_log_transport_write *node;
-    size_t i;
 
     if (list_empty(&__android_log_transport_write)) {
         return kLogUninitialized;
     }
-    for (i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
-        write_transport_for_each(node, &__android_log_transport_write) {
-            if (node->write &&
-                    (!node->available || ((*node->available)(i) >= 0))) {
-                return kLogAvailable;
-            }
+
+    write_transport_for_each(node, &__android_log_transport_write) {
+        __android_log_cache_available(node);
+        if (node->logMask) {
+            return kLogAvailable;
         }
     }
     return kLogNotAvailable;
@@ -77,6 +142,11 @@
 
     __android_log_config_write();
     write_transport_for_each_safe(transport, n, &__android_log_transport_write) {
+        __android_log_cache_available(transport);
+        if (!transport->logMask) {
+            list_remove(&transport->node);
+            continue;
+        }
         if (!transport->open || ((*transport->open)() < 0)) {
             if (transport->close) {
                 (*transport->close)();
@@ -87,6 +157,11 @@
         ++ret;
     }
     write_transport_for_each_safe(transport, n, &__android_log_persist_write) {
+        __android_log_cache_available(transport);
+        if (!transport->logMask) {
+            list_remove(&transport->node);
+            continue;
+        }
         if (!transport->open || ((*transport->open)() < 0)) {
             if (transport->close) {
                 (*transport->close)();
@@ -127,50 +202,13 @@
 
 #if defined(__BIONIC__)
     if (log_id == LOG_ID_SECURITY) {
-        uid_t uid;
-
         if (vec[0].iov_len < 4) {
             return -EINVAL;
         }
 
-        uid = __android_log_uid();
-        /* Matches clientHasLogCredentials() in logd */
-        if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
-            uid = geteuid();
-            if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
-                gid_t gid = getgid();
-                if ((gid != AID_SYSTEM) &&
-                        (gid != AID_ROOT) &&
-                        (gid != AID_LOG)) {
-                    gid = getegid();
-                    if ((gid != AID_SYSTEM) &&
-                            (gid != AID_ROOT) &&
-                            (gid != AID_LOG)) {
-                        int num_groups;
-                        gid_t *groups;
-
-                        num_groups = getgroups(0, NULL);
-                        if (num_groups <= 0) {
-                            return -EPERM;
-                        }
-                        groups = calloc(num_groups, sizeof(gid_t));
-                        if (!groups) {
-                            return -ENOMEM;
-                        }
-                        num_groups = getgroups(num_groups, groups);
-                        while (num_groups > 0) {
-                            if (groups[num_groups - 1] == AID_LOG) {
-                                break;
-                            }
-                            --num_groups;
-                        }
-                        free(groups);
-                        if (num_groups <= 0) {
-                            return -EPERM;
-                        }
-                    }
-                }
-            }
+        ret = check_log_uid_permissions();
+        if (ret < 0) {
+            return ret;
         }
         if (!__android_log_security()) {
             /* If only we could reset downstream logd counter */
@@ -262,8 +300,9 @@
 #endif
 
     ret = 0;
+    i = 1 << log_id;
     write_transport_for_each(node, &__android_log_transport_write) {
-        if (node->write) {
+        if (node->logMask & i) {
             ssize_t retval;
             retval = (*node->write)(log_id, &ts, vec, nr);
             if (ret >= 0) {
@@ -273,7 +312,7 @@
     }
 
     write_transport_for_each(node, &__android_log_persist_write) {
-        if (node->write) {
+        if (node->logMask & i) {
             (void)(*node->write)(log_id, &ts, vec, nr);
         }
     }
@@ -343,12 +382,12 @@
     }
 #endif
 
-    vec[0].iov_base   = (unsigned char *) &prio;
-    vec[0].iov_len    = 1;
-    vec[1].iov_base   = (void *) tag;
-    vec[1].iov_len    = strlen(tag) + 1;
-    vec[2].iov_base   = (void *) msg;
-    vec[2].iov_len    = strlen(msg) + 1;
+    vec[0].iov_base = (unsigned char *)&prio;
+    vec[0].iov_len  = 1;
+    vec[1].iov_base = (void *)tag;
+    vec[1].iov_len  = strlen(tag) + 1;
+    vec[2].iov_base = (void *)msg;
+    vec[2].iov_len  = strlen(msg) + 1;
 
     return write_to_log(bufID, vec, 3);
 }