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);
+}