Merge "libcutils: add socket_get_local_port()."
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 6cffb11..ee56a5e 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -60,6 +60,9 @@
 	liblog \
 	libunwind \
 
+libbacktrace_static_libraries := \
+	libcutils
+
 module := libbacktrace
 module_tag := optional
 build_type := target
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index a936455..8517c9f 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -18,6 +18,8 @@
 #include <inttypes.h>
 #include <signal.h>
 #include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
@@ -25,6 +27,7 @@
 #include <log/logger.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
+#include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
@@ -368,6 +371,48 @@
         return;
     }
 
+    /* Matches clientHasLogCredentials() in logd */
+    uid_t uid = getuid();
+    gid_t gid = getgid();
+    bool clientHasLogCredentials = true;
+    if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)
+     && (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
+        uid_t euid = geteuid();
+        if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
+            gid_t egid = getegid();
+            if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
+                int num_groups = getgroups(0, NULL);
+                if (num_groups > 0) {
+                    gid_t groups[num_groups];
+                    num_groups = getgroups(num_groups, groups);
+                    while (num_groups > 0) {
+                        if (groups[num_groups - 1] == AID_LOG) {
+                            break;
+                        }
+                        --num_groups;
+                    }
+                }
+                if (num_groups <= 0) {
+                    clientHasLogCredentials = false;
+                }
+            }
+        }
+    }
+    if (!clientHasLogCredentials) {
+        fprintf(stderr, "WARNING: "
+                "not in system context, 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(
@@ -415,7 +460,12 @@
 
     android_logger_list_close(logger_list);
 
-    EXPECT_EQ(1, count);
+    bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
+    if (!clientHasSecurityCredentials) {
+        fprintf(stderr, "WARNING: "
+                "not system, content submitted but can not check end-to-end\n");
+    }
+    EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
 
 }
 
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index ec63850..dbb4dab 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -199,7 +199,7 @@
 	return 0;
 }
 
-static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t crc32)
+static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t *crc32)
 {
 	uint32_t file_crc32;
 	int ret;
@@ -213,7 +213,7 @@
 		return ret;
 	}
 
-	if (file_crc32 != crc32) {
+	if (crc32 != NULL && file_crc32 != *crc32) {
 		return -EINVAL;
 	}
 
@@ -257,7 +257,7 @@
 			}
 			return chunk_header->chunk_sz;
 		case CHUNK_TYPE_CRC32:
-			ret = process_crc32_chunk(fd, chunk_data_size, *crc_ptr);
+			ret = process_crc32_chunk(fd, chunk_data_size, crc_ptr);
 			if (ret < 0) {
 				verbose_error(s->verbose, -EINVAL, "crc block at %" PRId64,
 						offset);
@@ -374,6 +374,7 @@
 		ret = read_all(fd, buf, to_read);
 		if (ret < 0) {
 			error("failed to read sparse file");
+			free(buf);
 			return ret;
 		}
 
@@ -401,6 +402,7 @@
 		block++;
 	}
 
+	free(buf);
 	return 0;
 }
 
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 48036d3..fd45c4a0 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -93,3 +93,11 @@
 bool FlushCommand::hasReadLogs(SocketClient *client) {
     return clientHasLogCredentials(client);
 }
+
+static bool clientHasSecurityCredentials(SocketClient *client) {
+    return (client->getUid() == AID_SYSTEM) || (client->getGid() == AID_SYSTEM);
+}
+
+bool FlushCommand::hasSecurityLogs(SocketClient *client) {
+    return clientHasSecurityCredentials(client);
+}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index e0f2212..9224773 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -45,6 +45,7 @@
     virtual void runSocketCommand(SocketClient *client);
 
     static bool hasReadLogs(SocketClient *client);
+    static bool hasSecurityLogs(SocketClient *client);
 };
 
 #endif
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 9e0d451..8c30f79 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -907,7 +907,8 @@
 }
 
 uint64_t LogBuffer::flushTo(
-        SocketClient *reader, const uint64_t start, bool privileged,
+        SocketClient *reader, const uint64_t start,
+        bool privileged, bool security,
         int (*filter)(const LogBufferElement *element, void *arg), void *arg) {
     LogBufferElementCollection::iterator it;
     uint64_t max = start;
@@ -938,6 +939,10 @@
             continue;
         }
 
+        if (!security && (element->getLogId() == LOG_ID_SECURITY)) {
+            continue;
+        }
+
         if (element->getSequence() <= start) {
             continue;
         }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 03739c7..7e99236 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -111,7 +111,7 @@
             uid_t uid, pid_t pid, pid_t tid,
             const char *msg, unsigned short len);
     uint64_t flushTo(SocketClient *writer, const uint64_t start,
-                     bool privileged,
+                     bool privileged, bool security,
                      int (*filter)(const LogBufferElement *element, void *arg) = NULL,
                      void *arg = NULL);
 
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index c2d65b6..667a3f2 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -163,6 +163,7 @@
                        logbuf().isMonotonic() && android::isMonotonic(start));
 
         logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),
+                         FlushCommand::hasSecurityLogs(cli),
                          logFindStart.callback, &logFindStart);
 
         if (!logFindStart.found()) {
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index b4c97a9..a4b96d3 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -126,6 +126,7 @@
     LogBuffer &logbuf = me->mReader.logbuf();
 
     bool privileged = FlushCommand::hasReadLogs(client);
+    bool security = FlushCommand::hasSecurityLogs(client);
 
     me->leadingDropped = true;
 
@@ -150,10 +151,10 @@
         unlock();
 
         if (me->mTail) {
-            logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+            logbuf.flushTo(client, start, privileged, security, FilterFirstPass, me);
             me->leadingDropped = true;
         }
-        start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
+        start = logbuf.flushTo(client, start, privileged, security, FilterSecondPass, me);
 
         lock();
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index e400c85..f617d72 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -201,6 +201,10 @@
     # enable armv8_deprecated instruction hooks
     write /proc/sys/abi/swp 1
 
+    # Linux's execveat() syscall may construct paths containing /dev/fd
+    # expecting it to point to /proc/self/fd
+    symlink /proc/self/fd /dev/fd
+
 # Healthd can trigger a full boot from charger mode by signaling this
 # property when the power button is held.
 on property:sys.boot_from_charger_mode=1