merge in jb-release history after reset to master
diff --git a/include/ion/ion.h b/include/ion/ion.h
new file mode 100644
index 0000000..879eab3
--- /dev/null
+++ b/include/ion/ion.h
@@ -0,0 +1,32 @@
+/*
+ *  ion.c
+ *
+ * Memory Allocator functions for ion
+ *
+ *   Copyright 2011 Google, Inc
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#include <linux/ion.h>
+
+int ion_open();
+int ion_close(int fd);
+int ion_alloc(int fd, size_t len, size_t align, unsigned int flags,
+              struct ion_handle **handle);
+int ion_free(int fd, struct ion_handle *handle);
+int ion_map(int fd, struct ion_handle *handle, size_t length, int prot,
+            int flags, off_t offset, unsigned char **ptr, int *map_fd);
+int ion_share(int fd, struct ion_handle *handle, int *share_fd);
+int ion_import(int fd, int share_fd, struct ion_handle **handle);
+
diff --git a/include/system/window.h b/include/system/window.h
index 1cc4a0a..9602445 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -18,6 +18,7 @@
 #define SYSTEM_CORE_INCLUDE_ANDROID_WINDOW_H
 
 #include <stdint.h>
+#include <string.h>
 #include <sys/cdefs.h>
 #include <system/graphics.h>
 #include <cutils/native_handle.h>
diff --git a/init/Android.mk b/init/Android.mk
index d71cbc4..b456e43 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -34,6 +34,12 @@
 
 LOCAL_STATIC_LIBRARIES := libcutils libc
 
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_STATIC_LIBRARIES += libselinux
+LOCAL_C_INCLUDES := external/libselinux/include
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif
+
 include $(BUILD_EXECUTABLE)
 
 # Make a symlink from /sbin/ueventd to /init
diff --git a/init/builtins.c b/init/builtins.c
index 3781dcd..9aa2345 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -33,6 +33,11 @@
 #include <cutils/partition_utils.h>
 #include <sys/system_properties.h>
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
+
 #include "init.h"
 #include "keywords.h"
 #include "property_service.h"
@@ -436,6 +441,28 @@
 
 }
 
+int do_setcon(int nargs, char **args) {
+#ifdef HAVE_SELINUX
+    if (is_selinux_enabled() <= 0)
+        return 0;
+    if (setcon(args[1]) < 0) {
+        return -errno;
+    }
+#endif
+    return 0;
+}
+
+int do_setenforce(int nargs, char **args) {
+#ifdef HAVE_SELINUX
+    if (is_selinux_enabled() <= 0)
+        return 0;
+    if (security_setenforce(atoi(args[1])) < 0) {
+        return -errno;
+    }
+#endif
+    return 0;
+}
+
 int do_setkey(int nargs, char **args)
 {
     struct kbentry kbe;
@@ -649,6 +676,64 @@
     return 0;
 }
 
+int do_restorecon(int nargs, char **args) {
+#ifdef HAVE_SELINUX
+    char *secontext = NULL;
+    struct stat sb;
+    int i;
+
+    if (is_selinux_enabled() <= 0 || !sehandle)
+        return 0;
+
+    for (i = 1; i < nargs; i++) {
+        if (lstat(args[i], &sb) < 0)
+            return -errno;
+        if (selabel_lookup(sehandle, &secontext, args[i], sb.st_mode) < 0)
+            return -errno;
+        if (lsetfilecon(args[i], secontext) < 0) {
+            freecon(secontext);
+            return -errno;
+        }
+        freecon(secontext);
+    }
+#endif
+    return 0;
+}
+
+int do_setsebool(int nargs, char **args) {
+#ifdef HAVE_SELINUX
+    SELboolean *b = alloca(nargs * sizeof(SELboolean));
+    char *v;
+    int i;
+
+    if (is_selinux_enabled() <= 0)
+        return 0;
+
+    for (i = 1; i < nargs; i++) {
+        char *name = args[i];
+        v = strchr(name, '=');
+        if (!v) {
+            ERROR("setsebool: argument %s had no =\n", name);
+            return -EINVAL;
+        }
+        *v++ = 0;
+        b[i-1].name = name;
+        if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
+            b[i-1].value = 1;
+        else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
+            b[i-1].value = 0;
+        else {
+            ERROR("setsebool: invalid value %s\n", v);
+            return -EINVAL;
+        }
+    }
+
+    if (security_set_boolean_list(nargs - 1, b, 0) < 0)
+        return -errno;
+#endif
+    return 0;
+}
+
 int do_loglevel(int nargs, char **args) {
     if (nargs == 2) {
         klog_set_level(atoi(args[1]));
diff --git a/init/devices.c b/init/devices.c
index a2f84aa..3b4d369 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -29,6 +29,12 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <linux/netlink.h>
+
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
+
 #include <private/android_filesystem_config.h>
 #include <sys/time.h>
 #include <asm/page.h>
@@ -45,6 +51,10 @@
 #define FIRMWARE_DIR1   "/etc/firmware"
 #define FIRMWARE_DIR2   "/vendor/firmware"
 
+#ifdef HAVE_SELINUX
+static struct selabel_handle *sehandle;
+#endif
+
 static int device_fd = -1;
 
 struct uevent {
@@ -180,8 +190,17 @@
     unsigned gid;
     mode_t mode;
     dev_t dev;
+#ifdef HAVE_SELINUX
+    char *secontext = NULL;
+#endif
 
     mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
+#ifdef HAVE_SELINUX
+    if (sehandle) {
+        selabel_lookup(sehandle, &secontext, path, mode);
+        setfscreatecon(secontext);
+    }
+#endif
     dev = makedev(major, minor);
     /* Temporarily change egid to avoid race condition setting the gid of the
      * device node. Unforunately changing the euid would prevent creation of
@@ -192,8 +211,40 @@
     mknod(path, mode, dev);
     chown(path, uid, -1);
     setegid(AID_ROOT);
+#ifdef HAVE_SELINUX
+    if (secontext) {
+        freecon(secontext);
+        setfscreatecon(NULL);
+    }
+#endif
 }
 
+
+static int make_dir(const char *path, mode_t mode)
+{
+    int rc;
+
+#ifdef HAVE_SELINUX
+    char *secontext = NULL;
+
+    if (sehandle) {
+        selabel_lookup(sehandle, &secontext, path, mode);
+        setfscreatecon(secontext);
+    }
+#endif
+
+    rc = mkdir(path, mode);
+
+#ifdef HAVE_SELINUX
+    if (secontext) {
+        freecon(secontext);
+        setfscreatecon(NULL);
+    }
+#endif
+    return rc;
+}
+
+
 static void add_platform_device(const char *name)
 {
     int name_len = strlen(name);
@@ -506,7 +557,7 @@
         return;
 
     snprintf(devpath, sizeof(devpath), "%s%s", base, name);
-    mkdir(base, 0755);
+    make_dir(base, 0755);
 
     if (!strncmp(uevent->path, "/devices/platform/", 18))
         links = parse_platform_block_device(uevent);
@@ -535,10 +586,10 @@
              int bus_id = uevent->minor / 128 + 1;
              int device_id = uevent->minor % 128 + 1;
              /* build directories */
