|
From: <ew...@us...> - 2007-06-20 18:33:24
|
Revision: 2482
http://svn.sourceforge.net/selinux/?rev=2482&view=rev
Author: ewalsh
Date: 2007-06-20 11:33:23 -0700 (Wed, 20 Jun 2007)
Log Message:
-----------
This patch includes the file contexts backend code.
Signed-off-by: Eamon Walsh <ew...@ty...>
Acked-by: Stephen Smalley <sd...@ty...>
Added Paths:
-----------
trunk/libselinux/src/label_file.c
Added: trunk/libselinux/src/label_file.c
===================================================================
--- trunk/libselinux/src/label_file.c (rev 0)
+++ trunk/libselinux/src/label_file.c 2007-06-20 18:33:23 UTC (rev 2482)
@@ -0,0 +1,642 @@
+/*
+ * File contexts backend for labeling system
+ *
+ * Author : Eamon Walsh <ew...@ty...>
+ * Author : Stephen Smalley <sd...@ty...>
+ *
+ * This library derived in part from setfiles and the setfiles.pl script
+ * developed by Secure Computing Corporation.
+ */
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+/*
+ * Internals, mostly moved over from matchpathcon.c
+ */
+
+/* A file security context specification. */
+typedef 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 */
+ regex_t regex; /* compiled regular expression */
+ mode_t mode; /* mode format value */
+ int matches; /* number of matching pathnames */
+ int hasMetaChars; /* regular expression has meta-chars */
+ int stem_id; /* indicates which stem-compression item */
+} spec_t;
+
+/* A regular expression stem */
+typedef struct stem {
+ char *buf;
+ int len;
+} stem_t;
+
+/* Our stored configuration */
+struct saved_data {
+ /*
+ * The array of specifications, initially in the same order as in
+ * the specification file. Sorting occurs based on hasMetaChars.
+ */
+ spec_t *spec_arr;
+ unsigned int nspec;
+
+ /*
+ * The array of regular expression stems.
+ */
+ stem_t *stem_arr;
+ int num_stems;
+ int alloc_stems;
+};
+
+/* Return the length of the text that can be considered the stem, returns 0
+ * if there is no identifiable stem */
+static int get_stem_from_spec(const char *const buf)
+{
+ const char *tmp = strchr(buf + 1, '/');
+ const char *ind;
+
+ if (!tmp)
+ return 0;
+
+ for (ind = buf; ind < tmp; ind++) {
+ if (strchr(".^$?*+|[({", (int)*ind))
+ return 0;
+ }
+ return tmp - buf;
+}
+
+/* return the length of the text that is the stem of a file name */
+static int get_stem_from_file_name(const char *const buf)
+{
+ const char *tmp = strchr(buf + 1, '/');
+
+ if (!tmp)
+ return 0;
+ return tmp - buf;
+}
+
+/* find the stem of a file spec, returns the index into stem_arr for a new
+ * or existing stem, (or -1 if there is no possible stem - IE for a file in
+ * the root directory or a regex that is too complex for us). Makes buf
+ * point to the text AFTER the stem. */
+static int find_stem_from_spec(struct saved_data *data, const char **buf)
+{
+ int i, num = data->num_stems;
+ int stem_len = get_stem_from_spec(*buf);
+
+ if (!stem_len)
+ return -1;
+ for (i = 0; i < num; i++) {
+ if (stem_len == data->stem_arr[i].len
+ && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
+ *buf += stem_len;
+ return i;
+ }
+ }
+ if (data->alloc_stems == num) {
+ stem_t *tmp_arr;
+ data->alloc_stems = data->alloc_stems * 2 + 16;
+ tmp_arr = realloc(data->stem_arr,
+ sizeof(stem_t) * data->alloc_stems);
+ if (!tmp_arr)
+ return -1;
+ data->stem_arr = tmp_arr;
+ }
+ data->stem_arr[num].len = stem_len;
+ data->stem_arr[num].buf = malloc(stem_len + 1);
+ if (!data->stem_arr[num].buf)
+ return -1;
+ memcpy(data->stem_arr[num].buf, *buf, stem_len);
+ data->stem_arr[num].buf[stem_len] = '\0';
+ data->num_stems++;
+ *buf += stem_len;
+ return num;
+}
+
+/* find the stem of a file name, returns the index into stem_arr (or -1 if
+ * there is no match - IE for a file in the root directory or a regex that is
+ * too complex for us). Makes buf point to the text AFTER the stem. */
+static int find_stem_from_file(struct saved_data *data, const char **buf)
+{
+ int i;
+ int stem_len = get_stem_from_file_name(*buf);
+
+ if (!stem_len)
+ return -1;
+ for (i = 0; i < data->num_stems; i++) {
+ if (stem_len == data->stem_arr[i].len
+ && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
+ *buf += stem_len;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Warn about duplicate specifications.
+ */
+static void nodups_specs(struct saved_data *data, const char *path)
+{
+ unsigned int ii, jj;
+ struct spec *curr_spec, *spec_arr = data->spec_arr;
+
+ 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))
+ && (!spec_arr[jj].mode || !curr_spec->mode
+ || spec_arr[jj].mode == curr_spec->mode)) {
+ if (strcmp
+ (spec_arr[jj].lr.ctx_raw,
+ curr_spec->lr.ctx_raw)) {
+ COMPAT_LOG
+ (SELINUX_WARNING,
+ "%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);
+ } else {
+ COMPAT_LOG
+ (SELINUX_WARNING,
+ "%s: Multiple same specifications for %s.\n",
+ path, curr_spec->regex_str);
+ }
+ }
+ }
+ }
+}
+
+/* Determine if the regular expression specification has any meta characters. */
+static void spec_hasMetaChars(struct spec *spec)
+{
+ char *c;
+ int len;
+ char *end;
+
+ c = spec->regex_str;
+ len = strlen(spec->regex_str);
+ end = c + len;
+
+ spec->hasMetaChars = 0;
+
+ /* Look at each character in the RE specification string for a
+ * meta character. Return when any meta character reached. */
+ while (c != end) {
+ switch (*c) {
+ case '.':
+ case '^':
+ case '$':
+ case '?':
+ case '*':
+ case '+':
+ case '|':
+ case '[':
+ case '(':
+ case '{':
+ spec->hasMetaChars = 1;
+ return;
+ case '\\': /* skip the next character */
+ c++;
+ break;
+ default:
+ break;
+
+ }
+ c++;
+ }
+ return;
+}
+
+static int process_line(struct selabel_handle *rec,
+ const char *path, const char *prefix,
+ char *line_buf, int pass, unsigned lineno)
+{
+ int items, len, regerr;
+ char *buf_p, *regex, *anchored_regex, *type, *context;
+ const char *reg_buf;
+ struct saved_data *data = (struct saved_data *)rec->data;
+ spec_t *spec_arr = data->spec_arr;
+ unsigned int nspec = data->nspec;
+
+ len = strlen(line_buf);
+ if (line_buf[len - 1] == '\n')
+ line_buf[len - 1] = 0;
+ buf_p = line_buf;
+ while (isspace(*buf_p))
+ buf_p++;
+ /* Skip comment lines and empty lines. */
+ if (*buf_p == '#' || *buf_p == 0)
+ return 0;
+ items = sscanf(line_buf, "%as %as %as", ®ex, &type, &context);
+ if (items < 2) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d is missing fields, skipping\n", path,
+ lineno);
+ return 0;
+ } else if (items == 2) {
+ /* The type field is optional. */
+ free(context);
+ context = type;
+ type = 0;
+ }
+
+ reg_buf = regex;
+ len = get_stem_from_spec(reg_buf);
+ if (len && prefix && strncmp(prefix, regex, len)) {
+ /* Stem of regex does not match requested prefix, discard. */
+ free(regex);
+ free(type);
+ free(context);
+ return 0;
+ }
+
+ if (pass == 1) {
+ /* On the second pass, compile and store the specification in spec. */
+ char *cp;
+ spec_arr[nspec].stem_id = find_stem_from_spec(data, ®_buf);
+ spec_arr[nspec].regex_str = regex;
+
+ /* 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. */
+ regerr =
+ regcomp(&spec_arr[nspec].regex,
+ anchored_regex, REG_EXTENDED | REG_NOSUB);
+ if (regerr != 0) {
+ size_t errsz = 0;
+ char *errbuf = NULL;
+ errsz = regerror(regerr, &spec_arr[nspec].regex,
+ errbuf, errsz);
+ if (errsz)
+ errbuf = malloc(errsz);
+ if (errbuf)
+ (void)regerror(regerr,
+ &spec_arr[nspec].regex,
+ errbuf, errsz);
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid regex %s: %s\n",
+ path, lineno, anchored_regex,
+ (errbuf ? errbuf : "out of memory"));
+ free(anchored_regex);
+ return 0;
+ }
+ free(anchored_regex);
+
+ /* Convert the type string to a mode format */
+ spec_arr[nspec].type_str = type;
+ spec_arr[nspec].mode = 0;
+ if (!type)
+ goto skip_type;
+ len = strlen(type);
+ if (type[0] != '-' || len != 2) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid file type %s\n",
+ path, lineno, type);
+ return 0;
+ }
+ switch (type[1]) {
+ case 'b':
+ spec_arr[nspec].mode = S_IFBLK;
+ break;
+ case 'c':
+ spec_arr[nspec].mode = S_IFCHR;
+ break;
+ case 'd':
+ spec_arr[nspec].mode = S_IFDIR;
+ break;
+ case 'p':
+ spec_arr[nspec].mode = S_IFIFO;
+ break;
+ case 'l':
+ spec_arr[nspec].mode = S_IFLNK;
+ break;
+ case 's':
+ spec_arr[nspec].mode = S_IFSOCK;
+ break;
+ case '-':
+ spec_arr[nspec].mode = S_IFREG;
+ break;
+ default:
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid file type %s\n",
+ path, lineno, type);
+ return 0;
+ }
+
+ skip_type:
+ 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;
+ if (pass == 0) {
+ free(regex);
+ if (type)
+ free(type);
+ free(context);
+ }
+ return 0;
+}
+
+static int init(struct selabel_handle *rec, struct selinux_opt *opts,
+ unsigned n)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ const char *path = NULL;
+ const char *prefix = NULL;
+ FILE *fp;
+ FILE *localfp = NULL;
+ FILE *homedirfp = NULL;
+ char local_path[PATH_MAX + 1];
+ char homedir_path[PATH_MAX + 1];
+ char *line_buf = NULL;
+ size_t line_len = 0;
+ unsigned int lineno, pass, i, j, maxnspec;
+ spec_t *spec_copy = NULL;
+ int status = -1, baseonly = 0;
+ struct stat sb;
+
+ /* Process arguments */
+ while (n--)
+ switch(opts[n].type) {
+ case SELABEL_OPT_PATH:
+ path = opts[n].value;
+ break;
+ case SELABEL_OPT_SUBSET:
+ prefix = opts[n].value;
+ break;
+ case SELABEL_OPT_BASEONLY:
+ baseonly = !!opts[n].value;
+ break;
+ }
+
+ /* Open the specification file. */
+ if (!path)
+ path = selinux_file_context_path();
+ if ((fp = fopen(path, "r")) == NULL)
+ return -1;
+ __fsetlocking(fp, FSETLOCKING_BYCALLER);
+
+ if (fstat(fileno(fp), &sb) < 0)
+ return -1;
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!baseonly) {
+ snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
+ path);
+ homedirfp = fopen(homedir_path, "r");
+ if (homedirfp != NULL)
+ __fsetlocking(homedirfp, FSETLOCKING_BYCALLER);
+
+ snprintf(local_path, sizeof(local_path), "%s.local", path);
+ localfp = fopen(local_path, "r");
+ if (localfp != NULL)
+ __fsetlocking(localfp, FSETLOCKING_BYCALLER);
+ }
+
+ /*
+ * Perform two passes over the specification file.
+ * The first pass counts the number of specifications and
+ * performs simple validation of the input. At the end
+ * of the first pass, the spec array is allocated.
+ * The second pass performs detailed validation of the input
+ * and fills in the spec array.
+ */
+ maxnspec = UINT_MAX / sizeof(spec_t);
+ for (pass = 0; pass < 2; pass++) {
+ lineno = 0;
+ data->nspec = 0;
+ while (getline(&line_buf, &line_len, fp) > 0
+ && data->nspec < maxnspec) {
+ if (process_line(rec, path, prefix, line_buf,
+ pass, ++lineno) != 0)
+ goto finish;
+ }
+ lineno = 0;
+ if (homedirfp)
+ while (getline(&line_buf, &line_len, homedirfp) > 0
+ && data->nspec < maxnspec) {
+ if (process_line
+ (rec, homedir_path, prefix,
+ line_buf, pass, ++lineno) != 0)
+ goto finish;
+ }
+
+ lineno = 0;
+ if (localfp)
+ while (getline(&line_buf, &line_len, localfp) > 0
+ && data->nspec < maxnspec) {
+ if (process_line
+ (rec, local_path, prefix, line_buf,
+ pass, ++lineno) != 0)
+ goto finish;
+ }
+
+ if (pass == 0) {
+ if (data->nspec == 0) {
+ status = 0;
+ goto finish;
+ }
+ if (NULL == (data->spec_arr =
+ malloc(sizeof(spec_t) * data->nspec)))
+ goto finish;
+ memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
+ maxnspec = data->nspec;
+ rewind(fp);
+ if (homedirfp)
+ rewind(homedirfp);
+ if (localfp)
+ rewind(localfp);
+ }
+ }
+ free(line_buf);
+
+ /* Move exact pathname specifications to the end. */
+ spec_copy = malloc(sizeof(spec_t) * data->nspec);
+ if (!spec_copy)
+ goto finish;
+ j = 0;
+ for (i = 0; i < data->nspec; i++)
+ if (data->spec_arr[i].hasMetaChars)
+ memcpy(&spec_copy[j++],
+ &data->spec_arr[i], sizeof(spec_t));
+ for (i = 0; i < data->nspec; i++)
+ if (!data->spec_arr[i].hasMetaChars)
+ memcpy(&spec_copy[j++],
+ &data->spec_arr[i], sizeof(spec_t));
+ free(data->spec_arr);
+ data->spec_arr = spec_copy;
+
+ nodups_specs(data, path);
+
+ status = 0;
+finish:
+ fclose(fp);
+ if (data->spec_arr != spec_copy)
+ free(data->spec_arr);
+ if (homedirfp)
+ fclose(homedirfp);
+ if (localfp)
+ fclose(localfp);
+ return status;
+}
+
+/*
+ * Backend interface routines
+ */
+static void close(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ struct spec *spec;
+ struct stem *stem;
+ unsigned int i;
+
+ for (i = 0; i < data->nspec; i++) {
+ spec = &data->spec_arr[i];
+ free(spec->regex_str);
+ free(spec->type_str);
+ free(spec->lr.ctx_raw);
+ free(spec->lr.ctx_trans);
+ regfree(&spec->regex);
+ }
+
+ for (i = 0; i < (unsigned int)data->num_stems; i++) {
+ stem = &data->stem_arr[i];
+ free(stem->buf);
+ }
+
+ if (data->spec_arr)
+ free(data->spec_arr);
+ if (data->stem_arr)
+ free(data->stem_arr);
+
+ memset(data, 0, sizeof(*data));
+}
+
+static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
+ const char *key, int type)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ spec_t *spec_arr = data->spec_arr;
+ int i, rc, file_stem;
+ mode_t mode = (mode_t)type;
+ const char *buf = key;
+
+ if (!data->nspec) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ file_stem = find_stem_from_file(data, &buf);
+ mode &= S_IFMT;
+
+ /*
+ * Check for matching specifications in reverse order, so that
+ * the last matching specification is used.
+ */
+ for (i = data->nspec - 1; i >= 0; i--) {
+ /* if the spec in question matches no stem or has the same
+ * stem as the file AND if the spec in question has no mode
+ * specified or if the mode matches the file mode then we do
+ * a regex check */
+ if ((spec_arr[i].stem_id == -1
+ || spec_arr[i].stem_id == file_stem)
+ && (!mode || !spec_arr[i].mode
+ || mode == spec_arr[i].mode)) {
+ if (spec_arr[i].stem_id == -1)
+ rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
+ else
+ rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
+
+ if (rc == 0) {
+ spec_arr[i].matches++;
+ break;
+ }
+ if (rc == REG_NOMATCH)
+ continue;
+ /* else it's an error */
+ return NULL;
+ }
+ }
+
+ if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
+ /* No matching specification. */
+ errno = ENOENT;
+ return NULL;
+ }
+
+ return &spec_arr[i].lr;
+}
+
+static void stats(struct selabel_handle *rec)
+{
+ struct saved_data *data = (struct saved_data *)rec->data;
+ unsigned int i, nspec = data->nspec;
+ spec_t *spec_arr = data->spec_arr;
+
+ for (i = 0; i < nspec; i++) {
+ if (spec_arr[i].matches == 0) {
+ if (spec_arr[i].type_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);
+ } else {
+ COMPAT_LOG(SELINUX_WARNING,
+ "Warning! No matches for (%s, %s)\n",
+ spec_arr[i].regex_str,
+ spec_arr[i].lr.ctx_raw);
+ }
+ }
+ }
+}
+
+int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
+ unsigned nopts)
+{
+ struct saved_data *data;
+
+ data = (struct saved_data *)malloc(sizeof(*data));
+ if (!data)
+ return -1;
+ memset(data, 0, sizeof(*data));
+
+ rec->data = data;
+ rec->func_close = &close;
+ rec->func_stats = &stats;
+ rec->func_lookup = &lookup;
+
+ return init(rec, opts, nopts);
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ssm...@us...> - 2007-11-20 16:19:52
|
Revision: 2687
http://selinux.svn.sourceforge.net/selinux/?rev=2687&view=rev
Author: ssmalley
Date: 2007-11-20 08:19:43 -0800 (Tue, 20 Nov 2007)
Log Message:
-----------
Author: Stephen Smalley
Email: sd...@ty...
Subject: libselinux: lazily compile regexes to reduce overhead of matchpathcon / selabel_lookup
Date: Thu, 15 Nov 2007 12:55:01 -0500
On Thu, 2007-11-15 at 12:40 -0500, Stephen Smalley wrote:
> Ulrich Drepper noted that we could reduce the overhead of matchpathcon
> by lazily compiling the pathname regexes on demand when there is a stem
> match rather than compiling them all. Below is a patch that does that
> for the libselinux 2.x series. As with the context validation, the
> regex compilation defaults to being done lazily for typical users, but
> will still be done up front if the caller requested validation, as
> setfiles does. Thus, setfiles will still compile and check the entire
> specification up front for errors, while most other programs will
> compile the regexes lazily. Back porting to the libselinux 1.x series
> wouldn't be difficult, although it would have to be done manually.
>
> Signed-off-by: Stephen Smalley <sd...@ty...>
Revised to drop some unused vars.
Modified Paths:
--------------
trunk/libselinux/src/label_file.c
Modified: trunk/libselinux/src/label_file.c
===================================================================
--- trunk/libselinux/src/label_file.c 2007-11-19 04:33:54 UTC (rev 2686)
+++ trunk/libselinux/src/label_file.c 2007-11-20 16:19:43 UTC (rev 2687)
@@ -30,6 +30,7 @@
char *regex_str; /* regular expession string for diagnostics */
char *type_str; /* type string for diagnostic messages */
regex_t regex; /* compiled regular expression */
+ char regcomp; /* regex_str has been compiled to regex */
mode_t mode; /* mode format value */
int matches; /* number of matching pathnames */
int hasMetaChars; /* regular expression has meta-chars */
@@ -50,6 +51,7 @@
*/
spec_t *spec_arr;
unsigned int nspec;
+ unsigned int ncomp;
/*
* The array of regular expression stems.
@@ -88,21 +90,18 @@
/* find the stem of a file spec, returns the index into stem_arr for a new
* or existing stem, (or -1 if there is no possible stem - IE for a file in
- * the root directory or a regex that is too complex for us). Makes buf
- * point to the text AFTER the stem. */
-static int find_stem_from_spec(struct saved_data *data, const char **buf)
+ * the root directory or a regex that is too complex for us). */
+static int find_stem_from_spec(struct saved_data *data, const char *buf)
{
int i, num = data->num_stems;
- int stem_len = get_stem_from_spec(*buf);
+ int stem_len = get_stem_from_spec(buf);
if (!stem_len)
return -1;
for (i = 0; i < num; i++) {
if (stem_len == data->stem_arr[i].len
- && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
- *buf += stem_len;
+ && !strncmp(buf, data->stem_arr[i].buf, stem_len))
return i;
- }
}
if (data->alloc_stems == num) {
stem_t *tmp_arr;
@@ -117,10 +116,10 @@
data->stem_arr[num].buf = malloc(stem_len + 1);
if (!data->stem_arr[num].buf)
return -1;
- memcpy(data->stem_arr[num].buf, *buf, stem_len);
+ memcpy(data->stem_arr[num].buf, buf, stem_len);
data->stem_arr[num].buf[stem_len] = '\0';
data->num_stems++;
- *buf += stem_len;
+ buf += stem_len;
return num;
}
@@ -220,13 +219,64 @@
return;
}
+static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
+{
+ char *reg_buf, *anchored_regex, *cp;
+ stem_t *stem_arr = data->stem_arr;
+ size_t len;
+ int regerr;
+
+ if (spec->regcomp)
+ return 0; /* already done */
+
+ data->ncomp++; /* how many compiled regexes required */
+
+ /* 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. */
+ regerr = regcomp(&spec->regex, anchored_regex,
+ REG_EXTENDED | REG_NOSUB);
+ if (regerr != 0) {
+ size_t errsz = 0;
+ errsz = regerror(regerr, &spec->regex, NULL, 0);
+ if (errsz && errbuf)
+ *errbuf = malloc(errsz);
+ if (errbuf && *errbuf)
+ (void)regerror(regerr, &spec->regex,
+ *errbuf, errsz);
+
+ free(anchored_regex);
+ return -1;
+ }
+ free(anchored_regex);
+
+ /* Done. */
+ spec->regcomp = 1;
+
+ return 0;
+}
+
+
static int process_line(struct selabel_handle *rec,
const char *path, const char *prefix,
char *line_buf, int pass, unsigned lineno)
{
- int items, len, regerr;
- char *buf_p, *regex, *anchored_regex, *type, *context;
- const char *reg_buf;
+ int items, len;
+ char *buf_p, *regex, *type, *context;
struct saved_data *data = (struct saved_data *)rec->data;
spec_t *spec_arr = data->spec_arr;
unsigned int nspec = data->nspec;
@@ -253,8 +303,7 @@
type = 0;
}
- reg_buf = regex;
- len = get_stem_from_spec(reg_buf);
+ len = get_stem_from_spec(regex);
if (len && prefix && strncmp(prefix, regex, len)) {
/* Stem of regex does not match requested prefix, discard. */
free(regex);
@@ -264,45 +313,16 @@
}
if (pass == 1) {
- /* On the second pass, compile and store the specification in spec. */
- char *cp;
- spec_arr[nspec].stem_id = find_stem_from_spec(data, ®_buf);
+ /* On the second pass, process and store the specification in spec. */
+ char *errbuf = NULL;
+ spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
spec_arr[nspec].regex_str = regex;
-
- /* 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. */
- regerr =
- regcomp(&spec_arr[nspec].regex,
- anchored_regex, REG_EXTENDED | REG_NOSUB);
- if (regerr != 0) {
- size_t errsz = 0;
- char *errbuf = NULL;
- errsz = regerror(regerr, &spec_arr[nspec].regex,
- errbuf, errsz);
- if (errsz)
- errbuf = malloc(errsz);
- if (errbuf)
- (void)regerror(regerr,
- &spec_arr[nspec].regex,
- errbuf, errsz);
+ if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
COMPAT_LOG(SELINUX_WARNING,
- "%s: line %d has invalid regex %s: %s\n",
- path, lineno, anchored_regex,
- (errbuf ? errbuf : "out of memory"));
- free(anchored_regex);
- return 0;
+ "%s: line %d has invalid regex %s: %s\n",
+ path, lineno, regex,
+ (errbuf ? errbuf : "out of memory"));
}
- free(anchored_regex);
/* Convert the type string to a mode format */
spec_arr[nspec].type_str = type;
@@ -437,6 +457,7 @@
for (pass = 0; pass < 2; pass++) {
lineno = 0;
data->nspec = 0;
+ data->ncomp = 0;
while (getline(&line_buf, &line_len, fp) > 0
&& data->nspec < maxnspec) {
if (process_line(rec, path, prefix, line_buf,
@@ -574,6 +595,8 @@
|| spec_arr[i].stem_id == file_stem)
&& (!mode || !spec_arr[i].mode
|| mode == spec_arr[i].mode)) {
+ if (compile_regex(data, &spec_arr[i], NULL) < 0)
+ return NULL;
if (spec_arr[i].stem_id == -1)
rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
else
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|