@@ -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;
}
@@ -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;
}
@@ -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);
@@ -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);
}
}
}
@@ -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, ®ex, 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;
@@ -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;
};
@@ -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);
}
@@ -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;
@@ -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);
}
@@ -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);