[PATCH] libselinux: Enhance file context support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Update file contexts generation and loading to use common code. Also fix
to correct sort order.

The file labeling code has also had minor formatting, white space
removal etc. changes.

These changes bring file context processing in line with Android [1]
apart from some minor build differences.

label_file.c - Move process_line function to label_file.h
sefcontext_compile.c - Update to use common process_line code. Now frees
all malloc'ed memory, checked by valgrind. Also added optional -o output
file parameter - updated man page to reflect this change.

[1] https://android-review.googlesource.com/#/c/153580/

Signed-off-by: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>
---
 libselinux/man/man8/sefcontext_compile.8 |  49 +++++-
 libselinux/src/label_file.c              | 171 +++-----------------
 libselinux/src/label_file.h              | 156 +++++++++++++++++-
 libselinux/src/label_internal.h          |   2 +-
 libselinux/utils/sefcontext_compile.c    | 268 ++++++++++++++++---------------
 5 files changed, 354 insertions(+), 292 deletions(-)

diff --git a/libselinux/man/man8/sefcontext_compile.8 b/libselinux/man/man8/sefcontext_compile.8
index 810d22a..584c4c6 100644
--- a/libselinux/man/man8/sefcontext_compile.8
+++ b/libselinux/man/man8/sefcontext_compile.8
@@ -1,15 +1,56 @@
-.TH "sefcontext_compile" "8" "27 Jun 2013" "dwalsh@xxxxxxxxxx" "SELinux Command Line documentation"
+.TH "sefcontext_compile" "8" "12 Jun 2015" "dwalsh@xxxxxxxxxx" "SELinux Command Line documentation"
 .SH "NAME"
 sefcontext_compile \- compile file context regular expression files
 .
 .SH "SYNOPSIS"
-.B sefcontext_compile inputfile
+.B sefcontext_compile
+.RB [ \-o
+.IR outputfile ]
+.I inputfile
 .
 .SH "DESCRIPTION"
-sefcontext_compile is used libsemanage to compile file context regular expressions into prce format.  sefcontext_compile writes the compiled prce file with the .bin suffix appended "inputfile".bin.  This compiled file is used by libselinux file labeling functions.
+.B sefcontext_compile
+is used to compile file context regular expressions into
+.BR prce (3)
+format.
+.sp
+The compiled file is used by libselinux file labeling functions.
+.sp
+By default
+.B sefcontext_compile
+writes the compiled prce file with the
+.B .bin
+suffix appended (e.g. \fIinputfile\fB.bin\fR).
+.SH OPTIONS
+.TP
+.B \-o
+Specify an
+.I outputfile
+that must be a fully qualified file name as the
+.B .bin
+suffix is not automatically added.
+.
+.SH "RETURN VALUE"
+On error -1 is returned.  On success 0 is returned.
 
-.SH "EXAMPLE"
+.SH "EXAMPLES"
+.B Example 1:
+.br
 sefcontext_compile /etc/selinux/targeted/contexts/files/file_contexts
+.sp
+Results in the following file being generated:
+.RS
+/etc/selinux/targeted/contexts/files/file_contexts.bin
+.RE
+.sp
+.B Example 2:
+.br
+sefcontext_compile -o new_fc.bin /etc/selinux/targeted/contexts/files/file_contexts
+.sp
+Results in the following file being generated in the cwd:
+.RS
+new_fc.bin
+.RE
 .
 .SH AUTHOR
 Dan Walsh, <dwalsh@xxxxxxxxxx>
diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 60aae66..1d6c36e 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -15,13 +15,11 @@
 #include <limits.h>
 #include <stdint.h>
 #include <pcre.h>
-
-#include <linux/limits.h>
-
+#include <unistd.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <unistd.h>
+
 #include "callbacks.h"
 #include "label_internal.h"
 #include "label_file.h"