-             mkdir("/dev/bus", 0755);
-             mkdir("/dev/bus/usb", 0755);
+             make_dir("/dev/bus", 0755);
+             make_dir("/dev/bus/usb", 0755);
              snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
-             mkdir(devpath, 0755);
+             make_dir(devpath, 0755);
              snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
          } else {
              /* ignore other USB events */
@@ -546,29 +597,29 @@
          }
      } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
          base = "/dev/graphics/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
          base = "/dev/oncrpc/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
          base = "/dev/adsp/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
          base = "/dev/msm_camera/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if(!strncmp(uevent->subsystem, "input", 5)) {
          base = "/dev/input/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
          base = "/dev/mtd/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if(!strncmp(uevent->subsystem, "sound", 5)) {
          base = "/dev/snd/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
      } else if(!strncmp(uevent->subsystem, "misc", 4) &&
                  !strncmp(name, "log_", 4)) {
          base = "/dev/log/";
-         mkdir(base, 0755);
+         make_dir(base, 0755);
          name += 4;
      } else
          base = "/dev/";
@@ -819,7 +870,14 @@
     suseconds_t t0, t1;
     struct stat info;
     int fd;
+#ifdef HAVE_SELINUX
+    struct selinux_opt seopts[] = {
+        { SELABEL_OPT_PATH, "/file_contexts" }
+    };
 
+    if (is_selinux_enabled() > 0)
+        sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+#endif
     /* is 64K enough? udev uses 16MB! */
     device_fd = uevent_open_socket(64*1024, true);
     if(device_fd < 0)
diff --git a/init/init.c b/init/init.c
index c3be93d..71c28b5 100755
--- a/init/init.c
+++ b/init/init.c
@@ -31,6 +31,13 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+
+#ifdef HAVE_SELINUX
+#include <sys/mman.h>
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
+
 #include <libgen.h>
 
 #include <cutils/list.h>
@@ -52,6 +59,10 @@
 #include "util.h"
 #include "ueventd.h"
 
+#ifdef HAVE_SELINUX
+struct selabel_handle *sehandle;
+#endif
+
 static int property_triggers_enabled = 0;
 
 #if BOOTCHART
@@ -64,6 +75,11 @@
 static unsigned revision = 0;
 static char qemu[32];
 
+#ifdef HAVE_SELINUX
+static int selinux_enabled = 1;
+static int selinux_enforcing = 0;
+#endif
+
 static struct action *cur_action = NULL;
 static struct command *cur_command = NULL;
 static struct listnode *command_queue = NULL;
@@ -145,7 +161,10 @@
     pid_t pid;
     int needs_console;
     int n;
-
+#ifdef HAVE_SELINUX
+    char *scon = NULL;
+    int rc;
+#endif
         /* starting a service removes it from the disabled or reset
          * state and immediately takes it out of the restarting
          * state if it was in there
@@ -182,6 +201,34 @@
         return;
     }
 
+#ifdef HAVE_SELINUX
+    if (is_selinux_enabled() > 0) {
+        char *mycon = NULL, *fcon = NULL;
+
+        INFO("computing context for service '%s'\n", svc->args[0]);
+        rc = getcon(&mycon);
+        if (rc < 0) {
+            ERROR("could not get context while starting '%s'\n", svc->name);
+            return;
+        }
+
+        rc = getfilecon(svc->args[0], &fcon);
+        if (rc < 0) {
+            ERROR("could not get context while starting '%s'\n", svc->name);
+            freecon(mycon);
+            return;
+        }
+
+        rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
+        freecon(mycon);
+        freecon(fcon);
+        if (rc < 0) {
+            ERROR("could not get context while starting '%s'\n", svc->name);
+            return;
+        }
+    }
+#endif
+
     NOTICE("starting '%s'\n", svc->name);
 
     pid = fork();
@@ -201,6 +248,10 @@
         for (ei = svc->envvars; ei; ei = ei->next)
             add_environment(ei->name, ei->value);
 
+#ifdef HAVE_SELINUX
+        setsockcreatecon(scon);
+#endif
+
         for (si = svc->sockets; si; si = si->next) {
             int socket_type = (
                     !strcmp(si->type, "stream") ? SOCK_STREAM :
@@ -212,6 +263,12 @@
             }
         }
 
+#ifdef HAVE_SELINUX
+        freecon(scon);
+        scon = NULL;
+        setsockcreatecon(NULL);
+#endif
+
         if (svc->ioprio_class != IoSchedClass_NONE) {
             if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
                 ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
@@ -257,6 +314,15 @@
             }
         }
 
+#ifdef HAVE_SELINUX
+        if (svc->seclabel) {
+            if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
+                ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
+                _exit(127);
+            }
+        }
+#endif
+
         if (!dynamic_args) {
             if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
                 ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
@@ -282,6 +348,10 @@
         _exit(127);
     }
 
+#ifdef HAVE_SELINUX
+    freecon(scon);
+#endif
+
     if (pid < 0) {
         ERROR("failed to start '%s'\n", svc->name);
         svc->pid = 0;
@@ -531,6 +601,14 @@
     *value++ = 0;
     if (name_len == 0) return;
 
+#ifdef HAVE_SELINUX
+    if (!strcmp(name,"enforcing")) {
+        selinux_enforcing = atoi(value);
+    } else if (!strcmp(name,"selinux")) {
+        selinux_enabled = atoi(value);
+    }
+#endif
+
     if (for_emulator) {
         /* in the emulator, export any kernel option with the
          * ro.kernel. prefix */
@@ -678,6 +756,97 @@
 }
 #endif
 
