Blob Blame History Raw
diff --git a/libselinux/include/selinux/label.h b/libselinux/include/selinux/label.h
index 8263f32..9ef10fc 100644
--- a/libselinux/include/selinux/label.h
+++ b/libselinux/include/selinux/label.h
@@ -48,8 +48,10 @@ struct selabel_handle;
 #define SELABEL_OPT_PATH	3
 /* select a subset of the search space as an optimization (file backend) */
 #define SELABEL_OPT_SUBSET	4
+/* like subset, but an array of subsets */
+#define SELABEL_OPT_PREFIXES	5
 /* total number of options */
-#define SELABEL_NOPT		5
+#define SELABEL_NOPT		6
 
 /*
  * Label operations
diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h
index 6f483c9..9a5509e 100644
--- a/libselinux/include/selinux/selinux.h
+++ b/libselinux/include/selinux/selinux.h
@@ -139,7 +139,10 @@ struct av_decision {
 /* Structure for passing options, used by AVC and label subsystems */
 struct selinux_opt {
 	int type;
-	const char *value;
+	union {
+		const char *value;
+		const char **values;
+	};
 };
 
 /* Callback facilities */
@@ -420,6 +423,11 @@ extern int matchpathcon_init(const char *path);
    regexes that have stems that are prefixes of 'prefix'. */
 extern int matchpathcon_init_prefix(const char *path, const char *prefix);
 
+/* Same as matchpathcon_init, but only load entries with
+ * regexes that have stems that are prefixes of the 'prefixes'
+ * array of entries.  The last entry must be NULL. */
+extern int matchpathcon_init_prefixes(const char *patch, const char **prefixes);
+
 /* Free the memory allocated by matchpathcon_init. */
 extern void matchpathcon_fini(void);
 
@@ -473,6 +481,14 @@ extern int matchmediacon(const char *media, security_context_t * con);
 extern int selinux_getenforcemode(int *enforce);
 
 /*
+  selinux_boolean_sub reads the /etc/selinux/TYPE/booleans.subs_dist file
+  looking for a record with boolean_name.  If a record exists selinux_boolean_sub
+  returns the translated name otherwise it returns the original name.
+  The returned value needs to be freed. On failure NULL will be returned.
+ */
+extern char *selinux_boolean_sub(const char *boolean_name);
+
+/*
   selinux_getpolicytype reads the /etc/selinux/config file and determines 
   what the default policy for the machine is.  Calling application must 
   free policytype.
@@ -488,7 +504,9 @@ extern const char *selinux_policy_root(void);
 
 /* These functions return the paths to specific files under the 
    policy root directory. */
+extern const char *selinux_current_policy_path(void);
 extern const char *selinux_binary_policy_path(void);
+extern char *selinux_binary_policy_path_min_max(int min, int *max);
 extern const char *selinux_failsafe_context_path(void);
 extern const char *selinux_removable_context_path(void);
 extern const char *selinux_default_context_path(void);
@@ -502,10 +520,12 @@ extern const char *selinux_homedir_context_path(void);
 extern const char *selinux_media_context_path(void);
 extern const char *selinux_virtual_domain_context_path(void);
 extern const char *selinux_virtual_image_context_path(void);
+extern const char *selinux_lxc_contexts_path(void);
 extern const char *selinux_x_context_path(void);
 extern const char *selinux_sepgsql_context_path(void);
 extern const char *selinux_contexts_path(void);
 extern const char *selinux_securetty_types_path(void);
+extern const char *selinux_booleans_subs_path(void);
 extern const char *selinux_booleans_path(void);
 extern const char *selinux_customizable_types_path(void);
 extern const char *selinux_users_path(void);
diff --git a/libselinux/man/man3/matchpathcon.3 b/libselinux/man/man3/matchpathcon.3
index cdbb252..b6814ed 100644
--- a/libselinux/man/man3/matchpathcon.3
+++ b/libselinux/man/man3/matchpathcon.3
@@ -8,7 +8,9 @@ matchpathcon, matchpathcon_index \- get the default SELinux security context for
 
 .BI "int matchpathcon_init(const char *" path ");"
 
-.BI "int matchpathcon_init_prefix(const char *" path ", const char *" subset ");"
+.BI "int matchpathcon_init_prefix(const char *" path ", const char *" prefix ");"
+
+.BI "int matchpathcon_init_prefixes(const char *" path ", const char **" prefixes ");"
 
 .BI "int matchpathcon_fini(void);"
 .sp
@@ -50,6 +52,14 @@ by
 .I prefix.
 
 .sp
+.B matchpathcon_init_prefixes
+is the same as
+.B matchpathcon_init_prefix
+but takes an array of
+.I prefixes
+instead of a single prefix.  The last entry in the array must be NULL.
+
+.sp
 .B matchpathcon_fini
 frees the memory allocated by a prior call to
 .B matchpathcon_init.
diff --git a/libselinux/man/man3/selabel_open.3 b/libselinux/man/man3/selabel_open.3
index 8674e37..fc5b120 100644
--- a/libselinux/man/man3/selabel_open.3
+++ b/libselinux/man/man3/selabel_open.3
@@ -37,8 +37,11 @@ structures of length
 .ta 4n 16n 24n
 .nf
 struct selinux_opt {
-	int	type;
-	const char	*value;
+	int type;
+	union {
+		const char *value;
+		const char **values;
+	};
 };
 .fi
 .ta
