merge in mnc-release history after reset to mnc-dev
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 2347028..23dcd62 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -463,19 +463,19 @@
 
         // Construct "SERVERS=<comma-separated string of DNS addresses>".
         static const char kServerTag[] = "SERVERS=";
-        static const int kTagLength = strlen(kServerTag);
+        static const size_t kTagLength = strlen(kServerTag);
         // Reserve sufficient space for an IPv6 link-local address: all but the
         // last address are followed by ','; the last is followed by '\0'.
-        static const int kMaxSingleAddressLength =
+        static const size_t kMaxSingleAddressLength =
                 INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
-        const int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
+        const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
         char *buf = (char *) malloc(bufsize);
         if (!buf) {
             SLOGE("RDNSS option: out of memory\n");
             return false;
         }
         strcpy(buf, kServerTag);
-        int pos = kTagLength;
+        size_t pos = kTagLength;
 
         struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
         for (int i = 0; i < numaddrs; i++) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2ac182b..9019b1f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -533,6 +533,7 @@
     class core
     critical
     seclabel u:r:healthd:s0
+    group root system
 
 service console /system/bin/sh
     class core
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index ba4d70c..41bf045 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -151,7 +151,7 @@
     perm_t perm;
     userid_t userid;
     uid_t uid;
-    mode_t mode;
+    bool under_android;
 
     struct node *next;          /* per-dir sibling list */
     struct node *child;         /* first contained file by this dir */
@@ -419,11 +419,20 @@
         attr->gid = multiuser_get_uid(node->userid, fuse->gid);
     }
 
-    /* Filter requested mode based on underlying file, and
-     * pass through file type. */
-    int visible_mode = node->mode;
-    if (node->perm != PERM_PRE_ROOT) {
-        visible_mode = visible_mode & ~fuse->mask;
+    int visible_mode = 0775 & ~fuse->mask;
+    if (node->perm == PERM_PRE_ROOT) {
+        /* Top of multi-user view should always be visible to ensure
+         * secondary users can traverse inside. */
+        visible_mode = 0711;
+    } else if (node->under_android) {
+        /* Block "other" access to Android directories, since only apps
+         * belonging to a specific user should be in there; we still
+         * leave +x open for the default view. */
+        if (fuse->gid == AID_SDCARD_RW) {
+            visible_mode = visible_mode & ~0006;
+        } else {
+            visible_mode = visible_mode & ~0007;
+        }
     }
     int owner_mode = s->st_mode & 0700;
     int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
@@ -452,7 +461,7 @@
     node->perm = PERM_INHERIT;
     node->userid = parent->userid;
     node->uid = parent->uid;
-    node->mode = parent->mode;
+    node->under_android = parent->under_android;
 
     /* Derive custom permissions based on parent and current node */
     switch (parent->perm) {
@@ -463,33 +472,28 @@
         /* Legacy internal layout places users at top level */
         node->perm = PERM_ROOT;
         node->userid = strtoul(node->name, NULL, 10);
-        node->mode = 0771;
         break;
     case PERM_ROOT:
         /* Assume masked off by default. */
-        node->mode = 0770;
         if (!strcasecmp(node->name, "Android")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID;
-            node->mode = 0771;
+            node->under_android = true;
         }
         break;
     case PERM_ANDROID:
         if (!strcasecmp(node->name, "data")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_DATA;
-            node->mode = 0771;
         } else if (!strcasecmp(node->name, "obb")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_OBB;
-            node->mode = 0771;
             /* Single OBB directory is always shared */
             node->graft_path = fuse->global->obb_path;
             node->graft_pathlen = strlen(fuse->global->obb_path);
         } else if (!strcasecmp(node->name, "media")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_MEDIA;
-            node->mode = 0771;
         }
         break;
     case PERM_ANDROID_DATA:
@@ -499,7 +503,6 @@
         if (appid != 0) {
             node->uid = multiuser_get_uid(parent->userid, appid);
         }
-        node->mode = 0770;
         break;
     }
 }
@@ -1730,6 +1733,7 @@
     ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
             "    -u: specify UID to run as\n"
             "    -g: specify GID to run as\n"
+            "    -U: specify user ID that owns device\n"
             "    -m: source_path is multi-user\n"
             "    -w: runtime_write mount has full write access\n"
             "\n");
@@ -1763,7 +1767,7 @@
 }
 
 static void run(const char* source_path, const char* label, uid_t uid,
-        gid_t gid, bool multi_user, bool full_write) {
+        gid_t gid, userid_t userid, bool multi_user, bool full_write) {
     struct fuse_global global;
     struct fuse fuse_default;
     struct fuse fuse_read;
@@ -1796,18 +1800,17 @@
     global.root.refcount = 2;
     global.root.namelen = strlen(source_path);
     global.root.name = strdup(source_path);
-    global.root.userid = 0;
+    global.root.userid = userid;
     global.root.uid = AID_ROOT;
+    global.root.under_android = false;
 
     strcpy(global.source_path, source_path);
 
     if (multi_user) {
         global.root.perm = PERM_PRE_ROOT;
-        global.root.mode = 0711;
         snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
     } else {
         global.root.perm = PERM_ROOT;
-        global.root.mode = 0771;
         snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
     }
 
@@ -1833,11 +1836,25 @@
 
     umask(0);
 
-    if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
-            || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
-            || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
-        ERROR("failed to fuse_setup\n");
-        exit(1);
+    if (multi_user) {
+        /* Multi-user storage is fully isolated per user, so "other"
+         * permissions are completely masked off. */
+        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+                || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
+                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
+            ERROR("failed to fuse_setup\n");
+            exit(1);
+        }
+    } else {
+        /* Physical storage is readable by all users on device, but
+         * the Android directories are masked off to a single user
+         * deep inside attr_from_stat(). */
+        if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+                || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
+                || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
+            ERROR("failed to fuse_setup\n");
+            exit(1);
+        }
     }
 
     /* Drop privs */
@@ -1875,6 +1892,7 @@
     const char *label = NULL;
     uid_t uid = 0;
     gid_t gid = 0;
+    userid_t userid = 0;
     bool multi_user = false;
     bool full_write = false;
     int i;
@@ -1882,7 +1900,7 @@
     int fs_version;
 
     int opt;
-    while ((opt = getopt(argc, argv, "u:g:mw")) != -1) {
+    while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
         switch (opt) {
             case 'u':
                 uid = strtoul(optarg, NULL, 10);
@@ -1890,6 +1908,9 @@
             case 'g':
                 gid = strtoul(optarg, NULL, 10);
                 break;
+            case 'U':
+                userid = strtoul(optarg, NULL, 10);
+                break;
             case 'm':
                 multi_user = true;
                 break;
@@ -1938,6 +1959,6 @@
         sleep(1);
     }
 
-    run(source_path, label, uid, gid, multi_user, full_write);
+    run(source_path, label, uid, gid, userid, multi_user, full_write);
     return 1;
 }