Extend init and ueventd for SE Android.

Add SE Android support for init and ueventd.

init:
- Load policy at boot.
- Set the security context for service daemons and their sockets.
- New built-in commands: setcon, setenforce, restorecon, setsebool.
- New option for services: seclabel.

ueventd:
- Set the security context for device directories and nodes.

Change-Id: I98ed752cde503c94d99dfa5b5a47e3c33db16aac
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)