Re: [PATCH] [RFC] nodups_specs: speedup

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

 



On 08/29/2016 12:22 PM, william.c.roberts@xxxxxxxxx wrote:
> From: William Roberts <william.c.roberts@xxxxxxxxx>
> 
> I noticed, via gprof, that the time spent in nodups_specs()
> accounts for 100% of the label_open() call.
> 
> It seems as though the N^2 comparison using strcmp is very
> slow.
> 
> Do two major things:
> 1. move the rec->validating check to the left, check the simple
>    thing first before runnning the expensive strcmp(). strcmp()
>    is used to check string equality, check lengths first.
> 2. strlen() is used all over to calculate lengths, just store
>    it in a struct with the string so its usable elsewhere, rather
>    than recalculating it.
> 
> text 21.4% speedup:
> before text: 248
> after text: 195
> 
> binary 24.6% speedup:
> before bin: 236
> after bin: 178
> 
> Some things to ponder:
> 1. We can use C ABI safe pointer instead of len_str structure
>    https://bitbucket.org/billcroberts/twist
>    There are pros and cons to this approach, namely if someone
>    calls free(x) instead of twist_free(x)
>    It also currently has 0 support for stack based strings (simple
>    enough to add). I think this approach is overkill here.

Agreed.

> 
> 2. The location of the str_len struct and routines should likely
>    move elsewhere.

Agreed.

> 
> 3. The impact on Android is currently unmeasured, that's next.
>    Also, bionic uses something from label_file.h for processing
>    property_contexts for the Android property subsystem... so
>    need to ensure that all works as advertised still.
> 
> Things to do:
> 1. Cleanup the code locations, likely a util.h or a len_str.h,
>    a better name would be nice.
> 2. Spell check this commit message

Seems a bit prone to the str and len fields getting out of sync since
they are both directly manipulated.