@@ -66,6 +69,13 @@ A non-null value for this option enables context validation.  By default,
 is used; a custom validation function can be provided via
 .BR selinux_set_callback (3).
 Note that an invalid context may not be treated as an error unless it is actually encountered during a lookup operation.
+.TP
+.B SELABEL_OPT_SUBSET
+A ":" separates string of path prefixes that tell the system to only loads entries with regular expressions that could match this strings. For example "/dev:/var/run:/tmp".  This option can cause the system to use less memory and work faster, but you should only use paths that begin with a prefix.
+.TP
+.B SELABEL_OPT_PATH
+A string representing an alternate path the the regular expressions.
+.sp
 
 .SH "BACKENDS"
 
@@ -99,4 +109,3 @@ Eamon Walsh <ewalsh@tycho.nsa.gov>
 .BR selabel_stats (3),
 .BR selinux_set_callback (3),
 .BR selinux (8)
-
diff --git a/libselinux/man/man3/selinux_binary_policy_path.3 b/libselinux/man/man3/selinux_binary_policy_path.3
index 8ead1a4..c68ace5 100644
--- a/libselinux/man/man3/selinux_binary_policy_path.3
+++ b/libselinux/man/man3/selinux_binary_policy_path.3
@@ -17,6 +17,8 @@ extern const char *selinux_policy_root(void);
 
 extern const char *selinux_binary_policy_path(void);
 
+extern const char *selinux_current_policy_path(void);
+
 extern const char *selinux_failsafe_context_path(void);
 
 extern const char *selinux_removable_context_path(void);
@@ -52,7 +54,9 @@ selinux_path() - top-level SELinux configuration directory
 .sp
 selinux_policy_root() - top-level policy directory 
 .sp
-selinux_binary_policy_path() - binary policy file loaded into kernel
+selinux_current_policy_path() - binary policy file loaded into kernel
+.sp
+selinux_binary_policy_path() - binary policy path on disk
 .sp
 selinux_default_type_path - context file mapping roles to default types.
 .sp
diff --git a/libselinux/man/man3/selinux_boolean_sub.3 b/libselinux/man/man3/selinux_boolean_sub.3
new file mode 100644
index 0000000..8d54c88
--- /dev/null
+++ b/libselinux/man/man3/selinux_boolean_sub.3
@@ -0,0 +1,25 @@
+.TH "selinux_boolean_subs" "3" "11 June 2012" "dwalsh@redhat.com" "SELinux API documentation"
+.SH "NAME"
+selinux_boolean_subs
+.SH "SYNOPSIS"
+.B #include <selinux/selinux.h>
+.sp
+.BI "char *selinux_boolean_subs(const char * " boolean_name, ");"
+.sp
+.SH "DESCRIPTION"
+.B selinux_boolean_sub
+searches the /etc/selinux/POLICYTYPE/booleans.subs_dist file
+for a maching boolean_name record.  If the record exists the boolean substitution name is returned.  If not
+.B selinux_boolean_sub
+returns the original boolean_name.
+
+.SH "RETURN VALUE"
+.BR selinux_boolean_subs
+returns the
+.I boolean_name
+or the substituted name on success.  The returned value must be freed with
+.BR free "(3)."
+.BR selinux_boolean_subs
+returns NULL on error.
+.SH "SEE ALSO"
+security_get_boolean_names.3
diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile
index b333f07..74e53bb 100644
--- a/libselinux/src/Makefile
+++ b/libselinux/src/Makefile
@@ -13,12 +13,10 @@ SHLIBDIR ?= $(DESTDIR)/lib
 INCLUDEDIR ?= $(PREFIX)/include
 PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])')
 PYINC ?= $(shell pkg-config --cflags $(PYPREFIX))
-PYTHONLIBDIR ?= $(shell pkg-config --libs $(PYPREFIX))
 PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER)
 RUBYLIBVER ?= $(shell $(RUBY) -e 'print RUBY_VERSION.split(".")[0..1].join(".")')
 RUBYPLATFORM ?= $(shell $(RUBY) -e 'print RUBY_PLATFORM')
 RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER))
-RUBYLIBDIR ?= $(shell pkg-config --libs ruby-$(RUBYLIBVER))
 RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM)
 LIBBASE=$(shell basename $(LIBDIR))
 
@@ -106,10 +104,10 @@ $(SWIGRUBYLOBJ): $(SWIGRUBYCOUT)
 	$(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $<
 
 $(SWIGSO): $(SWIGLOBJ)
-	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR) $(PYTHONLIBDIR)
+	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR)
 
 $(SWIGRUBYSO): $(SWIGRUBYLOBJ)
-	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR) -Wl,-soname,$@
+	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR)
 
 $(LIBA): $(OBJS)
 	$(AR) rcs $@ $^
@@ -129,7 +127,7 @@ $(AUDIT2WHYLOBJ): audit2why.c
 	$(CC) $(filter-out -Werror, $(CFLAGS)) $(PYINC) -fPIC -DSHARED -c -o $@ $<
 
 $(AUDIT2WHYSO): $(AUDIT2WHYLOBJ)
-	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) -Wl,-soname,$@
+	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR)
 
 %.o:  %.c policy.h
 	$(CC) $(CFLAGS) $(TLSFLAGS) -c -o $@ $<
