Merge "Prevent bit shifting if num bits is negative"
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 4431ba7..d985ee3 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -185,6 +185,117 @@
return 0;
}
+/* This is relevant only for ADB daemon running inside the emulator. */
+#if !ADB_HOST
+/*
+ * Redefine open and write for qemu_pipe.h that contains inlined references
+ * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ */
+#undef open
+#undef write
+#define open adb_open
+#define write adb_write
+#include <hardware/qemu_pipe.h>
+#undef open
+#undef write
+#define open ___xxx_open
+#define write ___xxx_write
+
+/* A worker thread that monitors host connections, and registers a transport for
+ * every new host connection. This thread replaces server_socket_thread on
+ * condition that adbd daemon runs inside the emulator, and emulator uses QEMUD
+ * pipe to communicate with adbd daemon inside the guest. This is done in order
+ * to provide more robust communication channel between ADB host and guest. The
+ * main issue with server_socket_thread approach is that it runs on top of TCP,
+ * and thus is sensitive to network disruptions. For instance, the
+ * ConnectionManager may decide to reset all network connections, in which case
+ * the connection between ADB host and guest will be lost. To make ADB traffic
+ * independent from the network, we use here 'adb' QEMUD service to transfer data
+ * between the host, and the guest. See external/qemu/android/adb-*.* that
+ * implements the emulator's side of the protocol. Another advantage of using
+ * QEMUD approach is that ADB will be up much sooner, since it doesn't depend
+ * anymore on network being set up.
+ * The guest side of the protocol contains the following phases:
+ * - Connect with adb QEMUD service. In this phase a handle to 'adb' QEMUD service
+ * is opened, and it becomes clear whether or not emulator supports that
+ * protocol.
+ * - Wait for the ADB host to create connection with the guest. This is done by
+ * sending an 'accept' request to the adb QEMUD service, and waiting on
+ * response.
+ * - When new ADB host connection is accepted, the connection with adb QEMUD
+ * service is registered as the transport, and a 'start' request is sent to the
+ * adb QEMUD service, indicating that the guest is ready to receive messages.
+ * Note that the guest will ignore messages sent down from the emulator before
+ * the transport registration is completed. That's why we need to send the
+ * 'start' request after the transport is registered.
+ */
+static void *qemu_socket_thread(void * arg)
+{
+/* 'accept' request to the adb QEMUD service. */
+static const char _accept_req[] = "accept";
+/* 'start' request to the adb QEMUD service. */
+static const char _start_req[] = "start";
+/* 'ok' reply from the adb QEMUD service. */
+static const char _ok_resp[] = "ok";
+
+ const int port = (int)arg;
+ int res, fd;
+ char tmp[256];
+ char con_name[32];
+
+ D("transport: qemu_socket_thread() starting\n");
+
+ /* adb QEMUD service connection request. */
+ snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
+
+ /* Connect to the adb QEMUD service. */
+ fd = qemu_pipe_open(con_name);
+ if (fd < 0) {
+ /* This could be an older version of the emulator, that doesn't
+ * implement adb QEMUD service. Fall back to the old TCP way. */
+ adb_thread_t thr;
+ D("adb service is not available. Falling back to TCP socket.\n");
+ adb_thread_create(&thr, server_socket_thread, arg);
+ return 0;
+ }
+
+ for(;;) {
+ /*
+ * Wait till the host creates a new connection.
+ */
+
+ /* Send the 'accept' request. */
+ res = adb_write(fd, _accept_req, strlen(_accept_req));
+ if (res == strlen(_accept_req)) {
+ /* Wait for the response. In the response we expect 'ok' on success,
+ * or 'ko' on failure. */
+ res = adb_read(fd, tmp, sizeof(tmp));
+ if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
+ D("Accepting ADB host connection has failed.\n");
+ adb_close(fd);
+ } else {
+ /* Host is connected. Register the transport, and start the
+ * exchange. */
+ register_socket_transport(fd, "host", port, 1);
+ adb_write(fd, _start_req, strlen(_start_req));
+ }
+
+ /* Prepare for accepting of the next ADB host connection. */
+ fd = qemu_pipe_open(con_name);
+ if (fd < 0) {
+ D("adb service become unavailable.\n");
+ return 0;
+ }
+ } else {
+ D("Unable to send the '%s' request to ADB service.\n", _accept_req);
+ return 0;
+ }
+ }
+ D("transport: qemu_socket_thread() exiting\n");
+ return 0;
+}
+#endif // !ADB_HOST
+
void local_init(int port)
{
adb_thread_t thr;
@@ -193,7 +304,21 @@
if(HOST) {
func = client_socket_thread;
} else {
+#if ADB_HOST
func = server_socket_thread;
+#else
+ /* For the adbd daemon in the system image we need to distinguish
+ * between the device, and the emulator. */
+ char is_qemu[PROPERTY_VALUE_MAX];
+ property_get("ro.kernel.qemu", is_qemu, "");
+ if (!strcmp(is_qemu, "1")) {
+ /* Running inside the emulator: use QEMUD pipe as the transport. */
+ func = qemu_socket_thread;
+ } else {
+ /* Running inside the device: use TCP socket as the transport. */
+ func = server_socket_thread;
+ }
+#endif !ADB_HOST
}
D("transport: local %s init\n", HOST ? "client" : "server");
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 7ae6372..5d8a831 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -113,7 +113,18 @@
#define VENDOR_ID_ARCHOS 0x0E79
// Positivo's USB Vendor ID
#define VENDOR_ID_POSITIVO 0x1662
-
+// Fujitsu's USB Vendor ID
+#define VENDOR_ID_FUJITSU 0x04C5
+// Lumigon's USB Vendor ID
+#define VENDOR_ID_LUMIGON 0x25E3
+//Intel's USB Vendor ID
+#define VENDOR_ID_INTEL 0x8087
+// Quanta's USB Vendor ID
+#define VENDOR_ID_QUANTA 0x0408
+// INQ Mobile's USB Vendor ID
+#define VENDOR_ID_INQ_MOBILE 0x2314
+// Sony's USB Vendor ID
+#define VENDOR_ID_SONY 0x054C
/** built-in vendor list */
int builtInVendorIds[] = {
@@ -156,6 +167,12 @@
VENDOR_ID_PEGATRON,
VENDOR_ID_ARCHOS,
VENDOR_ID_POSITIVO,
+ VENDOR_ID_FUJITSU,
+ VENDOR_ID_LUMIGON,
+ VENDOR_ID_INTEL,
+ VENDOR_ID_QUANTA,
+ VENDOR_ID_INQ_MOBILE,
+ VENDOR_ID_SONY,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index fe0af7a..fb7ac4d 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -158,6 +158,7 @@
(info->dev_vendor != 0x22b8) && // Motorola
(info->dev_vendor != 0x0955) && // Nvidia
(info->dev_vendor != 0x413c) && // DELL
+ (info->dev_vendor != 0x2314) && // INQ Mobile
(info->dev_vendor != 0x0bb4)) // HTC
return -1;
if(info->ifc_class != 0xff) return -1;
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index 1ba87e6..cbc64e4 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -139,10 +139,11 @@
ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
- ctrl.wIndex = 0;
+ //language ID (en-us) for serial number string
+ ctrl.wIndex = 0x0409;
ctrl.wLength = sizeof(buffer);
ctrl.data = buffer;
- ctrl.timeout = 50;
+ ctrl.timeout = 50;
result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
if (result > 0) {
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c
index 570a456..6df5d2c 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.c
@@ -331,7 +331,8 @@
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (kUSBStringDesc << 8) | serialIndex;
- req.wIndex = 0;
+ //language ID (en-us) for serial number string
+ req.wIndex = 0x0409;
req.pData = buffer;
req.wLength = sizeof(buffer);
kr = (*dev)->DeviceRequest(dev, &req);
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
index 1e0af7d..0194962 100644
--- a/include/system/audio_policy.h
+++ b/include/system/audio_policy.h
@@ -38,6 +38,9 @@
AUDIO_POLICY_OUTPUT_FLAG_DIRECT = 0x1
} audio_policy_output_flags_t;
+/* for future compatibility */
+typedef audio_policy_output_flags_t audio_output_flags_t;
+
/* device categories used for audio_policy->set_force_use() */
typedef enum {
AUDIO_POLICY_FORCE_NONE,
diff --git a/include/system/graphics.h b/include/system/graphics.h
index 729e92c..d42a0d3 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -86,7 +86,8 @@
*/
HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar
-
+ /* Forward compatibility */
+ HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,
/* Legacy formats (deprecated), used by ImageFormat.java */
HAL_PIXEL_FORMAT_YCbCr_422_SP = 0x10, // NV16
diff --git a/init/Android.mk b/init/Android.mk
index 162c226..e9fd884 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -30,6 +30,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..1ee88a7 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");
@@ -766,7 +940,7 @@
}
/* run all property triggers based on current state of the properties */
- queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");
+ queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
#if BOOTCHART
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 13c9ca2..3a4b10b 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/libcutils/Android.mk b/libcutils/Android.mk
index effaae0..b83ce68 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -94,6 +94,17 @@
include $(BUILD_HOST_STATIC_LIBRARY)
+# Static library for host, 64-bit
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := lib64cutils
+LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
+LOCAL_LDLIBS := -lpthread
+LOCAL_STATIC_LIBRARIES := lib64log
+LOCAL_CFLAGS += $(hostSmpFlag) -m64
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
# Shared and static library for target
# ========================================================
include $(CLEAR_VARS)
diff --git a/liblog/Android.mk b/liblog/Android.mk
index bd4fed4..bd2590e 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -40,6 +40,7 @@
liblog_host_sources := $(liblog_sources) fake_log_device.c
+
# Static library for host
# ========================================================
LOCAL_MODULE := liblog
@@ -48,6 +49,17 @@
LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
include $(BUILD_HOST_STATIC_LIBRARY)
+
+# Static library for host, 64-bit
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := lib64log
+LOCAL_SRC_FILES := $(liblog_host_sources)
+LOCAL_LDLIBS := -lpthread
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
# Shared and static library for target
# ========================================================
include $(CLEAR_VARS)
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 6a80560..dd777c0 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include "private/android_filesystem_config.h"
#include "cutils/log.h"
@@ -34,13 +35,13 @@
void usage() {
fatal(
- "Usage: logwrapper [-x] BINARY [ARGS ...]\n"
+ "Usage: logwrapper [-d] BINARY [ARGS ...]\n"
"\n"
"Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
"the Android logging system. Tag is set to BINARY, priority is\n"
"always LOG_INFO.\n"
"\n"
- "-x: Causes logwrapper to SIGSEGV when BINARY terminates\n"
+ "-d: Causes logwrapper to SIGSEGV when BINARY terminates\n"
" fault address is set to the status of wait()\n");
}
@@ -51,6 +52,10 @@
int a = 0; // start index of unprocessed data
int b = 0; // end index of unprocessed data
int sz;
+
+ char *btag = basename(tag);
+ if (!btag) btag = (char*) tag;
+
while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
sz += b;
@@ -60,7 +65,7 @@
buffer[b] = '\0';
} else if (buffer[b] == '\n') {
buffer[b] = '\0';
- ALOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, btag, "%s", &buffer[a]);
a = b + 1;
}
}
@@ -68,7 +73,7 @@
if (a == 0 && b == sizeof(buffer) - 1) {
// buffer is full, flush
buffer[b] = '\0';
- ALOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, btag, "%s", &buffer[a]);
b = 0;
} else if (a != b) {
// Keep left-overs
@@ -84,11 +89,11 @@
// Flush remaining data
if (a != b) {
buffer[b] = '\0';
- ALOG(LOG_INFO, tag, "%s", &buffer[a]);
+ ALOG(LOG_INFO, btag, "%s", &buffer[a]);
}
status = 0xAAAA;
if (wait(&status) != -1) { // Wait for child
- if (WIFEXITED(status))
+ if (WIFEXITED(status) && WEXITSTATUS(status))
ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1e3ed8c..28cd26c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -159,7 +159,7 @@
# give system access to wpa_supplicant.conf for backup and restore
mkdir /data/misc/wifi 0770 wifi wifi
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
- mkdir /data/local 0771 shell shell
+ mkdir /data/local 0751 root root
mkdir /data/local/tmp 0771 shell shell
mkdir /data/data 0771 system system
mkdir /data/app-private 0771 system system
@@ -177,8 +177,9 @@
# create the lost+found directories, so as to enforce our permissions
mkdir /data/lost+found 0770 root root
- # create directory for DRM plug-ins
- mkdir /data/drm 0774 drm drm
+ # create directory for DRM plug-ins - give drm the read/write access to
+ # the following directory.
+ mkdir /data/drm 0770 drm drm
# If there is no fs-post-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index d7a675a..9daeed3 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -57,6 +57,21 @@
touch \
lsof
+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
@@ -68,6 +83,14 @@
LOCAL_SHARED_LIBRARIES := libcutils libc libusbhost
+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/chown.c b/toolbox/chown.c
index e9d108b..7b24c52 100644
--- a/toolbox/chown.c
+++ b/toolbox/chown.c
@@ -62,7 +62,7 @@
for (i = 2; i < argc; i++) {
if (chown(argv[i], uid, gid) < 0) {
- fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno));
+ fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno));
return 10;
}
}
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);
+}