Blob Blame Raw
diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h
index a4079aa..aba6e33 100644
--- a/libselinux/include/selinux/selinux.h
+++ b/libselinux/include/selinux/selinux.h
@@ -498,7 +498,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);
diff --git a/libselinux/man/man3/selinux_binary_policy_path.3 b/libselinux/man/man3/selinux_binary_policy_path.3
index ec97dcf..68f8fdf 100644
--- a/libselinux/man/man3/selinux_binary_policy_path.3
+++ b/libselinux/man/man3/selinux_binary_policy_path.3
@@ -17,6 +17,8 @@ directories and files
 .sp
 .B const char *selinux_binary_policy_path(void);
 .sp
+.B const char *selinux_current_policy_path(void);
+.sp
 .B const char *selinux_failsafe_context_path(void);
 .sp
 .B const char *selinux_removable_context_path(void);
@@ -52,8 +54,11 @@ returns the top-level SELinux configuration directory.
 .BR selinux_policy_root ()
 returns the top-level policy directory.
 .sp
+.BR selinux_current_policy_path()
+returns the binary policy file loaded into the kernel
+.sp
 .BR selinux_binary_policy_path ()
-returns the binary policy file loaded into kernel.
+returns the binary policy file on disk
 .sp
 .BR selinux_default_type_path ()
 returns the context file mapping roles to default types.