> 
> Signed-off-by: William Roberts <william.c.roberts@xxxxxxxxx>
> ---
>  libselinux/src/label.c                  |  8 ++--
>  libselinux/src/label_android_property.c | 44 +++++++++----------
>  libselinux/src/label_db.c               |  7 +--
>  libselinux/src/label_file.c             | 63 ++++++++++++++------------
>  libselinux/src/label_file.h             | 78 +++++++++++++++++++--------------
>  libselinux/src/label_internal.h         | 22 +++++++++-
>  libselinux/src/label_media.c            |  5 ++-
>  libselinux/src/label_support.c          | 32 ++++++++------
>  libselinux/src/label_x.c                |  5 ++-
>  libselinux/src/matchpathcon.c           |  2 +-
>  10 files changed, 159 insertions(+), 107 deletions(-)
> 
> diff --git a/libselinux/src/label.c b/libselinux/src/label.c
> index 963bfcb..11324ea 100644
> --- a/libselinux/src/label.c
> +++ b/libselinux/src/label.c
> @@ -209,7 +209,7 @@ int selabel_validate(struct selabel_handle *rec,
>  	if (!rec->validating || contexts->validated)
>  		goto out;
>  
> -	rc = selinux_validate(&contexts->ctx_raw);
> +	rc = selinux_validate(&contexts->ctx_raw.str);
>  	if (rc < 0)
>  		goto out;
>  
> @@ -248,7 +248,7 @@ static int selabel_fini(struct selabel_handle *rec,
>  		return -1;
>  
>  	if (translating && !lr->ctx_trans &&
> -	    selinux_raw_to_trans_context(lr->ctx_raw, &lr->ctx_trans))
> +	    selinux_raw_to_trans_context(lr->ctx_raw.str, &lr->ctx_trans))
>  		return -1;
>  
>  	return 0;
> @@ -369,7 +369,7 @@ int selabel_lookup_raw(struct selabel_handle *rec, char **con,
>  	if (!lr)
>  		return -1;
>  
> -	*con = strdup(lr->ctx_raw);
> +	*con = strdup(lr->ctx_raw.str);
>  	return *con ? 0 : -1;
>  }
>  
> @@ -429,7 +429,7 @@ int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
>  	if (!lr)
>  		return -1;
>  
> -	*con = strdup(lr->ctx_raw);
> +	*con = strdup(lr->ctx_raw.str);
>  	return *con ? 0 : -1;
>  }
>  
> diff --git a/libselinux/src/label_android_property.c b/libselinux/src/label_android_property.c
> index 290b438..af0b9a8 100644
> --- a/libselinux/src/label_android_property.c
> +++ b/libselinux/src/label_android_property.c
> @@ -16,7 +16,7 @@
>  /* A property security context specification. */
>  typedef struct spec {
>  	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
> -	char *property_key;		/* property key string */
> +	struct len_str property_key;		/* property key string */
>  } spec_t;
>  
>  /* Our stored configuration */
> @@ -33,13 +33,13 @@ static int cmp(const void *A, const void *B)
>  {
>  	const struct spec *sp1 = A, *sp2 = B;
>  
> -	if (strncmp(sp1->property_key, "*", 1) == 0)
> +	if (strncmp(sp1->property_key.str, "*", 1) == 0)
>  		return 1;
> -	if (strncmp(sp2->property_key, "*", 1) == 0)
> +	if (strncmp(sp2->property_key.str, "*", 1) == 0)
>  		return -1;
>  
> -	size_t L1 = strlen(sp1->property_key);
> -	size_t L2 = strlen(sp2->property_key);
> +	size_t L1 = sp1->property_key.len;
> +	size_t L2 = sp2->property_key.len;
>  
>  	return (L1 < L2) - (L1 > L2);
>  }
> @@ -56,23 +56,23 @@ 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].property_key,
> -					    curr_spec->property_key)) {
> +			if (len_str_eq(&spec_arr[jj].property_key,
> +					    &curr_spec->property_key)) {
>  				rc = -1;
>  				errno = EINVAL;
> -				if (strcmp(spec_arr[jj].lr.ctx_raw,
> -						    curr_spec->lr.ctx_raw)) {
> +				if (!len_str_eq(&spec_arr[jj].lr.ctx_raw,
> +						    &curr_spec->lr.ctx_raw)) {
>  					selinux_log
>  						(SELINUX_ERROR,
>  						 "%s: Multiple different specifications for %s  (%s and %s).\n",
> -						 path, curr_spec->property_key,
> -						 spec_arr[jj].lr.ctx_raw,
> -						 curr_spec->lr.ctx_raw);
> +						 path, curr_spec->property_key.str,
> +						 spec_arr[jj].lr.ctx_raw.str,
> +						 curr_spec->lr.ctx_raw.str);
>  				} else {
>  					selinux_log
>  						(SELINUX_ERROR,
>  						 "%s: Multiple same specifications for %s.\n",
> -						 path, curr_spec->property_key);
> +						 path, curr_spec->property_key.str);
>  				}
>  			}
>  		}
> @@ -85,7 +85,7 @@ static int process_line(struct selabel_handle *rec,
>  			int pass, unsigned lineno)
>  {
>  	int items;
> -	char *prop = NULL, *context = NULL;
> +	struct len_str *prop = { 0 }, *context = { 0 };
>  	struct saved_data *data = (struct saved_data *)rec->data;
>  	spec_t *spec_arr = data->spec_arr;
>  	unsigned int nspec = data->nspec;
> @@ -118,14 +118,14 @@ static int process_line(struct selabel_handle *rec,
>  		free(context);
>  	} else if (pass == 1) {
>  		/* On the second pass, process and store the specification in spec. */
> -		spec_arr[nspec].property_key = prop;
> -		spec_arr[nspec].lr.ctx_raw = context;
> +		memcpy(&spec_arr[nspec].property_key, prop, sizeof(*prop));
> +		memcpy(&spec_arr[nspec].lr.ctx_raw, context, sizeof(*context));
>  
>  		if (rec->validating) {
>  			if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
>  				selinux_log(SELINUX_ERROR,
>  					    "%s:  line %u has invalid context %s\n",
> -					    path, lineno, spec_arr[nspec].lr.ctx_raw);
> +					    path, lineno, spec_arr[nspec].lr.ctx_raw.str);
>  				errno = EINVAL;
>  				return -1;
>  			}
> @@ -233,8 +233,8 @@ static void closef(struct selabel_handle *rec)
>  
>  	for (i = 0; i < data->nspec; i++) {
>  		spec = &data->spec_arr[i];
> -		free(spec->property_key);
> -		free(spec->lr.ctx_raw);
> +		free(spec->property_key.str);
> +		free(spec->lr.ctx_raw.str);
>  		free(spec->lr.ctx_trans);
>  	}
>  
> @@ -259,11 +259,11 @@ static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
>  	}
>  
>  	for (i = 0; i < data->nspec; i++) {
> -		if (strncmp(spec_arr[i].property_key, key,
> -			    strlen(spec_arr[i].property_key)) == 0) {
> +		if (strncmp(spec_arr[i].property_key.str, key,
> +			    spec_arr[i].property_key.len) == 0) {
>  			break;
>  		}
> -		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
> +		if (strncmp(spec_arr[i].property_key.str, "*", 1) == 0)
>  			break;
>  	}
>  
> diff --git a/libselinux/src/label_db.c b/libselinux/src/label_db.c
> index 1155bcc..c700aca 100644
> --- a/libselinux/src/label_db.c
> +++ b/libselinux/src/label_db.c
> @@ -153,7 +153,8 @@ process_line(const char *path, char *line_buf, unsigned int line_num,
>  
>  	free(type);
>  	spec->key = key;
> -	spec->lr.ctx_raw = context;
> +	spec->lr.ctx_raw.str = context;
> +	spec->lr.ctx_raw.len = strlen(context);
>  
>  	catalog->nspec++;
>  
> @@ -181,7 +182,7 @@ db_close(struct selabel_handle *rec)
>  	for (i = 0; i < catalog->nspec; i++) {
>  		spec = &catalog->specs[i];
>  		free(spec->key);
> -		free(spec->lr.ctx_raw);
> +		free(spec->lr.ctx_raw.str);
>  		free(spec->lr.ctx_trans);
>  	}
>  	free(catalog);
> @@ -333,7 +334,7 @@ out_error:
>  		spec_t	       *spec = &catalog->specs[i];
>  
>  		free(spec->key);
> -		free(spec->lr.ctx_raw);
> +		free(spec->lr.ctx_raw.str);
>  		free(spec->lr.ctx_trans);
>  	}
>  	free(catalog);
> diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> index 68c566b..ade07d8 100644
> --- a/libselinux/src/label_file.c
> +++ b/libselinux/src/label_file.c
> @@ -71,25 +71,24 @@ 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 (len_str_eq(&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 (!len_str_eq(&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",
> -						 path, curr_spec->regex_str,
> -						 spec_arr[jj].lr.ctx_raw,
> -						 curr_spec->lr.ctx_raw);
> +						 path, curr_spec->regex_str.str,
> +						 spec_arr[jj].lr.ctx_raw.str,
> +						 curr_spec->lr.ctx_raw.str);
>  				} else {
>  					COMPAT_LOG
>  						(SELINUX_ERROR,
>  						 "%s: Multiple same specifications for %s.\n",
> -						 path, curr_spec->regex_str);
> +						 path, curr_spec->regex_str.str);
>  				}
>  			}
>  		}
> @@ -475,12 +474,13 @@ static int read_binary_file(struct selabel_handle *rec)
>  			goto out;
>  		}
>  
> -		spec->lr.ctx_raw = str_buf;
> +		spec->lr.ctx_raw.str = str_buf;
> +		spec->lr.ctx_raw.len = entry_len -1;
>  
> -		if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) {
> +		if (rec->validating && strcmp(spec->lr.ctx_raw.str, "<<none>>")) {
>  			if (selabel_validate(rec, &spec->lr) < 0) {
>  				selinux_log(SELINUX_ERROR, "%s: context %s is invalid\n",
> -						data->path, spec->lr.ctx_raw);
> +						data->path, spec->lr.ctx_raw.str);
>  				errno = EINVAL;
>  				free(str_buf);
>  				goto out;
> @@ -492,14 +492,16 @@ static int read_binary_file(struct selabel_handle *rec)
>  		if (err < 0 || !entry_len)
>  			goto out;
>  
> -		spec->regex_str = (char *) map_area->next_addr;
> +		spec->regex_str.str = (char *) map_area->next_addr;
>  		err = next_entry(NULL, map_area, entry_len);
>  		if (err < 0)
>  			goto out;
>  
> -		if (spec->regex_str[entry_len - 1] != '\0')
> +		if (spec->regex_str.str[entry_len - 1] != '\0')
>  			goto out;
>  
> +		spec->regex_str.len = entry_len - 1;
> +
>  		/* Process mode */
>  		if (version >= SELINUX_COMPILED_FCONTEXT_MODE)
>  			err = next_entry(&mode, map_area, sizeof(mode));
> @@ -715,11 +717,13 @@ static void closef(struct selabel_handle *rec)
>  	for (i = 0; i < data->nspec; i++) {
>  		spec = &data->spec_arr[i];
>  		free(spec->lr.ctx_trans);
> -		free(spec->lr.ctx_raw);
> +		free(spec->lr.ctx_raw.str);
>  		if (spec->from_mmap)
>  			continue;
> -		free(spec->regex_str);
> -		free(spec->type_str);
> +
> +		free(spec->regex_str.str);
> +		free(spec->type_str.str);
> +
>  		if (spec->regcomp) {
>  			pcre_free(spec->regex);
>  			pcre_free_study(spec->sd);
> @@ -767,6 +771,11 @@ static struct spec *lookup_common(struct selabel_handle *rec,
>  	const char *prev_slash, *next_slash;
>  	unsigned int sofar = 0;
>  
> +	struct len_str none = {
> +			.str = (char *)"<<none>>",
> +			.len = 8
> +	};
> +
>  	if (!data->nspec) {
>  		errno = ENOENT;
>  		goto finish;
> @@ -834,7 +843,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
>  		}
>  	}
>  
> -	if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
> +	if (i < 0 || len_str_eq(&spec_arr[i].lr.ctx_raw, &none)) {
>  		/* No matching specification. */
>  		errno = ENOENT;
>  		goto finish;
> @@ -926,8 +935,8 @@ static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, co
>  	selinux_log(SELINUX_INFO,
>  		    "selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n",
>  		    reason,
> -		    i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw,
> -		    j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw);
> +		    i, spec1->regex_str.str, spec1->mode, spec1->lr.ctx_raw.str,
> +		    j, spec2->regex_str.str, spec2->mode, spec2->lr.ctx_raw.str);
>  	return SELABEL_INCOMPARABLE;
>  }
>  
> @@ -976,7 +985,7 @@ static enum selabel_cmp_result cmp(struct selabel_handle *h1,
>  			    memcmp(spec1->regex, spec2->regex, len1))
>  				return incomp(spec1, spec2, "regex", i, j);
>  		} else {
> -			if (strcmp(spec1->regex_str, spec2->regex_str))
> +			if (strcmp(spec1->regex_str.str, spec2->regex_str.str))
>  				return incomp(spec1, spec2, "regex_str", i, j);
>  		}
>  
> @@ -995,7 +1004,7 @@ static enum selabel_cmp_result cmp(struct selabel_handle *h1,
>  				return incomp(spec1, spec2, "stem", i, j);
>  		}
>  
> -		if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw))
> +		if (!len_str_eq(&spec1->lr.ctx_raw, &spec2->lr.ctx_raw))
>  			return incomp(spec1, spec2, "ctx_raw", i, j);
>  
>  		i++;
> @@ -1020,17 +1029,17 @@ static void stats(struct selabel_handle *rec)
>  
>  	for (i = 0; i < nspec; i++) {
>  		if (spec_arr[i].matches == 0) {
> -			if (spec_arr[i].type_str) {
> +			if (spec_arr[i].type_str.str) {
>  				COMPAT_LOG(SELINUX_WARNING,
>  				    "Warning!  No matches for (%s, %s, %s)\n",
> -				    spec_arr[i].regex_str,
> -				    spec_arr[i].type_str,
> -				    spec_arr[i].lr.ctx_raw);
> +				    spec_arr[i].regex_str.str,
> +				    spec_arr[i].type_str.str,
> +				    spec_arr[i].lr.ctx_raw.str);
>  			} else {
>  				COMPAT_LOG(SELINUX_WARNING,
>  				    "Warning!  No matches for (%s, %s)\n",
> -				    spec_arr[i].regex_str,
> -				    spec_arr[i].lr.ctx_raw);
> +				    spec_arr[i].regex_str.str,
> +				    spec_arr[i].lr.ctx_raw.str);
>  			}
>  		}
>  	}
> diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
> index da06164..cd021f4 100644
> --- a/libselinux/src/label_file.h
> +++ b/libselinux/src/label_file.h
> @@ -26,10 +26,10 @@
>  
>  /* A file security context specification. */
>  struct spec {
> -	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
> -	char *regex_str;	/* regular expession string for diagnostics */
> -	char *type_str;		/* type string for diagnostic messages */
> -	pcre *regex;		/* compiled regular expression */
> +	struct selabel_lookup_rec lr; /* holds contexts for lookup result */
> +	struct len_str regex_str;     /* regular expession string for diagnostics */
> +	struct len_str type_str;     /* type string for diagnostic messages */
> +	pcre *regex;                  /* compiled regular expression */
>  	union {
>  		pcre_extra *sd;	/* pointer to extra compiled stuff */
>  		pcre_extra lsd;	/* used to hold the mmap'd version */
> @@ -90,16 +90,19 @@ static inline pcre_extra *get_pcre_extra(struct spec *spec)
>  		return spec->sd;
>  }
>  
> -static inline mode_t string_to_mode(char *mode)
> +static inline mode_t string_to_mode(struct len_str *mode)
>  {
>  	size_t len;
>  
>  	if (!mode)
>  		return 0;
> -	len = strlen(mode);
> -	if (mode[0] != '-' || len != 2)
> +
> +	len = mode->len;
> +
> +	if (mode->str[0] != '-' || len != 2)
>  		return -1;
> -	switch (mode[1]) {
> +
> +	switch (mode->str[1]) {
>  	case 'b':
>  		return S_IFBLK;
>  	case 'c':
> @@ -153,8 +156,8 @@ static inline void spec_hasMetaChars(struct spec *spec)
>  	int len;
>  	char *end;
>  
> -	c = spec->regex_str;
> -	len = strlen(spec->regex_str);
> +	c = spec->regex_str.str;
> +	len = spec->regex_str.len;
>  	end = c + len;
>  
>  	spec->hasMetaChars = 0;
> @@ -175,7 +178,7 @@ static inline void spec_hasMetaChars(struct spec *spec)
>  		case '(':
>  		case '{':
>  			spec->hasMetaChars = 1;
> -			spec->prefix_len = c - spec->regex_str;
> +			spec->prefix_len = c - spec->regex_str.str;
>  			return;
>  		case '\\':	/* skip the next character */
>  			c++;
> @@ -327,13 +330,16 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec,
>  	if (spec->regcomp)
>  		return 0; /* already done */
>  
> +	len = spec->regex_str.len;
> +	reg_buf = spec->regex_str.str;
> +
>  	/* Skip the fixed stem. */
> -	reg_buf = spec->regex_str;
> -	if (spec->stem_id >= 0)
> +	if (spec->stem_id >= 0) {
>  		reg_buf += stem_arr[spec->stem_id].len;
> +		len -= 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;
> @@ -375,7 +381,15 @@ static inline int process_line(struct selabel_handle *rec,
>  			char *line_buf, unsigned lineno)
>  {
>  	int items, len, rc;
> -	char *regex = NULL, *type = NULL, *context = NULL;
> +
> +	struct len_str regex = { 0 } , type = { 0 }, context  = { 0 };
> +
> +	/* XXX Export this as a const */
> +	struct len_str none = {
> +			.str = (char *)"<<none>>",
> +			.len = 8
> +	};
> +
>  	struct saved_data *data = (struct saved_data *)rec->data;
>  	struct spec *spec_arr;
>  	unsigned int nspec = data->nspec;
> @@ -399,21 +413,21 @@ static inline int process_line(struct selabel_handle *rec,
>  			    "%s:  line %u is missing fields\n", path,
>  			    lineno);
>  		if (items == 1)
> -			free(regex);
> +			free(regex.str);
>  		errno = EINVAL;
>  		return -1;
>  	} else if (items == 2) {
>  		/* The type field is optional. */
>  		context = type;
> -		type = 0;
> +		memset(&type, 0, sizeof(type));
>  	}
>  
> -	len = get_stem_from_spec(regex);
> -	if (len && prefix && strncmp(prefix, regex, len)) {
> +	len = get_stem_from_spec(regex.str);
> +	if (len && prefix && strncmp(prefix, regex.str, len)) {
>  		/* Stem of regex does not match requested prefix, discard. */
> -		free(regex);
> -		free(type);
> -		free(context);
> +		free(regex.str);
> +		free(type.str);
> +		free(context.str);
>  		return 0;
>  	}
>  
> @@ -424,13 +438,13 @@ static inline int process_line(struct selabel_handle *rec,
>  	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;
> -
> -	spec_arr[nspec].type_str = type;
> +	spec_arr[nspec].stem_id = find_stem_from_spec(data, regex.str);
> +	memcpy(&spec_arr[nspec].regex_str, &regex, sizeof(regex));
> +	memcpy(&spec_arr[nspec].lr.ctx_raw, &context, sizeof(context));
>  	spec_arr[nspec].mode = 0;
>  
> -	spec_arr[nspec].lr.ctx_raw = context;
> +	if (type.str)
> +		memcpy(&spec_arr[nspec].type_str, &type, sizeof(type));
>  
>  	/*
>  	 * bump data->nspecs to cause closef() to cover it in its free
> @@ -442,19 +456,19 @@ static inline int process_line(struct selabel_handle *rec,
>  			    compile_regex(data, &spec_arr[nspec], &errbuf)) {
>  		COMPAT_LOG(SELINUX_ERROR,
>  			   "%s:  line %u has invalid regex %s:  %s\n",
> -			   path, lineno, regex,
> +			   path, lineno, regex.str,
>  			   (errbuf ? errbuf : "out of memory"));
>  		errno = EINVAL;
>  		return -1;
>  	}
>  
> -	if (type) {
> -		mode_t mode = string_to_mode(type);
> +	if (type.str) {
> +		mode_t mode = string_to_mode(&type);
>  
>  		if (mode == (mode_t)-1) {
>  			COMPAT_LOG(SELINUX_ERROR,
>  				   "%s:  line %u has invalid file type %s\n",
> -				   path, lineno, type);
> +				   path, lineno, type.str);
>  			errno = EINVAL;
>  			return -1;
>  		}
> @@ -465,7 +479,7 @@ static inline int process_line(struct selabel_handle *rec,
>  	 * any meta characters in the RE */
>  	spec_hasMetaChars(&spec_arr[nspec]);
>  
> -	if (strcmp(context, "<<none>>") && rec->validating)
> +	if (rec->validating && !len_str_eq(&context, &none))
>  		compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
>  
>  	return 0;
> diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h
> index aa48fff..51aa33d 100644
> --- a/libselinux/src/label_internal.h
> +++ b/libselinux/src/label_internal.h
> @@ -71,8 +71,28 @@ extern struct selabel_sub *selabel_subs_init(const char *path,
>  				    struct selabel_sub *list,
>  				    struct selabel_digest *digest);
>  
> +/*
> + * A simple struct for tracking string lengths
> + * with strings.
> + */
> +struct len_str {
> +	size_t len;
> +	char *str;
> +};
> +
> +static inline bool len_str_eq(struct len_str *a, struct len_str *b)
> +{
> +	if (a->len != b->len)
> +		return false;
> +
> +	if (a->str == b->str)
> +		return true;
> +
> +	return !strcmp(a->str, b->str);
> +}
> +
>  struct selabel_lookup_rec {
> -	char * ctx_raw;
> +	struct len_str ctx_raw;
>  	char * ctx_trans;
>  	int validated;
>  };
> diff --git a/libselinux/src/label_media.c b/libselinux/src/label_media.c
> index 622741b..e85e973 100644
> --- a/libselinux/src/label_media.c
> +++ b/libselinux/src/label_media.c
> @@ -56,7 +56,8 @@ static int process_line(const char *path, char *line_buf, int pass,
>  
>  	if (pass == 1) {
>  		data->spec_arr[data->nspec].key = key;
> -		data->spec_arr[data->nspec].lr.ctx_raw = context;
> +		data->spec_arr[data->nspec].lr.ctx_raw.str = context;
> +		data->spec_arr[data->nspec].lr.ctx_raw.len = strlen(context);
>  	}
>  
>  	data->nspec++;
> @@ -159,7 +160,7 @@ static void close(struct selabel_handle *rec)
>  	for (i = 0; i < data->nspec; i++) {
>  		spec = &spec_arr[i];
>  		free(spec->key);
> -		free(spec->lr.ctx_raw);
> +		free(spec->lr.ctx_raw.str);
>  		free(spec->lr.ctx_trans);
>  	}
>  
> diff --git a/libselinux/src/label_support.c b/libselinux/src/label_support.c
> index 26f9ef1..e9b842f 100644
> --- a/libselinux/src/label_support.c
> +++ b/libselinux/src/label_support.c
> @@ -22,16 +22,17 @@
>   *            errno will be set.
>   *
>   */
> -static inline int read_spec_entry(char **entry, char **ptr, int *len, const char **errbuf)
> +static inline int read_spec_entry(struct len_str *entry, char **ptr, const char **errbuf)
>  {
> -	*entry = NULL;
> +	size_t len = 0;
>  	char *tmp_buf = NULL;
>  
> +	memset(entry, 0, sizeof(*entry));
> +
>  	while (isspace(**ptr) && **ptr != '\0')
>  		(*ptr)++;
>  
>  	tmp_buf = *ptr;
> -	*len = 0;
>  
>  	while (!isspace(**ptr) && **ptr != '\0') {
>  		if (!isascii(**ptr)) {
> @@ -40,13 +41,15 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len, const char
>  			return -1;
>  		}
>  		(*ptr)++;
> -		(*len)++;
> +		len++;
>  	}
>  
> -	if (*len) {
> -		*entry = strndup(tmp_buf, *len);
> -		if (!*entry)
> +	if (len) {
> +		entry->str = strndup(tmp_buf, len);
> +		if (!entry->str)
>  			return -1;
> +
> +		entry->len = len;
>  	}
>  
>  	return 0;
> @@ -56,7 +59,7 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len, const char
>   * line_buf - Buffer containing the spec entries .
>   * errbuf   - Double pointer used for passing back specific error messages.
>   * num_args - The number of spec parameter entries to process.
> - * ...      - A 'char **spec_entry' for each parameter.
> + * ...      - A 'struct len_str **spec_entry' for each parameter.
>   * returns  - The number of items processed. On error, it returns -1 with errno
>   *            set and may set errbuf to a specific error message.
>   *
> @@ -65,8 +68,9 @@ static inline int read_spec_entry(char **entry, char **ptr, int *len, const char
>   */
>  int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args, ...)
>  {
> -	char **spec_entry, *buf_p;
> -	int len, rc, items, entry_len = 0;
> +	struct len_str *spec_entry;
> +	char *buf_p;
> +	int len, rc, items;
>  	va_list ap;
>  
>  	*errbuf = NULL;
> @@ -93,20 +97,22 @@ int hidden read_spec_entries(char *line_buf, const char **errbuf, int num_args,
>  
>  	items = 0;
>  	while (items < num_args) {
> -		spec_entry = va_arg(ap, char **);
> +		spec_entry = va_arg(ap, struct len_str *);
>  
>  		if (len - 1 == buf_p - line_buf) {
>  			va_end(ap);
>  			return items;
>  		}
>  
> -		rc = read_spec_entry(spec_entry, &buf_p, &entry_len, errbuf);
> +		rc = read_spec_entry(spec_entry, &buf_p, errbuf);
>  		if (rc < 0) {
>  			va_end(ap);
>  			return rc;
>  		}
> -		if (entry_len)
> +
> +		if (spec_entry->len) {
>  			items++;
> +		}
>  	}
>  	va_end(ap);
>  	return items;
> diff --git a/libselinux/src/label_x.c b/libselinux/src/label_x.c
> index 700def1..cdbac8c 100644
> --- a/libselinux/src/label_x.c
> +++ b/libselinux/src/label_x.c
> @@ -81,7 +81,8 @@ static int process_line(const char *path, char *line_buf, int pass,
>  			return 0;
>  		}
>  		data->spec_arr[data->nspec].key = key;
> -		data->spec_arr[data->nspec].lr.ctx_raw = context;
> +		data->spec_arr[data->nspec].lr.ctx_raw.str = context;
> +		data->spec_arr[data->nspec].lr.ctx_raw.len = strlen(context);
>  		free(type);
>  	}
>  
> @@ -186,7 +187,7 @@ static void close(struct selabel_handle *rec)
>  	for (i = 0; i < data->nspec; i++) {
>  		spec = &spec_arr[i];
>  		free(spec->key);
> -		free(spec->lr.ctx_raw);
> +		free(spec->lr.ctx_raw.str);
>  		free(spec->lr.ctx_trans);
>  	}
>  
> diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c
> index 4764ab7..96c39b4 100644
> --- a/libselinux/src/matchpathcon.c
> +++ b/libselinux/src/matchpathcon.c
> @@ -541,7 +541,7 @@ int compat_validate(struct selabel_handle *rec,
>  		    const char *path, unsigned lineno)
>  {
>  	int rc;
> -	char **ctx = &contexts->ctx_raw;
> +	char **ctx = &contexts->ctx_raw.str;
>  
>  	if (myinvalidcon)
>  		rc = myinvalidcon(path, lineno, *ctx);
> 

_______________________________________________
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