Re: [PATCH] libselinux: Enhance file context support

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

 



On 06/15/2015 08:33 AM, Richard Haines wrote:
> Update file contexts generation and loading to use common code. Also fix
> to correct sort order.

What do you mean by "correct sort order", and where is this changed in
this patch?

> 
> 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;
> 

_______________________________________________
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