diff --git a/libselinux/src/audit2why.c b/libselinux/src/audit2why.c
index ffe381b..73c07aa 100644
--- a/libselinux/src/audit2why.c
+++ b/libselinux/src/audit2why.c
@@ -191,49 +191,24 @@ static PyObject *finish(PyObject *self __attribute__((unused)), PyObject *args)
 static int __policy_init(const char *init_path)
 {
 	FILE *fp;
-	int vers = 0;
-	char path[PATH_MAX];
+	const char *path;
 	char errormsg[PATH_MAX];
 	struct sepol_policy_file *pf = NULL;
 	int rc;
 	unsigned int cnt;
 
-	path[PATH_MAX-1] = '\0';
-	if (init_path) {
-		strncpy(path, init_path, PATH_MAX-1);
-		fp = fopen(path, "r");
-		if (!fp) {
-			snprintf(errormsg, sizeof(errormsg), 
-				 "unable to open %s:  %s\n",
-				 path, strerror(errno));
-			PyErr_SetString( PyExc_ValueError, errormsg);
-			return 1;
-		}
-	} else {
-		vers = sepol_policy_kern_vers_max();
-		if (vers < 0) {
-			snprintf(errormsg, sizeof(errormsg), 
-				 "Could not get policy version:  %s\n",
-				 strerror(errno));
-			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");
-		}
-		if (!fp) {
-			snprintf(errormsg, sizeof(errormsg), 
-				 "unable to open %s.%d:  %s\n",
-				 selinux_binary_policy_path(),
-				 security_policyvers(), strerror(errno));
-			PyErr_SetString( PyExc_ValueError, errormsg);
-			return 1;
-		}
+	if (init_path)
+		path = init_path;
+	else
+		path = selinux_current_policy_path();
+
+	fp = fopen(path, "r");
+	if (!fp) {
+		snprintf(errormsg, sizeof(errormsg), 
+			 "unable to open %s:  %s\n",
+			 path, strerror(errno));
+		PyErr_SetString( PyExc_ValueError, errormsg);
+		return 1;
 	}
 
 	avc = calloc(sizeof(struct avc_t), 1);
@@ -310,10 +285,12 @@ static PyObject *init(PyObject *self __attribute__((unused)), PyObject *args) {
 }
 
 #define RETURN(X) \
-	PyTuple_SetItem(result, 0, Py_BuildValue("i", X));	\
-	return result;						
+	{ \
+		return Py_BuildValue("iO", (X), Py_None);	\
+	}					
 
 static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args) {
+	char *reason_buf = NULL;
 	security_context_t scon; 
 	security_context_t tcon;
 	char *tclassstr; 
@@ -328,10 +305,6 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args
 	struct sepol_av_decision avd;
 	int rc;
 	int i=0;
-	PyObject *result = PyTuple_New(2);
-	if (!result) return NULL;
-	Py_INCREF(Py_None);
-	PyTuple_SetItem(result, 1, Py_None);
 
 	if (!PyArg_ParseTuple(args,(char *)"sssO!:audit2why",&scon,&tcon,&tclassstr,&PyList_Type, &listObj)) 
 		return NULL;
@@ -342,22 +315,21 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args
 	/* should raise an error here. */
 	if (numlines < 0)	return NULL; /* Not a list */
 
-	if (!avc) {
+	if (!avc)
 		RETURN(NOPOLICY)
-	}
 
 	rc = sepol_context_to_sid(scon, strlen(scon) + 1, &ssid);
-	if (rc < 0) {
+	if (rc < 0)
 		RETURN(BADSCON)
-	}
+
 	rc = sepol_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
-	if (rc < 0) {
+	if (rc < 0)
 		RETURN(BADTCON)
-	}
+
 	tclass = string_to_security_class(tclassstr);
-	if (!tclass) {
+	if (!tclass)
 		RETURN(BADTCLASS)
-	}
+
 	/* Convert the permission list to an AV. */
 	av = 0;
 
@@ -377,21 +349,20 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args
 #endif
 		
 		perm = string_to_av_perm(tclass, permstr);
-		if (!perm) {
+		if (!perm)
 			RETURN(BADPERM)
-		}
+
 		av |= perm;
 	}
 
 	/* Reproduce the computation. */
-	rc = sepol_compute_av_reason(ssid, tsid, tclass, av, &avd, &reason);
-	if (rc < 0) {
+	rc = sepol_compute_av_reason_buffer(ssid, tsid, tclass, av, &avd, &reason, &reason_buf, 0);
+	if (rc < 0)
 		RETURN(BADCOMPUTE)
-	}
 
-	if (!reason) {
+	if (!reason)
 		RETURN(ALLOW)
-	}
+
 	if (reason & SEPOL_COMPUTEAV_TE) {
 		avc->ssid = ssid;
 		avc->tsid = tsid;
@@ -404,28 +375,34 @@ static PyObject *analyze(PyObject *self __attribute__((unused)) , PyObject *args
 				RETURN(TERULE)
 			}
 		} else {
-			PyTuple_SetItem(result, 0, Py_BuildValue("i", BOOLEAN));
+			PyObject *outboollist;
 			struct boolean_t *b = bools;
 			int len=0;
 			while (b->name) {
 				len++; b++;
 			}
 			b = bools;
-			PyObject *outboollist = PyTuple_New(len);
+			outboollist = PyList_New(len);
 			len=0;
 			while(b->name) {
-				PyObject *bool = Py_BuildValue("(si)", b->name, b->active);
-				PyTuple_SetItem(outboollist, len++, bool);
+				PyObject *bool_ = Py_BuildValue("(si)", b->name, b->active);
+				PyList_SetItem(outboollist, len++, bool_);
 				b++;
 			}
 			free(bools);
-			PyTuple_SetItem(result, 1, outboollist);
-			return result;
+			/* 'N' steals the reference to outboollist */
+			return Py_BuildValue("iN", BOOLEAN, outboollist);
 		}
 	}
 
 	if (reason & SEPOL_COMPUTEAV_CONS) {
-		RETURN(CONSTRAINT);
+		if (reason_buf) {
+			PyObject *result = NULL;
+			result = Py_BuildValue("is", CONSTRAINT, reason_buf);
+			free(reason_buf);
+			return result;
+		} 
+		RETURN(CONSTRAINT)
 	}
 
 	if (reason & SEPOL_COMPUTEAV_RBAC)
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/get_context_list.c b/libselinux/src/get_context_list.c
index b9e8002..355730a 100644
--- a/libselinux/src/get_context_list.c
+++ b/libselinux/src/get_context_list.c
@@ -426,7 +426,7 @@ int get_ordered_context_list(const char *user,
 	/* Initialize ordering array. */
 	ordering = malloc(nreach * sizeof(unsigned int));
 	if (!ordering)
-		goto oom_order;
+		goto failsafe;
 	for (i = 0; i < nreach; i++)
 		ordering[i] = nreach;
 
@@ -435,7 +435,7 @@ int get_ordered_context_list(const char *user,
 	fname_len = strlen(user_contexts_path) + strlen(user) + 2;
 	fname = malloc(fname_len);
 	if (!fname)
-		goto oom_order;
+		goto failsafe;
 	snprintf(fname, fname_len, "%s%s", user_contexts_path, user);
 	fp = fopen(fname, "r");
 	if (fp) {
@@ -465,31 +465,28 @@ int get_ordered_context_list(const char *user,
 		}
 	}
 
+	if (!nordered)
+		goto failsafe;
+
 	/* Apply the ordering. */
-	if (nordered) {
-		co = malloc(nreach * sizeof(struct context_order));
-		if (!co)
-			goto oom_order;
-		for (i = 0; i < nreach; i++) {
-			co[i].con = reachable[i];
-			co[i].order = ordering[i];
-		}
-		qsort(co, nreach, sizeof(struct context_order), order_compare);
-		for (i = 0; i < nreach; i++)
-			reachable[i] = co[i].con;
-		free(co);
+	co = malloc(nreach * sizeof(struct context_order));
+	if (!co)
+		goto failsafe;
+	for (i = 0; i < nreach; i++) {
+		co[i].con = reachable[i];
+		co[i].order = ordering[i];
 	}
+	qsort(co, nreach, sizeof(struct context_order), order_compare);
+	for (i = 0; i < nreach; i++)
+		reachable[i] = co[i].con;
+	free(co);
 
-	/* Return the ordered list. 
-	   If we successfully ordered it, then only report the ordered entries
-	   to the caller.  Otherwise, fall back to the entire reachable list. */
-	if (nordered && nordered < nreach) {
+	/* Only report the ordered entries to the caller. */
+	if (nordered < nreach) {
 		for (i = nordered; i < nreach; i++)
 			free(reachable[i]);
 		reachable[nordered] = NULL;
 		rc = nordered;
-	} else {
-		rc = nreach;
 	}
 
       out:
@@ -523,14 +520,6 @@ int get_ordered_context_list(const char *user,
 	}
 	rc = 1;			/* one context in the list */
 	goto out;
-
-      oom_order:
-	/* Unable to order context list due to OOM condition.
-	   Fall back to unordered reachable context list. */
-	fprintf(stderr, "%s:  out of memory, unable to order list\n",
-		__FUNCTION__);
-	rc = nreach;
-	goto out;
 }
 
 hidden_def(get_ordered_context_list)
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..2a00807 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);
 }
 
diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c
index 296f357..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/"
@@ -296,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);
diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h
index 2c7c85c..008aa6d 100644
--- a/libselinux/src/selinux_internal.h
+++ b/libselinux/src/selinux_internal.h
@@ -61,7 +61,9 @@ hidden_proto(selinux_mkload_policy)
     hidden_proto(security_deny_unknown)
     hidden_proto(selinux_boolean_sub)
     hidden_proto(selinux_binary_policy_path)
+    hidden_proto(selinux_binary_policy_path_min_max)
     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)