+#ifdef HAVE_SELINUX
+void selinux_load_policy(void)
+{
+    const char path_prefix[] = "/sepolicy";
+    struct selinux_opt seopts[] = {
+        { SELABEL_OPT_PATH, "/file_contexts" }
+    };
+    char path[PATH_MAX];
+    int fd, rc, vers;
+    struct stat sb;
+    void *map;
+
+    sehandle = NULL;
+    if (!selinux_enabled) {
+        INFO("SELinux:  Disabled by command line option\n");
+        return;
+    }
+
+    mkdir(SELINUXMNT, 0755);
+    if (mount("selinuxfs", SELINUXMNT, "selinuxfs", 0, NULL)) {
+        if (errno == ENODEV) {
+            /* SELinux not enabled in kernel */
+            return;
+        }
+        ERROR("SELinux:  Could not mount selinuxfs:  %s\n",
+              strerror(errno));
+        return;
+    }
+    set_selinuxmnt(SELINUXMNT);
+
+    vers = security_policyvers();
+    if (vers <= 0) {
+        ERROR("SELinux:  Unable to read policy version\n");
+        return;
+    }
+    INFO("SELinux:  Maximum supported policy version:  %d\n", vers);
+
+    snprintf(path, sizeof(path), "%s.%d",
+             path_prefix, vers);
+    fd = open(path, O_RDONLY);
+    while (fd < 0 && errno == ENOENT && --vers) {
+        snprintf(path, sizeof(path), "%s.%d",
+                 path_prefix, vers);
+        fd = open(path, O_RDONLY);
+    }
+    if (fd < 0) {
+        ERROR("SELinux:  Could not open %s:  %s\n",
+              path, strerror(errno));
+        return;
+    }
+    if (fstat(fd, &sb) < 0) {
+        ERROR("SELinux:  Could not stat %s:  %s\n",
+              path, strerror(errno));
+        return;
+    }
+    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+        ERROR("SELinux:  Could not map %s:  %s\n",
+              path, strerror(errno));
+        return;
+    }
+
+    rc = security_load_policy(map, sb.st_size);
+    if (rc < 0) {
+        ERROR("SELinux:  Could not load policy:  %s\n",
+              strerror(errno));
+        return;
+    }
+
+    rc = security_setenforce(selinux_enforcing);
+    if (rc < 0) {
+        ERROR("SELinux:  Could not set enforcing mode to %s:  %s\n",
+              selinux_enforcing ? "enforcing" : "permissive", strerror(errno));
+        return;
+    }
+
+    munmap(map, sb.st_size);
+    close(fd);
+    INFO("SELinux: Loaded policy from %s\n", path);
+
+    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+    if (!sehandle) {
+        ERROR("SELinux:  Could not load file_contexts:  %s\n",
+              strerror(errno));
+        return;
+    }
+    INFO("SELinux: Loaded file contexts from %s\n", seopts[0].value);
+    return;
+}
+#endif
+
 int main(int argc, char **argv)
 {
     int fd_count = 0;
@@ -728,6 +897,11 @@
 
     process_kernel_cmdline();
 
+#ifdef HAVE_SELINUX
+    INFO("loading selinux policy\n");
+    selinux_load_policy();
+#endif
+
     is_charger = !strcmp(bootmode, "charger");
 
     INFO("property init\n");
diff --git a/init/init.h b/init/init.h
index a91d9d4..58bbbfe 100644
--- a/init/init.h
+++ b/init/init.h
@@ -95,6 +95,10 @@
     gid_t supp_gids[NR_SVC_SUPP_GIDS];
     size_t nr_supp_gids;
 
+#ifdef HAVE_SELINUX
+    char *seclabel;
+#endif
+
     struct socketinfo *sockets;
     struct svcenvinfo *envvars;
 
@@ -132,4 +136,8 @@
 
 int load_565rle_image( char *file_name );
 
+#ifdef HAVE_SELINUX
+extern struct selabel_handle *sehandle;
+#endif
+
 #endif	/* _INIT_INIT_H */
diff --git a/init/init_parser.c b/init/init_parser.c
index d255db9..f538450 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -131,15 +131,20 @@
         break;
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
+        if (!strcmp(s, "estorecon")) return K_restorecon;
         if (!strcmp(s, "mdir")) return K_rmdir;
         if (!strcmp(s, "m")) return K_rm;
         break;
     case 's':
+        if (!strcmp(s, "eclabel")) return K_seclabel;
         if (!strcmp(s, "ervice")) return K_service;
+        if (!strcmp(s, "etcon")) return K_setcon;
+        if (!strcmp(s, "etenforce")) return K_setenforce;
         if (!strcmp(s, "etenv")) return K_setenv;
         if (!strcmp(s, "etkey")) return K_setkey;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
+        if (!strcmp(s, "etsebool")) return K_setsebool;
         if (!strcmp(s, "ocket")) return K_socket;
         if (!strcmp(s, "tart")) return K_start;
         if (!strcmp(s, "top")) return K_stop;
@@ -792,6 +797,16 @@
             svc->uid = decode_uid(args[1]);
         }
         break;
+    case K_seclabel:
+#ifdef HAVE_SELINUX
+        if (nargs != 2) {
+            parse_error(state, "seclabel option requires a label string\n");
+        } else {
+            svc->seclabel = args[1];
+        }
+#endif
+        break;
+
     default:
         parse_error(state, "invalid option '%s'\n", args[0]);
     }
diff --git a/init/keywords.h b/init/keywords.h
index 3e3733f..307c084 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -14,11 +14,15 @@
 int do_mkdir(int nargs, char **args);
 int do_mount(int nargs, char **args);
 int do_restart(int nargs, char **args);
