diff --git a/.gitignore b/.gitignore index 51678eb..ed25720 100644 --- a/.gitignore +++ b/.gitignore @@ -193,3 +193,4 @@ libselinux-2.0.96.tgz /libselinux-2.1.9.tgz /libselinux-2.1.10.tgz /libselinux-2.1.11.tgz +/libselinux-2.1.12.tgz diff --git a/libselinux-rhat.patch b/libselinux-rhat.patch index 3424edd..a146711 100644 --- a/libselinux-rhat.patch +++ b/libselinux-rhat.patch @@ -1,63 +1,8 @@ -diff --git a/libselinux/include/selinux/label.h b/libselinux/include/selinux/label.h -index 8263f32..9ef10fc 100644 ---- a/libselinux/include/selinux/label.h -+++ b/libselinux/include/selinux/label.h -@@ -48,8 +48,10 @@ struct selabel_handle; - #define SELABEL_OPT_PATH 3 - /* select a subset of the search space as an optimization (file backend) */ - #define SELABEL_OPT_SUBSET 4 -+/* like subset, but an array of subsets */ -+#define SELABEL_OPT_PREFIXES 5 - /* total number of options */ --#define SELABEL_NOPT 5 -+#define SELABEL_NOPT 6 - - /* - * Label operations diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h -index 6f483c9..9a5509e 100644 +index 6b9089d..85b0cfc 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h -@@ -139,7 +139,10 @@ struct av_decision { - /* Structure for passing options, used by AVC and label subsystems */ - struct selinux_opt { - int type; -- const char *value; -+ union { -+ const char *value; -+ const char **values; -+ }; - }; - - /* Callback facilities */ -@@ -420,6 +423,11 @@ extern int matchpathcon_init(const char *path); - regexes that have stems that are prefixes of 'prefix'. */ - extern int matchpathcon_init_prefix(const char *path, const char *prefix); - -+/* Same as matchpathcon_init, but only load entries with -+ * regexes that have stems that are prefixes of the 'prefixes' -+ * array of entries. The last entry must be NULL. */ -+extern int matchpathcon_init_prefixes(const char *patch, const char **prefixes); -+ - /* Free the memory allocated by matchpathcon_init. */ - extern void matchpathcon_fini(void); - -@@ -473,6 +481,14 @@ extern int matchmediacon(const char *media, security_context_t * con); - extern int selinux_getenforcemode(int *enforce); - - /* -+ selinux_boolean_sub reads the /etc/selinux/TYPE/booleans.subs_dist file -+ looking for a record with boolean_name. If a record exists selinux_boolean_sub -+ returns the translated name otherwise it returns the original name. -+ The returned value needs to be freed. On failure NULL will be returned. -+ */ -+extern char *selinux_boolean_sub(const char *boolean_name); -+ -+/* - selinux_getpolicytype reads the /etc/selinux/config file and determines - what the default policy for the machine is. Calling application must - free policytype. -@@ -488,7 +504,9 @@ extern const char *selinux_policy_root(void); +@@ -496,7 +496,9 @@ extern const char *selinux_policy_root(void); /* These functions return the paths to specific files under the policy root directory. */ @@ -67,86 +12,6 @@ index 6f483c9..9a5509e 100644 extern const char *selinux_failsafe_context_path(void); extern const char *selinux_removable_context_path(void); extern const char *selinux_default_context_path(void); -@@ -502,10 +520,12 @@ extern const char *selinux_homedir_context_path(void); - extern const char *selinux_media_context_path(void); - extern const char *selinux_virtual_domain_context_path(void); - extern const char *selinux_virtual_image_context_path(void); -+extern const char *selinux_lxc_contexts_path(void); - extern const char *selinux_x_context_path(void); - extern const char *selinux_sepgsql_context_path(void); - extern const char *selinux_contexts_path(void); - extern const char *selinux_securetty_types_path(void); -+extern const char *selinux_booleans_subs_path(void); - extern const char *selinux_booleans_path(void); - extern const char *selinux_customizable_types_path(void); - extern const char *selinux_users_path(void); -diff --git a/libselinux/man/man3/matchpathcon.3 b/libselinux/man/man3/matchpathcon.3 -index cdbb252..b6814ed 100644 ---- a/libselinux/man/man3/matchpathcon.3 -+++ b/libselinux/man/man3/matchpathcon.3 -@@ -8,7 +8,9 @@ matchpathcon, matchpathcon_index \- get the default SELinux security context for - - .BI "int matchpathcon_init(const char *" path ");" - --.BI "int matchpathcon_init_prefix(const char *" path ", const char *" subset ");" -+.BI "int matchpathcon_init_prefix(const char *" path ", const char *" prefix ");" -+ -+.BI "int matchpathcon_init_prefixes(const char *" path ", const char **" prefixes ");" - - .BI "int matchpathcon_fini(void);" - .sp -@@ -50,6 +52,14 @@ by - .I prefix. - - .sp -+.B matchpathcon_init_prefixes -+is the same as -+.B matchpathcon_init_prefix -+but takes an array of -+.I prefixes -+instead of a single prefix. The last entry in the array must be NULL. -+ -+.sp - .B matchpathcon_fini - frees the memory allocated by a prior call to - .B matchpathcon_init. -diff --git a/libselinux/man/man3/selabel_open.3 b/libselinux/man/man3/selabel_open.3 -index 8674e37..fc5b120 100644 ---- a/libselinux/man/man3/selabel_open.3 -+++ b/libselinux/man/man3/selabel_open.3 -@@ -37,8 +37,11 @@ structures of length - .ta 4n 16n 24n - .nf - struct selinux_opt { -- int type; -- const char *value; -+ int type; -+ union { -+ const char *value; -+ const char **values; -+ }; - }; - .fi - .ta -@@ -66,6 +69,13 @@ A non-null value for this option enables context validation. By default, - is used; a custom validation function can be provided via - .BR selinux_set_callback (3). - Note that an invalid context may not be treated as an error unless it is actually encountered during a lookup operation. -+.TP -+.B SELABEL_OPT_SUBSET -+A ":" separates string of path prefixes that tell the system to only loads entries with regular expressions that could match this strings. For example "/dev:/var/run:/tmp". This option can cause the system to use less memory and work faster, but you should only use paths that begin with a prefix. -+.TP -+.B SELABEL_OPT_PATH -+A string representing an alternate path the the regular expressions. -+.sp - - .SH "BACKENDS" - -@@ -99,4 +109,3 @@ Eamon Walsh - .BR selabel_stats (3), - .BR selinux_set_callback (3), - .BR selinux (8) -- diff --git a/libselinux/man/man3/selinux_binary_policy_path.3 b/libselinux/man/man3/selinux_binary_policy_path.3 index 8ead1a4..c68ace5 100644 --- a/libselinux/man/man3/selinux_binary_policy_path.3 @@ -171,84 +36,22 @@ index 8ead1a4..c68ace5 100644 .sp selinux_default_type_path - context file mapping roles to default types. .sp -diff --git a/libselinux/man/man3/selinux_boolean_sub.3 b/libselinux/man/man3/selinux_boolean_sub.3 -new file mode 100644 -index 0000000..8d54c88 ---- /dev/null -+++ b/libselinux/man/man3/selinux_boolean_sub.3 -@@ -0,0 +1,25 @@ -+.TH "selinux_boolean_subs" "3" "11 June 2012" "dwalsh@redhat.com" "SELinux API documentation" -+.SH "NAME" -+selinux_boolean_subs -+.SH "SYNOPSIS" -+.B #include -+.sp -+.BI "char *selinux_boolean_subs(const char * " boolean_name, ");" -+.sp -+.SH "DESCRIPTION" -+.B selinux_boolean_sub -+searches the /etc/selinux/POLICYTYPE/booleans.subs_dist file -+for a maching boolean_name record. If the record exists the boolean substitution name is returned. If not -+.B selinux_boolean_sub -+returns the original boolean_name. -+ -+.SH "RETURN VALUE" -+.BR selinux_boolean_subs -+returns the -+.I boolean_name -+or the substituted name on success. The returned value must be freed with -+.BR free "(3)." -+.BR selinux_boolean_subs -+returns NULL on error. -+.SH "SEE ALSO" -+security_get_boolean_names.3 -diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile -index b333f07..74e53bb 100644 ---- a/libselinux/src/Makefile -+++ b/libselinux/src/Makefile -@@ -13,12 +13,10 @@ SHLIBDIR ?= $(DESTDIR)/lib - INCLUDEDIR ?= $(PREFIX)/include - PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])') - PYINC ?= $(shell pkg-config --cflags $(PYPREFIX)) --PYTHONLIBDIR ?= $(shell pkg-config --libs $(PYPREFIX)) - PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER) - RUBYLIBVER ?= $(shell $(RUBY) -e 'print RUBY_VERSION.split(".")[0..1].join(".")') - RUBYPLATFORM ?= $(shell $(RUBY) -e 'print RUBY_PLATFORM') - RUBYINC ?= $(shell pkg-config --cflags ruby-$(RUBYLIBVER)) --RUBYLIBDIR ?= $(shell pkg-config --libs ruby-$(RUBYLIBVER)) - RUBYINSTALL ?= $(LIBDIR)/ruby/site_ruby/$(RUBYLIBVER)/$(RUBYPLATFORM) - LIBBASE=$(shell basename $(LIBDIR)) - -@@ -106,10 +104,10 @@ $(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) - $(CC) $(CFLAGS) $(SWIG_CFLAGS) $(RUBYINC) -fPIC -DSHARED -c -o $@ $< - - $(SWIGSO): $(SWIGLOBJ) -- $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR) $(PYTHONLIBDIR) -+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR) - - $(SWIGRUBYSO): $(SWIGRUBYLOBJ) -- $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR) -Wl,-soname,$@ -+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR) - - $(LIBA): $(OBJS) - $(AR) rcs $@ $^ -@@ -129,7 +127,7 @@ $(AUDIT2WHYLOBJ): audit2why.c - $(CC) $(filter-out -Werror, $(CFLAGS)) $(PYINC) -fPIC -DSHARED -c -o $@ $< - - $(AUDIT2WHYSO): $(AUDIT2WHYLOBJ) -- $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) -Wl,-soname,$@ -+ $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR) - - %.o: %.c policy.h - $(CC) $(CFLAGS) $(TLSFLAGS) -c -o $@ $< diff --git a/libselinux/src/audit2why.c b/libselinux/src/audit2why.c -index 02483a3..f7750fc 100644 +index 02483a3..89953d7 100644 --- a/libselinux/src/audit2why.c +++ b/libselinux/src/audit2why.c -@@ -214,19 +214,12 @@ static int __policy_init(const char *init_path) - PyErr_SetString( PyExc_ValueError, errormsg); +@@ -206,27 +206,12 @@ static int __policy_init(const char *init_path) return 1; } + } else { +- vers = sepol_policy_kern_vers_max(); +- if (vers < 0) { +- snprintf(errormsg, sizeof(errormsg), +- "Could not get policy version: %s\n", +- strerror(errno)); +- PyErr_SetString( PyExc_ValueError, errormsg); +- return 1; +- } - snprintf(path, PATH_MAX, "%s.%d", - selinux_binary_policy_path(), vers); - fp = fopen(path, "r"); @@ -281,358 +84,296 @@ index 802a07f..6ff83a7 100644 return rc; } -diff --git a/libselinux/src/booleans.c b/libselinux/src/booleans.c -index 1510043..b5e6655 100644 ---- a/libselinux/src/booleans.c -+++ b/libselinux/src/booleans.c -@@ -5,6 +5,7 @@ - * Dan Walsh - Added security_load_booleans(). +diff --git a/libselinux/src/file_path_suffixes.h b/libselinux/src/file_path_suffixes.h +index 825f295..d11c8dc 100644 +--- a/libselinux/src/file_path_suffixes.h ++++ b/libselinux/src/file_path_suffixes.h +@@ -26,4 +26,4 @@ S_(BINPOLICY, "/policy/policy") + S_(FILE_CONTEXT_SUBS, "/contexts/files/file_contexts.subs") + S_(FILE_CONTEXT_SUBS_DIST, "/contexts/files/file_contexts.subs_dist") + S_(SEPGSQL_CONTEXTS, "/contexts/sepgsql_contexts") +- S_(BOOLEAN_SUBS, "/booleans.subs") ++ S_(BOOLEAN_SUBS, "/booleans.subs_dist") +diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c +index 02b3cd2..fad8bbd 100644 +--- a/libselinux/src/label_file.c ++++ b/libselinux/src/label_file.c +@@ -8,6 +8,7 @@ + * developed by Secure Computing Corporation. */ +#include + #include + #include + #include +@@ -16,7 +17,12 @@ + #include + #include + #include ++#include + #include ++ ++#include ++ ++#include #include #include - #include -@@ -86,44 +87,145 @@ int security_get_boolean_names(char ***names, int *len) + #include +@@ -229,6 +235,167 @@ static int process_line(struct selabel_handle *rec, + return 0; } - hidden_def(security_get_boolean_names) -+ -+char *selinux_boolean_sub(const char *name) ++static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *stat) +{ -+ char *sub = NULL; -+ char *line_buf = NULL; -+ size_t line_len; -+ FILE *cfg; ++ struct saved_data *data = (struct saved_data *)rec->data; ++ char mmap_path[PATH_MAX + 1]; ++ int mmapfd; ++ int rc, i; ++ struct stat mmap_stat; ++ char *addr; ++ size_t len; ++ int stem_map_len, *stem_map; ++ ++ uint32_t *magic; ++ uint32_t *section_len; ++ uint32_t *plen; ++ ++ rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path); ++ if (rc >= sizeof(mmap_path)) ++ return -1; + -+ if (!name) -+ return NULL; ++ mmapfd = open(mmap_path, O_RDONLY); ++ if (!mmapfd) ++ return -1; + -+ cfg = fopen(selinux_booleans_subs_path(), "r"); -+ if (!cfg) -+ goto out; ++ rc = fstat(mmapfd, &mmap_stat); ++ if (rc < 0) ++ return -1; + -+ while (getline(&line_buf, &line_len, cfg) > -1) { -+ char *ptr; -+ char *src = line_buf; -+ char *dst; -+ while (*src && isspace(*src)) -+ src++; -+ if (!*src) -+ continue; -+ if (src[0] == '#') -+ continue; -+ ptr = src; -+ while (*ptr && !isspace(*ptr)) -+ ptr++; -+ *ptr++ = '\0'; -+ if (strcmp(src, name) != 0) -+ continue; ++ /* if mmap is old, ignore it */ ++ if (mmap_stat.st_mtime < stat->st_mtime) ++ return -1; + -+ dst = ptr; -+ while (*dst && isspace(*dst)) -+ dst++; -+ if (!*dst) -+ continue; -+ ptr=dst; -+ while (*ptr && !isspace(*ptr)) -+ ptr++; -+ *ptr='\0'; ++ if (mmap_stat.st_mtime == stat->st_mtime && ++ mmap_stat.st_mtim.tv_nsec < stat->st_mtim.tv_nsec) ++ return -1; + -+ sub = strdup(dst); ++ /* ok, read it in... */ ++ len = mmap_stat.st_size; ++ len += (sysconf(_SC_PAGE_SIZE) - 1); ++ len &= ~(sysconf(_SC_PAGE_SIZE) - 1); + -+ break; ++ addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, mmapfd, 0); ++ close(mmapfd); ++ if (addr == MAP_FAILED) { ++ perror("mmap"); ++ return -1; + } -+ free(line_buf); -+ fclose(cfg); -+out: -+ if (!sub) -+ sub = strdup(name); -+ return sub; -+} + -+hidden_def(selinux_boolean_sub) -+ -+static int bool_open(const char *name, int flag) { -+ char *fname = NULL; -+ char *alt_name = NULL; -+ int len; -+ int fd = -1; -+ int ret; -+ char *ptr; -+ -+ if (!name) { -+ errno = EINVAL; ++ /* check if this looks like an fcontext file */ ++ magic = (uint32_t *)addr; ++ if (*magic != SELINUX_MAGIC_COMPILED_FCONTEXT) + return -1; -+ } ++ addr += sizeof(uint32_t); + -+ /* note the 'sizeof' gets us enough room for the '\0' */ -+ len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); -+ fname = malloc(sizeof(char) * len); -+ if (!fname) ++ /* check if this version is higher than we understand */ ++ section_len = (uint32_t *)addr; ++ if (*section_len > SELINUX_COMPILED_FCONTEXT_MAX_VERS) ++ return -1; ++ addr += sizeof(uint32_t); ++ ++ /* allocate the stems_data array */ ++ section_len = (uint32_t *)addr; ++ addr += sizeof(uint32_t); ++ ++ /* ++ * map indexed by the stem # in the mmap file and contains the stem ++ * number in the data stem_arr ++ */ ++ stem_map_len = *section_len; ++ stem_map = calloc(stem_map_len, sizeof(*stem_map)); ++ if (!stem_map) + return -1; + -+ ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); -+ if (ret < 0) -+ goto out; -+ assert(ret < len); ++ for (i = 0; i < *section_len; i++) { ++ char *buf; ++ uint32_t stem_len; ++ int newid; ++ ++ /* the length does not inlude the nul */ ++ plen = (uint32_t *)addr; ++ addr += sizeof(uint32_t); ++ ++ stem_len = *plen; ++ buf = (char *)addr; ++ addr += (stem_len + 1); // +1 is the nul ++ ++ /* store the mapping between old and new */ ++ newid = find_stem(data, buf, stem_len); ++ if (newid < 0) { ++ newid = store_stem(data, buf, stem_len); ++ if (newid < 0) ++ return newid; ++ data->stem_arr[newid].from_mmap = 1; ++ } ++ stem_map[i] = newid; ++ } + -+ fd = open(fname, flag); -+ if (fd >= 0 || errno != ENOENT) -+ goto out; ++ /* allocate the regex array */ ++ section_len = (uint32_t *)addr; ++ addr += sizeof(*section_len); ++ ++ for (i = 0; i < *section_len; i++) { ++ struct spec *spec; ++ int32_t stem_id; ++ ++ rc = grow_specs(data); ++ if (rc < 0) ++ return rc; ++ ++ spec = &data->spec_arr[data->nspec]; ++ spec->from_mmap = 1; ++ spec->regcomp = 1; ++ ++ plen = (uint32_t *)addr; ++ addr += sizeof(uint32_t); ++ spec->lr.ctx_raw = strdup((char *)addr); ++ if (!spec->lr.ctx_raw) ++ return -1; ++ addr += *plen; ++ ++ plen = (uint32_t *)addr; ++ addr += sizeof(uint32_t); ++ spec->regex_str = (char *)addr; ++ addr += *plen; ++ ++ spec->mode = *(mode_t *)addr; ++ addr += sizeof(mode_t); ++ ++ /* map the stem id from the mmap file to the data->stem_arr */ ++ stem_id = *(int32_t *)addr; ++ if (stem_id == -1) { ++ spec->stem_id = -1; ++ } else { ++ assert(stem_id <= stem_map_len); ++ spec->stem_id = stem_map[stem_id]; ++ } ++ addr += sizeof(int32_t); + -+ alt_name = selinux_boolean_sub(name); -+ if (!alt_name) -+ goto out; ++ /* retrieve the hasMetaChars bit */ ++ spec->hasMetaChars = *(uint32_t *)addr; ++ addr += sizeof(uint32_t); + -+ /* note the 'sizeof' gets us enough room for the '\0' */ -+ len = strlen(alt_name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); -+ ptr = realloc(fname, len); -+ if (!ptr) -+ goto out; -+ fname = ptr; ++ plen = (uint32_t *)addr; ++ addr += sizeof(uint32_t); ++ spec->regex = (pcre *)addr; ++ addr += *plen; + -+ ret = snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, alt_name); -+ if (ret < 0) -+ goto out; -+ assert(ret < len); ++ plen = (uint32_t *)addr; ++ addr += sizeof(uint32_t); ++ spec->lsd.study_data = (void *)addr; ++ spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA; ++ addr += *plen; + -+ fd = open(fname, flag); -+out: -+ free(fname); -+ free(alt_name); ++ data->nspec++; ++ } + -+ return fd; ++ free(stem_map); ++ ++ /* win */ ++ return 0; +} + - #define STRBUF_SIZE 3 - static int get_bool_value(const char *name, char **buf) + static int process_file(const char *path, const char *suffix, struct selabel_handle *rec, const char *prefix) { - int fd, len; -- char *fname = NULL; -+ int errno_tmp; - - if (!selinux_mnt) { - errno = ENOENT; + FILE *fp; +@@ -261,6 +428,10 @@ static int process_file(const char *path, const char *suffix, struct selabel_han return -1; } -- *buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1)); -+ *buf = malloc(sizeof(char) * (STRBUF_SIZE + 1)); - if (!*buf) -- goto out; -- (*buf)[STRBUF_SIZE] = 0; -+ return -1; - -- len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); -- fname = (char *)malloc(sizeof(char) * len); -- if (!fname) -- goto out; -- snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); -+ (*buf)[STRBUF_SIZE] = 0; - -- fd = open(fname, O_RDONLY); -+ fd = bool_open(name, O_RDONLY); - if (fd < 0) -- goto out; -+ goto out_err; - - len = read(fd, *buf, STRBUF_SIZE); -+ errno_tmp = errno; - close(fd); -+ errno = errno_tmp; - if (len != STRBUF_SIZE) -- goto out; -+ goto out_err; - -- free(fname); - return 0; -- out: -- if (*buf) -- free(*buf); -- if (fname) -- free(fname); -+out_err: -+ free(*buf); - return -1; - } - -@@ -164,8 +266,8 @@ hidden_def(security_get_boolean_active) ++ rc = load_mmap(rec, path, &sb); ++ if (rc == 0) ++ goto out; ++ + /* + * The do detailed validation of the input and fill the spec array + */ +@@ -270,6 +441,7 @@ static int process_file(const char *path, const char *suffix, struct selabel_han + if (rc) + return rc; + } ++out: + free(line_buf); + fclose(fp); - int security_set_boolean(const char *name, int value) - { -- int fd, ret, len; -- char buf[2], *fname; -+ int fd, ret; -+ char buf[2]; +@@ -357,6 +529,8 @@ static void closef(struct selabel_handle *rec) - if (!selinux_mnt) { - errno = ENOENT; -@@ -176,17 +278,9 @@ int security_set_boolean(const char *name, int value) - return -1; + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; ++ if (spec->from_mmap) ++ continue; + free(spec->regex_str); + free(spec->type_str); + free(spec->lr.ctx_raw); +@@ -369,6 +543,8 @@ static void closef(struct selabel_handle *rec) + + for (i = 0; i < (unsigned int)data->num_stems; i++) { + stem = &data->stem_arr[i]; ++ if (stem->from_mmap) ++ continue; + free(stem->buf); } -- len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR); -- fname = (char *)malloc(sizeof(char) * len); -- if (!fname) -+ fd = bool_open(name, O_WRONLY); -+ if (fd < 0) - return -1; -- snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name); -- -- fd = open(fname, O_WRONLY); -- if (fd < 0) { -- ret = -1; -- goto out; -- } +diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h +index cb5633b..9799bbb 100644 +--- a/libselinux/src/label_file.h ++++ b/libselinux/src/label_file.h +@@ -5,24 +5,32 @@ - if (value) - buf[0] = '1'; -@@ -196,8 +290,7 @@ int security_set_boolean(const char *name, int value) - - ret = write(fd, buf, 2); - close(fd); -- out: -- free(fname); -+ - if (ret > 0) - return 0; - else -@@ -256,7 +349,7 @@ static char *strtrim(char *dest, char *source, int size) - static int process_boolean(char *buffer, char *name, int namesize, int *val) - { - char name1[BUFSIZ]; -- char *ptr; -+ char *ptr = NULL; - char *tok = strtok_r(buffer, "=", &ptr); - if (tok) { - strncpy(name1, tok, BUFSIZ - 1); -diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c -index b245364..7c47222 100644 ---- a/libselinux/src/callbacks.c -+++ b/libselinux/src/callbacks.c -@@ -16,6 +16,7 @@ default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) - { - int rc; - va_list ap; -+ if (is_selinux_enabled() == 0) return 0; - va_start(ap, fmt); - rc = vfprintf(stderr, fmt, ap); - va_end(ap); -diff --git a/libselinux/src/file_path_suffixes.h b/libselinux/src/file_path_suffixes.h -index 0b00156..d11c8dc 100644 ---- a/libselinux/src/file_path_suffixes.h -+++ b/libselinux/src/file_path_suffixes.h -@@ -22,6 +22,8 @@ S_(BINPOLICY, "/policy/policy") - S_(COLORS, "/secolor.conf") - S_(VIRTUAL_DOMAIN, "/contexts/virtual_domain_context") - S_(VIRTUAL_IMAGE, "/contexts/virtual_image_context") -+ S_(LXC_CONTEXTS, "/contexts/lxc_contexts") - S_(FILE_CONTEXT_SUBS, "/contexts/files/file_contexts.subs") - S_(FILE_CONTEXT_SUBS_DIST, "/contexts/files/file_contexts.subs_dist") - S_(SEPGSQL_CONTEXTS, "/contexts/sepgsql_contexts") -+ S_(BOOLEAN_SUBS, "/booleans.subs_dist") -diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c -index 7bc46cc..82a608c 100644 ---- a/libselinux/src/label_file.c -+++ b/libselinux/src/label_file.c -@@ -27,6 +27,7 @@ - * Internals, mostly moved over from matchpathcon.c - */ + #include "label_internal.h" -+#define MAX_PREFIX 100 ++#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a ++#define SELINUX_COMPILED_FCONTEXT_MAX_VERS 1 ++ /* A file security context specification. */ - typedef struct spec { + struct spec { struct selabel_lookup_rec lr; /* holds contexts for lookup result */ -@@ -276,7 +277,7 @@ static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf) - + char *regex_str; /* regular expession string for diagnostics */ + char *type_str; /* type string for diagnostic messages */ + pcre *regex; /* compiled regular expression */ +- pcre_extra *sd; /* extra compiled stuff */ ++ union { ++ pcre_extra *sd; /* pointer to extra compiled stuff */ ++ pcre_extra lsd; /* used to hold the mmap'd version */ ++ }; + mode_t mode; /* mode format value */ + int matches; /* number of matching pathnames */ + int stem_id; /* indicates which stem-compression item */ + char hasMetaChars; /* regular expression has meta-chars */ + char regcomp; /* regex_str has been compiled to regex */ ++ char from_mmap; /* this spec is from an mmap of the data */ + }; - static int process_line(struct selabel_handle *rec, -- const char *path, const char *prefix, -+ const char *path, const char **prefix_array, - char *line_buf, int pass, unsigned lineno) - { - int items, len; -@@ -310,12 +311,24 @@ static int process_line(struct selabel_handle *rec, - } + /* A regular expression stem */ + struct stem { + char *buf; + int len; ++ char from_mmap; + }; - 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; -+ if (len && prefix_array[0]) { -+ int i = 0; -+ int found = 0; -+ while (i < MAX_PREFIX && prefix_array[i]) { -+ if (strncmp(prefix_array[i], regex, len) == 0) { -+ found = 1; -+ break; -+ } -+ i++; -+ } -+ -+ if (! found) { -+ /* Stem of regex does not match requested prefix, discard. */ -+ free(regex); -+ free(type); -+ free(context); -+ return 0; -+ } - } + /* Our stored configuration */ +@@ -45,7 +53,10 @@ struct saved_data { - if (pass == 1) { -@@ -397,7 +410,8 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, + static inline pcre_extra *get_pcre_extra(struct spec *spec) { - struct saved_data *data = (struct saved_data *)rec->data; - const char *path = NULL; -- const char *prefix = NULL; -+ const char *static_prefix_array[2] = {NULL, }; -+ const char **prefix_array = static_prefix_array; - FILE *fp; - FILE *localfp = NULL; - FILE *homedirfp = NULL; -@@ -418,7 +432,10 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, - path = opts[n].value; - break; - case SELABEL_OPT_SUBSET: -- prefix = opts[n].value; -+ static_prefix_array[0] = opts[n].value; -+ break; -+ case SELABEL_OPT_PREFIXES: -+ prefix_array = opts[n].values; - break; - case SELABEL_OPT_BASEONLY: - baseonly = !!opts[n].value; -@@ -481,7 +498,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, - while (getline(&line_buf, &line_len, fp) > 0) { - if (data->nspec >= maxnspec) - break; -- status = process_line(rec, path, prefix, line_buf, pass, ++lineno); -+ status = process_line(rec, path, prefix_array, line_buf, pass, ++lineno); - if (status) - goto finish; - } -@@ -497,7 +514,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, - while (getline(&line_buf, &line_len, homedirfp) > 0) { - if (data->nspec >= maxnspec) - break; -- status = process_line(rec, homedir_path, prefix, line_buf, pass, ++lineno); -+ status = process_line(rec, homedir_path, prefix_array, line_buf, pass, ++lineno); - if (status) - goto finish; - } -@@ -507,7 +524,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts, - while (getline(&line_buf, &line_len, localfp) > 0) { - if (data->nspec >= maxnspec) - break; -- status = process_line(rec, local_path, prefix, line_buf, pass, ++lineno); -+ status = process_line(rec, local_path, prefix_array, line_buf, pass, ++lineno); - if (status) - goto finish; - } +- return spec->sd; ++ if (spec->from_mmap) ++ return &spec->lsd; ++ else ++ return spec->sd; + } + + static inline mode_t string_to_mode(char *mode) diff --git a/libselinux/src/load_policy.c b/libselinux/src/load_policy.c index 10e29b9..888dab5 100644 --- a/libselinux/src/load_policy.c @@ -740,7 +481,7 @@ index 10e29b9..888dab5 100644 } diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c -index 2d7369e..eb292f2 100644 +index 2d7369e..2a00807 100644 --- a/libselinux/src/matchpathcon.c +++ b/libselinux/src/matchpathcon.c @@ -2,6 +2,7 @@ @@ -760,60 +501,8 @@ index 2d7369e..eb292f2 100644 va_end(ap); } -@@ -306,7 +307,7 @@ static void matchpathcon_init_once(void) - destructor_key_initialized = 1; - } - --int matchpathcon_init_prefix(const char *path, const char *subset) -+int matchpathcon_init_prefixes(const char *path, const char **prefixes) - { - if (!mycanoncon) - mycanoncon = default_canoncon; -@@ -314,15 +315,22 @@ int matchpathcon_init_prefix(const char *path, const char *subset) - __selinux_once(once, matchpathcon_init_once); - __selinux_setspecific(destructor_key, (void *)1); - -- options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET; -- options[SELABEL_OPT_SUBSET].value = subset; -+ options[SELABEL_OPT_PREFIXES].type = SELABEL_OPT_PREFIXES; -+ options[SELABEL_OPT_PREFIXES].values = prefixes; - options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH; - options[SELABEL_OPT_PATH].value = path; - - hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT); - return hnd ? 0 : -1; - } -+hidden_def(matchpathcon_init_prefixes) - -+int matchpathcon_init_prefix(const char *path, const char *prefix) -+{ -+ const char *prefixes[2] = { prefix, NULL }; -+ -+ return matchpathcon_init_prefixes(path, prefixes); -+} - hidden_def(matchpathcon_init_prefix) - - int matchpathcon_init(const char *path) -@@ -397,10 +405,13 @@ int realpath_not_final(const char *name, char *resolved_path) - goto out; - } - -- resolved_path += len; -- strcpy(resolved_path, "/"); -- resolved_path += 1; -- strcpy(resolved_path, last_component); -+ p = resolved_path; -+ p += len; -+ if (strcmp(resolved_path, "/") != 0) { -+ strcpy(p, "/"); -+ p += 1; -+ } -+ strcpy(p, last_component); - out: - free(tmp_path); - return rc; diff --git a/libselinux/src/selinux_config.c b/libselinux/src/selinux_config.c -index f42cb7c..cb65666 100644 +index 296f357..cb65666 100644 --- a/libselinux/src/selinux_config.c +++ b/libselinux/src/selinux_config.c @@ -9,6 +9,7 @@ @@ -824,18 +513,7 @@ index f42cb7c..cb65666 100644 #include "get_default_type_internal.h" #define SELINUXDIR "/etc/selinux/" -@@ -46,7 +47,9 @@ - #define FILE_CONTEXT_SUBS 23 - #define SEPGSQL_CONTEXTS 24 - #define FILE_CONTEXT_SUBS_DIST 25 --#define NEL 26 -+#define LXC_CONTEXTS 26 -+#define BOOLEAN_SUBS 27 -+#define NEL 28 - - /* Part of one-time lazy init */ - static pthread_once_t once = PTHREAD_ONCE_INIT; -@@ -294,13 +297,57 @@ const char *selinux_removable_context_path(void) +@@ -296,13 +297,57 @@ const char *selinux_removable_context_path(void) hidden_def(selinux_removable_context_path) @@ -894,293 +572,431 @@ index f42cb7c..cb65666 100644 const char *selinux_file_context_path(void) { return get_path(FILE_CONTEXTS); -@@ -418,6 +465,19 @@ const char *selinux_virtual_image_context_path(void) - - hidden_def(selinux_virtual_image_context_path) - -+const char *selinux_lxc_contexts_path(void) -+{ -+ return get_path(LXC_CONTEXTS); -+} -+ -+hidden_def(selinux_lxc_contexts_path) -+ -+const char * selinux_booleans_subs_path(void) { -+ return get_path(BOOLEAN_SUBS); -+} -+ -+hidden_def(selinux_booleans_subs_path) -+ - const char * selinux_file_context_subs_path(void) { - return get_path(FILE_CONTEXT_SUBS); - } diff --git a/libselinux/src/selinux_internal.h b/libselinux/src/selinux_internal.h -index 00df405..c47add9 100644 +index 2c7c85c..75ebc88 100644 --- a/libselinux/src/selinux_internal.h +++ b/libselinux/src/selinux_internal.h -@@ -59,13 +59,18 @@ hidden_proto(selinux_mkload_policy) - hidden_proto(security_getenforce) - hidden_proto(security_setenforce) +@@ -61,7 +61,9 @@ hidden_proto(selinux_mkload_policy) hidden_proto(security_deny_unknown) -+ hidden_proto(selinux_binary_policy_path_min_max) -+ hidden_proto(selinux_boolean_sub) + hidden_proto(selinux_boolean_sub) hidden_proto(selinux_binary_policy_path) -+ hidden_proto(selinux_booleans_subs_path) ++ hidden_proto(selinux_binary_policy_path_min_max); + hidden_proto(selinux_booleans_subs_path) + hidden_proto(selinux_current_policy_path) hidden_proto(selinux_default_context_path) hidden_proto(selinux_securetty_types_path) hidden_proto(selinux_failsafe_context_path) - hidden_proto(selinux_removable_context_path) - hidden_proto(selinux_virtual_domain_context_path) - hidden_proto(selinux_virtual_image_context_path) -+ hidden_proto(selinux_lxc_contexts_path) - hidden_proto(selinux_file_context_path) - hidden_proto(selinux_file_context_homedir_path) - hidden_proto(selinux_file_context_local_path) -@@ -82,6 +87,7 @@ hidden_proto(selinux_mkload_policy) - hidden_proto(selinux_path) - hidden_proto(selinux_check_passwd_access) - hidden_proto(selinux_check_securetty_context) -+ hidden_proto(matchpathcon_init_prefixes) - hidden_proto(matchpathcon_init_prefix) - hidden_proto(selinux_users_path) - hidden_proto(selinux_usersconf_path); diff --git a/libselinux/src/seusers.c b/libselinux/src/seusers.c -index 73ad42c..569fa43 100644 +index cfea186..8b1eba6 100644 --- a/libselinux/src/seusers.c +++ b/libselinux/src/seusers.c -@@ -276,13 +276,19 @@ int getseuser(const char *username, const char *service, - if (fp == NULL) goto err; - __fsetlocking(fp, FSETLOCKING_BYCALLER); - while (getline(&buffer, &size, fp) > 0) { -- if (strncmp(buffer, "*:", 2) == 0) { -+ -+ if (!service) { -+ rec = strdup(buffer); -+ break; -+ } -+ -+ if (strncmp(buffer, "*:", 2) == 0) -+ { - free(rec); - rec = strdup(buffer); - continue; - } -- if (!service) -- continue; -+ - len = strlen(service); - if ((strncmp(buffer, service, len) == 0) && - (buffer[len] == ':')) { -@@ -298,6 +304,7 @@ int getseuser(const char *username, const char *service, - - seuser++; - level = strchr(seuser, ':'); -+ if (! level) goto err; - *level = 0; - level++; - *r_seuser = strdup(seuser); -diff --git a/libselinux/utils/avcstat.c b/libselinux/utils/avcstat.c -index 7239ef2..73432f2 100644 ---- a/libselinux/utils/avcstat.c -+++ b/libselinux/utils/avcstat.c -@@ -139,6 +139,7 @@ int main(int argc, char **argv) - - sa.sa_handler = sighandler; - sa.sa_flags = SA_RESTART; -+ sigemptyset(&sa.sa_mask); - - i = sigaction(SIGWINCH, &sa, NULL); - if (i < 0) -diff --git a/libselinux/utils/getdefaultcon.c b/libselinux/utils/getdefaultcon.c -index 049e75c..6bafedb 100644 ---- a/libselinux/utils/getdefaultcon.c -+++ b/libselinux/utils/getdefaultcon.c -@@ -21,10 +21,11 @@ int main(int argc, char **argv) - { - security_context_t usercon = NULL, cur_context = NULL; - char *user = NULL, *level = NULL, *role=NULL, *seuser=NULL, *dlevel=NULL; -+ char *service = NULL; - int ret, opt; - int verbose = 0; - -- while ((opt = getopt(argc, argv, "l:r:v")) > 0) { -+ while ((opt = getopt(argc, argv, "l:r:s:v")) > 0) { - switch (opt) { - case 'l': - level = strdup(optarg); -@@ -32,6 +33,9 @@ int main(int argc, char **argv) - case 'r': - role = strdup(optarg); +@@ -125,7 +125,7 @@ static int check_group(const char *group, const char *name, const gid_t gid) { + rbuf = malloc(rbuflen); + if (rbuf == NULL) + return 0; +- int retval = getgrnam_r(group, &gbuf, rbuf, ++ int retval = getgrnam_r(group, &gbuf, rbuf, + rbuflen, &grent); + if ( retval == ERANGE ) + { +@@ -198,13 +198,13 @@ int getseuserbyname(const char *name, char **r_seuser, char **r_level) + if (!strcmp(username, name)) break; -+ case 's': -+ service = strdup(optarg); -+ break; - case 'v': - verbose = 1; - break; -@@ -61,7 +65,7 @@ int main(int argc, char **argv) - } else - cur_context = argv[optind + 1]; -- if ((ret = getseuserbyname(user, &seuser, &dlevel)) == 0) { -+ if ((ret = getseuser(user, service, &seuser, &dlevel)) == 0) { - if (! level) level=dlevel; - if (role != NULL && role[0]) - ret=get_default_context_with_rolelevel(seuser, role, level,cur_context,&usercon); -@@ -74,7 +78,7 @@ int main(int argc, char **argv) - if (verbose) { - printf("%s: %s from %s %s %s %s -> %s\n", argv[0], user, cur_context, seuser, role, level, usercon); +- if (username[0] == '%' && +- !groupseuser && ++ if (username[0] == '%' && ++ !groupseuser && + check_group(&username[1], name, gid)) { + groupseuser = seuser; + grouplevel = level; } else { -- printf("%s", usercon); -+ printf("%s\n", usercon); - } - } +- if (!defaultseuser && ++ if (!defaultseuser && + !strcmp(username, "__default__")) { + defaultseuser = seuser; + defaultlevel = level; +@@ -258,7 +258,7 @@ int getseuserbyname(const char *name, char **r_seuser, char **r_level) + return 0; + } -diff --git a/libselinux/utils/getsebool.c b/libselinux/utils/getsebool.c -index 3a90449..9ae9243 100644 ---- a/libselinux/utils/getsebool.c -+++ b/libselinux/utils/getsebool.c -@@ -87,14 +87,22 @@ int main(int argc, char **argv) - rc = -1; - goto out; - } -+ char *alt_name = selinux_boolean_sub(names[i]); -+ if (! alt_name) { -+ perror("Out of memory\n"); -+ rc = -1; -+ goto out; +-int getseuser(const char *username, const char *service, ++int getseuser(const char *username, const char *service, + char **r_seuser, char **r_level) { + int ret = -1; + int len = 0; +diff --git a/libselinux/utils/.gitignore b/libselinux/utils/.gitignore +index 8b9294d..060eaab 100644 +--- a/libselinux/utils/.gitignore ++++ b/libselinux/utils/.gitignore +@@ -13,6 +13,7 @@ getsebool + getseuser + matchpathcon + policyvers ++sefcontext_compile + selinux_check_securetty_context + selinuxenabled + selinuxexeccon +diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile +index 5f3e047..f469924 100644 +--- a/libselinux/utils/Makefile ++++ b/libselinux/utils/Makefile +@@ -28,6 +28,7 @@ LDLIBS += -L../src -lselinux -L$(LIBDIR) + + TARGETS=$(patsubst %.c,%,$(wildcard *.c)) + ++sefcontext_compile: LDLIBS += -lpcre + + ifeq ($(DISABLE_AVC),y) + UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel +diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c +new file mode 100644 +index 0000000..f8a5fea +--- /dev/null ++++ b/libselinux/utils/sefcontext_compile.c +@@ -0,0 +1,345 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "../src/label_file.h" ++ ++static int process_file(struct saved_data *data, const char *filename) ++{ ++ struct spec *spec; ++ unsigned int line_num; ++ char *line_buf = NULL; ++ size_t line_len; ++ ssize_t len; ++ FILE *context_file; ++ ++ context_file = fopen(filename, "r"); ++ if (!context_file) ++ return -1; ++ ++ line_num = 0; ++ while ((len = getline(&line_buf, &line_len, context_file)) != -1) { ++ char *context; ++ char *mode; ++ char *regex; ++ char *cp, *anchored_regex; ++ char *buf_p; ++ pcre *re; ++ pcre_extra *sd; ++ const char *err; ++ int items, erroff, rc; ++ size_t regex_len; ++ int32_t stem_id; ++ ++ 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) ++ continue; ++ ++ items = sscanf(line_buf, "%ms %ms %ms", ®ex, &mode, &context); ++ if (items < 2 || items > 3) { ++ fprintf(stderr, "invalid entry, skipping:%s", line_buf); ++ continue; + } + - if (pending != active) { -- printf("%s --> %s pending: %s\n", names[i], -+ printf("%s --> %s pending: %s\n", alt_name, - (active ? "on" : "off"), - (pending ? "on" : "off")); - } else { -- printf("%s --> %s\n", names[i], -+ printf("%s --> %s\n", alt_name, - (active ? "on" : "off")); - } -+ free(alt_name); - } - - out: -diff --git a/libselinux/utils/matchpathcon.c b/libselinux/utils/matchpathcon.c -index b1adadd..a3a21ca 100644 ---- a/libselinux/utils/matchpathcon.c -+++ b/libselinux/utils/matchpathcon.c -@@ -45,21 +45,27 @@ static int printmatchpathcon(const char *path, int header, int mode) - - int main(int argc, char **argv) - { -- int i, init = 0; -+ int i, force_mode = 0; - int header = 1, opt; - int verify = 0; - int notrans = 0; - int error = 0; - int quiet = 0; -+ const char *prefixes[100]; -+ char *file = NULL; -+ int prefix=0; - - if (argc < 2) - usage(argv[0]); - -- while ((opt = getopt(argc, argv, "Nnf:p:Vq")) > 0) { -+ while ((opt = getopt(argc, argv, "m:Nnf:p:Vq")) > 0) { - switch (opt) { - case 'n': - header = 0; - break; -+ case 'm': -+ force_mode = atoi(optarg); -+ break; - case 'V': - verify = 1; - break; -@@ -68,36 +74,24 @@ int main(int argc, char **argv) - set_matchpathcon_flags(MATCHPATHCON_NOTRANS); - break; - case 'f': -- if (init) { -+ if (prefix) { - fprintf(stderr, - "%s: -f and -p are exclusive\n", - argv[0]); - exit(1); - } -- init = 1; -- if (matchpathcon_init(optarg)) { -- fprintf(stderr, -- "Error while processing %s: %s\n", -- optarg, -- errno ? strerror(errno) : "invalid"); -- exit(1); -- } -+ file = optarg; - break; - case 'p': -- if (init) { -+ if (file) { - fprintf(stderr, - "%s: -f and -p are exclusive\n", - argv[0]); - exit(1); - } -- init = 1; -- if (matchpathcon_init_prefix(NULL, optarg)) { -- fprintf(stderr, -- "Error while processing %s: %s\n", -- optarg, -- errno ? strerror(errno) : "invalid"); -- exit(1); -- } -+ prefixes[prefix]=optarg; -+ prefix++; -+ prefixes[prefix]=NULL; - break; - case 'q': - quiet = 1; -@@ -106,6 +100,26 @@ int main(int argc, char **argv) - usage(argv[0]); - } - } -+ if (prefix > 0) { -+ if (matchpathcon_init_prefixes(file, prefixes)) { -+ fprintf(stderr, -+ "Error while processing %s: %s\n", -+ file, -+ errno ? strerror(errno) : "invalid"); -+ exit(1); ++ if (items == 2) { ++ context = mode; ++ mode = NULL; ++ } ++ ++ rc = grow_specs(data); ++ if (rc) ++ return rc; ++ ++ spec = &data->spec_arr[data->nspec]; ++ ++ spec->lr.ctx_raw = context; ++ spec->mode = string_to_mode(mode); ++ if (spec->mode == -1) { ++ fprintf(stderr, "%s: line %d has invalid file type %s\n", ++ regex, line_num + 1, mode); ++ spec->mode = 0; + } -+ } else { -+ if (file) { -+ if (matchpathcon_init(file)) { -+ fprintf(stderr, -+ "Error inwhile processing %s: %s\n", -+ file, -+ errno ? strerror(errno) : "invalid"); -+ exit(1); -+ } ++ 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) ++ return -1; ++ ++ *cp++ = '^'; ++ memcpy(cp, regex, regex_len); ++ cp += regex_len; ++ *cp++ = '$'; ++ *cp = '\0'; ++ ++ spec_hasMetaChars(spec); ++ ++ re = pcre_compile(anchored_regex, 0, &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; ++ ++ line_num++; ++ data->nspec++; + } + - for (i = optind; i < argc; i++) { - int rc, mode = 0; - struct stat buf; -@@ -114,8 +128,11 @@ int main(int argc, char **argv) - if (len > 1 && path[len - 1 ] == '/') - path[len - 1 ] = '\0'; - -- if (lstat(path, &buf) == 0) -- mode = buf.st_mode; -+ if (! force_mode) { -+ if (lstat(path, &buf) == 0) -+ mode = buf.st_mode; -+ } else -+ mode = force_mode; - - if (verify) { - rc = selinux_file_context_verify(path, mode); ++ free(line_buf); ++ fclose(context_file); ++ ++ return 0; ++} ++ ++/* ++ * File Format ++ * ++ * u32 - magic number ++ * u32 - version ++ * u32 - number of stems ++ * ** Stems ++ * 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 the upcoming regex_str ++ * char - char array of the original regex string including the stem. ++ * mode_t - mode bits ++ * s32 - stemid associated with the regex ++ * u32 - spec has meta characters ++ * u32 - data length of the pcre regex ++ * char - a bufer holding the raw pcre regex info ++ * u32 - data length of the pcre regex study daya ++ * char - a buffer holding the raw pcre regex study data ++ */ ++static int write_binary_file(struct saved_data *data, char *filename) ++{ ++ struct spec *specs = data->spec_arr; ++ FILE *bin_file; ++ size_t len; ++ uint32_t magic = SELINUX_MAGIC_COMPILED_FCONTEXT; ++ uint32_t section_len; ++ uint32_t i; ++ ++ bin_file = fopen(filename, "w"); ++ if (!bin_file) { ++ perror("fopen output_file"); ++ exit(EXIT_FAILURE); ++ } ++ ++ /* write some magic number */ ++ len = fwrite(&magic, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* write the version */ ++ section_len = SELINUX_COMPILED_FCONTEXT_MAX_VERS; ++ len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* write the number of stems coming */ ++ section_len = data->num_stems; ++ len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ for (i = 0; i < section_len; i++) { ++ char *stem = data->stem_arr[i].buf; ++ uint32_t stem_len = data->stem_arr[i].len; ++ ++ /* write the strlen (aka no nul) */ ++ len = fwrite(&stem_len, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* include the nul in the file */ ++ stem_len += 1; ++ len = fwrite(stem, sizeof(char), stem_len, bin_file); ++ if (len != stem_len) ++ return -1; ++ } ++ ++ /* write the number of regexes coming */ ++ section_len = data->nspec; ++ len = fwrite(§ion_len, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ for (i = 0; i < section_len; i++) { ++ char *context = specs[i].lr.ctx_raw; ++ char *regex_str = specs[i].regex_str; ++ mode_t mode = specs[i].mode; ++ int32_t stem_id = specs[i].stem_id; ++ pcre *re = specs[i].regex; ++ pcre_extra *sd = get_pcre_extra(&specs[i]); ++ uint32_t to_write; ++ size_t size; ++ int rc; ++ ++ /* length of the context string (including nul) */ ++ to_write = strlen(context) + 1; ++ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* original context strin (including nul) */ ++ len = fwrite(context, sizeof(char), to_write, bin_file); ++ if (len != to_write) ++ return -1; ++ ++ /* length of the original regex string (including nul) */ ++ to_write = strlen(regex_str) + 1; ++ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* original regex string */ ++ len = fwrite(regex_str, sizeof(char), to_write, bin_file); ++ if (len != to_write) ++ return -1; ++ ++ /* binary F_MODE bits */ ++ len = fwrite(&mode, sizeof(mode), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* stem for this regex (could be -1) */ ++ len = fwrite(&stem_id, sizeof(stem_id), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* does this spec have a metaChar? */ ++ to_write = specs[i].hasMetaChars; ++ len = fwrite(&to_write, sizeof(to_write), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* determine the size of the pcre data in bytes */ ++ rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size); ++ if (rc < 0) ++ return -1; ++ ++ /* write the number of bytes in the pcre data */ ++ to_write = size; ++ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* write the actual pcre data as a char array */ ++ len = fwrite(re, 1, to_write, bin_file); ++ if (len != to_write) ++ return -1; ++ ++ /* determine the size of the pcre study info */ ++ rc = pcre_fullinfo(re, sd, PCRE_INFO_STUDYSIZE, &size); ++ if (rc < 0) ++ return -1; ++ ++ /* write the number of bytes in the pcre study data */ ++ to_write = size; ++ len = fwrite(&to_write, sizeof(uint32_t), 1, bin_file); ++ if (len != 1) ++ return -1; ++ ++ /* write the actual pcre study data as a char array */ ++ len = fwrite(sd->study_data, 1, to_write, bin_file); ++ if (len != to_write) ++ return -1; ++ } ++ ++ fclose(bin_file); ++ ++ return 0; ++} ++ ++static int free_specs(struct saved_data *data) ++{ ++ struct spec *specs = data->spec_arr; ++ unsigned int num_entries = data->nspec; ++ unsigned int i; ++ ++ for (i = 0; i < num_entries; i++) { ++ free(specs[i].lr.ctx_raw); ++ free(specs[i].lr.ctx_trans); ++ free(specs[i].regex_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++) { ++ free(data->stem_arr[i].buf); ++ } ++ free(data->stem_arr); ++ ++ memset(data, 0, sizeof(*data)); ++ return 0; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct saved_data data; ++ const char *path; ++ char stack_path[PATH_MAX + 1]; ++ int rc; ++ ++ if (argc != 2) { ++ fprintf(stderr, "usage: %s input_file\n", argv[0]); ++ exit(EXIT_FAILURE); ++ } ++ ++ memset(&data, 0, sizeof(data)); ++ ++ path = argv[1]; ++ ++ rc = process_file(&data, path); ++ if (rc < 0) ++ return rc; ++ ++ rc = sort_specs(&data); ++ if (rc) ++ return rc; ++ ++ rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path); ++ if (rc < 0 || rc >= sizeof(stack_path)) ++ return rc; ++ rc = write_binary_file(&data, stack_path); ++ if (rc < 0) ++ return rc; ++ ++ rc = free_specs(&data); ++ if (rc < 0) ++ return rc; ++ ++ return 0; ++} diff --git a/libselinux.spec b/libselinux.spec index ca2847f..d6a4840 100644 --- a/libselinux.spec +++ b/libselinux.spec @@ -4,23 +4,23 @@ %define ruby_inc %(pkg-config --cflags ruby-1.9) %define ruby_sitearch %(ruby -rrbconfig -e "puts RbConfig::CONFIG['vendorarchdir']") -%define libsepolver 2.1.5-1 +%define libsepolver 2.1.7-4 %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} Summary: SELinux library and simple utilities Name: libselinux -Version: 2.1.11 -Release: 6%{?dist} +Version: 2.1.12 +Release: 1%{?dist} License: Public Domain Group: System Environment/Libraries Source: %{name}-%{version}.tgz Url: http://oss.tresys.com/git/selinux.git Patch1: libselinux-rhat.patch -BuildRequires: pkgconfig python-devel ruby-devel ruby libsepol-static >= %{libsepolver} swig +BuildRequires: pkgconfig python-devel ruby-devel ruby libsepol-static >= %{libsepolver} swig pcre-devel %if 0%{?with_python3} BuildRequires: python3-devel %endif # if with_python3 -Requires: libsepol >= %{libsepolver} +Requires: libsepol >= %{libsepolver} pcre Conflicts: filesystem < 3 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -187,6 +187,7 @@ rm -rf %{buildroot} %{_libdir}/libselinux.so.* /var/run/setrans %{_sbindir}/matchpathcon +%{_sbindir}/sefcontext_compile /usr/lib/tmpfiles.d/libselinux.conf %files utils @@ -235,6 +236,40 @@ rm -rf %{buildroot} %{ruby_sitearch}/selinux.so %changelog +* Thu Sep 13 2012 Dan Walsh - 2.1.12-1 +- Update to upstream + * Add support for lxc_contexts_path + * utils: add service to getdefaultcon + * libsemanage: do not set soname needlessly + * libsemanage: remove PYTHONLIBDIR and ruby equivalent + * boolean name equivalency + * getsebool: support boolean name substitution + * Add man page for new selinux_boolean_sub function. + * expose selinux_boolean_sub + * matchpathcon: add -m option to force file type check + * utils: avcstat: clear sa_mask set + * seusers: Check for strchr failure + * booleans: initialize pointer to silence coveriety + * stop messages when SELinux disabled + * label_file: use PCRE instead of glibc regex functions + * label_file: remove all typedefs + * label_file: move definitions to include file + * label_file: do string to mode_t conversion in a helper function + * label_file: move error reporting back into caller + * label_file: move stem/spec handling to header + * label_file: drop useless ncomp field from label_file data + * label_file: move spec_hasMetaChars to header + * label_file: fix potential read past buffer in spec_hasMetaChars + * label_file: move regex sorting to the header + * label_file: add accessors for the pcre extra data + * label_file: only run regex files one time + * label_file: new process_file function + * label_file: break up find_stem_from_spec + * label_file: struct reorg + * label_file: only run array once when sorting + * Ensure that we only close the selinux netlink socket once. + * improve the file_contexts.5 manual page + * Fri Aug 03 2012 David Malcolm - 2.1.11-6 - rebuild for https://fedoraproject.org/wiki/Features/Python_3.3 diff --git a/sources b/sources index 4e67dff..822ff4e 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -34ba81b68ddf832a0a4272fe889050dc libselinux-2.1.11.tgz +71a3a6ade9be8b31567fa9437e00698d libselinux-2.1.12.tgz