Merge "zygote/dex2oat: Grant additional symlink permissions"
diff --git a/adbd.te b/adbd.te
index 9d3d30d..c21e703 100644
--- a/adbd.te
+++ b/adbd.te
@@ -60,6 +60,14 @@
 allow adbd adb_keys_file:dir search;
 allow adbd adb_keys_file:file r_file_perms;
 
+userdebug_or_eng(`
+  # Write debugging information to /data/adb
+  # when persist.adb.trace_mask is set
+  # https://code.google.com/p/android/issues/detail?id=72895
+  allow adbd adb_data_file:dir rw_dir_perms;
+  allow adbd adb_data_file:file create_file_perms;
+')
+
 # ndk-gdb invokes adb forward to forward the gdbserver socket.
 allow adbd app_data_file:dir search;
 allow adbd app_data_file:sock_file write;
diff --git a/app.te b/app.te
index be3ead8..ea74cb0 100644
--- a/app.te
+++ b/app.te
@@ -19,7 +19,7 @@
 allow appdomain zygote_exec:file rx_file_perms;
 
 # gdbserver for ndk-gdb ptrace attaches to app process.
-allow appdomain self:process ptrace;
+allow { appdomain -isolated_app } self:process ptrace;
 
 # Read system properties managed by zygote.
 allow appdomain zygote_tmpfs:file read;
@@ -46,8 +46,8 @@
 allow appdomain surfaceflinger:unix_stream_socket { read write setopt getattr getopt shutdown };
 
 # App sandbox file accesses.
-allow { appdomain -isolated_app } app_data_file:dir create_dir_perms;
-allow { appdomain -isolated_app } app_data_file:notdevfile_class_set create_file_perms;
+allow appdomain app_data_file:dir create_dir_perms;
+allow appdomain app_data_file:notdevfile_class_set create_file_perms;
 
 # lib subdirectory of /data/data dir is system-owned.
 allow appdomain system_data_file:dir r_dir_perms;
@@ -284,7 +284,8 @@
 # Write to various other parts of /data.
 neverallow appdomain drm_data_file:dir_file_class_set
     { create write setattr relabelfrom relabelto append unlink link rename };
-neverallow appdomain gps_data_file:dir_file_class_set
+neverallow { appdomain -system_app }
+    gps_data_file:dir_file_class_set
     { create write setattr relabelfrom relabelto append unlink link rename };
 neverallow { appdomain -platform_app }
     apk_data_file:dir_file_class_set
diff --git a/device.te b/device.te
index c1f3d28..20e95a5 100644
--- a/device.te
+++ b/device.te
@@ -11,6 +11,7 @@
 type loop_device, dev_type;
 type radio_device, dev_type;
 type ram_device, dev_type;
+type vold_device, dev_type;
 type console_device, dev_type;
 type cpuctl_device, dev_type;
 type fscklogs, dev_type;
@@ -82,3 +83,8 @@
 
 # Block device for any swap partition.
 type swap_block_device, dev_type;
+
+# Metadata block device used for encryption metadata.
+# Assign this type to the partition specified by the encryptable=
+# mount option in your fstab file in the entry for userdata.
+type metadata_block_device, dev_type;
diff --git a/domain.te b/domain.te
index 86aeb07..3851506 100644
--- a/domain.te
+++ b/domain.te
@@ -170,8 +170,8 @@
 ### neverallow rules
 ###
 
-# Do not allow any confined domain to create new unlabeled files.
-neverallow { domain -unconfineddomain -recovery } unlabeled:dir_file_class_set create;
+# Do not allow any domain other than init or recovery to create unlabeled files.
+neverallow { domain -init -recovery } unlabeled:dir_file_class_set create;
 
 # Limit ability to ptrace or read sensitive /proc/pid files of processes
 # with other UIDs to these whitelisted domains.
@@ -231,7 +231,7 @@
 neverallow { domain -init } kernel:security setsecparam;
 
 # Only init, ueventd and system_server should be able to access HW RNG
-neverallow { domain -init -system_server -ueventd -unconfineddomain } hw_random_device:chr_file *;
+neverallow { domain -init -system_server -ueventd } hw_random_device:chr_file *;
 
 # Ensure that all entrypoint executables are in exec_type.
 neverallow domain { file_type -exec_type }:file entrypoint;
@@ -254,12 +254,13 @@
 
 # Don't allow raw read/write/open access to block_device
 # Rather force a relabel to a more specific type
-neverallow { domain -kernel -init -recovery -vold -uncrypt -install_recovery -fsck } block_device:blk_file { open read write };
+neverallow { domain -kernel -init -recovery -vold -uncrypt -install_recovery } block_device:blk_file { open read write };
 
 # Don't allow raw read/write/open access to generic devices.
 # Rather force a relabel to a more specific type.
-# ueventd is exempt from this, as its managing these devices.
-neverallow { domain -unconfineddomain -ueventd } device:chr_file { open read write };
+# init is exempt from this as there are character devices that only it uses.
+# ueventd is exempt from this, as it is managing these devices.
+neverallow { domain -init -ueventd } device:chr_file { open read write };
 
 # Limit what domains can mount filesystems or change their mount flags.
 # sdcard_type / vfat is exempt as a larger set of domains need
diff --git a/file.te b/file.te
index cc11677..5c91cf0 100644
--- a/file.te
+++ b/file.te
@@ -52,6 +52,8 @@
 type install_data_file, file_type, data_file_type;
 # /data/drm - DRM plugin data
 type drm_data_file, file_type, data_file_type;
+# /data/adb - adb debugging files
+type adb_data_file, file_type, data_file_type;
 # /data/anr - ANR traces
 type anr_data_file, file_type, data_file_type, mlstrustedobject;
 # /data/tombstones - core dumps
diff --git a/file_contexts b/file_contexts
index 2efd7e9..1d81cbf 100644
--- a/file_contexts
+++ b/file_contexts
@@ -40,7 +40,9 @@
 /dev/audio.*		u:object_r:audio_device:s0
 /dev/binder		u:object_r:binder_device:s0
 /dev/block(/.*)?	u:object_r:block_device:s0
+/dev/block/dm-[0-9]+	u:object_r:dm_device:s0
 /dev/block/loop[0-9]*	u:object_r:loop_device:s0
+/dev/block/vold/[0-9]+:[0-9]+	u:object_r:vold_device:s0
 /dev/block/ram[0-9]*	u:object_r:ram_device:s0
 /dev/bus/usb(.*)?       u:object_r:usb_device:s0
 /dev/cam		u:object_r:camera_device:s0
@@ -124,6 +126,7 @@
 #
 /system(/.*)?		u:object_r:system_file:s0
 /system/bin/e2fsck	--	u:object_r:fsck_exec:s0
+/system/bin/fsck\.f2fs	--	u:object_r:fsck_exec:s0
 /system/bin/toolbox	--	u:object_r:toolbox_exec:s0
 /system/bin/logcat	--	u:object_r:logcat_exec:s0
 /system/bin/sh		--	u:object_r:shell_exec:s0
@@ -186,6 +189,7 @@
 /data/resource-cache(/.*)? u:object_r:resourcecache_data_file:s0
 /data/dalvik-cache(/.*)? u:object_r:dalvikcache_data_file:s0
 /data/dalvik-cache/profiles(/.*)? u:object_r:dalvikcache_profiles_data_file:s0
+/data/adb(/.*)?		u:object_r:adb_data_file:s0
 /data/anr(/.*)?		u:object_r:anr_data_file:s0
 /data/app(/.*)?                       u:object_r:apk_data_file:s0
 /data/app/vmdl.*\.tmp(/.*)?           u:object_r:apk_tmp_file:s0
diff --git a/fsck.te b/fsck.te
index d255175..b4eb698 100644
--- a/fsck.te
+++ b/fsck.te
@@ -10,13 +10,9 @@
 allow fsck tmpfs:chr_file { read write ioctl };
 
 # Inherit and use pty created by android_fork_execvp_ext().
-allow fsck devpts:chr_file { read write ioctl };
+allow fsck devpts:chr_file { read write ioctl getattr };
 
 # Run e2fsck on block devices.
-# TODO:  Assign userdata and cache block device types to the corresponding
-# block devices in all device policies, and then remove access to
-# block_device:blk_file from here.
-allow fsck block_device:blk_file rw_file_perms;
 allow fsck userdata_block_device:blk_file rw_file_perms;
 allow fsck cache_block_device:blk_file rw_file_perms;
 
diff --git a/init.te b/init.te
index a6fadbd..cce2e41 100644
--- a/init.te
+++ b/init.te
@@ -102,6 +102,28 @@
 # set scheduling parameters for a kernel domain task.
 allow init kernel:process setsched;
 
+# swapon() needs write access to swap device
+# system/core/fs_mgr/fs_mgr.c - fs_mgr_swapon_all
+allow init swap_block_device:blk_file rw_file_perms;
+
+# Read from /dev/hw_random if present.
+# system/core/init/init.c - mix_hwrng_into_linux_rng_action
+allow init hw_random_device:chr_file r_file_perms;
+
+# Create and access /dev files without a specific type,
+# e.g. /dev/.coldboot_done.
+# TODO:  Move these files into their own type unless they are
+# only ever accessed by init.
+allow init device:file create_file_perms;
+auditallow init device:file create_file_perms;
+
+# Access character devices without a specific type,
+# e.g. /dev/keychord.
+# TODO: Move these devices into their own type unless they
+# are only ever accessed by init.
+allow init device:chr_file { rw_file_perms setattr };
+auditallow init device:chr_file { rw_file_perms setattr };
+
 ###
 ### neverallow rules
 ###
diff --git a/init_shell.te b/init_shell.te
deleted file mode 100644
index 51dbd07..0000000
--- a/init_shell.te
+++ /dev/null
@@ -1,10 +0,0 @@
-# Restricted domain for shell processes spawned by init.
-# Normally these are shell commands or scripts invoked via sh
-# from an init*.rc file.  No service should ever run in this domain.
-type init_shell, domain;
-domain_auto_trans(init, shell_exec, init_shell)
-permissive_or_unconfined(init_shell)
-
-# Run helpers from / or /system without changing domain.
-allow init_shell rootfs:file execute_no_trans;
-allow init_shell system_file:file execute_no_trans;
diff --git a/isolated_app.te b/isolated_app.te
index 6fc7a99..f17372a 100644
--- a/isolated_app.te
+++ b/isolated_app.te
@@ -12,12 +12,6 @@
 type isolated_app, domain;
 app_domain(isolated_app)
 
-# Access already open app data files received over Binder or local socket IPC.
-allow isolated_app app_data_file:file { read write getattr };
-
-# Isolated apps should not directly open app data files themselves.
-neverallow isolated_app app_data_file:file open;
-
 # Isolated apps shouldn't be able to access the driver directly.
 neverallow isolated_app gpu_device:file { rw_file_perms execute };
 
diff --git a/keystore.te b/keystore.te
index f2c5039..700b99b 100644
--- a/keystore.te
+++ b/keystore.te
@@ -21,8 +21,8 @@
 neverallow { domain -keystore } keystore_data_file:dir ~{ open create read getattr setattr search relabelto };
 neverallow { domain -keystore } keystore_data_file:notdevfile_class_set ~{ relabelto getattr };
 
-neverallow { domain -keystore -init -kernel -recovery } keystore_data_file:dir *;
-neverallow { domain -keystore -init -kernel -recovery } keystore_data_file:notdevfile_class_set *;
+neverallow { domain -keystore -init } keystore_data_file:dir *;
+neverallow { domain -keystore -init } keystore_data_file:notdevfile_class_set *;
 
 neverallow domain keystore:process ptrace;
 
diff --git a/logd.te b/logd.te
index ca6719a..70a894c 100644
--- a/logd.te
+++ b/logd.te
@@ -19,6 +19,8 @@
   allow logd logd_debug:file create_file_perms;
 ')
 
+allow logd kernel:system syslog_mod;
+
 ###
 ### Neverallow rules
 ###
diff --git a/recovery.te b/recovery.te
index 75a024c..204c096 100644
--- a/recovery.te
+++ b/recovery.te
@@ -29,7 +29,7 @@
 
   # We may be asked to set an SELinux label for a type not known to the
   # currently loaded policy. Allow it.
-  allow recovery unlabeled:file { create_file_perms relabelfrom relabelto };
+  allow recovery unlabeled:{ file lnk_file } { create_file_perms relabelfrom relabelto };
   allow recovery unlabeled:dir { create_dir_perms relabelfrom relabelto };
 
   # 0eb17d944704b3eb140bb9dded299d3be3aed77e in build/ added SELinux
diff --git a/system_server.te b/system_server.te
index 020f2ab..e1528f9 100644
--- a/system_server.te
+++ b/system_server.te
@@ -405,3 +405,10 @@
 # Do not allow accessing SDcard files as unsafe ejection could
 # cause the kernel to kill the system_server.
 neverallow system_server sdcard_type:file rw_file_perms;
+
+# system server should never be opening zygote spawned app data
+# files directly. Rather, they should always be passed via a
+# file descriptor.
+# Types extracted from seapp_contexts type= fields, excluding
+# those types that system_server needs to open directly.
+neverallow system_server { bluetooth_data_file nfc_data_file shell_data_file app_data_file }:file open;
diff --git a/tools/README b/tools/README
index 8a8dce1..2aa520a 100644
--- a/tools/README
+++ b/tools/README
@@ -94,3 +94,37 @@
     -foo -bar is expanded to individual allow rules by the policy
     compiler).  Domains with unconfineddomain will typically have such
     duplicate rules as a natural side effect and can be ignored.
+
+    PERMISSIVE DOMAINS
+    sepolicy-analyze -p -P out/target/product/<board>/root/sepolicy
+
+    Displays domains in the policy that are permissive, i.e. avc
+    denials are logged but not enforced for these domains.  While
+    permissive domains can be helpful during development, they
+    should not be present in a final -user build.
+
+    NEVERALLOW CHECKING
+    sepolicy-analyze [-w] [-z] -n neverallows.conf -P out/target/product/<board>/root/sepolicy
+
+    Check whether the sepolicy file violates any of the neverallow rules
+    from neverallows.conf.  neverallows.conf is a file containing neverallow
+    statements in the same format as the SELinux policy.conf file, i.e. after
+    m4 macro expansion of the rules from a .te file.  You can use an entire
+    policy.conf file as the neverallows.conf file and sepolicy-analyze will
+    ignore everything except for the neverallows within it.  If there are
+    no violations, sepolicy-analyze will exit successfully with no output.
+    Otherwise, sepolicy-analyze will report all violations and exit
+    with a non-zero exit status.
+
+    The -w or --warn option may be used to warn on any types, attributes,
+    classes, or permissions from a neverallow rule that could not be resolved
+    within the sepolicy file.  This can be normal due to differences between
+    the policy from which the neverallow rules were taken and the policy
+    being checked.  Such values are ignored for the purposes of neverallow
+    checking.
+
+    The -z (-d was already taken!) or --debug option may be used to cause
+    sepolicy-analyze to emit the neverallow rules as it parses them from
+    the neverallows.conf file.  This is principally a debugging facility
+    for the parser but could also be used to extract neverallow rules from
+    a full policy.conf file and output them in a more easily parsed format.
diff --git a/tools/sepolicy-analyze.c b/tools/sepolicy-analyze.c
index c9dab81..afebd69 100644
--- a/tools/sepolicy-analyze.c
+++ b/tools/sepolicy-analyze.c
@@ -12,10 +12,14 @@
 #include <sepol/policydb/expand.h>
 #include <sepol/policydb/util.h>
 #include <stdbool.h>
+#include <ctype.h>
+
+static int debug;
+static int warn;
 
 void usage(char *arg0)
 {
-    fprintf(stderr, "%s [-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive] -P <policy file>\n", arg0);
+    fprintf(stderr, "%s [-w|--warn] [-z|--debug] [-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive] [-n|--neverallow <neverallow file>] -P <policy file>\n", arg0);
     exit(1);
 }
 
@@ -425,24 +429,466 @@
     return 0;
 }
 
+static int read_typeset(policydb_t *policydb, char **ptr, char *end,
+                        type_set_t *typeset, uint32_t *flags)
+{
+    const char *keyword = "self";
+    size_t keyword_size = strlen(keyword), len;
+    char *p = *ptr;
+    unsigned openparens = 0;
+    char *start, *id;
+    type_datum_t *type;
+    struct ebitmap_node *n;
+    unsigned int bit;
+    bool negate = false;
+    int rc;
+
+    do {
+        while (p < end && isspace(*p))
+            p++;
+
+        if (p == end)
+            goto err;
+
+        if (*p == '~') {
+            if (debug)
+                printf(" ~");
+            typeset->flags = TYPE_COMP;
+            p++;
+            while (p < end && isspace(*p))
+                p++;
+            if (p == end)
+                goto err;
+        }
+
+        if (*p == '{') {
+            if (debug && !openparens)
+                printf(" {");
+            openparens++;
+            p++;
+            continue;
+        }
+
+        if (*p == '}') {
+            if (debug && openparens == 1)
+                printf(" }");
+            if (openparens == 0)
+                goto err;
+            openparens--;
+            p++;
+            continue;
+        }
+
+        if (*p == '*') {
+            if (debug)
+                printf(" *");
+            typeset->flags = TYPE_STAR;
+            p++;
+            continue;
+        }
+
+        if (*p == '-') {
+            if (debug)
+                printf(" -");
+            negate = true;
+            p++;
+            continue;
+        }
+
+        if (*p == '#') {
+            while (p < end && *p != '\n')
+                p++;
+            continue;
+        }
+
+        start = p;
+        while (p < end && !isspace(*p) && *p != ':' && *p != ';' && *p != '{' && *p != '}' && *p != '#')
+            p++;
+
+        if (p == start)
+            goto err;
+
+        len = p - start;
+        if (len == keyword_size && !strncmp(start, keyword, keyword_size)) {
+            if (debug)
+                printf(" self");
+            *flags |= RULE_SELF;
+            continue;
+        }
+
+        id = calloc(1, len + 1);
+        if (!id)
+            goto err;
+        memcpy(id, start, len);
+        if (debug)
+            printf(" %s", id);
+        type = hashtab_search(policydb->p_types.table, id);
+        if (!type) {
+            if (warn)
+                fprintf(stderr, "Warning!  Type or attribute %s used in neverallow undefined in policy being checked.\n", id);
+            negate = false;
+            continue;
+        }
+        free(id);
+
+        if (type->flavor == TYPE_ATTRIB) {
+            if (negate)
+                rc = ebitmap_union(&typeset->negset, &policydb->attr_type_map[type->s.value - 1]);
+            else
+                rc = ebitmap_union(&typeset->types, &policydb->attr_type_map[type->s.value - 1]);
+        } else if (negate) {
+            rc = ebitmap_set_bit(&typeset->negset, type->s.value - 1, 1);
+        } else {
+            rc = ebitmap_set_bit(&typeset->types, type->s.value - 1, 1);
+        }
+
+        negate = false;
+
+        if (rc)
+            goto err;
+
+    } while (p < end && openparens);
+
+    if (p == end)
+        goto err;
+
+    if (typeset->flags & TYPE_STAR) {
+        for (bit = 0; bit < policydb->p_types.nprim; bit++) {
+            if (ebitmap_get_bit(&typeset->negset, bit))
+                continue;
+            if (policydb->type_val_to_struct[bit] &&
+                policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB)
+                continue;
+            if (ebitmap_set_bit(&typeset->types, bit, 1))
+                goto err;
+        }
+    }
+
+    ebitmap_for_each_bit(&typeset->negset, n, bit) {
+        if (!ebitmap_node_get_bit(n, bit))
+            continue;
+        if (ebitmap_set_bit(&typeset->types, bit, 0))
+            goto err;
+    }
+
+    if (typeset->flags & TYPE_COMP) {
+        for (bit = 0; bit < policydb->p_types.nprim; bit++) {
+            if (policydb->type_val_to_struct[bit] &&
+                policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB)
+                continue;
+            if (ebitmap_get_bit(&typeset->types, bit))
+                ebitmap_set_bit(&typeset->types, bit, 0);
+            else {
+                if (ebitmap_set_bit(&typeset->types, bit, 1))
+                    goto err;
+            }
+        }
+    }
+
+    if (warn && ebitmap_length(&typeset->types) == 0 && !(*flags))
+        fprintf(stderr, "Warning!  Empty type set\n");
+
+    *ptr = p;
+    return 0;
+err:
+    return -1;
+}
+
+static int read_classperms(policydb_t *policydb, char **ptr, char *end,
+                           class_perm_node_t **perms)
+{
+    char *p = *ptr;
+    unsigned openparens = 0;
+    char *id, *start;
+    class_datum_t *cls = NULL;
+    perm_datum_t *perm = NULL;
+    class_perm_node_t *classperms = NULL, *node = NULL;
+    bool complement = false;
+
+    while (p < end && isspace(*p))
+        p++;
+
+    if (p == end || *p != ':')
+        goto err;
+    p++;
+
+    if (debug)
+        printf(" :");
+
+    do {
+        while (p < end && isspace(*p))
+            p++;
+
+        if (p == end)
+            goto err;
+
+        if (*p == '{') {
+            if (debug && !openparens)
+                printf(" {");
+            openparens++;
+            p++;
+            continue;
+        }
+
+        if (*p == '}') {
+            if (debug && openparens == 1)
+                printf(" }");
+            if (openparens == 0)
+                goto err;
+            openparens--;
+            p++;
+            continue;
+        }
+
+        if (*p == '#') {
+            while (p < end && *p != '\n')
+                p++;
+            continue;
+        }
+
+        start = p;
+        while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#')
+            p++;
+
+        if (p == start)
+            goto err;
+
+        id = calloc(1, p - start + 1);
+        if (!id)
+            goto err;
+        memcpy(id, start, p - start);
+        if (debug)
+            printf(" %s", id);
+        cls = hashtab_search(policydb->p_classes.table, id);
+        if (!cls) {
+            if (warn)
+                fprintf(stderr, "Warning!  Class %s used in neverallow undefined in policy being checked.\n", id);
+            continue;
+        }
+
+        node = calloc(1, sizeof *node);
+        if (!node)
+            goto err;
+        node->class = cls->s.value;
+        node->next = classperms;
+        classperms = node;
+        free(id);
+    } while (p < end && openparens);
+
+    if (p == end)
+        goto err;
+
+    if (warn && !classperms)
+        fprintf(stderr, "Warning!  Empty class set\n");
+
+    do {
+        while (p < end && isspace(*p))
+            p++;
+
+        if (p == end)
+            goto err;
+
+        if (*p == '~') {
+            if (debug)
+                printf(" ~");
+            complement = true;
+            p++;
+            while (p < end && isspace(*p))
+                p++;
+            if (p == end)
+                goto err;
+        }
+
+        if (*p == '{') {
+            if (debug && !openparens)
+                printf(" {");
+            openparens++;
+            p++;
+            continue;
+        }
+
+        if (*p == '}') {
+            if (debug && openparens == 1)
+                printf(" }");
+            if (openparens == 0)
+                goto err;
+            openparens--;
+            p++;
+            continue;
+        }
+
+        if (*p == '#') {
+            while (p < end && *p != '\n')
+                p++;
+            continue;
+        }
+
+        start = p;
+        while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#')
+            p++;
+
+        if (p == start)
+            goto err;
+
+        id = calloc(1, p - start + 1);
+        if (!id)
+            goto err;
+        memcpy(id, start, p - start);
+        if (debug)
+            printf(" %s", id);
+
+        if (!strcmp(id, "*")) {
+            for (node = classperms; node; node = node->next)
+                node->data = ~0;
+            continue;
+        }
+
+        for (node = classperms; node; node = node->next) {
+            cls = policydb->class_val_to_struct[node->class-1];
+            perm = hashtab_search(cls->permissions.table, id);
+            if (cls->comdatum && !perm)
+                perm = hashtab_search(cls->comdatum->permissions.table, id);
+            if (!perm) {
+                if (warn)
+                    fprintf(stderr, "Warning!  Permission %s used in neverallow undefined in class %s in policy being checked.\n", id, policydb->p_class_val_to_name[node->class-1]);
+                continue;
+            }
+            node->data |= 1U << (perm->s.value - 1);
+        }
+        free(id);
+    } while (p < end && openparens);
+
+    if (p == end)
+        goto err;
+
+    if (complement) {
+        for (node = classperms; node; node = node->next)
+            node->data = ~node->data;
+    }
+
+    if (warn) {
+        for (node = classperms; node; node = node->next)
+            if (!node->data)
+                fprintf(stderr, "Warning!  Empty permission set\n");
+    }
+
+    *perms = classperms;
+    *ptr = p;
+    return 0;
+err:
+    return -1;
+}
+
+static int check_neverallows(policydb_t *policydb, const char *filename)
+{
+    const char *keyword = "neverallow";
+    size_t keyword_size = strlen(keyword), len;
+    struct avrule *neverallows = NULL, *avrule;
+    int fd;
+    struct stat sb;
+    char *text, *end, *start;
+    char *p;
+
+    fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "Could not open %s:  %s\n", filename, strerror(errno));
+        return -1;
+    }
+    if (fstat(fd, &sb) < 0) {
+        fprintf(stderr, "Can't stat '%s':  %s\n", filename, strerror(errno));
+        close(fd);
+        return -1;
+    }
+    text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    end = text + sb.st_size;
+    if (text == MAP_FAILED) {
+        fprintf(stderr, "Can't mmap '%s':  %s\n", filename, strerror(errno));
+        close(fd);
+        return -1;
+    }
+    close(fd);
+
+    p = text;
+    while (p < end) {
+        while (p < end && isspace(*p))
+            p++;
+
+        if (*p == '#') {
+            while (p < end && *p != '\n')
+                p++;
+            continue;
+        }
+
+        start = p;
+        while (p < end && !isspace(*p))
+            p++;
+
+        len = p - start;
+        if (len != keyword_size || strncmp(start, keyword, keyword_size))
+            continue;
+
+        if (debug)
+            printf("neverallow");
+
+        avrule = calloc(1, sizeof *avrule);
+        if (!avrule)
+            goto err;
+
+        avrule->specified = AVRULE_NEVERALLOW;
+
+        if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags))
+            goto err;
+
+        if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags))
+            goto err;
+
+        if (read_classperms(policydb, &p, end, &avrule->perms))
+            goto err;
+
+        while (p < end && *p != ';')
+            p++;
+
+        if (p == end || *p != ';')
+            goto err;
+
+        if (debug)
+            printf(";\n");
+
+        avrule->next = neverallows;
+        neverallows = avrule;
+    }
+
+    return check_assertions(NULL, policydb, neverallows);
+err:
+    if (errno == ENOMEM) {
+        fprintf(stderr, "Out of memory while parsing %s\n", filename);
+    } else
+        fprintf(stderr, "Error while parsing %s\n", filename);
+    return -1;
+}
+
 int main(int argc, char **argv)
 {
-    char *policy = NULL;
+    char *policy = NULL, *neverallows = NULL;
     struct policy_file pf;
     policydb_t policydb;
     char ch;
     char equiv = 0, diff = 0, dups = 0, permissive = 0;
+    int rc = 0;
 
     struct option long_options[] = {
         {"equiv", no_argument, NULL, 'e'},
+        {"debug", no_argument, NULL, 'z'},
         {"diff", no_argument, NULL, 'd'},
         {"dups", no_argument, NULL, 'D'},
+        {"neverallow", required_argument, NULL, 'n'},
         {"permissive", no_argument, NULL, 'p'},
         {"policy", required_argument, NULL, 'P'},
+        {"warn", no_argument, NULL, 'w'},
         {NULL, 0, NULL, 0}
     };
 
-    while ((ch = getopt_long(argc, argv, "edDpP:", long_options, NULL)) != -1) {
+    while ((ch = getopt_long(argc, argv, "edDpn:P:wz", long_options, NULL)) != -1) {
         switch (ch) {
         case 'e':
             equiv = 1;
@@ -453,18 +899,27 @@
         case 'D':
             dups = 1;
             break;
+        case 'n':
+            neverallows = optarg;
+            break;
         case 'p':
             permissive = 1;
             break;
         case 'P':
             policy = optarg;
             break;
+        case 'w':
+            warn = 1;
+            break;
+        case 'z':
+            debug = 1;
+            break;
         default:
             usage(argv[0]);
         }
     }
 
-    if (!policy || (!equiv && !diff && !dups && !permissive))
+    if (!policy || (!equiv && !diff && !dups && !permissive && !neverallows))
         usage(argv[0]);
 
     if (load_policy(policy, &policydb, &pf))
@@ -479,7 +934,10 @@
     if (permissive)
         list_permissive(&policydb);
 
+    if (neverallows)
+        rc |= check_neverallows(&policydb, neverallows);
+
     policydb_destroy(&policydb);
 
-    return 0;
+    return rc;
 }
diff --git a/unconfined.te b/unconfined.te
index a76c3d8..1a51942 100644
--- a/unconfined.te
+++ b/unconfined.te
@@ -55,6 +55,7 @@
     -security_file
     -shell_data_file
     -app_data_file
+    -unlabeled
 }:{ dir lnk_file sock_file fifo_file } ~relabelto;
 allow unconfineddomain exec_type:dir r_dir_perms;
 allow unconfineddomain exec_type:file { r_file_perms execute };
@@ -69,8 +70,9 @@
     -contextmount_type
     -rootfs
     -sdcard_type
+    -device
 }:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
-allow unconfineddomain {dev_type -kmem_device}:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
+allow unconfineddomain {dev_type -device -kmem_device -hw_random_device}:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
 allow unconfineddomain {
     file_type
     -keystore_data_file
@@ -80,6 +82,7 @@
     -security_file
     -shell_data_file
     -app_data_file
+    -unlabeled
 }:{ chr_file file } ~{entrypoint execute_no_trans execmod execute relabelto};
 allow unconfineddomain rootfs:file execute;
 allow unconfineddomain contextmount_type:dir r_dir_perms;
diff --git a/untrusted_app.te b/untrusted_app.te
index 7e67ea8..2b2a2e7 100644
--- a/untrusted_app.te
+++ b/untrusted_app.te
@@ -101,4 +101,4 @@
 
 # Allow verifier to access staged apks.
 allow untrusted_app { apk_tmp_file apk_private_tmp_file }:dir r_dir_perms;
-allow untrusted_app { apk_tmp_file apk_private_tmp_file }:file r_file_perms;
\ No newline at end of file
+allow untrusted_app { apk_tmp_file apk_private_tmp_file }:file r_file_perms;
diff --git a/vold.te b/vold.te
index ef3924b..f605f8a 100644
--- a/vold.te
+++ b/vold.te
@@ -5,9 +5,11 @@
 init_daemon_domain(vold)
 
 typeattribute vold mlstrustedsubject;
+allow vold self:process setfscreate;
 allow vold system_file:file x_file_perms;
 allow vold block_device:dir create_dir_perms;
 allow vold block_device:blk_file create_file_perms;
+auditallow vold block_device:blk_file create_file_perms;
 allow vold device:dir write;
 allow vold devpts:chr_file rw_file_perms;
 allow vold rootfs:dir mounton;
@@ -22,8 +24,10 @@
 allow vold self:netlink_kobject_uevent_socket create_socket_perms;
 allow vold app_data_file:dir search;
 allow vold app_data_file:file rw_file_perms;
-allow vold loop_device:blk_file rw_file_perms;
+allow vold loop_device:blk_file create_file_perms;
+allow vold vold_device:blk_file create_file_perms;
 allow vold dm_device:chr_file rw_file_perms;
+allow vold dm_device:blk_file rw_file_perms;
 # For vold Process::killProcessesWithOpenFiles function.
 allow vold domain:dir r_dir_perms;
 allow vold domain:{ file lnk_file } r_file_perms;
@@ -94,4 +98,6 @@
 
 # Access userdata block device.
 allow vold userdata_block_device:blk_file rw_file_perms;
-auditallow vold userdata_block_device:blk_file rw_file_perms;
+
+# Access metadata block device used for encryption meta-data.
+allow vold metadata_block_device:blk_file rw_file_perms;