+int do_restorecon(int nargs, char **args);
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
+int do_setcon(int nargs, char **args);
+int do_setenforce(int nargs, char **args);
 int do_setkey(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
+int do_setsebool(int nargs, char **args);
 int do_start(int nargs, char **args);
 int do_stop(int nargs, char **args);
 int do_trigger(int nargs, char **args);
@@ -61,13 +65,18 @@
     KEYWORD(oneshot,     OPTION,  0, 0)
     KEYWORD(onrestart,   OPTION,  0, 0)
     KEYWORD(restart,     COMMAND, 1, do_restart)
+    KEYWORD(restorecon,  COMMAND, 1, do_restorecon)
     KEYWORD(rm,          COMMAND, 1, do_rm)
     KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
+    KEYWORD(seclabel,    OPTION,  0, 0)
     KEYWORD(service,     SECTION, 0, 0)
+    KEYWORD(setcon,      COMMAND, 1, do_setcon)
+    KEYWORD(setenforce,  COMMAND, 1, do_setenforce)
     KEYWORD(setenv,      OPTION,  2, 0)
     KEYWORD(setkey,      COMMAND, 0, do_setkey)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
+    KEYWORD(setsebool,   COMMAND, 1, do_setsebool)
     KEYWORD(socket,      OPTION,  0, 0)
     KEYWORD(start,       COMMAND, 1, do_start)
     KEYWORD(stop,        COMMAND, 1, do_stop)
diff --git a/init/util.c b/init/util.c
index cb00f84..7d79f39 100755
--- a/init/util.c
+++ b/init/util.c
@@ -23,6 +23,10 @@
 #include <errno.h>
 #include <time.h>
 
+#ifdef HAVE_SELINUX
+#include <selinux/label.h>
+#endif
+
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -33,6 +37,7 @@
 
 #include <private/android_filesystem_config.h>
 
+#include "init.h"
 #include "log.h"
 #include "util.h"
 
@@ -84,6 +89,9 @@
 {
     struct sockaddr_un addr;
     int fd, ret;
+#ifdef HAVE_SELINUX
+    char *secon;
+#endif
 
     fd = socket(PF_UNIX, type, 0);
     if (fd < 0) {
@@ -102,12 +110,26 @@
         goto out_close;
     }
 
+#ifdef HAVE_SELINUX
+    secon = NULL;
+    if (sehandle) {
+        ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
+        if (ret == 0)
+            setfscreatecon(secon);
+    }
+#endif
+
     ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
     if (ret) {
         ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
         goto out_unlink;
     }
 
+#ifdef HAVE_SELINUX
+    setfscreatecon(NULL);
+    freecon(secon);
+#endif
+
     chown(addr.sun_path, uid, gid);
     chmod(addr.sun_path, perm);
 
diff --git a/libion/Android.mk b/libion/Android.mk
new file mode 100644
index 0000000..6abac3c
--- /dev/null
+++ b/libion/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ion.c
+LOCAL_MODULE := libion
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := liblog
+include $(BUILD_HEAPTRACKED_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ion.c ion_test.c
+LOCAL_MODULE := iontest
+LOCAL_MODULE_TAGS := optional tests
+LOCAL_SHARED_LIBRARIES := liblog
+include $(BUILD_HEAPTRACKED_EXECUTABLE)
diff --git a/libion/ion.c b/libion/ion.c
new file mode 100644
index 0000000..dbeac23
--- /dev/null
+++ b/libion/ion.c
@@ -0,0 +1,134 @@
+/*
+ *  ion.c
+ *
+ * Memory Allocator functions for ion
+ *
+ *   Copyright 2011 Google, Inc
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+#define LOG_TAG "ion"
+
+#include <cutils/log.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <linux/ion.h>
+#include <ion/ion.h>
+
+int ion_open()
+{
+        int fd = open("/dev/ion", O_RDWR);
+        if (fd < 0)
+                ALOGE("open /dev/ion failed!\n");
+        return fd;
+}
+
+int ion_close(int fd)
+{
+        return close(fd);
+}
+
+static int ion_ioctl(int fd, int req, void *arg)
+{
+        int ret = ioctl(fd, req, arg);
+        if (ret < 0) {
+                ALOGE("ioctl %x failed with code %d: %s\n", req,
+                       ret, strerror(errno));
+                return -errno;
+        }
+        return ret;
+}
+
+int ion_alloc(int fd, size_t len, size_t align, unsigned int flags,
+              struct ion_handle **handle)
+{
+        int ret;
+        struct ion_allocation_data data = {
+                .len = len,
+                .align = align,
+                .flags = flags,
+        };
+
+        ret = ion_ioctl(fd, ION_IOC_ALLOC, &data);
+        if (ret < 0)
+                return ret;
+        *handle = data.handle;
+        return ret;
+}
+
+int ion_free(int fd, struct ion_handle *handle)
+{
+        struct ion_handle_data data = {
+                .handle = handle,
+        };
+        return ion_ioctl(fd, ION_IOC_FREE, &data);
+}
+
+int ion_map(int fd, struct ion_handle *handle, size_t length, int prot,
+            int flags, off_t offset, unsigned char **ptr, int *map_fd)
+{
+        struct ion_fd_data data = {
+                .handle = handle,
+        };
+
+        int ret = ion_ioctl(fd, ION_IOC_MAP, &data);
+        if (ret < 0)
+                return ret;
+        *map_fd = data.fd;
+        if (*map_fd < 0) {
+                ALOGE("map ioctl returned negative fd\n");
+                return -EINVAL;
+        }
+        *ptr = mmap(NULL, length, prot, flags, *map_fd, offset);
+        if (*ptr == MAP_FAILED) {
+                ALOGE("mmap failed: %s\n", strerror(errno));
+                return -errno;
+        }
+        return ret;
+}
+
+int ion_share(int fd, struct ion_handle *handle, int *share_fd)
+{
+        int map_fd;
+        struct ion_fd_data data = {
+                .handle = handle,
+        };
+
+        int ret = ion_ioctl(fd, ION_IOC_SHARE, &data);
+        if (ret < 0)
+                return ret;
+        *share_fd = data.fd;
+        if (*share_fd < 0) {
+                ALOGE("share ioctl returned negative fd\n");
+                return -EINVAL;
+        }
+        return ret;
+}
+
+int ion_import(int fd, int share_fd, struct ion_handle **handle)
+{
+        struct ion_fd_data data = {
+                .fd = share_fd,
+        };
+
+        int ret = ion_ioctl(fd, ION_IOC_IMPORT, &data);
+        if (ret < 0)
+                return ret;
+        *handle = data.handle;
+        return ret;
+}
diff --git a/libion/ion_test.c b/libion/ion_test.c
new file mode 100644
index 0000000..3f2d7cc
--- /dev/null
+++ b/libion/ion_test.c
@@ -0,0 +1,282 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <ion/ion.h>
+#include <linux/ion.h>
+#include <linux/omap_ion.h>
+
+size_t len = 1024*1024, align = 0;
+int prot = PROT_READ | PROT_WRITE;
+int map_flags = MAP_SHARED;
+int alloc_flags = 0;
+int test = -1;
+size_t width = 1024*1024, height = 1024*1024;
+size_t stride;
+
+int _ion_alloc_test(int *fd, struct ion_handle **handle)
+{
+	int ret;
+
+	*fd = ion_open();
+	if (*fd < 0)
+		return *fd;
+
+	ret = ion_alloc(*fd, len, align, alloc_flags, handle);
+
+	if (ret)
+		printf("%s failed: %s\n", __func__, strerror(ret));
+	return ret;
+}
+
+void ion_alloc_test()
+{
+	int fd, ret;
+	struct ion_handle *handle;
+
+	if(_ion_alloc_test(&fd, &handle))
+			return;
+
+	ret = ion_free(fd, handle);
+	if (ret) {
+		printf("%s failed: %s %p\n", __func__, strerror(ret), handle);
+		return;
+	}
+	ion_close(fd);
+	printf("ion alloc test: passed\n");
+}
+
+void ion_map_test()
+{
+	int fd, map_fd, ret;
+	size_t i;
+	struct ion_handle *handle;
+	unsigned char *ptr;
+
+	if(_ion_alloc_test(&fd, &handle))
+		return;
+
+	ret = ion_map(fd, handle, len, prot, map_flags, 0, &ptr, &map_fd);
+	if (ret)
+		return;
+
+	for (i = 0; i < len; i++) {
+		ptr[i] = (unsigned char)i;
+	}
+	for (i = 0; i < len; i++)
+		if (ptr[i] != (unsigned char)i)
+			printf("%s failed wrote %d read %d from mapped "
+			       "memory\n", __func__, i, ptr[i]);
+	/* clean up properly */
+	ret = ion_free(fd, handle);
+	ion_close(fd);
+	munmap(ptr, len);
+	close(map_fd);
+
+	_ion_alloc_test(&fd, &handle);
+	close(fd);
+
+#if 0
+	munmap(ptr, len);
+	close(map_fd);
+	ion_close(fd);
+
+	_ion_alloc_test(len, align, flags, &fd, &handle);
+	close(map_fd);
+	ret = ion_map(fd, handle, len, prot, flags, 0, &ptr, &map_fd);
+	/* don't clean up */
+#endif
+}
+
+void ion_share_test()
+
+{
+	struct ion_handle *handle;
+	int sd[2];
+	int num_fd = 1;
+	struct iovec count_vec = {
+		.iov_base = &num_fd,
+		.iov_len = sizeof num_fd,
+	};
+	char buf[CMSG_SPACE(sizeof(int))];
+	socketpair(AF_UNIX, SOCK_STREAM, 0, sd);
+	if (fork()) {
+		struct msghdr msg = {
+			.msg_control = buf,
+			.msg_controllen = sizeof buf,
+			.msg_iov = &count_vec,
+			.msg_iovlen = 1,
+		};
+
+		struct cmsghdr *cmsg;
+		int fd, share_fd, ret;
+		char *ptr;
+		/* parent */
+		if(_ion_alloc_test(&fd, &handle))
+			return;
+		ret = ion_share(fd, handle, &share_fd);
+		if (ret)
+			printf("share failed %s\n", strerror(errno));
+		ptr = mmap(NULL, len, prot, map_flags, share_fd, 0);
+		if (ptr == MAP_FAILED) {
+			return;
+		}
+		strcpy(ptr, "master");
+		cmsg = CMSG_FIRSTHDR(&msg);
+		cmsg->cmsg_level = SOL_SOCKET;
+		cmsg->cmsg_type = SCM_RIGHTS;
+		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+		*(int *)CMSG_DATA(cmsg) = share_fd;
+		/* send the fd */
+		printf("master? [%10s] should be [master]\n", ptr);
+		printf("master sending msg 1\n");
+		sendmsg(sd[0], &msg, 0);
+		if (recvmsg(sd[0], &msg, 0) < 0)
+			perror("master recv msg 2");
+		printf("master? [%10s] should be [child]\n", ptr);
+
+		/* send ping */
+		sendmsg(sd[0], &msg, 0);
+		printf("master->master? [%10s]\n", ptr);
+		if (recvmsg(sd[0], &msg, 0) < 0)
+			perror("master recv 1");
+	} else {
+		struct msghdr msg;
+		struct cmsghdr *cmsg;
+		char* ptr;
+		int fd, recv_fd;
+		char* child_buf[100];
+		/* child */
+		struct iovec count_vec = {
+			.iov_base = child_buf,
+			.iov_len = sizeof child_buf,
+		};
+
+		struct msghdr child_msg = {
+			.msg_control = buf,
+			.msg_controllen = sizeof buf,
+			.msg_iov = &count_vec,
+			.msg_iovlen = 1,
+		};
+
+		if (recvmsg(sd[1], &child_msg, 0) < 0)
+			perror("child recv msg 1");
+		cmsg = CMSG_FIRSTHDR(&child_msg);
+		if (cmsg == NULL) {
+			printf("no cmsg rcvd in child");
+			return;
+		}
+		recv_fd = *(int*)CMSG_DATA(cmsg);
+		if (recv_fd < 0) {
+			printf("could not get recv_fd from socket");
+			return;
+		}
+		printf("child %d\n", recv_fd);
+		fd = ion_open();
+		ptr = mmap(NULL, len, prot, map_flags, recv_fd, 0);
+		if (ptr == MAP_FAILED) {
+			return;
+		}
+		printf("child? [%10s] should be [master]\n", ptr);
+		strcpy(ptr, "child");
+		printf("child sending msg 2\n");
+		sendmsg(sd[1], &child_msg, 0);
+	}
+}
+
+int main(int argc, char* argv[]) {
+	int c;
+	enum tests {
+		ALLOC_TEST = 0, MAP_TEST, SHARE_TEST,
+	};
+
+	while (1) {
+		static struct option opts[] = {
+			{"alloc", no_argument, 0, 'a'},
+			{"alloc_flags", required_argument, 0, 'f'},
+			{"map", no_argument, 0, 'm'},
+			{"share", no_argument, 0, 's'},
+			{"len", required_argument, 0, 'l'},
+			{"align", required_argument, 0, 'g'},
+			{"map_flags", required_argument, 0, 'z'},
+			{"prot", required_argument, 0, 'p'},
+			{"width", required_argument, 0, 'w'},
+			{"height", required_argument, 0, 'h'},
+		};
+		int i = 0;
+		c = getopt_long(argc, argv, "af:h:l:mr:stw:", opts, &i);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'l':
+			len = atol(optarg);
+			break;
+		case 'g':
+			align = atol(optarg);
+			break;
+		case 'z':
+			map_flags = 0;
+			map_flags |= strstr(optarg, "PROT_EXEC") ?
+				PROT_EXEC : 0;
+			map_flags |= strstr(optarg, "PROT_READ") ?
+				PROT_READ: 0;
+			map_flags |= strstr(optarg, "PROT_WRITE") ?
+				PROT_WRITE: 0;
+			map_flags |= strstr(optarg, "PROT_NONE") ?
+				PROT_NONE: 0;
+			break;
+		case 'p':
+			prot = 0;
+			prot |= strstr(optarg, "MAP_PRIVATE") ?
+				MAP_PRIVATE	 : 0;
+			prot |= strstr(optarg, "MAP_SHARED") ?
+				MAP_PRIVATE	 : 0;
+			break;
+		case 'f':
+			alloc_flags = atol(optarg);
+			break;
+		case 'a':
+			test = ALLOC_TEST;
+			break;
+		case 'm':
+			test = MAP_TEST;
+			break;
+		case 's':
+			test = SHARE_TEST;
+			break;
+		case 'w':
+			width = atol(optarg);
+			break;
+		case 'h':
+			height = atol(optarg);
+			break;
+		}
+	}
+	printf("test %d, len %u, width %u, height %u align %u, "
+		   "map_flags %d, prot %d, alloc_flags %d\n", test, len, width,
+		   height, align, map_flags, prot, alloc_flags);
+	switch (test) {
+		case ALLOC_TEST:
+			ion_alloc_test();
+			break;
+		case MAP_TEST:
+			ion_map_test();
+			break;
+		case SHARE_TEST:
+			ion_share_test();
+			break;
+		default:
+			printf("must specify a test (alloc, map, share)\n");
+	}
+	return 0;
+}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index ae56c41..b71ce86 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -253,7 +253,7 @@
     int max = 0;
     int ret;
     int queued_lines = 0;
-    bool sleep = true;
+    bool sleep = false;
 
     int result;
     fd_set readset;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 7e20448..be95e7c 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -58,6 +58,21 @@
 	lsof \
 	md5
 
+ifeq ($(HAVE_SELINUX),true)
+
+TOOLS += \
+	getenforce \
+	setenforce \
+	chcon \
+	restorecon \
+	runcon \
+	getsebool \
+	setsebool \
+	load_policy
+
+endif
+
+
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
 TOOLS += r
 endif
@@ -71,6 +86,14 @@
 
 LOCAL_C_INCLUDES := bionic/libc/bionic
 
+ifeq ($(HAVE_SELINUX),true)
+
+LOCAL_CFLAGS += -DHAVE_SELINUX
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_C_INCLUDES += external/libselinux/include
+
+endif
+
 LOCAL_MODULE:= toolbox
 
 # Including this will define $(intermediates).
diff --git a/toolbox/chcon.c b/toolbox/chcon.c
new file mode 100644
index 0000000..d594b9b
--- /dev/null
+++ b/toolbox/chcon.c
@@ -0,0 +1,25 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+int chcon_main(int argc, char **argv)
+{
+    int rc, i;
+
+    if (argc < 3) {
+        fprintf(stderr, "usage:  %s context path...\n", argv[0]);
+        exit(1);
+    }
+
+    for (i = 2; i < argc; i++) {
+        rc = setfilecon(argv[i], argv[1]);
+        if (rc < 0) {
+            fprintf(stderr, "%s:  Could not label %s with %s:  %s\n",
+                    argv[0], argv[i], argv[1], strerror(errno));
+            exit(2);
+        }
+    }
+    exit(0);
+}
diff --git a/toolbox/getenforce.c b/toolbox/getenforce.c
new file mode 100644
index 0000000..9e7589a
--- /dev/null
+++ b/toolbox/getenforce.c
@@ -0,0 +1,30 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+int getenforce_main(int argc, char **argv)
+{
+    int rc;
+
+    rc = is_selinux_enabled();
+    if (rc <= 0) {
+        printf("Disabled\n");
+        return 0;
+    }
+
+    rc = security_getenforce();
+    if (rc < 0) {
+        fprintf(stderr, "Could not get enforcing status:  %s\n",
+                strerror(errno));
+        return 2;
+    }
+
+    if (rc)
+        printf("Enforcing\n");
+    else
+        printf("Permissive\n");
+
+    return 0;
+}
diff --git a/toolbox/getsebool.c b/toolbox/getsebool.c
new file mode 100644
index 0000000..aab5200
--- /dev/null
+++ b/toolbox/getsebool.c
@@ -0,0 +1,104 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+#include <string.h>
+#include <selinux/selinux.h>
+
+static void usage(const char *progname)
+{
+    fprintf(stderr, "usage:  %s -a or %s boolean...\n", progname, progname);
+    exit(1);
+}
+
+int getsebool_main(int argc, char **argv)
+{
+    int i, get_all = 0, rc = 0, active, pending, len = 0, opt;
+    char **names;
+
+    while ((opt = getopt(argc, argv, "a")) > 0) {
+        switch (opt) {
+        case 'a':
+            if (argc > 2)
+                usage(argv[0]);
+            if (is_selinux_enabled() <= 0) {
+                fprintf(stderr, "%s:  SELinux is disabled\n",
+                        argv[0]);
+                return 1;
+            }
+            errno = 0;
+            rc = security_get_boolean_names(&names, &len);
+            if (rc) {
+                fprintf(stderr,
+                        "%s:  Unable to get boolean names:  %s\n",
+                        argv[0], strerror(errno));
+                return 1;
+            }
+            if (!len) {
+                printf("No booleans\n");
+                return 0;
+            }
+            get_all = 1;
+            break;
+        default:
+            usage(argv[0]);
+        }
+    }
+
+    if (is_selinux_enabled() <= 0) {
+        fprintf(stderr, "%s:  SELinux is disabled\n", argv[0]);
+        return 1;
+    }
+    if (!len) {
+        if (argc < 2)
+            usage(argv[0]);
+        len = argc - 1;
+        names = malloc(sizeof(char *) * len);
+        if (!names) {
+            fprintf(stderr, "%s:  out of memory\n", argv[0]);
+            return 2;
+        }
+        for (i = 0; i < len; i++) {
+            names[i] = strdup(argv[i + 1]);
+            if (!names[i]) {
+                fprintf(stderr, "%s:  out of memory\n",
+                        argv[0]);
+                return 2;
+            }
+        }
+    }
+
+    for (i = 0; i < len; i++) {
+        active = security_get_boolean_active(names[i]);
+        if (active < 0) {
+            if (get_all && errno == EACCES)
+                continue;
+            fprintf(stderr, "Error getting active value for %s\n",
+                    names[i]);
+            rc = -1;
+            goto out;
+        }
+        pending = security_get_boolean_pending(names[i]);
+        if (pending < 0) {
+            fprintf(stderr, "Error getting pending value for %s\n",
+                    names[i]);
+            rc = -1;
+            goto out;
+        }
+        if (pending != active) {
+            printf("%s --> %s pending: %s\n", names[i],
+                   (active ? "on" : "off"),
+                   (pending ? "on" : "off"));
+        } else {
+            printf("%s --> %s\n", names[i],
+                   (active ? "on" : "off"));
+        }
+    }
+
+out:
+    for (i = 0; i < len; i++)
+        free(names[i]);
+    free(names);
+    return rc;
+}
diff --git a/toolbox/id.c b/toolbox/id.c
index bb03cad..bc79288 100644
--- a/toolbox/id.c
+++ b/toolbox/id.c
@@ -5,6 +5,10 @@
 #include <pwd.h>
 #include <grp.h>
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
 static void print_uid(uid_t uid)
 {
     struct passwd *pw = getpwuid(uid);
@@ -30,6 +34,9 @@
 {
     gid_t list[64];
     int n, max;
+#ifdef HAVE_SELINUX
+    char *secctx;
+#endif
 
     max = getgroups(64, list);
     if (max < 0) max = 0;
@@ -46,6 +53,12 @@
             print_gid(list[n]);
         }
     }
+#ifdef HAVE_SELINUX
+    if (getcon(&secctx) == 0) {
+        printf(" context=%s", secctx);
+        free(secctx);
+    }
+#endif
     printf("\n");
     return 0;
 }
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
new file mode 100644
index 0000000..eb5aba6
--- /dev/null
+++ b/toolbox/load_policy.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+int load_policy_main(int argc, char **argv)
+{
+    int fd, rc, vers;
+    struct stat sb;
+    void *map;
+    const char *path;
+
+    if (argc != 2) {
+        fprintf(stderr, "usage:  %s policy-file\n", argv[0]);
+        exit(1);
+    }
+
+    path = argv[1];
+    fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        fprintf(stderr, "Could not open %s:  %s\n", path, strerror(errno));
+        exit(2);
+    }
+
+    if (fstat(fd, &sb) < 0) {
+        fprintf(stderr, "Could not stat %s:  %s\n", path, strerror(errno));
+        exit(3);
+    }
+
+    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+        fprintf(stderr, "Could not mmap %s:  %s\n", path, strerror(errno));
+        exit(4);
+    }
+
+    rc = security_load_policy(map, sb.st_size);
+    if (rc < 0) {
+        fprintf(stderr, "Could not load %s:  %s\n", path, strerror(errno));
+        exit(5);
+    }
+    munmap(map, sb.st_size);
+    close(fd);
+    exit(0);
+}
diff --git a/toolbox/ls.c b/toolbox/ls.c
index bee365c..a4db99c 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -5,6 +5,10 @@
 #include <dirent.h>
 #include <errno.h>
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
 #include <sys/stat.h>
 #include <unistd.h>
 #include <time.h>