@@ -72,12 +70,14 @@ static int nodups_specs(struct saved_data *data, const char *path)
 	for (ii = 0; ii < data->nspec; ii++) {
 		curr_spec = &spec_arr[ii];
 		for (jj = ii + 1; jj < data->nspec; jj++) {
-			if ((!strcmp(spec_arr[jj].regex_str, curr_spec->regex_str))
+			if ((!strcmp(spec_arr[jj].regex_str,
+				curr_spec->regex_str))
 			    && (!spec_arr[jj].mode || !curr_spec->mode
 				|| spec_arr[jj].mode == curr_spec->mode)) {
 				rc = -1;
 				errno = EINVAL;
-				if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
+				if (strcmp(spec_arr[jj].lr.ctx_raw,
+					    curr_spec->lr.ctx_raw)) {
 					COMPAT_LOG
 						(SELINUX_ERROR,
 						 "%s: Multiple different specifications for %s  (%s and %s).\n",
@@ -96,136 +96,8 @@ static int nodups_specs(struct saved_data *data, const char *path)
 	return rc;
 }
 
-static int compile_regex(struct saved_data *data, struct spec *spec, const char **errbuf)
-{
-	const char *tmperrbuf;
-	char *reg_buf, *anchored_regex, *cp;
-	struct stem *stem_arr = data->stem_arr;
-	size_t len;
-	int erroff;
-
-	if (spec->regcomp)
-		return 0; /* already done */
-
-	/* Skip the fixed stem. */
-	reg_buf = spec->regex_str;
-	if (spec->stem_id >= 0)
-		reg_buf += stem_arr[spec->stem_id].len;
-
-	/* Anchor the regular expression. */
-	len = strlen(reg_buf);
-	cp = anchored_regex = malloc(len + 3);
-	if (!anchored_regex)
-		return -1;
-
-	/* Create ^...$ regexp.  */
-	*cp++ = '^';
-	cp = mempcpy(cp, reg_buf, len);
-	*cp++ = '$';
-	*cp = '\0';
-
-	/* Compile the regular expression. */
-	spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf, &erroff, NULL);
-	free(anchored_regex);
-	if (!spec->regex) {
-		if (errbuf)
-			*errbuf=tmperrbuf;
-		return -1;
-	}
-
-	spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
-	if (!spec->sd && tmperrbuf) {
-		if (errbuf)
-			*errbuf=tmperrbuf;
-		return -1;
-	}
-
-	/* Done. */
-	spec->regcomp = 1;
-
-	return 0;
-}
-
-static int process_line(struct selabel_handle *rec,
-			const char *path, const char *prefix,
-			char *line_buf, unsigned lineno)
-{
-	int items, len, rc;
-	char *regex = NULL, *type = NULL, *context = NULL;
-	struct saved_data *data = (struct saved_data *)rec->data;
-	struct spec *spec_arr;
-	unsigned int nspec = data->nspec;
-	const char *errbuf = NULL;
-
-	items = read_spec_entries(line_buf, 3, &regex, &type, &context);
-	if (items <= 0)
-		return items;
-
-	if (items < 2) {
-		COMPAT_LOG(SELINUX_WARNING,
-			    "%s:  line %u is missing fields, skipping\n", path,
-			    lineno);
-		if (items == 1)
-			free(regex);
-		return 0;
-	} else if (items == 2) {
-		/* The type field is optional. */
-		free(context);
-		context = type;
-		type = 0;
-	}
-
-	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;
-	}
-
-	rc = grow_specs(data);
-	if (rc)
-		return rc;
-
-	spec_arr = data->spec_arr;
-
-	/* process and store the specification in spec. */
-	spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
-	spec_arr[nspec].regex_str = regex;
-	if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
-		COMPAT_LOG(SELINUX_WARNING, "%s:  line %u has invalid regex %s:  %s\n",
-			   path, lineno, regex, (errbuf ? errbuf : "out of memory"));
-	}
-
-	/* Convert the type string to a mode format */
-	spec_arr[nspec].type_str = type;
-	spec_arr[nspec].mode = 0;
-	if (type) {
-		mode_t mode = string_to_mode(type);
-		if (mode == (mode_t)-1) {
-			COMPAT_LOG(SELINUX_WARNING, "%s:  line %u has invalid file type %s\n",
-				   path, lineno, type);
-			mode = 0;
-		}
-		spec_arr[nspec].mode = mode;
-	}
-
-	spec_arr[nspec].lr.ctx_raw = context;
-
-	/* Determine if specification has
-	 * any meta characters in the RE */
-	spec_hasMetaChars(&spec_arr[nspec]);
-
-	if (strcmp(context, "<<none>>") && rec->validating)
-		compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
-
-	data->nspec = ++nspec;
-
-	return 0;
-}
-
-static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *sb)
+static int load_mmap(struct selabel_handle *rec, const char *path,
+						    struct stat *sb)
 {
 	struct saved_data *data = (struct saved_data *)rec->data;
 	char mmap_path[PATH_MAX + 1];
@@ -259,12 +131,6 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
 		return -1;
 	}
 
-	if (mmap_stat.st_mtime == sb->st_mtime &&
-	    mmap_stat.st_mtim.tv_nsec < sb->st_mtim.tv_nsec) {
-		close(mmapfd);
-		return -1;
-	}
-
 	/* ok, read it in... */
 	len = mmap_stat.st_size;
 	len += (sysconf(_SC_PAGE_SIZE) - 1);
@@ -460,7 +326,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
 		if (rc < 0)
 			goto err;
 
-		if (stem_id < 0 || stem_id >= stem_map_len)
+		if (stem_id < 0 || stem_id >= (int32_t)stem_map_len)
 			spec->stem_id = -1;
 		 else
 			spec->stem_id = stem_map[stem_id];
@@ -520,19 +386,21 @@ err:
 	return rc;
 }
 
