Merge "init.rc: Remove cpu weight set on the root cgroup" into nyc-mr1-dev
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index c220a0c..5ccd80e 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -89,6 +89,12 @@
 #define AID_DEBUGGERD     1045  /* debuggerd unprivileged user */
 #define AID_MEDIA_CODEC   1046  /* mediacodec process */
 #define AID_CAMERASERVER  1047  /* cameraserver process */
+#define AID_FIREWALL      1048  /* firewalld process */
+#define AID_TRUNKS        1049  /* trunksd process (TPM daemon) */
+#define AID_NVRAM         1050  /* Access-controlled NVRAM */
+#define AID_DNS           1051  /* DNS resolution daemon (system: netd) */
+#define AID_DNS_TETHER    1052  /* DNS resolution daemon (tether: dnsmasq) */
+/* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -196,6 +202,11 @@
     { "debuggerd",     AID_DEBUGGERD, },
     { "mediacodec",    AID_MEDIA_CODEC, },
     { "cameraserver",  AID_CAMERASERVER, },
+    { "firewall",      AID_FIREWALL, },
+    { "trunks",        AID_TRUNKS, },
+    { "nvram",         AID_NVRAM, },
+    { "dns",           AID_DNS, },
+    { "dns_tether",    AID_DNS_TETHER, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index a006082..cddbab4 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -88,7 +88,7 @@
  * "dst" becomes \xE3\x81\x82\xE3\x81\x84
  * (note that "dst" is NOT null-terminated, like strncpy)
  */
-void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst);
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len);
 
 /**
  * Returns the unicode value at "index".
@@ -110,7 +110,7 @@
  * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
  * NULL terminator.
  */
-void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst);
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len);
 
 /**
  * Returns the length of "src" when "src" is valid UTF-8 string.
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index ac12f2e..c097a12 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -66,9 +66,12 @@
 static int bg_cpuset_fd = -1;
 static int fg_cpuset_fd = -1;
 static int ta_cpuset_fd = -1; // special cpuset for top app
+#endif
+
+// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error
 static int bg_schedboost_fd = -1;
 static int fg_schedboost_fd = -1;
-#endif
+static int ta_schedboost_fd = -1;
 
 /* Add tid to the scheduling group defined by the policy */
 static int add_tid_to_cgroup(int tid, int fd)
@@ -138,6 +141,8 @@
         ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC);
 
 #ifdef USE_SCHEDBOOST
+        filename = "/dev/stune/top-app/tasks";
+        ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
         filename = "/dev/stune/foreground/tasks";
         fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC);
         filename = "/dev/stune/tasks";
@@ -294,11 +299,11 @@
     case SP_AUDIO_APP:
     case SP_AUDIO_SYS:
         fd = fg_cpuset_fd;
-        boost_fd = bg_schedboost_fd;
+        boost_fd = fg_schedboost_fd;
         break;
     case SP_TOP_APP :
         fd = ta_cpuset_fd;
-        boost_fd = fg_schedboost_fd;
+        boost_fd = ta_schedboost_fd;
         break;
     case SP_SYSTEM:
         fd = system_bg_cpuset_fd;
@@ -313,10 +318,12 @@
             return -errno;
     }
 
+#ifdef USE_SCHEDBOOST
     if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
         if (errno != ESRCH && errno != ENOENT)
             return -errno;
     }
+#endif
 
     return 0;
 #endif
@@ -373,19 +380,26 @@
 #endif
 
     if (__sys_supports_schedgroups) {
-        int fd;
+        int fd = -1;
+        int boost_fd = -1;
         switch (policy) {
         case SP_BACKGROUND:
             fd = bg_cgroup_fd;
+            boost_fd = bg_schedboost_fd;
             break;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
+            fd = fg_cgroup_fd;
+            boost_fd = fg_schedboost_fd;
+            break;
         case SP_TOP_APP:
             fd = fg_cgroup_fd;
+            boost_fd = ta_schedboost_fd;
             break;
         default:
             fd = -1;
+            boost_fd = -1;
             break;
         }
 
@@ -394,6 +408,13 @@
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
+
+#ifdef USE_SCHEDBOOST
+        if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
+            if (errno != ESRCH && errno != ENOENT)
+                return -errno;
+        }
+#endif
     } else {
         struct sched_param param;
 
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 771d312..755e0d1 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -104,20 +104,21 @@
 {
     if (len == 0) return getEmptyString();
 
-    const ssize_t bytes = utf16_to_utf8_length(in, len);
-    if (bytes < 0) {
+     // Allow for closing '\0'
+    const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
+    if (resultStrLen < 1) {
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
 
-    char* str = (char*)buf->data();
-    utf16_to_utf8(in, len, str);
-    return str;
+    char* resultStr = (char*)buf->data();
+    utf16_to_utf8(in, len, resultStr, resultStrLen);
+    return resultStr;
 }
 
 static char* allocFromUTF32(const char32_t* in, size_t len)
@@ -126,21 +127,21 @@
         return getEmptyString();
     }
 
-    const ssize_t bytes = utf32_to_utf8_length(in, len);
-    if (bytes < 0) {
+    const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
+    if (resultStrLen < 1) {
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
 
-    char* str = (char*) buf->data();
-    utf32_to_utf8(in, len, str);
+    char* resultStr = (char*) buf->data();
+    utf32_to_utf8(in, len, resultStr, resultStrLen);
 
-    return str;
+    return resultStr;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index f1f8bc9..6e31ce4 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
+#include <log/log.h>
 #include <utils/Unicode.h>
 
 #include <stddef.h>
 
+#include <string>
+#include <sstream>
+
 #if defined(_WIN32)
 # undef  nhtol
 # undef  htonl
@@ -182,7 +186,7 @@
     return ret;
 }
 
-void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst)
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == NULL || src_len == 0 || dst == NULL) {
         return;
@@ -193,9 +197,12 @@
     char *cur = dst;
     while (cur_utf32 < end_utf32) {
         size_t len = utf32_codepoint_utf8_length(*cur_utf32);
+        LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
         utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len);
         cur += len;
+        dst_len -= len;
     }
+    LOG_ALWAYS_FATAL_IF(dst_len < 1, "dst_len < 1: %zu < 1", dst_len);
     *cur = '\0';
 }
 