@@ -25,6 +29,7 @@
 #define LIST_SIZE           (1 << 4)
 #define LIST_LONG_NUMERIC   (1 << 5)
 #define LIST_CLASSIFY       (1 << 6)
+#define LIST_MACLABEL       (1 << 7)
 
 // fwd
 static int listpath(const char *name, int flags);
@@ -234,9 +239,75 @@
     return 0;
 }
 
+static int listfile_maclabel(const char *path, int flags)
+{
+    struct stat s;
+    char mode[16];
+    char user[16];
+    char group[16];
+    char *maclabel = NULL;
+    const char *name;
+
+    /* name is anything after the final '/', or the whole path if none*/
+    name = strrchr(path, '/');
+    if(name == 0) {
+        name = path;
+    } else {
+        name++;
+    }
+
+    if(lstat(path, &s) < 0) {
+        return -1;
+    }
+
+#ifdef HAVE_SELINUX
+    lgetfilecon(path, &maclabel);
+#else
+    maclabel = strdup("-");
+#endif
+    if (!maclabel) {
+        return -1;
+    }
+
+    mode2str(s.st_mode, mode);
+    user2str(s.st_uid, user);
+    group2str(s.st_gid, group);
+
+    switch(s.st_mode & S_IFMT) {
+    case S_IFLNK: {
+        char linkto[256];
+        int len;
+
+        len = readlink(path, linkto, sizeof(linkto));
+        if(len < 0) return -1;
+
+        if(len > sizeof(linkto)-1) {
+            linkto[sizeof(linkto)-4] = '.';
+            linkto[sizeof(linkto)-3] = '.';
+            linkto[sizeof(linkto)-2] = '.';
+            linkto[sizeof(linkto)-1] = 0;
+        } else {
+            linkto[len] = 0;
+        }
+
+        printf("%s %-8s %-8s          %s %s -> %s\n",
+               mode, user, group, maclabel, name, linkto);
+        break;
+    }
+    default:
+        printf("%s %-8s %-8s          %s %s\n",
+               mode, user, group, maclabel, name);
+
+    }
+
+    free(maclabel);
+
+    return 0;
+}
+
 static int listfile(const char *dirname, const char *filename, int flags)
 {
-    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY)) == 0) {
+    if ((flags & LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL) == 0) {
         printf("%s\n", filename);
         return 0;
     }
@@ -251,7 +322,9 @@
         pathname = filename;
     }
 