-static int process_file(const char *path, const char *suffix, struct selabel_handle *rec, const char *prefix)
+static int process_file(const char *path, const char *suffix,
+			  struct selabel_handle *rec, const char *prefix)
 {
 	FILE *fp;
 	struct stat sb;
 	unsigned int lineno;
-	size_t line_len;
+	size_t line_len = 0;
 	char *line_buf = NULL;
 	int rc;
 	char stack_path[PATH_MAX + 1];
 
 	/* append the path suffix if we have one */
 	if (suffix) {
-		rc = snprintf(stack_path, sizeof(stack_path), "%s.%s", path, suffix);
+		rc = snprintf(stack_path, sizeof(stack_path),
+					    "%s.%s", path, suffix);
 		if (rc >= (int)sizeof(stack_path)) {
 			errno = ENAMETOOLONG;
 			return -1;
@@ -563,13 +431,13 @@ static int process_file(const char *path, const char *suffix, struct selabel_han
 	while (getline(&line_buf, &line_len, fp) > 0) {
 		rc = process_line(rec, path, prefix, line_buf, ++lineno);
 		if (rc)
-			return rc;
+			goto out;
 	}
+
 out:
 	free(line_buf);
 	fclose(fp);
-
-	return 0;
+	return rc;
 }
 
 static int init(struct selabel_handle *rec, struct selinux_opt *opts,
@@ -609,7 +477,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 
 	rec->spec_file = strdup(path);
 
-	/* 
+	/*
 	 * The do detailed validation of the input and fill the spec array
 	 */
 	status = process_file(path, NULL, rec, prefix);
@@ -634,7 +502,6 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
 
 	status = sort_specs(data);
 
-	status = 0;
 finish:
 	if (status)
 		free(data->spec_arr);
@@ -731,7 +598,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
 	if (partial)
 		pcre_options |= PCRE_PARTIAL_SOFT;
 
-	/* 
+	/*
 	 * Check for matching specifications in reverse order, so that
 	 * the last matching specification is used.
 	 */
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index a8d1e51..814b4de 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -3,6 +3,7 @@
 
 #include <sys/stat.h>
 
+#include "callbacks.h"
 #include "label_internal.h"
 
 #define SELINUX_MAGIC_COMPILED_FCONTEXT	0xf97cff8a
@@ -14,7 +15,7 @@
 
 #define SELINUX_COMPILED_FCONTEXT_MAX_VERS	SELINUX_COMPILED_FCONTEXT_MODE
 
-/* Prior to verison 8.20, libpcre did not have pcre_free_study() */
+/* Prior to version 8.20, libpcre did not have pcre_free_study() */
 #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
 #define pcre_free_study  pcre_free
 #endif
@@ -173,7 +174,6 @@ static inline void spec_hasMetaChars(struct spec *spec)
 		}
 		c++;
 	}
-	return;
 }
 
 /* Move exact pathname specifications to the end. */
@@ -200,9 +200,9 @@ static inline int sort_specs(struct saved_data *data)
 	}
 
 	/*
-	 * now the exact pathnames are at the end, but they are in the reverse order.
-	 * since 'front' is now the first of the 'exact' we can run that part of the
-	 * array switching the front and back element.
+	 * now the exact pathnames are at the end, but they are in the reverse
+	* order. Since 'front' is now the first of the 'exact' we can run
+	* that part of the array switching the front and back element.
 	 */
 	back = data->nspec - 1;
 	while (front < back) {
@@ -242,7 +242,8 @@ static inline int get_stem_from_spec(const char *const buf)
 /*
  * return the stemid given a string and a length
  */
-static inline int find_stem(struct saved_data *data, const char *buf, int stem_len)
+static inline int find_stem(struct saved_data *data, const char *buf,
+						    int stem_len)
 {
 	int i;
 
@@ -317,4 +318,147 @@ static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes)
 	return 0;
 }
 