@@ -348,7 +355,7 @@
            : 0);
 }
 
-void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst)
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == NULL || src_len == 0 || dst == NULL) {
         return;
@@ -369,9 +376,12 @@
             utf32 = (char32_t) *cur_utf16++;
         }
         const size_t len = utf32_codepoint_utf8_length(utf32);
+        LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
         utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len);
         cur += len;
+        dst_len -= len;
     }
+    LOG_ALWAYS_FATAL_IF(dst_len < 1, "%zu < 1", dst_len);
     *cur = '\0';
 }
 
@@ -422,8 +432,35 @@
     return ret;
 }
 
+// DO NOT USE. Flawed version, kept only to check whether the flaw is being exploited.
+static ssize_t flawed_utf16_to_utf8_length(const char16_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return 47;
+    }
+
+    size_t ret = 0;
+    const char16_t* const end = src + src_len;
+    while (src < end) {
+        if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
+                // Shouldn't increment src here as to be consistent with utf16_to_utf8
+                && (*++src & 0xFC00) == 0xDC00) {
+            // surrogate pairs are always 4 bytes.
+            ret += 4;
+            // Should increment src here by two.
+            src++;
+        } else {
+            ret += utf32_codepoint_utf8_length((char32_t) *src++);
+        }
+    }
+    return ret;
+}
+
 ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
 {
+    // Keep the original pointer to compute the flawed length. Unused if we remove logging.
+    const char16_t *orig_src = src;
+
     if (src == NULL || src_len == 0) {
         return -1;
     }
@@ -432,14 +469,27 @@
     const char16_t* const end = src + src_len;
     while (src < end) {
         if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
-                && (*++src & 0xFC00) == 0xDC00) {
+                && (*(src + 1) & 0xFC00) == 0xDC00) {
             // surrogate pairs are always 4 bytes.
             ret += 4;
-            src++;
+            src += 2;
         } else {
             ret += utf32_codepoint_utf8_length((char32_t) *src++);
         }
     }
+    // Log whether b/29250543 is being exploited. It seems reasonable to assume that
+    // at least 5 bytes would be needed for an exploit. A single misplaced character might lead to
+    // a difference of 4, so this would rule out many false positives.
+    long ret_difference = ret - flawed_utf16_to_utf8_length(orig_src, src_len);
+    if (ret_difference >= 5) {
+        // Log the difference between new and old calculation. A high number, or equal numbers
+        // appearing frequently, would be indicative of an attack.
+        std::ostringstream logged_string_stream;
+        logged_string_stream << ret_difference;
+        std::string logged_string = logged_string_stream.str();
+        android_errorWriteWithInfoLog(0x534e4554, "29250543", -1 /* int_uid */,
+            logged_string.c_str(), logged_string.length() + 1);
+    }
     return ret;
 }
 
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index 01e64f6..3947a5f 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "String8_test"
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/String16.h>
 
 #include <gtest/gtest.h>
 
@@ -77,4 +78,22 @@
     EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
 }
 
+// http://b/29250543
+TEST_F(String8Test, CorrectInvalidSurrogate) {
+    // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
+    // first character in the pair and handling the rest correctly.
+    String16 string16(u"\xd841\xd841\xdc41\x0000");
+    String8 string8(string16);
+
+    EXPECT_EQ(4U, string8.length());
+}
+
+TEST_F(String8Test, CheckUtf32Conversion) {
+    // Since bound checks were added, check the conversion can be done without fatal errors.
+    // The utf8 lengths of these are chars are 1 + 2 + 3 + 4 = 10.
+    const char32_t string32[] = U"\x0000007f\x000007ff\x0000911\x0010fffe";
+    String8 string8(string32);
+    EXPECT_EQ(10U, string8.length());
+}
+
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0e81bb2..fba0ba0 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -50,12 +50,16 @@
     mkdir /dev/stune
     mount cgroup none /dev/stune schedtune
     mkdir /dev/stune/foreground
+    mkdir /dev/stune/top-app
     chown system system /dev/stune
     chown system system /dev/stune/foreground
+    chown system system /dev/stune/top-app
     chown system system /dev/stune/tasks
     chown system system /dev/stune/foreground/tasks
+    chown system system /dev/stune/top-app/tasks
     chmod 0664 /dev/stune/tasks
     chmod 0664 /dev/stune/foreground/tasks
+    chmod 0664 /dev/stune/top-app/tasks
 
     # Mount staging areas for devices managed by vold
     # See storage config details at http://source.android.com/tech/storage/