-    if ((flags & LIST_LONG) != 0) {
+    if ((flags & LIST_MACLABEL) != 0) {
+        return listfile_maclabel(pathname, flags);
+    } else if ((flags & LIST_LONG) != 0) {
         return listfile_long(pathname, flags);
     } else /*((flags & LIST_SIZE) != 0)*/ {
         return listfile_size(pathname, filename, flags);
@@ -386,6 +459,7 @@
                     case 's': flags |= LIST_SIZE; break;
                     case 'R': flags |= LIST_RECURSIVE; break;
                     case 'd': flags |= LIST_DIRECTORIES; break;
+                    case 'Z': flags |= LIST_MACLABEL; break;
                     case 'a': flags |= LIST_ALL; break;
                     case 'F': flags |= LIST_CLASSIFY; break;
                     default:
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 2aa3efb..7c3de4a 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -13,7 +13,6 @@
 
 #include <cutils/sched_policy.h>
 
-
 static char *nexttoksep(char **strp, char *sep)
 {
     char *p = strsep(strp,sep);
@@ -28,6 +27,7 @@
 #define SHOW_TIME 2
 #define SHOW_POLICY 4
 #define SHOW_CPU  8
+#define SHOW_MACLABEL 16
 
 static int display_flags = 0;
 
@@ -35,6 +35,7 @@
 {
     char statline[1024];
     char cmdline[1024];
+    char macline[1024];
     char user[32];
     struct stat stats;
     int fd, r;
@@ -51,9 +52,11 @@
     if(tid) {
         sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
         cmdline[0] = 0;
+        snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
     } else {
         sprintf(statline, "/proc/%d/stat", pid);
-        sprintf(cmdline, "/proc/%d/cmdline", pid);    
+        sprintf(cmdline, "/proc/%d/cmdline", pid);
+        snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
         fd = open(cmdline, O_RDONLY);
         if(fd == 0) {
             r = 0;
@@ -142,6 +145,19 @@
     }
     
     if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
+        if (display_flags & SHOW_MACLABEL) {
+            fd = open(macline, O_RDONLY);
+            strcpy(macline, "-");
+            if (fd >= 0) {
+                r = read(fd, macline, sizeof(macline)-1);
+                close(fd);
+                if (r > 0)
+                    macline[r] = 0;
+            }
+            printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name);
+            return 0;
+        }
+
         printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
         if (display_flags & SHOW_CPU)
             printf(" %-2d", psr);
@@ -206,6 +222,8 @@
             threads = 1;
         } else if(!strcmp(argv[1],"-x")) {
             display_flags |= SHOW_TIME;
+        } else if(!strcmp(argv[1], "-Z")) {
+            display_flags |= SHOW_MACLABEL;
         } else if(!strcmp(argv[1],"-P")) {
             display_flags |= SHOW_POLICY;
         } else if(!strcmp(argv[1],"-p")) {
@@ -221,10 +239,14 @@
         argv++;
     }
 
-    printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC         NAME\n",
-           (display_flags&SHOW_CPU)?"CPU ":"",
-           (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
-           (display_flags&SHOW_POLICY)?"PCY " : "");
+    if (display_flags & SHOW_MACLABEL) {
+        printf("LABEL                          USER     PID   PPID  NAME\n");
+    } else {
+        printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC         NAME\n",
+               (display_flags&SHOW_CPU)?"CPU ":"",
+               (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
+               (display_flags&SHOW_POLICY)?"PCY " : "");
+    }
     while((de = readdir(d)) != 0){
         if(isdigit(de->d_name[0])){
             int pid = atoi(de->d_name);
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
new file mode 100644
index 0000000..5ef0ef1
--- /dev/null
+++ b/toolbox/restorecon.c
@@ -0,0 +1,141 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+
+#define FCPATH "/file_contexts"
+
+static struct selabel_handle *sehandle;
+static const char *progname;
+static int nochange;
+static int verbose;
+
+static void usage(void)
+{
+    fprintf(stderr, "usage:  %s [-f file_contexts] [-nrRv] pathname...\n", progname);
+    exit(1);
+}
+
+static int restore(const char *pathname, const struct stat *sb)
+{
+    char *oldcontext, *newcontext;
+
+    if (lgetfilecon(pathname, &oldcontext) < 0) {
+        fprintf(stderr, "Could not get context of %s:  %s\n",
+                pathname, strerror(errno));
+        return -1;
+    }
+    if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) {
+        fprintf(stderr, "Could not lookup context for %s:  %s\n", pathname,
+                strerror(errno));
+        return -1;
+    }
+    if (strcmp(newcontext, "<<none>>") &&
+        strcmp(oldcontext, newcontext)) {
+        if (verbose)
+            printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext);
+        if (!nochange) {
+            if (lsetfilecon(pathname, newcontext) < 0) {
+                fprintf(stderr, "Could not label %s with %s:  %s\n",
+                        pathname, newcontext, strerror(errno));
+                return -1;
+            }
+        }
+    }
+    freecon(oldcontext);
+    freecon(newcontext);
+    return 0;
+}
+
+int restorecon_main(int argc, char **argv)
+{
+    struct selinux_opt seopts[] = {
+        { SELABEL_OPT_PATH, FCPATH }
+    };
+    int ch, recurse = 0, ftsflags = FTS_PHYSICAL;
+
+    progname = argv[0];
+
+    do {
+        ch = getopt(argc, argv, "f:nrRv");
+        if (ch == EOF)
+            break;
+        switch (ch) {
+        case 'f':
+            seopts[0].value = optarg;
+            break;
+        case 'n':
+            nochange = 1;
+            break;
+        case 'r':
+        case 'R':
+            recurse = 1;
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        default:
+            usage();
+        }
+    } while (1);
+
+    argc -= optind;
+    argv += optind;
+    if (!argc)
+        usage();
+
+    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+    if (!sehandle) {
+        fprintf(stderr, "Could not load file contexts from %s:  %s\n", seopts[0].value,
+                strerror(errno));
+        return -1;
+    }
+
+    if (recurse) {
+        FTS *fts;
+        FTSENT *ftsent;
+        fts = fts_open(argv, ftsflags, NULL);
+        if (!fts) {
+            fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n",
+                    argv[0], strerror(errno));
+            return -1;
+        }
+        while ((ftsent = fts_read(fts))) {
+            switch (ftsent->fts_info) {
+            case FTS_DP:
+                break;
+            case FTS_DNR:
+            case FTS_ERR:
+            case FTS_NS:
+                fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path,
+                        strerror(errno));
+                fts_set(fts, ftsent, FTS_SKIP);
+                break;
+            default:
+                if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
+                    fts_set(fts, ftsent, FTS_SKIP);
+                break;
+            }
+        }
+    } else {
+        int i, rc;
+        struct stat sb;
+
+        for (i = 0; i < argc; i++) {
+            rc = lstat(argv[i], &sb);
+            if (rc < 0) {
+                fprintf(stderr, "Could not stat %s:  %s\n", argv[i],
+                        strerror(errno));
+                continue;
+            }
+            restore(argv[i], &sb);
+        }
+    }
+
+    return 0;
+}
diff --git a/toolbox/runcon.c b/toolbox/runcon.c
new file mode 100644
index 0000000..4a57bf3
--- /dev/null
+++ b/toolbox/runcon.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+int runcon_main(int argc, char **argv)
+{
+    int rc;
+
+    if (argc < 3) {
+        fprintf(stderr, "usage:  %s context program args...\n", argv[0]);
+        exit(1);
+    }
+
+    rc = setexeccon(argv[1]);
+    if (rc < 0) {
+        fprintf(stderr, "Could not set context to %s:  %s\n", argv[1], strerror(errno));
+        exit(2);
+    }
+
+    argv += 2;
+    argc -= 2;
+    execvp(argv[0], argv);
+    fprintf(stderr, "Could not exec %s:  %s\n", argv[0], strerror(errno));
+    exit(3);
+}
diff --git a/toolbox/setenforce.c b/toolbox/setenforce.c
new file mode 100644
index 0000000..1b0ea5c
--- /dev/null
+++ b/toolbox/setenforce.c
@@ -0,0 +1,44 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+void usage(const char *progname)
+{
+    fprintf(stderr, "usage:  %s [ Enforcing | Permissive | 1 | 0 ]\n",
+            progname);
+    exit(1);
+}
+
+int setenforce_main(int argc, char **argv)
+{
+    int rc = 0;
+    if (argc != 2) {
+        usage(argv[0]);
+    }
+
+    if (is_selinux_enabled() <= 0) {
+        fprintf(stderr, "%s: SELinux is disabled\n", argv[0]);
+        return 1;
+    }
+    if (strlen(argv[1]) == 1 && (argv[1][0] == '0' || argv[1][0] == '1')) {
+        rc = security_setenforce(atoi(argv[1]));
+    } else {
+        if (strcasecmp(argv[1], "enforcing") == 0) {
+            rc = security_setenforce(1);
+        } else if (strcasecmp(argv[1], "permissive") == 0) {
+            rc = security_setenforce(0);
+        } else
+            usage(argv[0]);
+    }
+    if (rc < 0) {
+        fprintf(stderr, "%s:  Could not set enforcing status:  %s\n",
+                argv[0], strerror(errno));
+        return 2;
+    }
+    return 0;
+}
diff --git a/toolbox/setsebool.c b/toolbox/setsebool.c
new file mode 100644
index 0000000..4a3d87d
--- /dev/null
+++ b/toolbox/setsebool.c
@@ -0,0 +1,55 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+#include <errno.h>
+
+static int do_setsebool(int nargs, char **args) {
+    SELboolean *b = alloca(nargs * sizeof(SELboolean));
+    char *v;
+    int i;
+
+    if (is_selinux_enabled() <= 0)
+        return 0;
+
+    for (i = 1; i < nargs; i++) {
+        char *name = args[i];
+        v = strchr(name, '=');
+        if (!v) {
+            fprintf(stderr, "setsebool: argument %s had no =\n", name);
+            return -1;
+        }
+        *v++ = 0;
+        b[i-1].name = name;
+        if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
+            b[i-1].value = 1;
+        else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
+            b[i-1].value = 0;
+        else {
+            fprintf(stderr, "setsebool: invalid value %s\n", v);
+            return -1;
+        }
+    }
+
+    if (security_set_boolean_list(nargs - 1, b, 0) < 0)
+    {
+        fprintf(stderr, "setsebool: unable to set booleans: %s", strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+int setsebool_main(int argc, char **argv)
+{
+    if (argc < 2) {
+        fprintf(stderr, "Usage:  %s name=value...\n", argv[0]);
+        exit(1);
+    }
+
+    return do_setsebool(argc, argv);
+}