+static inline int compile_regex(struct saved_data *data, struct spec *spec,
+					    const char **errbuf)
+{
+	const char *tmperrbuf;
+	char *reg_buf, *anchored_regex, *cp;
+	struct stem *stem_arr = data->stem_arr;
+	size_t len;
+	int erroff;
+
+	if (spec->regcomp)
+		return 0; /* already done */
+
+	/* Skip the fixed stem. */
+	reg_buf = spec->regex_str;
+	if (spec->stem_id >= 0)
+		reg_buf += stem_arr[spec->stem_id].len;
+
+	/* Anchor the regular expression. */
+	len = strlen(reg_buf);
+	cp = anchored_regex = malloc(len + 3);
+	if (!anchored_regex)
+		return -1;
+
+	/* Create ^...$ regexp.  */
+	*cp++ = '^';
+	memcpy(cp, reg_buf, len);
+	cp += len;
+	*cp++ = '$';
+	*cp = '\0';
+
+	/* Compile the regular expression. */
+	spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf,
+						    &erroff, NULL);
+	free(anchored_regex);
+	if (!spec->regex) {
+		if (errbuf)
+			*errbuf = tmperrbuf;
+		return -1;
+	}
+
+	spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
+	if (!spec->sd && tmperrbuf) {
+		if (errbuf)
+			*errbuf = tmperrbuf;
+		return -1;
+	}
+
+	/* Done. */
+	spec->regcomp = 1;
+
+	return 0;
+}
+
+/* This service is used by label_file.c process_file() and
+ * utils/sefcontext_compile.c */
+static inline int process_line(struct selabel_handle *rec,
+			const char *path, const char *prefix,
+			char *line_buf, unsigned lineno)
+{
+	int items, len, rc;
+	char *regex = NULL, *type = NULL, *context = NULL;
+	struct saved_data *data = (struct saved_data *)rec->data;
+	struct spec *spec_arr;
+	unsigned int nspec = data->nspec;
+	const char *errbuf = NULL;
+
+	items = read_spec_entries(line_buf, 3, &regex, &type, &context);
+	if (items <= 0)
+		return items;
+
+	if (items < 2) {
+		COMPAT_LOG(SELINUX_WARNING,
+			    "%s:  line %u is missing fields, skipping\n", path,
+			    lineno);
+		if (items == 1)
+			free(regex);
+		return 0;
+	} else if (items == 2) {
+		/* The type field is optional. */
+		context = type;
+		type = 0;
+	}
+
+	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;
+	}
+
+	rc = grow_specs(data);
+	if (rc)
+		return rc;
+
+	spec_arr = data->spec_arr;
+
+	/* process and store the specification in spec. */
+	spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
+	spec_arr[nspec].regex_str = regex;
+	if (rec->validating &&
+			    compile_regex(data, &spec_arr[nspec], &errbuf)) {
+		COMPAT_LOG(SELINUX_WARNING,
+			   "%s:  line %u has invalid regex %s:  %s\n",
+			   path, lineno, regex,
+			   (errbuf ? errbuf : "out of memory"));
+	}
+
+	/* Convert the type string to a mode format */
+	spec_arr[nspec].type_str = type;
+	spec_arr[nspec].mode = 0;
+	if (type) {
+		mode_t mode = string_to_mode(type);
+
+		if (mode == (mode_t)-1) {
+			COMPAT_LOG(SELINUX_WARNING,
+				   "%s:  line %u has invalid file type %s\n",
+				   path, lineno, type);
+			mode = 0;
+		}
+		spec_arr[nspec].mode = mode;
+	}
+
+	spec_arr[nspec].lr.ctx_raw = context;
+
+	/* Determine if specification has
+	 * any meta characters in the RE */
+	spec_hasMetaChars(&spec_arr[nspec]);
+
+	if (strcmp(context, "<<none>>") && rec->validating) {
+		if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
+			COMPAT_LOG(SELINUX_WARNING,
+				    "%s:  line %d has invalid context %s\n",
+				    path, lineno, spec_arr[nspec].lr.ctx_raw);
+		}
+	}
+
+	data->nspec = ++nspec;
+
+	return 0;
+}
+
 #endif /* _SELABEL_FILE_H_ */
diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h
index 0e582b6..5300319 100644
--- a/libselinux/src/label_internal.h
+++ b/libselinux/src/label_internal.h
@@ -90,7 +90,7 @@ selabel_validate(struct selabel_handle *rec,
  */
 extern int myprintf_compat;
 extern void __attribute__ ((format(printf, 1, 2)))
-(*myprintf) (const char *fmt,...);
+(*myprintf) (const char *fmt, ...);
 
 #define COMPAT_LOG(type, fmt...) if (myprintf_compat)	  \
 		myprintf(fmt);				  \
diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
index 03bc0a7..a38001f 100644
--- a/libselinux/utils/sefcontext_compile.c
+++ b/libselinux/utils/sefcontext_compile.c
@@ -7,117 +7,69 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-
-#include <linux/limits.h>
+#include <getopt.h>
+#include <limits.h>
 
 #include "../src/label_file.h"
 
-static int process_file(struct saved_data *data, const char *filename)
+/*
+ * These three functions are here as process_line() is common code defined
+ * in label_file.h that make these calls.
+ *
+ * The selinux_log functions are used to display any errors such as invalid
+ * regex or file type (mode).
+ *
+ * As validation is not performed for sefcontext_compile, selabel_validate()
+ * returns success. Also see comment in main() regarding validation.
+ */
+static int __attribute__ ((format(printf, 2, 3)))
+default_selinux_log(int type __attribute__((unused)), const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+
+	va_start(ap, fmt);
+	rc = vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	return rc;
+}
+
+int __attribute__ ((format(printf, 2, 3)))
+(*selinux_log)(int, const char *, ...) =
+	default_selinux_log;
+
+int selabel_validate(struct selabel_handle __attribute__ ((unused)) *rec,
+		 struct selabel_lookup_rec __attribute__ ((unused)) *contexts)
+{
+	return 0;
+}
+
+static int process_file(struct selabel_handle *rec, const char *filename)
 {
-	struct spec *spec;
 	unsigned int line_num;
+	int rc;
 	char *line_buf = NULL;
-	size_t line_len;
-	ssize_t len;
+	size_t line_len = 0;
 	FILE *context_file;
+	const char *prefix = NULL;
 
 	context_file = fopen(filename, "r");
 	if (!context_file) {
-		fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno));
+		fprintf(stderr, "Error opening %s: %s\n",
+			    filename, strerror(errno));
 		return -1;
 	}
 
 	line_num = 0;