diff --git a/libselinux/src/audit2why.c b/libselinux/src/audit2why.c
index 02483a3..f7750fc 100644
--- a/libselinux/src/audit2why.c
+++ b/libselinux/src/audit2why.c
@@ -214,19 +214,12 @@ static int __policy_init(const char *init_path)
 			PyErr_SetString( PyExc_ValueError, errormsg);
 			return 1;
 		}
-		snprintf(path, PATH_MAX, "%s.%d",
-			 selinux_binary_policy_path(), vers);
-		fp = fopen(path, "r");
-		while (!fp && errno == ENOENT && --vers) {
-			snprintf(path, PATH_MAX, "%s.%d",
-				 selinux_binary_policy_path(), vers);
-			fp = fopen(path, "r");
-		}
+		fp = fopen(selinux_current_policy_path(), "r");
 		if (!fp) {
 			snprintf(errormsg, sizeof(errormsg), 
-				 "unable to open %s.%d:  %s\n",
-				 selinux_binary_policy_path(),
-				 security_policyvers(), strerror(errno));
+				 "unable to open %s:  %s\n",
+				 selinux_current_policy_path(),
+				 strerror(errno));
 			PyErr_SetString( PyExc_ValueError, errormsg);
 			return 1;
 		}
diff --git a/libselinux/src/avc.c b/libselinux/src/avc.c
index 802a07f..6ff83a7 100644
--- a/libselinux/src/avc.c
+++ b/libselinux/src/avc.c
@@ -827,6 +827,7 @@ int avc_has_perm(security_id_t ssid, security_id_t tsid,
 	errsave = errno;
 	avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
 	errno = errsave;
+	if (!avc_enforcing) return 0;
 	return rc;
 }
 
diff --git a/libselinux/src/booleans.c b/libselinux/src/booleans.c
index 1510043..b5e6655 100644
--- a/libselinux/src/booleans.c
+++ b/libselinux/src/booleans.c
@@ -5,6 +5,7 @@
  *   Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans().
  */
 
+#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -86,44 +87,145 @@ int security_get_boolean_names(char ***names, int *len)
 }
 
 hidden_def(security_get_boolean_names)
+
+char *selinux_boolean_sub(const char *name)
+{
+	char *sub = NULL;
+	char *line_buf = NULL;
+	size_t line_len;
+	FILE *cfg;
+
+	if (!name)
+		return NULL;
+
+	cfg = fopen(selinux_booleans_subs_path(), "r");
+	if (!cfg)
+		goto out;
+
+	while (getline(&line_buf, &line_len, cfg) > -1) {
+		char *ptr;
+		char *src = line_buf;
+		char *dst;
+		while (*src && isspace(*src))
+			src++;
+		if (!*src)
+			continue;
+		if (src[0] == '#')
+			continue;
+		ptr = src;
+		while (*ptr && !isspace(*ptr))
+			ptr++;
+		*ptr++ = '\0';
+		if (strcmp(src, name) != 0)
+			continue;
+
+		dst = ptr;
+		while (*dst && isspace(*dst))
+			dst++;
+		if (!*dst)
+			continue;
+		ptr=dst;
+		while (*ptr && !isspace(*ptr))
+			ptr++;
+		*ptr='\0';
+
+		sub = strdup(dst);
+
+		break;
+	}
+	free(line_buf);
+	fclose(cfg);
+out:
+	if (!sub)
+		sub = strdup(name);
+	return sub;
+}
+
+hidden_def(selinux_boolean_sub)
+
+static int bool_open(const char *name, int flag) {
+	char *fname = NULL;
+	char *alt_name = NULL;
+	int len;
+	int fd = -1;
+	int ret;
+	char *ptr;
+
+	if (!name) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* note the 'sizeof' gets us enough room for the '\0' */
+	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
+	fname = malloc(sizeof(char) * len);
+	if (!fname)
+		return -1;
+
+	ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
+	if (ret < 0)
+		goto out;
+	assert(ret < len);
+
+	fd = open(fname, flag);
+	if (fd >= 0 || errno != ENOENT)
+		goto out;
+
+	alt_name = selinux_boolean_sub(name);
+	if (!alt_name)
+		goto out;
+
+	/* note the 'sizeof' gets us enough room for the '\0' */
+	len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
+	ptr = realloc(fname, len);
+	if (!ptr)
+		goto out;
+	fname = ptr;
+
+	ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name);
+	if (ret < 0)
+		goto out;
+	assert(ret < len);
+
+	fd = open(fname, flag);
+out:
+	free(fname);
+	free(alt_name);
+
+	return fd;
+}
+
 #define STRBUF_SIZE 3
 static int get_bool_value(const char *name, char **buf)
 {
 	int fd, len;
-	char *fname = NULL;
+	int errno_tmp;
 
 	if (!selinux_mnt) {
 		errno = ENOENT;
 		return -1;
 	}
 
-	*buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1));
+	*buf = malloc(sizeof(char) * (STRBUF_SIZE + 1));
 	if (!*buf)
-		goto out;
-	(*buf)[STRBUF_SIZE] = 0;
+		return -1;
 
-	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
-	fname = (char *)malloc(sizeof(char) * len);
-	if (!fname)
-		goto out;
-	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
+	(*buf)[STRBUF_SIZE] = 0;
 
-	fd = open(fname, O_RDONLY);
+	fd = bool_open(name, O_RDONLY);
 	if (fd < 0)
-		goto out;
+		goto out_err;
 
 	len = read(fd, *buf, STRBUF_SIZE);
+	errno_tmp = errno;
 	close(fd);
+	errno = errno_tmp;
 	if (len != STRBUF_SIZE)
-		goto out;
+		goto out_err;
 
-	free(fname);
 	return 0;
-      out:
-	if (*buf)
-		free(*buf);
-	if (fname)
-		free(fname);
+out_err:
+	free(*buf);
 	return -1;
 }
 
@@ -164,8 +266,8 @@ hidden_def(security_get_boolean_active)
 
 int security_set_boolean(const char *name, int value)
 {
-	int fd, ret, len;
-	char buf[2], *fname;
+	int fd, ret;
+	char buf[2];
 
 	if (!selinux_mnt) {
 		errno = ENOENT;
@@ -176,17 +278,9 @@ int security_set_boolean(const char *name, int value)
 		return -1;
 	}
 
-	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
-	fname = (char *)malloc(sizeof(char) * len);
-	if (!fname)
+	fd = bool_open(name, O_WRONLY);
+	if (fd < 0)
 		return -1;
-	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
-
-	fd = open(fname, O_WRONLY);
-	if (fd < 0) {
-		ret = -1;
-		goto out;
-	}
 
 	if (value)
 		buf[0] = '1';
@@ -196,8 +290,7 @@ int security_set_boolean(const char *name, int value)
 
 	ret = write(fd, buf, 2);
 	close(fd);
-      out:
-	free(fname);
+
 	if (ret > 0)
 		return 0;
 	else
@@ -256,7 +349,7 @@ static char *strtrim(char *dest, char *source, int size)
 static int process_boolean(char *buffer, char *name, int namesize, int *val)
 {
 	char name1[BUFSIZ];
-	char *ptr;
+	char *ptr = NULL;
 	char *tok = strtok_r(buffer, "=", &ptr);
 	if (tok) {
 		strncpy(name1, tok, BUFSIZ - 1);
diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c
index b245364..7c47222 100644
--- a/libselinux/src/callbacks.c
+++ b/libselinux/src/callbacks.c
@@ -16,6 +16,7 @@ default_selinux_log(int type __attribute__((unused)), const char *fmt, ...)
 {
 	int rc;
 	va_list ap;
+	if (is_selinux_enabled() == 0) return 0;
 	va_start(ap, fmt);
 	rc = vfprintf(stderr, fmt, ap);
 	va_end(ap);
diff --git a/libselinux/src/file_path_suffixes.h b/libselinux/src/file_path_suffixes.h
index 0b00156..d11c8dc 100644
--- a/libselinux/src/file_path_suffixes.h
+++ b/libselinux/src/file_path_suffixes.h
@@ -22,6 +22,8 @@ S_(BINPOLICY, "/policy/policy")
     S_(COLORS, "/secolor.conf")
     S_(VIRTUAL_DOMAIN, "/contexts/virtual_domain_context")
     S_(VIRTUAL_IMAGE, "/contexts/virtual_image_context")
+    S_(LXC_CONTEXTS, "/contexts/lxc_contexts")
     S_(FILE_CONTEXT_SUBS, "/contexts/files/file_contexts.subs")
     S_(FILE_CONTEXT_SUBS_DIST, "/contexts/files/file_contexts.subs_dist")
     S_(SEPGSQL_CONTEXTS, "/contexts/sepgsql_contexts")
+    S_(BOOLEAN_SUBS, "/booleans.subs_dist")
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 7bc46cc..82a608c 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -27,6 +27,7 @@
  * Internals, mostly moved over from matchpathcon.c
  */
 
+#define MAX_PREFIX 100
 /* A file security context specification. */
 typedef struct spec {
 	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
@@ -276,7 +277,7 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
 
 
 static int process_line(struct selabel_handle *rec,
-			const char *path, const char *prefix,
+			const char *path, const char **prefix_array,
 			char *line_buf, int pass, unsigned lineno)
 {
 	int items, len;
@@ -310,12 +311,24 @@ static int process_line(struct selabel_handle *rec,
 	}
 
 	len = get_stem_from_spec(regex);
-	if (len && prefix && strncmp(prefix, regex, len)) {
-		/* Stem of regex does not match requested prefix, discard. */
-		free(regex);
-		free(type);
-		free(context);
-		return 0;
+	if (len && prefix_array[0]) {
+		int i = 0;
+		int found = 0;
+		while (i < MAX_PREFIX && prefix_array[i]) {
+			if (strncmp(prefix_array[i], regex, len) == 0) {
+				found = 1;
+				break;
+			}
+			i++;
+		}
+
+		if (! found) {
+			/* Stem of regex does not match requested prefix, discard. */
+			free(regex);
+			free(type);
+			free(context);
+			return 0;
+		}
 	}
 
 	if (pass == 1) {
@@ -397,7 +410,8 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 {
 	struct saved_data *data = (struct saved_data *)rec->data;
 	const char *path = NULL;
-	const char *prefix = NULL;
+	const char *static_prefix_array[2] = {NULL, };
+	const char **prefix_array = static_prefix_array;
 	FILE *fp;
 	FILE *localfp = NULL;
 	FILE *homedirfp = NULL;
@@ -418,7 +432,10 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 			path = opts[n].value;
 			break;
 		case SELABEL_OPT_SUBSET:
-			prefix = opts[n].value;
+			static_prefix_array[0] = opts[n].value;
+			break;
+		case SELABEL_OPT_PREFIXES:
+			prefix_array = opts[n].values;
 			break;
 		case SELABEL_OPT_BASEONLY:
 			baseonly = !!opts[n].value;
@@ -481,7 +498,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 		while (getline(&line_buf, &line_len, fp) > 0) {
 			if (data->nspec >= maxnspec)
 				break;
-			status = process_line(rec, path, prefix, line_buf, pass, ++lineno);
+			status = process_line(rec, path, prefix_array, line_buf, pass, ++lineno);
 			if (status)
 				goto finish;
 		}
@@ -497,7 +514,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 			while (getline(&line_buf, &line_len, homedirfp) > 0) {
 				if (data->nspec >= maxnspec)
 					break;
-				status = process_line(rec, homedir_path, prefix, line_buf, pass, ++lineno);
+				status = process_line(rec, homedir_path, prefix_array, line_buf, pass, ++lineno);
 				if (status)
 					goto finish;
 			}
@@ -507,7 +524,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 			while (getline(&line_buf, &line_len, localfp) > 0) {
 				if (data->nspec >= maxnspec)
 					break;
-				status = process_line(rec, local_path, prefix, line_buf, pass, ++lineno);
+				status = process_line(rec, local_path, prefix_array, line_buf, pass, ++lineno);
 				if (status)
 					goto finish;
 			}
diff --git a/libselinux/src/load_policy.c b/libselinux/src/load_policy.c
index 10e29b9..888dab5 100644
--- a/libselinux/src/load_policy.c
+++ b/libselinux/src/load_policy.c
@@ -49,8 +49,9 @@ int load_setlocaldefs hidden = 1;
 int selinux_mkload_policy(int preservebools)
 {	
 	int kernvers = security_policyvers();
-	int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION, vers;
+	int maxvers = kernvers, minvers = DEFAULT_POLICY_VERSION;
 	int setlocaldefs = load_setlocaldefs;
+	char *pol_path = NULL;
 	char path[PATH_MAX];
 	struct stat sb;
 	struct utsname uts;
@@ -162,29 +163,24 @@ checkbool:
 			maxvers = max(kernvers, maxvers);
 	}
 
-	vers = maxvers;
-      search:
-	snprintf(path, sizeof(path), "%s.%d",
-		 selinux_binary_policy_path(), vers);
-	fd = open(path, O_RDONLY);
-	while (fd < 0 && errno == ENOENT
-	       && --vers >= minvers) {
-		/* Check prior versions to see if old policy is available */
-		snprintf(path, sizeof(path), "%s.%d",
-			 selinux_binary_policy_path(), vers);
-		fd = open(path, O_RDONLY);
+search:
+	pol_path = selinux_binary_policy_path_min_max(minvers, &maxvers);
+	if (!pol_path) {
+		fprintf(stderr, "SELinux: unable to find usable policy file:  %s\n",
+			strerror(errno));
+		goto dlclose;
 	}
+
+	fd = open(pol_path, O_RDONLY);
 	if (fd < 0) {
-		fprintf(stderr,
-			"SELinux:  Could not open policy file <= %s.%d:  %s\n",
-			selinux_binary_policy_path(), maxvers, strerror(errno));
+		fprintf(stderr, "SELinux:  Could not open policy file %s:  %s\n",
+			pol_path, strerror(errno));
 		goto dlclose;
 	}
 
 	if (fstat(fd, &sb) < 0) {
-		fprintf(stderr,
-			"SELinux:  Could not stat policy file %s:  %s\n",
-			path, strerror(errno));
+		fprintf(stderr, "SELinux:  Could not stat policy file %s:  %s\n",
+			pol_path, strerror(errno));
 		goto close;
 	}
 
@@ -195,13 +191,12 @@ checkbool:
 	size = sb.st_size;
 	data = map = mmap(NULL, size, prot, MAP_PRIVATE, fd, 0);
 	if (map == MAP_FAILED) {
-		fprintf(stderr,
-			"SELinux:  Could not map policy file %s:  %s\n",
-			path, strerror(errno));
+		fprintf(stderr, "SELinux:  Could not map policy file %s:  %s\n",
+			pol_path, strerror(errno));
 		goto close;
 	}
 
-	if (vers > kernvers && usesepol) {
+	if (maxvers > kernvers && usesepol) {
 		/* Need to downgrade to kernel-supported version. */
 		if (policy_file_create(&pf))
 			goto unmap;
@@ -220,12 +215,12 @@ checkbool:
 			/* Downgrade failed, keep searching. */
 			fprintf(stderr,
 				"SELinux:  Could not downgrade policy file %s, searching for an older version.\n",
-				path);
+				pol_path);
 			policy_file_free(pf);
 			policydb_free(policydb);
 			munmap(map, sb.st_size);
 			close(fd);
-			vers--;
+			maxvers--;
 			goto search;
 		}
 		policy_file_free(pf);
@@ -281,7 +276,7 @@ checkbool:
 	if (rc)
 		fprintf(stderr,
 			"SELinux:  Could not load policy file %s:  %s\n",
-			path, strerror(errno));
+			pol_path, strerror(errno));
 
       unmap:
 	if (data != map)
@@ -296,6 +291,7 @@ checkbool:
 	if (libsepolh)
 		dlclose(libsepolh);
 #endif
+	free(pol_path);
 	return rc;
 }
 
diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c
index 2d7369e..eb292f2 100644
--- a/libselinux/src/matchpathcon.c
+++ b/libselinux/src/matchpathcon.c
@@ -2,6 +2,7 @@
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
+#include <syslog.h>
 #include "selinux_internal.h"
 #include "label_internal.h"
 #include "callbacks.h"
@@ -62,7 +63,7 @@ static void
 {
 	va_list ap;
 	va_start(ap, fmt);
-	vfprintf(stderr, fmt, ap);
+	vsyslog(LOG_ERR, fmt, ap);
 	va_end(ap);
 }
 
@@ -306,7 +307,7 @@ static void matchpathcon_init_once(void)
 		destructor_key_initialized = 1;
 }
 
-int matchpathcon_init_prefix(const char *path, const char *subset)
+int matchpathcon_init_prefixes(const char *path, const char **prefixes)
 {
 	if (!mycanoncon)
 		mycanoncon = default_canoncon;
@@ -314,15 +315,22 @@ int matchpathcon_init_prefix(const char *path, const char *subset)
 	__selinux_once(once, matchpathcon_init_once);
 	__selinux_setspecific(destructor_key, (void *)1);
 
-	options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
-	options[SELABEL_OPT_SUBSET].value = subset;
+	options[SELABEL_OPT_PREFIXES].type = SELABEL_OPT_PREFIXES;
+	options[SELABEL_OPT_PREFIXES].values = prefixes;
 	options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH;
 	options[SELABEL_OPT_PATH].value = path;
 
 	hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT);
 	return hnd ? 0 : -1;
 }
+hidden_def(matchpathcon_init_prefixes)
 
+int matchpathcon_init_prefix(const char *path, const char *prefix)
+{
+	const char *prefixes[2] = { prefix, NULL };
+
+	return matchpathcon_init_prefixes(path, prefixes);
+}
 hidden_def(matchpathcon_init_prefix)
 
 int matchpathcon_init(const char *path)
@@ -397,10 +405,13 @@ int realpath_not_final(const char *name, char *resolved_path)
 		goto out;
 	}
 
-	resolved_path += len;
-	strcpy(resolved_path, "/");
-	resolved_path += 1;
-	strcpy(resolved_path, last_component);
+	p = resolved_path;
+	p += len;
+	if (strcmp(resolved_path, "/") != 0) {
+		strcpy(p, "/");
+		p += 1;
+	}
+	strcpy(p, last_component);
 out:
 	free(tmp_path);
 	return rc;
diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c
index f42cb7c..cb65666 100644
--- a/libselinux/src/selinux_config.c
+++ b/libselinux/src/selinux_config.c
@@ -9,6 +9,7 @@
 #include <unistd.h>
 #include <pthread.h>
 #include "selinux_internal.h"
+#include "policy.h"
 #include "get_default_type_internal.h"
 
 #define SELINUXDIR "/etc/selinux/"
@@ -46,7 +47,9 @@
 #define FILE_CONTEXT_SUBS 23
 #define SEPGSQL_CONTEXTS  24
 #define FILE_CONTEXT_SUBS_DIST 25
-#define NEL               26
+#define LXC_CONTEXTS      26
+#define BOOLEAN_SUBS      27
+#define NEL               28
 
 /* Part of one-time lazy init */
 static pthread_once_t once = PTHREAD_ONCE_INIT;
@@ -294,13 +297,57 @@ const char *selinux_removable_context_path(void)
 
 hidden_def(selinux_removable_context_path)
 
+char *selinux_binary_policy_path_min_max(int min, int *max)
+{
+	int ret;
+	char *path = NULL;
+
+	while(*max >= min) {
+		ret = asprintf(&path, "%s.%d", get_path(BINPOLICY), *max);
+		if (ret < 0)
+			goto err;
+		ret = access(path, R_OK);
+		if (!ret)
+			return path;
+		free(path);
+		path = NULL;
+		*max = *max - 1;
+	}
+err:
+	free(path);
+	return NULL;
+}
+hidden_def(selinux_binary_policy_path_min_max)
+
 const char *selinux_binary_policy_path(void)
 {
 	return get_path(BINPOLICY);
 }
-
 hidden_def(selinux_binary_policy_path)
 
+const char *selinux_current_policy_path(void)
+{
+	int rc = 0;
+	int vers = 0;
+	static char policy_path[PATH_MAX];
+
+	snprintf(policy_path, sizeof(policy_path), "%s/policy", selinux_mnt);
+	if (access(policy_path, F_OK) != 0 ) {
+		vers = security_policyvers();
+		do {
+			/* Check prior versions to see if old policy is available */
+			snprintf(policy_path, sizeof(policy_path), "%s.%d",
+				 selinux_binary_policy_path(), vers);
+		} while ((rc = access(policy_path, F_OK)) && --vers > 0);
+
+		if (rc) return NULL;
+	}
+
+	return policy_path;
+}
+
+hidden_def(selinux_current_policy_path)
+
 const char *selinux_file_context_path(void)
 {
 	return get_path(FILE_CONTEXTS);
@@ -418,6 +465,19 @@ const char *selinux_virtual_image_context_path(void)
 
 hidden_def(selinux_virtual_image_context_path)
 
+const char *selinux_lxc_contexts_path(void)
+{
+	return get_path(LXC_CONTEXTS);
+}
+
+hidden_def(selinux_lxc_contexts_path)
+
+const char * selinux_booleans_subs_path(void) {
+	return get_path(BOOLEAN_SUBS);
+}
+
+hidden_def(selinux_booleans_subs_path)
+
 const char * selinux_file_context_subs_path(void) {
 	return get_path(FILE_CONTEXT_SUBS);
 }
diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h
index 00df405..c47add9 100644
--- a/libselinux/src/selinux_internal.h
+++ b/libselinux/src/selinux_internal.h
@@ -59,13 +59,18 @@ hidden_proto(selinux_mkload_policy)
     hidden_proto(security_getenforce)
     hidden_proto(security_setenforce)
     hidden_proto(security_deny_unknown)
+    hidden_proto(selinux_binary_policy_path_min_max)
+    hidden_proto(selinux_boolean_sub)
     hidden_proto(selinux_binary_policy_path)
+    hidden_proto(selinux_booleans_subs_path)
+    hidden_proto(selinux_current_policy_path)
     hidden_proto(selinux_default_context_path)
     hidden_proto(selinux_securetty_types_path)
     hidden_proto(selinux_failsafe_context_path)
     hidden_proto(selinux_removable_context_path)
     hidden_proto(selinux_virtual_domain_context_path)
     hidden_proto(selinux_virtual_image_context_path)
+    hidden_proto(selinux_lxc_contexts_path)
     hidden_proto(selinux_file_context_path)
     hidden_proto(selinux_file_context_homedir_path)
     hidden_proto(selinux_file_context_local_path)
@@ -82,6 +87,7 @@ hidden_proto(selinux_mkload_policy)
     hidden_proto(selinux_path)
     hidden_proto(selinux_check_passwd_access)
     hidden_proto(selinux_check_securetty_context)
+    hidden_proto(matchpathcon_init_prefixes)
     hidden_proto(matchpathcon_init_prefix)
     hidden_proto(selinux_users_path)
     hidden_proto(selinux_usersconf_path);
diff --git a/libselinux/src/seusers.c b/libselinux/src/seusers.c
index 73ad42c..569fa43 100644
--- a/libselinux/src/seusers.c
+++ b/libselinux/src/seusers.c
@@ -276,13 +276,19 @@ int getseuser(const char *username, const char *service,
 	if (fp == NULL) goto err;
 	__fsetlocking(fp, FSETLOCKING_BYCALLER);
 	while (getline(&buffer, &size, fp) > 0) {
-		if (strncmp(buffer, "*:", 2) == 0) {
+
+		if (!service) {
+			rec = strdup(buffer);
+			break;
+		}
+
+		if (strncmp(buffer, "*:", 2) == 0)
+		{
 			free(rec);
 			rec = strdup(buffer);
 			continue;
 		}
-		if (!service)
-			continue;
+
 		len = strlen(service);
 		if ((strncmp(buffer, service, len) == 0) &&
 		    (buffer[len] == ':')) {
@@ -298,6 +304,7 @@ int getseuser(const char *username, const char *service,
 
 	seuser++;
 	level = strchr(seuser, ':');
+	if (! level) goto err;
 	*level = 0;
 	level++;
 	*r_seuser = strdup(seuser);
diff --git a/libselinux/utils/avcstat.c b/libselinux/utils/avcstat.c
index 7239ef2..73432f2 100644
--- a/libselinux/utils/avcstat.c
+++ b/libselinux/utils/avcstat.c
@@ -139,6 +139,7 @@ int main(int argc, char **argv)
 
 	sa.sa_handler = sighandler;
 	sa.sa_flags = SA_RESTART;
+	sigemptyset(&sa.sa_mask);
 
 	i = sigaction(SIGWINCH, &sa, NULL);
 	if (i < 0)
diff --git a/libselinux/utils/getdefaultcon.c b/libselinux/utils/getdefaultcon.c
index 049e75c..6bafedb 100644
--- a/libselinux/utils/getdefaultcon.c
+++ b/libselinux/utils/getdefaultcon.c
@@ -21,10 +21,11 @@ int main(int argc, char **argv)
 {
 	security_context_t usercon = NULL, cur_context = NULL;
 	char *user = NULL, *level = NULL, *role=NULL, *seuser=NULL, *dlevel=NULL;
+	char *service = NULL;
 	int ret, opt;
 	int verbose = 0;
 
-	while ((opt = getopt(argc, argv, "l:r:v")) > 0) {
+	while ((opt = getopt(argc, argv, "l:r:s:v")) > 0) {
 		switch (opt) {
 		case 'l':
 			level = strdup(optarg);
@@ -32,6 +33,9 @@ int main(int argc, char **argv)
 		case 'r':
 			role = strdup(optarg);
 			break;
+		case 's':
+			service = strdup(optarg);
+			break;
 		case 'v':
 			verbose = 1;
 			break;
@@ -61,7 +65,7 @@ int main(int argc, char **argv)
 	} else
 		cur_context = argv[optind + 1];
 
-	if ((ret = getseuserbyname(user, &seuser, &dlevel)) == 0) {
+	if ((ret = getseuser(user, service, &seuser, &dlevel)) == 0) {
 		if (! level) level=dlevel;
 		if (role != NULL && role[0]) 
 			ret=get_default_context_with_rolelevel(seuser, role, level,cur_context,&usercon);
@@ -74,7 +78,7 @@ int main(int argc, char **argv)
 		if (verbose) {
 			printf("%s: %s from %s %s %s %s -> %s\n", argv[0], user, cur_context, seuser, role, level, usercon);
 		} else {
-			printf("%s", usercon);
+			printf("%s\n", usercon);
 		}
 	}
 
diff --git a/libselinux/utils/getsebool.c b/libselinux/utils/getsebool.c
index 3a90449..9ae9243 100644
--- a/libselinux/utils/getsebool.c
+++ b/libselinux/utils/getsebool.c
@@ -87,14 +87,22 @@ int main(int argc, char **argv)
 			rc = -1;
 			goto out;
 		}
+		char *alt_name = selinux_boolean_sub(names[i]);
+		if (! alt_name) {
+			perror("Out of memory\n");
+			rc = -1;
+			goto out;
+		}
+
 		if (pending != active) {
-			printf("%s --> %s pending: %s\n", names[i],
+			printf("%s --> %s pending: %s\n", alt_name,
 			       (active ? "on" : "off"),
 			       (pending ? "on" : "off"));
 		} else {
-			printf("%s --> %s\n", names[i],
+			printf("%s --> %s\n", alt_name,
 			       (active ? "on" : "off"));
 		}
+		free(alt_name);
 	}
 
       out:
diff --git a/libselinux/utils/matchpathcon.c b/libselinux/utils/matchpathcon.c
index b1adadd..a3a21ca 100644
--- a/libselinux/utils/matchpathcon.c
+++ b/libselinux/utils/matchpathcon.c
@@ -45,21 +45,27 @@ static int printmatchpathcon(const char *path, int header, int mode)
 
 int main(int argc, char **argv)
 {
-	int i, init = 0;
+	int i, force_mode = 0;
 	int header = 1, opt;
 	int verify = 0;
 	int notrans = 0;
 	int error = 0;
 	int quiet = 0;
+	const char *prefixes[100];
+	char *file = NULL;
+	int prefix=0;
 
 	if (argc < 2)
 		usage(argv[0]);
 
-	while ((opt = getopt(argc, argv, "Nnf:p:Vq")) > 0) {
+	while ((opt = getopt(argc, argv, "m:Nnf:p:Vq")) > 0) {
 		switch (opt) {
 		case 'n':
 			header = 0;
 			break;
+		case 'm':
+			force_mode = atoi(optarg);
+			break;
 		case 'V':
 			verify = 1;
 			break;
@@ -68,36 +74,24 @@ int main(int argc, char **argv)
 			set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
 			break;
 		case 'f':
-			if (init) {
+			if (prefix) {
 				fprintf(stderr,
 					"%s:  -f and -p are exclusive\n",
 					argv[0]);
 				exit(1);
 			}
-			init = 1;
-			if (matchpathcon_init(optarg)) {
-				fprintf(stderr,
-					"Error while processing %s:  %s\n",
-					optarg,
-					errno ? strerror(errno) : "invalid");
-				exit(1);
-			}
+			file = optarg;
 			break;
 		case 'p':
-			if (init) {
+			if (file) {
 				fprintf(stderr,
 					"%s:  -f and -p are exclusive\n",
 					argv[0]);
 				exit(1);
 			}
-			init = 1;
-			if (matchpathcon_init_prefix(NULL, optarg)) {
-				fprintf(stderr,
-					"Error while processing %s:  %s\n",
-					optarg,
-					errno ? strerror(errno) : "invalid");
-				exit(1);
-			}
+			prefixes[prefix]=optarg;
+			prefix++;
+			prefixes[prefix]=NULL;
 			break;
 		case 'q':
 			quiet = 1;
@@ -106,6 +100,26 @@ int main(int argc, char **argv)
 			usage(argv[0]);
 		}
 	}
+	if (prefix > 0) {
+		if (matchpathcon_init_prefixes(file, prefixes)) {
+			fprintf(stderr,
+				"Error while processing %s:  %s\n",
+				file,
+				errno ? strerror(errno) : "invalid");
+			exit(1);
+		}
+	} else {
+		if (file) {
+			if (matchpathcon_init(file)) {
+				fprintf(stderr,
+					"Error inwhile processing %s:  %s\n",
+					file,
+					errno ? strerror(errno) : "invalid");
+				exit(1);
+			}
+		}
+	}
+
 	for (i = optind; i < argc; i++) {
 		int rc, mode = 0;
 		struct stat buf;
@@ -114,8 +128,11 @@ int main(int argc, char **argv)
 		if (len > 1  && path[len - 1 ] == '/')
 			path[len - 1 ] = '\0';
 
-		if (lstat(path, &buf) == 0)
-			mode = buf.st_mode;
+		if (! force_mode) {
+			if (lstat(path, &buf) == 0)
+				mode = buf.st_mode;
+		} else
+			mode = force_mode;
 
 		if (verify) {
 			rc = selinux_file_context_verify(path, mode);