resolved conflicts for merge of 44898072 to master
Change-Id: Ib77a4d9161261306253a174727801526e7149621
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);
+}