-	while ((len = getline(&line_buf, &line_len, context_file)) != -1) {
-		char *context = NULL;
-		char *mode = NULL;
-		char *regex = NULL;
-		char *cp, *anchored_regex;
-		pcre *re;
-		pcre_extra *sd;
-		const char *err;
-		int items, erroff, rc;
-		size_t regex_len;
-		int32_t stem_id;
-
-		line_num++;
-
-		items = read_spec_entries(line_buf, 3, &regex, &mode, &context);
-		if (items < 0)
-			return -1;
-
-		if (items == 0)
-			continue;
-		else if (items == 1) {
-			fprintf(stderr,
-				 "line: %u has invalid entry - skipping: %s\n",
-				 line_num, line_buf);
-			continue;
-		} else if (items == 2) {
-			context = mode;
-			mode = NULL;
-		}
-
-		rc = grow_specs(data);
-		if (rc) {
-			fprintf(stderr, "grow_specs failed: %s\n", strerror(errno));
-			return rc;
-		}
-
-		spec = &data->spec_arr[data->nspec];
-
-		spec->lr.ctx_raw = context;
-		spec->mode = string_to_mode(mode);
-		if (spec->mode == (mode_t)-1) {
-			fprintf(stderr, "%s: line %u has invalid file type %s\n",
-				regex, line_num + 1, mode);
-			spec->mode = 0;
-		}
-		free(mode);
-		spec->regex_str = regex;
-
-		stem_id = find_stem_from_spec(data, regex);
-		spec->stem_id = stem_id;
-		/* skip past the fixed stem part */
-		if (stem_id != -1)
-			regex += data->stem_arr[stem_id].len;
-
-		regex_len = strlen(regex);
-		cp = anchored_regex = malloc(regex_len + 3);
-		if (!cp) {
-			fprintf(stderr, "Malloc Failed: %s\n", strerror(errno));
-			return -1;
-		}
-		*cp++ = '^';
-		memcpy(cp, regex, regex_len);
-		cp += regex_len;
-		*cp++ = '$';
-		*cp = '\0';
-
-		spec_hasMetaChars(spec);
-
-		re = pcre_compile(anchored_regex, PCRE_DOTALL, &err, &erroff, NULL);
-		if (!re) {
-			fprintf(stderr, "PCRE compilation failed for %s at offset %d: %s\n", anchored_regex, erroff, err);
-			return -1;
-		}
-		spec->regex = re;
-
-		sd = pcre_study(re, 0, &err);
-		if (!sd) {
-			fprintf(stderr, "PCRE study failed for %s: %s\n", anchored_regex, err);
-			return -1;
-		}
-		free(anchored_regex);
-		spec->sd = sd;
-
-		data->nspec++;
+	while (getline(&line_buf, &line_len, context_file) > 0) {
+		rc = process_line(rec, filename, prefix, line_buf, ++line_num);
+		if (rc)
+			goto out;
 	}
-
+out:
 	free(line_buf);
 	fclose(context_file);
-
-	return 0;
+	return rc;
 }
 
 /*
@@ -129,12 +81,12 @@ static int process_file(struct saved_data *data, const char *filename)
  * char - pcre version string EXCLUDING nul
  * u32 - number of stems
  * ** Stems
- * 	u32  - length of stem EXCLUDING nul
- * 	char - stem char array INCLUDING nul
+ *	u32  - length of stem EXCLUDING nul
+ *	char - stem char array INCLUDING nul
  * u32 - number of regexs
  * ** Regexes
- * 	u32  - length of upcoming context INCLUDING nul
- * 	char - char array of the raw context
+ *	u32  - length of upcoming context INCLUDING nul
+ *	char - char array of the raw context
  *	u32  - length of the upcoming regex_str
  *	char - char array of the original regex string including the stem.
  *	u32  - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE
@@ -301,7 +253,7 @@ err:
 	goto out;
 }
 
-static int free_specs(struct saved_data *data)
+static void free_specs(struct saved_data *data)
 {
 	struct spec *specs = data->spec_arr;
 	unsigned int num_entries = data->nspec;
@@ -311,59 +263,113 @@ static int free_specs(struct saved_data *data)
 		free(specs[i].lr.ctx_raw);
 		free(specs[i].lr.ctx_trans);
 		free(specs[i].regex_str);
+		free(specs[i].type_str);
 		pcre_free(specs[i].regex);
 		pcre_free_study(specs[i].sd);
 	}
 	free(specs);
 
 	num_entries = data->num_stems;
-	for (i = 0; i < num_entries; i++) {
+	for (i = 0; i < num_entries; i++)
 		free(data->stem_arr[i].buf);
-	}
 	free(data->stem_arr);
 
 	memset(data, 0, sizeof(*data));
-	return 0;
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr,
+		"usage: %s [-o out_file] fc_file\n"
+		"Where:\n\t"
+		"-o      Optional file name of the PCRE formatted binary\n\t"
+		"        file to be output. If not specified the default\n\t"
+		"        will be fc_file with the .bin suffix appended.\n\t"
+		"fc_file The text based file contexts file to be processed.\n",
+		progname);
+		exit(EXIT_FAILURE);
 }
 
 int main(int argc, char *argv[])
 {
-	struct saved_data data;
-	const char *path;
+	const char *path = NULL;
+	const char *out_file = NULL;
 	char stack_path[PATH_MAX + 1];
-	int rc;
-	char *tmp= NULL;
-	int fd;
+	char *tmp = NULL;
+	int fd, rc, opt;
 	struct stat buf;
-
-	if (argc != 2) {
-		fprintf(stderr, "usage: %s input_file\n", argv[0]);
-		exit(EXIT_FAILURE);
+	struct selabel_handle *rec = NULL;
+	struct saved_data *data = NULL;
+
+	if (argc < 2)
+		usage(argv[0]);
+
+	while ((opt = getopt(argc, argv, "o:")) > 0) {
+		switch (opt) {
+		case 'o':
+			out_file = optarg;
+			break;
+		default:
+			usage(argv[0]);
+		}
 	}
 
-	memset(&data, 0, sizeof(data));
-
-	path = argv[1];
+	if (optind >= argc)
+		usage(argv[0]);
 
+	path = argv[optind];
 	if (stat(path, &buf) < 0) {
 		fprintf(stderr, "Can not stat: %s: %m\n", path);
 		exit(EXIT_FAILURE);
 	}
 
-	rc = process_file(&data, path);
+	/* Generate dummy handle for process_line() function */
+	rec = (struct selabel_handle *)calloc(1, sizeof(*rec));
+	if (!rec) {
+		fprintf(stderr, "Failed to calloc handle\n");
+		exit(EXIT_FAILURE);
+	}
+	rec->backend = SELABEL_CTX_FILE;
+
+	/* Need to set validation on to get the bin file generated by the
+	 * process_line function, however as the bin file being generated
+	 * may not be related to the currently loaded policy (that it
+	 * would be validated against), then set callback to ignore any
+	 * validation. */
+	rec->validating = 1;
+
+	data = (struct saved_data *)calloc(1, sizeof(*data));
+	if (!data) {
+		fprintf(stderr, "Failed to calloc saved_data\n");
+		free(rec);
+		exit(EXIT_FAILURE);
+	}
+
+	rec->data = data;
+
+	rc = process_file(rec, path);
 	if (rc < 0)
-		return rc;
+		goto err;
 
-	rc = sort_specs(&data);
+	rc = sort_specs(data);
 	if (rc)
-		return rc;
+		goto err;
+
+	if (out_file)
+		rc = snprintf(stack_path, sizeof(stack_path), "%s", out_file);
+	else
+		rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
 
-	rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
 	if (rc < 0 || rc >= (int)sizeof(stack_path))
-		return rc;
+		goto err;
 
-	if (asprintf(&tmp, "%sXXXXXX", stack_path) < 0)
-		return -1;
+	tmp = malloc(strlen(stack_path) + 7);
+	if (!tmp)
+		goto err;
+
+	rc = sprintf(tmp, "%sXXXXXX", stack_path);
+	if (rc < 0)
+		goto err;
 
 	fd  = mkstemp(tmp);
 	if (fd < 0)
@@ -372,23 +378,27 @@ int main(int argc, char *argv[])
 	rc = fchmod(fd, buf.st_mode);
 	if (rc < 0) {
 		perror("fchmod failed to set permission on compiled regexs");
-		goto err;
+		goto err_unlink;
 	}
 
-	rc = write_binary_file(&data, fd);
-
+	rc = write_binary_file(data, fd);
 	if (rc < 0)
-		goto err;
+		goto err_unlink;
 
-	rename(tmp, stack_path);
-	rc = free_specs(&data);
+	rc = rename(tmp, stack_path);
 	if (rc < 0)
-		goto err;
+		goto err_unlink;
 
 	rc = 0;
 out:
+	free_specs(data);
+	free(rec);
+	free(data);
 	free(tmp);
 	return rc;
+
+err_unlink:
+	unlink(tmp);
 err:
 	rc = -1;
 	goto out;
-- 
2.1.0

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.



[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux