Re: [PATCH 1/2] libselinux: add support for pcre2

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

 



On Sep 7, 2016 11:29, "Jason Zaman" <jason@xxxxxxxxxxxxx> wrote:
>
> On Wed, Sep 07, 2016 at 09:40:43AM -0700, William Roberts wrote:
> > On Wed, Sep 7, 2016 at 8:02 AM, Stephen Smalley <sds@xxxxxxxxxxxxx> wrote:
> > > On 09/07/2016 04:08 AM, Janis Danisevskis wrote:
> > >> From: Janis Danisevskis <jdanis@xxxxxxxxxx>
> > >>
> > >> This patch moves all pcre1/2 dependencies into the new files regex.h
> > >> and regex.c implementing the common denominator of features needed
> > >> by libselinux. The compiler flag -DUSE_PCRE2 toggles between the
> > >> used implementations.
> > >>
> > >> As of this patch libselinux supports either pcre or pcre2 but not
> > >> both at the same time. The persistently stored file contexts
> > >> information differs. This means libselinux can only load file
> > >> context files generated by sefcontext_compile build with the
> > >> same pcre variant.
> > >
> > > Shouldn't the pcre variant be encoded in some manner in the
> > > file_contexts.bin file so that libselinux can tell immediately whether
> > > it is supported?
> >
> > Don't we have that in pcre_version()?
> >
> > >
> > >> Also, for pcre2 the persistent format is architecture dependant.
> > >> Stored precompiled regular expressions can only be used on the
> > >> same architecture they were generated on. If pcre2 is used and
> > >> sefcontext_compile shall generate portable output, it and libselinux
> > >> must be compiled with -DNO_PERSISTENTLY_STORED_PATTERNS, at the
> > >> cost of having to recompile the regular expressions at load time.
>
> I'd rather the arch was just added to the compiled files like is done
> for pcre version. It may not be a bad idea to add arch even for pcre1
> since those also seemed quite fragile in the past.
>
> > > Is it worth supporting the -DNO_PERSISTENTLY_STORED_PATTERNS case?  The
> > > point of using file_contexts.bin was to move the cost of compiling the
> > > regexes to build time rather than load time; if we cannot do that, then
> > > how much do we gain from using file_contexts.bin instead of just falling
> > > back to file_contexts?

I have some work that speeds up file_contexts load times by 25% and if we mmap file_contexts we get a slight bump. I'm confident i can speed it up even more. The binary format is 3 times the size. Gprof has most if the slowness shown in nodups on validation, I don't think regex compilation is the bottleneck. I has hoping I could get the speeds close and then propose ditching bin file support on Android.

> > >
> > > The #ifdef maze makes it very hard to read and maintain this code; that
> > > needs to be refactored.
> >
> > Perhaps set up some function pointers and hide the regex structure to be opaque
> > to the rest of selinux. This makes me think, should we just dlopen the
> > correct version of libpcre based on pcre_version()? Not sure how you
> > feel about dlopen calls....
>
> Please no :(. dlopen makes things harder to track in a distro. there are
> a ton of tools in gentoo that figure things out with ldd and dont work
> at all with dlopen (like keeping old libs around if other packages link
> to old .so versions and whatnot).

I didn't think dlopen would be fun.
>
> -- Jason
>
> > > valgrind is reporting numerous errors, including both use of
> > > uninitialised values and memory leaks with both patches applied.  Try:
> > > make DESTDIR=~/obj CFLAGS+=-g clean install
> > > LD_LIBRARY_PATH=~/obj/lib valgrind --leak-check=full
> > > ~/obj/usr/sbin/matchpathcon /etc
> > >
> > > On x86_64.
> > >
> > > Will provide review of the code itself later...
> > >
> > >>
> > >> Signed-off-by: Janis Danisevskis <jdanis@xxxxxxxxxx>
> > >> ---
> > >>  libselinux/Makefile                   |  13 ++
> > >>  libselinux/src/Makefile               |   4 +-
> > >>  libselinux/src/label_file.c           |  91 ++------
> > >>  libselinux/src/label_file.h           |  54 ++---
> > >>  libselinux/src/regex.c                | 405 ++++++++++++++++++++++++++++++++++
> > >>  libselinux/src/regex.h                | 168 ++++++++++++++
> > >>  libselinux/utils/Makefile             |   4 +-
> > >>  libselinux/utils/sefcontext_compile.c |  53 +----
> > >>  8 files changed, 637 insertions(+), 155 deletions(-)
> > >>  create mode 100644 libselinux/src/regex.c
> > >>  create mode 100644 libselinux/src/regex.h
> > >>
> > >> diff --git a/libselinux/Makefile b/libselinux/Makefile
> > >> index 6142b60..15d051e 100644
> > >> --- a/libselinux/Makefile
> > >> +++ b/libselinux/Makefile
> > >> @@ -24,6 +24,19 @@ ifeq ($(DISABLE_SETRANS),y)
> > >>  endif
> > >>  export DISABLE_AVC DISABLE_SETRANS DISABLE_RPM DISABLE_BOOL EMFLAGS
> > >>
> > >> +USE_PCRE2 ?= n
> > >> +DISABLE_PERSISTENTLY_STORED_REGEX_PATTERNS ?= n
> > >> +ifeq ($(USE_PCRE2),y)
> > >> +     PCRE_CFLAGS := -DUSE_PCRE2 -DPCRE2_CODE_UNIT_WIDTH=8
> > >> +     ifeq ($(DISABLE_PERSISTENTLY_STORED_REGEX_PATTERNS), y)
> > >> +             PCRE_CFLAGS += -DNO_PERSISTENTLY_STORED_PATTERNS
> > >> +     endif
> > >> +     PCRE_LDFLAGS := -lpcre2-8
> > >> +else
> > >> +     PCRE_LDFLAGS := -lpcre
> > >> +endif
> > >> +export PCRE_CFLAGS PCRE_LDFLAGS
> > >> +
> > >>  all install relabel clean distclean indent:
> > >>       @for subdir in $(SUBDIRS); do \
> > >>               (cd $$subdir && $(MAKE) $@) || exit 1; \
> > >> diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile
> > >> index 37d01af..66687e6 100644
> > >> --- a/libselinux/src/Makefile
> > >> +++ b/libselinux/src/Makefile
> > >> @@ -74,7 +74,7 @@ CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissi
> > >>            -fipa-pure-const -Wno-suggest-attribute=pure -Wno-suggest-attribute=const \
> > >>            -Werror -Wno-aggregate-return -Wno-redundant-decls
> > >>
> > >> -override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE $(EMFLAGS)
> > >> +override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE $(EMFLAGS) $(PCRE_CFLAGS)
> > >>
> > >>  SWIG_CFLAGS += -Wno-error -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-parameter \
> > >>               -Wno-shadow -Wno-uninitialized -Wno-missing-prototypes -Wno-missing-declarations
> > >> @@ -113,7 +113,7 @@ $(LIBA): $(OBJS)
> > >>       $(RANLIB) $@
> > >>
> > >>  $(LIBSO): $(LOBJS)
> > >> -     $(CC) $(CFLAGS) -shared -o $@ $^ -lpcre -ldl $(LDFLAGS) -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro
> > >> +     $(CC) $(CFLAGS) -shared -o $@ $^ $(PCRE_LDFLAGS) -ldl $(LDFLAGS) -L$(LIBDIR) -Wl,-soname,$(LIBSO),-z,defs,-z,relro
> > >>       ln -sf $@ $(TARGET)
> > >>
> > >>  $(LIBPC): $(LIBPC).in ../VERSION
> > >> diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> > >> index c89bb35..6698624 100644
> > >> --- a/libselinux/src/label_file.c
> > >> +++ b/libselinux/src/label_file.c
> > >> @@ -15,7 +15,6 @@
> > >>  #include <errno.h>
> > >>  #include <limits.h>
> > >>  #include <stdint.h>
> > >> -#include <pcre.h>
> > >>  #include <unistd.h>
> > >>  #include <sys/mman.h>
> > >>  #include <sys/types.h>
> > >> @@ -176,7 +175,10 @@ static int load_mmap(struct selabel_handle *rec, const char *path,
> > >>               return -1;
> > >>
> > >>       if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
> > >> -             len = strlen(pcre_version());
> > >> +             if (!regex_version()) {
> > >> +                     return -1;
> > >> +             }
> > >> +             len = strlen(regex_version());
> > >>
> > >>               rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
> > >>               if (rc < 0)
> > >> @@ -198,7 +200,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path,
> > >>               }
> > >>
> > >>               str_buf[entry_len] = '\0';
> > >> -             if ((strcmp(str_buf, pcre_version()) != 0)) {
> > >> +             if ((strcmp(str_buf, regex_version()) != 0)) {
> > >>                       free(str_buf);
> > >>                       return -1;
> > >>               }
> > >> @@ -278,7 +280,11 @@ static int load_mmap(struct selabel_handle *rec, const char *path,
> > >>
> > >>               spec = &data->spec_arr[data->nspec];
> > >>               spec->from_mmap = 1;
> > >> +#if defined USE_PCRE2 && defined NO_PERSISTENTLY_STORED_PATTERNS
> > >> +             spec->regcomp = 0;
> > >> +#else
> > >>               spec->regcomp = 1;
> > >> +#endif
> > >>
> > >>               /* Process context */
> > >>               rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
> > >> @@ -364,47 +370,10 @@ static int load_mmap(struct selabel_handle *rec, const char *path,
> > >>                       spec->prefix_len = prefix_len;
> > >>               }
> > >>
> > >> -             /* Process regex and study_data entries */
> > >> -             rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
> > >> -             if (rc < 0 || !entry_len) {
> > >> -                     rc = -1;
> > >> -                     goto err;
> > >> -             }
> > >> -             spec->regex = (pcre *)mmap_area->next_addr;
> > >> -             rc = next_entry(NULL, mmap_area, entry_len);
> > >> +             rc = regex_load_mmap(mmap_area, &spec->regex);
> > >>               if (rc < 0)
> > >>                       goto err;
> > >>
> > >> -             /* Check that regex lengths match. pcre_fullinfo()
> > >> -              * also validates its magic number. */
> > >> -             rc = pcre_fullinfo(spec->regex, NULL, PCRE_INFO_SIZE, &len);
> > >> -             if (rc < 0 || len != entry_len) {
> > >> -                     rc = -1;
> > >> -                     goto err;
> > >> -             }
> > >> -
> > >> -             rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
> > >> -             if (rc < 0 || !entry_len) {
> > >> -                     rc = -1;
> > >> -                     goto err;
> > >> -             }
> > >> -
> > >> -             if (entry_len) {
> > >> -                     spec->lsd.study_data = (void *)mmap_area->next_addr;
> > >> -                     spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA;
> > >> -                     rc = next_entry(NULL, mmap_area, entry_len);
> > >> -                     if (rc < 0)
> > >> -                             goto err;
> > >> -
> > >> -                     /* Check that study data lengths match. */
> > >> -                     rc = pcre_fullinfo(spec->regex, &spec->lsd,
> > >> -                                        PCRE_INFO_STUDYSIZE, &len);
> > >> -                     if (rc < 0 || len != entry_len) {
> > >> -                             rc = -1;
> > >> -                             goto err;
> > >> -                     }
> > >> -             }
> > >> -
> > >>               data->nspec++;
> > >>       }
> > >>
> > >> @@ -609,10 +578,7 @@ static void closef(struct selabel_handle *rec)
> > >>                       continue;
> > >>               free(spec->regex_str);
> > >>               free(spec->type_str);
> > >> -             if (spec->regcomp) {
> > >> -                     pcre_free(spec->regex);
> > >> -                     pcre_free_study(spec->sd);
> > >> -             }
> > >> +             regex_data_free(spec->regex);
> > >>       }
> > >>
> > >>       for (i = 0; i < (unsigned int)data->num_stems; i++) {
> > >> @@ -644,13 +610,14 @@ static struct spec *lookup_common(struct selabel_handle *rec,
> > >>  {
> > >>       struct saved_data *data = "" saved_data *)rec->data;
> > >>       struct spec *spec_arr = data->spec_arr;
> > >> -     int i, rc, file_stem, pcre_options = 0;
> > >> +     int i, rc, file_stem;
> > >>       mode_t mode = (mode_t)type;
> > >>       const char *buf;
> > >>       struct spec *ret = NULL;
> > >>       char *clean_key = NULL;
> > >>       const char *prev_slash, *next_slash;
> > >>       unsigned int sofar = 0;
> > >> +     struct regex_error_data regex_error_data;
> > >>
> > >>       if (!data->nspec) {
> > >>               errno = ENOENT;
> > >> @@ -677,9 +644,6 @@ static struct spec *lookup_common(struct selabel_handle *rec,
> > >>       file_stem = find_stem_from_file(data, &buf);
> > >>       mode &= S_IFMT;
> > >>
> > >> -     if (partial)
> > >> -             pcre_options |= PCRE_PARTIAL_SOFT;
> > >> -
> > >>       /*
> > >>        * Check for matching specifications in reverse order, so that
> > >>        * the last matching specification is used.
> > >> @@ -692,25 +656,19 @@ static struct spec *lookup_common(struct selabel_handle *rec,
> > >>                * a regex check        */
> > >>               if ((spec->stem_id == -1 || spec->stem_id == file_stem) &&
> > >>                   (!mode || !spec->mode || mode == spec->mode)) {
> > >> -                     if (compile_regex(data, spec, NULL) < 0)
> > >> +                     if (compile_regex(data, spec, &regex_error_data) < 0)
> > >>                               goto finish;
> > >>                       if (spec->stem_id == -1)
> > >> -                             rc = pcre_exec(spec->regex,
> > >> -                                                 get_pcre_extra(spec),
> > >> -                                                 key, strlen(key), 0,
> > >> -                                                 pcre_options, NULL, 0);
> > >> +                             rc = regex_match(spec->regex, key, partial);
> > >>                       else
> > >> -                             rc = pcre_exec(spec->regex,
> > >> -                                                 get_pcre_extra(spec),
> > >> -                                                 buf, strlen(buf), 0,
> > >> -                                                 pcre_options, NULL, 0);
> > >> -                     if (rc == 0) {
> > >> +                             rc = regex_match(spec->regex, buf, partial);
> > >> +                     if (rc == REGEX_MATCH) {
> > >>                               spec->matches++;
> > >>                               break;
> > >> -                     } else if (partial && rc == PCRE_ERROR_PARTIAL)
> > >> +                     } else if (partial && rc == REGEX_MATCH_PARTIAL)
> > >>                               break;
> > >>
> > >> -                     if (rc == PCRE_ERROR_NOMATCH)
> > >> +                     if (rc == REGEX_NO_MATCH)
> > >>                               continue;
> > >>
> > >>                       errno = ENOENT;
> > >> @@ -850,16 +808,9 @@ static enum selabel_cmp_result cmp(struct selabel_handle *h1,
> > >>               }
> > >>
> > >>               if (spec1->regcomp && spec2->regcomp) {
> > >> -                     size_t len1, len2;
> > >> -                     int rc;
> > >> -
> > >> -                     rc = pcre_fullinfo(spec1->regex, NULL, PCRE_INFO_SIZE, &len1);
> > >> -                     assert(rc == 0);
> > >> -                     rc = pcre_fullinfo(spec2->regex, NULL, PCRE_INFO_SIZE, &len2);
> > >> -                     assert(rc == 0);
> > >> -                     if (len1 != len2 ||
> > >> -                         memcmp(spec1->regex, spec2->regex, len1))
> > >> +                     if (regex_cmp(spec1->regex, spec2->regex) == SELABEL_INCOMPARABLE){
> > >>                               return incomp(spec1, spec2, "regex", i, j);
> > >> +                     }
> > >>               } else {
> > >>                       if (strcmp(spec1->regex_str, spec2->regex_str))
> > >>                               return incomp(spec1, spec2, "regex_str", i, j);
> > >> diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
> > >> index 6d1e890..a2e30e5 100644
> > >> --- a/libselinux/src/label_file.h
> > >> +++ b/libselinux/src/label_file.h
> > >> @@ -6,6 +6,14 @@
> > >>
> > >>  #include <sys/stat.h>
> > >>
> > >> +/*
> > >> + * regex.h/c were introduced to hold all dependencies on the regular
> > >> + * _expression_ back-end when we started supporting PCRE2. regex.h defines a
> > >> + * minimal interface required by libselinux, so that the remaining code
> > >> + * can be agnostic about the underlying implementation.
> > >> + */
> > >> +#include "regex.h"
> > >> +
> > >>  #include "callbacks.h"
> > >>  #include "label_internal.h"
> > >>
> > >> @@ -19,21 +27,12 @@
> > >>
> > >>  #define SELINUX_COMPILED_FCONTEXT_MAX_VERS   SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
> > >>
> > >> -/* Prior to version 8.20, libpcre did not have pcre_free_study() */
> > >> -#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
> > >> -#define pcre_free_study  pcre_free
> > >> -#endif
> > >> -
> > >>  /* 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_ */
> > >> -     union {
> > >> -             pcre_extra *sd; /* pointer to extra compiled stuff */
> > >> -             pcre_extra lsd; /* used to hold the mmap'd version */
> > >> -     };
> > >> +     struct regex_data * regex; /* backend dependent regular _expression_ data */
> > >>       mode_t mode;            /* mode format value */
> > >>       int matches;            /* number of matching pathnames */
> > >>       int stem_id;            /* indicates which stem-compression item */
> > >> @@ -78,17 +77,6 @@ struct saved_data {
> > >>       struct mmap_area *mmap_areas;
> > >>  };
> > >>
> > >> -static inline pcre_extra *get_pcre_extra(struct spec *spec)
> > >> -{
> > >> -     if (spec->from_mmap) {
> > >> -             if (spec->lsd.study_data)
> > >> -                     return &spec->lsd;
> > >> -             else
> > >> -                     return NULL;
> > >> -     } else
> > >> -             return spec->sd;
> > >> -}
> > >> -
> > >>  static inline mode_t string_to_mode(char *mode)
> > >>  {
> > >>       size_t len;
> > >> @@ -331,13 +319,12 @@ static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes)
> > >>  }
> > >>
> > >>  static inline int compile_regex(struct saved_data *data, struct spec *spec,
> > >> -                                         const char **errbuf)
> > >> +                                         struct regex_error_data * error_data)
> > >>  {
> > >> -     const char *tmperrbuf;
> > >>       char *reg_buf, *anchored_regex, *cp;
> > >>       struct stem *stem_arr = data->stem_arr;
> > >>       size_t len;
> > >> -     int erroff;
> > >> +     int rc;
> > >>
> > >>       if (spec->regcomp)
> > >>               return 0; /* already done */
> > >> @@ -361,19 +348,9 @@ static inline int compile_regex(struct saved_data *data, struct spec *spec,
> > >>       *cp = '\0';
> > >>
> > >>       /* Compile the regular _expression_. */
> > >> -     spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf,
> > >> -                                                 &erroff, NULL);
> > >> +     rc = regex_prepare_data(&spec->regex, anchored_regex, error_data);
> > >>       free(anchored_regex);
> > >> -     if (!spec->regex) {
> > >> -             if (errbuf)
> > >> -                     *errbuf = tmperrbuf;
> > >> -             return -1;
> > >> -     }
> > >> -
> > >> -     spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
> > >> -     if (!spec->sd && tmperrbuf) {
> > >> -             if (errbuf)
> > >> -                     *errbuf = tmperrbuf;
> > >> +     if (rc < 0) {
> > >>               return -1;
> > >>       }
> > >>
> > >> @@ -394,7 +371,8 @@ static inline int process_line(struct selabel_handle *rec,
> > >>       struct saved_data *data = "" saved_data *)rec->data;
> > >>       struct spec *spec_arr;
> > >>       unsigned int nspec = data->nspec;
> > >> -     const char *errbuf = NULL;
> > >> +     char const *errbuf;
> > >> +     struct regex_error_data error_data;
> > >>
> > >>       items = read_spec_entries(line_buf, &errbuf, 3, &regex, &type, &context);
> > >>       if (items < 0) {
> > >> @@ -454,7 +432,7 @@ static inline int process_line(struct selabel_handle *rec,
> > >>       data->nspec++;
> > >>
> > >>       if (rec->validating &&
> > >> -                         compile_regex(data, &spec_arr[nspec], &errbuf)) {
> > >> +                         compile_regex(data, &spec_arr[nspec], &error_data)) {
> > >>               COMPAT_LOG(SELINUX_ERROR,
> > >>                          "%s:  line %u has invalid regex %s:  %s\n",
> > >>                          path, lineno, regex,
> > >> diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
> > >> new file mode 100644
> > >> index 0000000..6b92b04
> > >> --- /dev/null
> > >> +++ b/libselinux/src/regex.c
> > >> @@ -0,0 +1,405 @@
> > >> +#include <assert.h>
> > >> +#include <stdint.h>
> > >> +#include <stdio.h>
> > >> +#include <string.h>
> > >> +
> > >> +#include "regex.h"
> > >> +#include "label_file.h"
> > >> +
> > >> +int regex_prepare_data(struct regex_data ** regex, char const * pattern_string,
> > >> +                     struct regex_error_data * errordata) {
> > >> +     memset(errordata, 0, sizeof(struct regex_error_data));
> > >> +     *regex = regex_data_create();
> > >> +     if (!(*regex))
> > >> +             return -1;
> > >> +#ifdef USE_PCRE2
> > >> +     (*regex)->regex = pcre2_compile((PCRE2_SPTR)pattern_string,
> > >> +                     PCRE2_ZERO_TERMINATED,
> > >> +                     PCRE2_DOTALL,
> > >> +                     &errordata->error_code,
> > >> +                     &errordata->error_offset, NULL);
> > >> +#else
> > >> +     (*regex)->regex = pcre_compile(pattern_string, PCRE_DOTALL,
> > >> +                                     &errordata->error_buffer,
> > >> +                                     &errordata->error_offset, NULL);
> > >> +#endif
> > >> +     if (!(*regex)->regex) {
> > >> +             goto err;
> > >> +     }
> > >> +
> > >> +#ifdef USE_PCRE2
> > >> +     (*regex)->match_data =
> > >> +             pcre2_match_data_create_from_pattern((*regex)->regex, NULL);
> > >> +     if (!(*regex)->match_data) {
> > >> +             goto err;
> > >> +     }
> > >> +#else
> > >> +     (*regex)->sd = pcre_study((*regex)->regex, 0, &errordata->error_buffer);
> > >> +     if (!(*regex)->sd && errordata->error_buffer) {
> > >> +             goto err;
> > >> +     }
> > >> +     (*regex)->extra_owned = !!(*regex)->sd;
> > >> +#endif
> > >> +     return 0;
> > >> +
> > >> +err: regex_data_free(*regex);
> > >> +     *regex = NULL;
> > >> +     return -1;
> > >> +}
> > >> +
> > >> +char const * regex_version(void) {
> > >> +#ifdef USE_PCRE2
> > >> +     static int initialized = 0;
> > >> +     static char * version_string = NULL;
> > >> +     size_t version_string_len;
> > >> +     if (!initialized) {
> > >> +             version_string_len = pcre2_config(PCRE2_CONFIG_VERSION, NULL);
> > >> +             version_string = (char*) malloc(version_string_len);
> > >> +             if (!version_string) {
> > >> +                     return NULL;
> > >> +             }
> > >> +             pcre2_config(PCRE2_CONFIG_VERSION, version_string);
> > >> +             initialized = 1;
> > >> +     }
> > >> +     return version_string;
> > >> +#else
> > >> +     return pcre_version();
> > >> +#endif
> > >> +}
> > >> +
> > >> +int regex_load_mmap(struct mmap_area * mmap_area, struct regex_data ** regex) {
> > >> +     int rc;
> > >> +     size_t entry_len;
> > >> +#ifndef USE_PCRE2
> > >> +     size_t info_len;
> > >> +#endif
> > >> +
> > >> +     rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
> > >> +#ifdef USE_PCRE2
> > >> +     if (rc < 0)
> > >> +             return -1;
> > >> +
> > >> +#ifndef NO_PERSISTENTLY_STORED_PATTERNS
> > >> +     /* this should yield exactly one because we store one pattern at a time
> > >> +      */
> > >> +     rc = pcre2_serialize_get_number_of_codes(mmap_area->next_addr);
> > >> +     if (rc != 1)
> > >> +             return -1;
> > >> +
> > >> +     *regex = regex_data_create();
> > >> +     if (!*regex)
> > >> +             return -1;
> > >> +
> > >> +     rc = pcre2_serialize_decode(&(*regex)->regex, 1,
> > >> +                     (PCRE2_SPTR)mmap_area->next_addr, NULL);
> > >> +     if (rc != 1)
> > >> +             goto err;
> > >> +
> > >> +     (*regex)->match_data =
> > >> +             pcre2_match_data_create_from_pattern((*regex)->regex, NULL);
> > >> +     if (!(*regex)->match_data)
> > >> +             goto err;
> > >> +
> > >> +#endif /* NO_PERSISTENTLY_STORED_PATTERNS */
> > >> +     /* and skip the decoded bit */
> > >> +     rc = next_entry(NULL, mmap_area, entry_len);
> > >> +     if (rc < 0)
> > >> +             goto err;
> > >> +
> > >> +     return 0;
> > >> +#else
> > >> +     if (rc < 0 || !entry_len) {
> > >> +             return -1;
> > >> +     }
> > >> +     *regex = regex_data_create();
> > >> +     if (!(*regex))
> > >> +             return -1;
> > >> +
> > >> +     (*regex)->extra_owned = 0;
> > >> +     (*regex)->regex = (pcre *) mmap_area->next_addr;
> > >> +     rc = next_entry(NULL, mmap_area, entry_len);
> > >> +     if (rc < 0)
> > >> +             goto err;
> > >> +
> > >> +     /* Check that regex lengths match. pcre_fullinfo()
> > >> +      * also validates its magic number. */
> > >> +     rc = pcre_fullinfo((*regex)->regex, NULL, PCRE_INFO_SIZE, &info_len);
> > >> +     if (rc < 0 || info_len != entry_len) {
> > >> +             goto err;
> > >> +     }
> > >> +
> > >> +     rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
> > >> +     if (rc < 0 || !entry_len) {
> > >> +             goto err;
> > >> +     }
> > >> +
> > >> +     if (entry_len) {
> > >> +             (*regex)->lsd.study_data = (void *) mmap_area->next_addr;
> > >> +             (*regex)->lsd.flags |= PCRE_EXTRA_STUDY_DATA;
> > >> +             rc = next_entry(NULL, mmap_area, entry_len);
> > >> +             if (rc < 0)
> > >> +                     goto err;
> > >> +
> > >> +             /* Check that study data lengths match. */
> > >> +             rc = pcre_fullinfo((*regex)->regex, &(*regex)->lsd,
> > >> +                                PCRE_INFO_STUDYSIZE, &info_len);
> > >> +             if (rc < 0 || info_len != entry_len)
> > >> +                     goto err;
> > >> +     }
> > >> +     return 0;
> > >> +#endif
> > >> +err:
> > >> +     regex_data_free(*regex);
> > >> +     *regex = NULL;
> > >> +     return -1;
> > >> +}
> > >> +
> > >> +int regex_writef(struct regex_data * regex, FILE * fp) {
> > >> +#if !defined USE_PCRE2 || !defined NO_PERSISTENTLY_STORED_PATTERNS
> > >> +     int rc;
> > >> +#endif
> > >> +     size_t len;
> > >> +#ifdef USE_PCRE2
> > >> +     PCRE2_SIZE to_write;
> > >> +#ifndef NO_PERSISTENTLY_STORED_PATTERNS
> > >> +     PCRE2_UCHAR * bytes;
> > >> +
> > >> +     /* encode the patter for serialization */
> > >> +     rc = pcre2_serialize_encode((const pcre2_code **)&regex->regex, 1,
> > >> +                                 &bytes, &to_write, NULL);
> > >> +     if (rc != 1)
> > >> +             return -1;
> > >> +
> > >> +#else
> > >> +     (void)regex; // silence unused parameter warning
> > >> +     to_write = 0;
> > >> +#endif
> > >> +     /* write serialized pattern's size */
> > >> +     len = fwrite(&to_write, sizeof(uint32_t), 1, fp);
> > >> +     if (len != 1) {
> > >> +#ifndef NO_PERSISTENTLY_STORED_PATTERNS
> > >> +             pcre2_serialize_free(bytes);
> > >> +#endif
> > >> +             return -1;
> > >> +     }
> > >> +
> > >> +#ifndef NO_PERSISTENTLY_STORED_PATTERNS
> > >> +     /* write serialized pattern */
> > >> +     len = fwrite(bytes, 1, to_write, fp);
> > >> +     if (len != to_write) {
> > >> +             pcre2_serialize_free(bytes);
> > >> +             return -1;
> > >> +     }
> > >> +     pcre2_serialize_free(bytes);
> > >> +#endif
> > >> +#else
> > >> +     uint32_t to_write;
> > >> +     size_t size;
> > >> +     pcre_extra * sd = regex->extra_owned ? regex->sd :
> > >> +                     (regex->lsd.study_data ? &regex->lsd : NULL);
> > >> +
> > >> +     /* determine the size of the pcre data in bytes */
> > >> +     rc = pcre_fullinfo(regex->regex, 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, fp);
> > >> +     if (len != 1)
> > >> +             return -1;
> > >> +
> > >> +     /* write the actual pcre data as a char array */
> > >> +     len = fwrite(regex->regex, 1, to_write, fp);
> > >> +     if (len != to_write)
> > >> +             return -1;
> > >> +
> > >> +     if (sd) {
> > >> +             /* determine the size of the pcre study info */
> > >> +             rc = pcre_fullinfo(regex->regex, sd, PCRE_INFO_STUDYSIZE,
> > >> +                             &size);
> > >> +             if (rc < 0)
> > >> +                     return -1;
> > >> +     } else
> > >> +             size = 0;
> > >> +
> > >> +     /* write the number of bytes in the pcre study data */
> > >> +     to_write = size;
> > >> +     len = fwrite(&to_write, sizeof(uint32_t), 1, fp);
> > >> +     if (len != 1)
> > >> +             return -1;
> > >> +
> > >> +     if (sd) {
> > >> +             /* write the actual pcre study data as a char array */
> > >> +             len = fwrite(sd->study_data, 1, to_write, fp);
> > >> +             if (len != to_write)
> > >> +                     return -1;
> > >> +     }
> > >> +#endif
> > >> +     return 0;
> > >> +}
> > >> +
> > >> +struct regex_data * regex_data_create(void) {
> > >> +     struct regex_data * dummy = (struct regex_data*) malloc(
> > >> +                     sizeof(struct regex_data));
> > >> +     if (dummy) {
> > >> +             memset(dummy, 0, sizeof(struct regex_data));
> > >> +     }
> > >> +     return dummy;
> > >> +}
> > >> +
> > >> +void regex_data_free(struct regex_data * regex) {
> > >> +     if (regex) {
> > >> +#ifdef USE_PCRE2
> > >> +             if (regex->regex) {
> > >> +                     pcre2_code_free(regex->regex);
> > >> +             }
> > >> +             if (regex->match_data) {
> > >> +                     pcre2_match_data_free(regex->match_data);
> > >> +             }
> > >> +#else
> > >> +             if (regex->regex)
> > >> +                     pcre_free(regex->regex);
> > >> +             if (regex->extra_owned && regex->sd) {
> > >> +                     pcre_free_study(regex->sd);
> > >> +             }
> > >> +#endif
> > >> +             free(regex);
> > >> +     }
> > >> +}
> > >> +
> > >> +int regex_match(struct regex_data * regex, char const * subject, int partial) {
> > >> +     int rc;
> > >> +#ifdef USE_PCRE2
> > >> +     rc = pcre2_match(regex->regex,
> > >> +                     (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0,
> > >> +                     partial ? PCRE2_PARTIAL_SOFT : 0, regex->match_data,
> > >> +                     NULL);
> > >> +     if (rc > 0)
> > >> +     return REGEX_MATCH;
> > >> +     switch (rc) {
> > >> +             case PCRE2_ERROR_PARTIAL:
> > >> +                     return REGEX_MATCH_PARTIAL;
> > >> +             case PCRE2_ERROR_NOMATCH:
> > >> +                     return REGEX_NO_MATCH;
> > >> +             default:
> > >> +                     return REGEX_ERROR;
> > >> +     }
> > >> +#else
> > >> +     rc = pcre_exec(regex->regex,
> > >> +                     regex->extra_owned ? regex->sd : &regex->lsd, subject,
> > >> +                     strlen(subject), 0, partial ? PCRE_PARTIAL_SOFT : 0,
> > >> +                     NULL,
> > >> +                     0);
> > >> +     switch (rc) {
> > >> +             case 0:
> > >> +                     return REGEX_MATCH;
> > >> +             case PCRE_ERROR_PARTIAL:
> > >> +                     return REGEX_MATCH_PARTIAL;
> > >> +             case PCRE_ERROR_NOMATCH:
> > >> +                     return REGEX_NO_MATCH;
> > >> +             default:
> > >> +                     return REGEX_ERROR;
> > >> +     }
> > >> +#endif
> > >> +}
> > >> +
> > >> +/* TODO Replace this compare function with something that actually compares the
> > >> + * regular expressions.
> > >> + * This compare function basically just compares the binary representations of
> > >> + * the automatons, and because this representation contains pointers and
> > >> + * metadata, it can only return a match if regex1 == regex2.
> > >> + * Preferably, this function would be replaced with an algorithm that computes
> > >> + * the equivalence of the automatons systematically.
> > >> + */
> > >> +int regex_cmp(struct regex_data * regex1, struct regex_data * regex2) {
> > >> +     int rc;
> > >> +     size_t len1, len2;
> > >> +#ifdef USE_PCRE2
> > >> +     rc = pcre2_pattern_info(regex1->regex, PCRE2_INFO_SIZE, &len1);
> > >> +     assert(rc == 0);
> > >> +     rc = pcre2_pattern_info(regex2->regex, PCRE2_INFO_SIZE, &len2);
> > >> +     assert(rc == 0);
> > >> +     if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1))
> > >> +             return SELABEL_INCOMPARABLE;
> > >> +#else
> > >> +     rc = pcre_fullinfo(regex1->regex, NULL, PCRE_INFO_SIZE, &len1);
> > >> +     assert(rc == 0);
> > >> +     rc = pcre_fullinfo(regex2->regex, NULL, PCRE_INFO_SIZE, &len2);
> > >> +     assert(rc == 0);
> > >> +     if (len1 != len2 || memcmp(regex1->regex, regex2->regex, len1))
> > >> +             return SELABEL_INCOMPARABLE;
> > >> +#endif
> > >> +     return SELABEL_EQUAL;
> > >> +}
> > >> +
> > >> +void regex_format_error(struct regex_error_data const * error_data,
> > >> +                     char * buffer, size_t buf_size) {
> > >> +     unsigned the_end_length = buf_size > 4 ? 4 : buf_size;
> > >> +     char * ptr = &buffer[buf_size - the_end_length];
> > >> +     int rc = 0;
> > >> +     size_t pos = 0;
> > >> +     if (!buffer || !buf_size)
> > >> +             return;
> > >> +     rc = snprintf(buffer, buf_size, "REGEX back-end error: ");
> > >> +     if (rc < 0)
> > >> +             /* If snprintf fails it constitutes a logical error that needs
> > >> +              * fixing.
> > >> +              */
> > >> +             abort();
> > >> +
> > >> +     pos += rc;
> > >> +     if (pos >= buf_size)
> > >> +             goto truncated;
> > >> +
> > >> +     if (error_data->error_offset > 0) {
> > >> +#ifdef USE_PCRE2
> > >> +             rc = snprintf(buffer + pos, buf_size - pos, "At offset %zu: ",
> > >> +                             error_data->error_offset);
> > >> +#else
> > >> +             rc = snprintf(buffer + pos, buf_size - pos, "At offset %d: ",
> > >> +                             error_data->error_offset);
> > >> +#endif
> > >> +             if (rc < 0)
> > >> +                     abort();
> > >> +
> > >> +     }
> > >> +     pos += rc;
> > >> +     if (pos >= buf_size)
> > >> +             goto truncated;
> > >> +
> > >> +#ifdef USE_PCRE2
> > >> +     rc = pcre2_get_error_message(error_data->error_code,
> > >> +                     (PCRE2_UCHAR*)(buffer + pos),
> > >> +                     buf_size - pos);
> > >> +     if (rc == PCRE2_ERROR_NOMEMORY)
> > >> +             goto truncated;
> > >> +#else
> > >> +     rc = snprintf(buffer + pos, buf_size - pos, "%s",
> > >> +                     error_data->error_buffer);
> > >> +     if (rc < 0)
> > >> +             abort();
> > >> +
> > >> +     if ((size_t)rc < strlen(error_data->error_buffer))
> > >> +             goto truncated;
> > >> +#endif
> > >> +
> > >> +     return;
> > >> +
> > >> +truncated:
> > >> +     /* replace end of string with "..." to indicate that it was truncated */
> > >> +     switch (the_end_length) {
> > >> +             /* no break statements, fall-through is intended */
> > >> +             case 4:
> > >> +                     *ptr++ = '.';
> > >> +             case 3:
> > >> +                     *ptr++ = '.';
> > >> +             case 2:
> > >> +                     *ptr++ = '.';
> > >> +             case 1:
> > >> +                     *ptr++ = '\0';
> > >> +             default:
> > >> +                     break;
> > >> +     }
> > >> +     return;
> > >> +}
> > >> diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
> > >> new file mode 100644
> > >> index 0000000..bdc10c0
> > >> --- /dev/null
> > >> +++ b/libselinux/src/regex.h
> > >> @@ -0,0 +1,168 @@
> > >> +#ifndef SRC_REGEX_H_
> > >> +#define SRC_REGEX_H_
> > >> +
> > >> +#include <stdio.h>
> > >> +
> > >> +#ifdef USE_PCRE2
> > >> +#include <pcre2.h>
> > >> +#else
> > >> +#include <pcre.h>
> > >> +#endif
> > >> +
> > >> +enum {
> > >> +     REGEX_MATCH,
> > >> +     REGEX_MATCH_PARTIAL,
> > >> +     REGEX_NO_MATCH,
> > >> +     REGEX_ERROR = -1,
> > >> +};
> > >> +
> > >> +#ifdef USE_PCRE2
> > >> +struct regex_data {
> > >> +     pcre2_code * regex; /* compiled regular _expression_ */
> > >> +     pcre2_match_data * match_data; /* match data block required for the compiled
> > >> +      pattern in regex2 */
> > >> +};
> > >> +
> > >> +struct regex_error_data {
> > >> +     int error_code;
> > >> +     PCRE2_SIZE error_offset;
> > >> +};
> > >> +
> > >> +/* ^^^^^^ USE_PCRE2  ^^^^^^ */
> > >> +#else
> > >> +/* vvvvvv USE_PCRE vvvvvv */
> > >> +
> > >> +/* Prior to version 8.20, libpcre did not have pcre_free_study() */
> > >> +#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
> > >> +#define pcre_free_study  pcre_free
> > >> +#endif
> > >> +
> > >> +struct regex_data {
> > >> +     pcre *regex; /* compiled regular _expression_ */
> > >> +     int extra_owned; /* non zero if pcre_extra is owned by this structure
> > >> +                       * and thus must be freed on destruction.
> > >> +                       */
> > >> +     union {
> > >> +             pcre_extra *sd; /* pointer to extra compiled stuff */
> > >> +             pcre_extra lsd; /* used to hold the mmap'd version */
> > >> +     };
> > >> +};
> > >> +
> > >> +struct regex_error_data {
> > >> +     char const * error_buffer;
> > >> +     int error_offset;
> > >> +};
> > >> +
> > >> +#endif /* USE_PCRE2 */
> > >> +
> > >> +struct mmap_area;
> > >> +
> > >> +/**
> > >> + * regex_verison returns the version string of the underlying regular
> > >> + * regular expressions library. In the case of PCRE it just returns the
> > >> + * result of pcre_version(). In the case of PCRE2, the very first time this
> > >> + * function is called it allocates a buffer large enough to hold the version
> > >> + * string and reads the PCRE2_CONFIG_VERSION option to fill the buffer.
> > >> + * The allocated buffer will linger in memory until the calling process is being
> > >> + * reaped.
> > >> + *
> > >> + * It may return NULL on error.
> > >> + */
> > >> +char const * regex_version(void);
> > >> +/**
> > >> + * This constructor function allocates a buffer for a regex_data structure.
> > >> + * The buffer is being initialized with zeroes.
> > >> + */
> > >> +struct regex_data * regex_data_create(void);
> > >> +/**
> > >> + * This complementary destructor function frees the a given regex_data buffer.
> > >> + * It also frees any non NULL member pointers with the appropriate pcreX_X_free
> > >> + * function. For PCRE this function respects the extra_owned field and frees
> > >> + * the pcre_extra data conditionally. Calling this function on a NULL pointer is
> > >> + * save.
> > >> + */
> > >> +void regex_data_free(struct regex_data * regex);
> > >> +/**
> > >> + * This function compiles the regular _expression_. Additionally, it prepares
> > >> + * data structures required by the different underlying engines. For PCRE
> > >> + * it calls pcre_study to generate optional data required for optimized
> > >> + * execution of the compiled pattern. In the case of PCRE2, it allocates
> > >> + * a pcre2_match_data structure of appropriate size to hold all possible
> > >> + * matches created by the pattern.
> > >> + *
> > >> + * @arg regex If successful, the structure returned through *regex was allocated
> > >> + *            with regex_data_create and must be freed with regex_data_free.
> > >> + * @arg pattern_string The pattern string that is to be compiled.
> > >> + * @arg errordata A pointer to a regex_error_data structure must be passed
> > >> + *                to this function. This structure depends on the underlying
> > >> + *                implementation. It can be passed to regex_format_error
> > >> + *                to generate a human readable error message.
> > >> + * @retval 0 on success
> > >> + * @retval -1 on error
> > >> + */
> > >> +int regex_prepare_data(struct regex_data ** regex, char const * pattern_string,
> > >> +                     struct regex_error_data * errordata);
> > >> +/**
> > >> + * This function loads a serialized precompiled pattern from a contiguous
> > >> + * data region given by map_area.
> > >> + *
> > >> + * @arg map_area Description of the memory region holding a serialized
> > >> + *               representation of the precompiled pattern.
> > >> + * @arg regex If successful, the structure returned through *regex was allocated
> > >> + *            with regex_data_create and must be freed with regex_data_free.
> > >> + *
> > >> + * @retval 0 on success
> > >> + * @retval -1 on error
> > >> + */
> > >> +int regex_load_mmap(struct mmap_area * map_area, struct regex_data ** regex);
> > >> +/**
> > >> + * This function stores a precompiled regular _expression_ to a file.
> > >> + * In the case of PCRE, it just dumps the binary representation of the
> > >> + * precomplied pattern into a file. In the case of PCRE2, it uses the
> > >> + * serialization function provided by the library.
> > >> + *
> > >> + * @arg regex The precomplied regular _expression_ data.
> > >> + * @arg fp A file stream specifying the output file.
> > >> + */
> > >> +int regex_writef(struct regex_data * regex, FILE * fp);
> > >> +/**
> > >> + * This function applies a precompiled pattern to a subject string and
> > >> + * returns whether or not a match was found.
> > >> + *
> > >> + * @arg regex The precompiled pattern.
> > >> + * @arg subject The subject string.
> > >> + * @arg partial Boolean indicating if partial matches are wanted. A nonzero
> > >> + *              value is equivalent to specifying PCRE[2]_PARTIAL_SOFT as
> > >> + *              option to pcre_exec of pcre2_match.
> > >> + * @retval REGEX_MATCH if a match was found
> > >> + * @retval REGEX_MATCH_PARTIAL if a partial match was found
> > >> + * @retval REGEX_NO_MATCH if no match was found
> > >> + * @retval REGEX_ERROR if an error was encountered during the execution of the
> > >> + *                     regular _expression_
> > >> + */
> > >> +int regex_match(struct regex_data * regex, char const * subject, int partial);
> > >> +/**
> > >> + * This function compares two compiled regular expressions (regex1 and regex2).
> > >> + * It compares the binary representations of the compiled patterns. It is a very
> > >> + * crude approximation because the binary representation holds data like
> > >> + * reference counters, that has nothing to do with the actual state machine.
> > >> + *
> > >> + * @retval SELABEL_EQUAL if the pattern's binary representations are exactly
> > >> + *                       the same
> > >> + * @retval SELABEL_INCOMPARABLE otherwise
> > >> + */
> > >> +int regex_cmp(struct regex_data * regex1, struct regex_data * regex2);
> > >> +/**
> > >> + * This function takes the error data returned by regex_prepare_data and turns
> > >> + * it in to a human readable error message.
> > >> + * If the buffer given to hold the error message is to small it truncates the
> > >> + * message and indicates the truncation with an ellipsis ("...") at the end of
> > >> + * the buffer.
> > >> + *
> > >> + * @arg error_data Error data as returned by regex_prepare_data.
> > >> + * @arg buffer String buffer to hold the formated error string.
> > >> + * @arg buf_size Total size of the given bufer in bytes.
> > >> + */
> > >> +void regex_format_error(struct regex_error_data const * error_data,
> > >> +                     char * buffer, size_t buf_size);
> > >> +#endif  /* SRC_REGEX_H_ */
> > >> diff --git a/libselinux/utils/Makefile b/libselinux/utils/Makefile
> > >> index 8497cb4..1e7a048 100644
> > >> --- a/libselinux/utils/Makefile
> > >> +++ b/libselinux/utils/Makefile
> > >> @@ -24,12 +24,12 @@ CFLAGS ?= -O -Wall -W -Wundef -Wformat-y2k -Wformat-security -Winit-self -Wmissi
> > >>            -fasynchronous-unwind-tables -fdiagnostics-show-option -funit-at-a-time \
> > >>            -fipa-pure-const -Wno-suggest-attribute=pure -Wno-suggest-attribute=const \
> > >>            -Werror -Wno-aggregate-return -Wno-redundant-decls
> > >> -override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE $(EMFLAGS)
> > >> +override CFLAGS += -I../include -I$(INCLUDEDIR) -D_GNU_SOURCE $(EMFLAGS) $(PCRE_CFLAGS)
> > >>  LDLIBS += -L../src -lselinux -L$(LIBDIR)
> > >>
> > >>  TARGETS=$(patsubst %.c,%,$(wildcard *.c))
> > >>
> > >> -sefcontext_compile: LDLIBS += -lpcre ../src/libselinux.a -lsepol
> > >> +sefcontext_compile: LDLIBS += $(PCRE_LDFLAGS) ../src/libselinux.a -lsepol
> > >>
> > >>  selinux_restorecon: LDLIBS += -lsepol
> > >>
> > >> diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
> > >> index fd6fb78..8ff73f4 100644
> > >> --- a/libselinux/utils/sefcontext_compile.c
> > >> +++ b/libselinux/utils/sefcontext_compile.c
> > >> @@ -1,6 +1,5 @@
> > >>  #include <ctype.h>
> > >>  #include <errno.h>
> > >> -#include <pcre.h>
> > >>  #include <stdint.h>
> > >>  #include <stdio.h>
> > >>  #include <string.h>
> > >> @@ -13,6 +12,7 @@
> > >>  #include <sepol/sepol.h>
> > >>
> > >>  #include "../src/label_file.h"
> > >> +#include "../src/regex.h"
> > >>
> > >>  const char *policy_file;
> > >>  static int ctx_err;
> > >> @@ -119,12 +119,14 @@ static int write_binary_file(struct saved_data *data, int fd)
> > >>       if (len != 1)
> > >>               goto err;
> > >>
> > >> -     /* write the pcre version */
> > >> -     section_len = strlen(pcre_version());
> > >> +     /* write version of the regex back-end */
> > >> +     if (!regex_version())
> > >> +             goto err;
> > >> +     section_len = strlen(regex_version());
> > >>       len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> > >>       if (len != 1)
> > >>               goto err;
> > >> -     len = fwrite(pcre_version(), sizeof(char), section_len, bin_file);
> > >> +     len = fwrite(regex_version(), sizeof(char), section_len, bin_file);
> > >>       if (len != section_len)
> > >>               goto err;
> > >>
> > >> @@ -162,10 +164,8 @@ static int write_binary_file(struct saved_data *data, int fd)
> > >>               mode_t mode = specs[i].mode;
> > >>               size_t prefix_len = specs[i].prefix_len;
> > >>               int32_t stem_id = specs[i].stem_id;
> > >> -             pcre *re = specs[i].regex;
> > >> -             pcre_extra *sd = get_pcre_extra(&specs[i]);
> > >> +             struct regex_data *re = specs[i].regex;
> > >>               uint32_t to_write;
> > >> -             size_t size;
> > >>
> > >>               /* length of the context string (including nul) */
> > >>               to_write = strlen(context) + 1;
> > >> @@ -212,42 +212,10 @@ static int write_binary_file(struct saved_data *data, int fd)
> > >>               if (len != 1)
> > >>                       goto err;
> > >>
> > >> -             /* determine the size of the pcre data in bytes */
> > >> -             rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size);
> > >> +             /* Write regex related data */
> > >> +             rc = regex_writef(re, bin_file);
> > >>               if (rc < 0)
> > >>                       goto err;
> > >> -
> > >> -             /* 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)
> > >> -                     goto err;
> > >> -
> > >> -             /* write the actual pcre data as a char array */
> > >> -             len = fwrite(re, 1, to_write, bin_file);
> > >> -             if (len != to_write)
> > >> -                     goto err;
> > >> -
> > >> -             if (sd) {
> > >> -                     /* determine the size of the pcre study info */
> > >> -                     rc = pcre_fullinfo(re, sd, PCRE_INFO_STUDYSIZE, &size);
> > >> -                     if (rc < 0)
> > >> -                             goto err;
> > >> -             } else
> > >> -                     size = 0;
> > >> -
> > >> -             /* 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)
> > >> -                     goto err;
> > >> -
> > >> -             if (sd) {
> > >> -                     /* write the actual pcre study data as a char array */
> > >> -                     len = fwrite(sd->study_data, 1, to_write, bin_file);
> > >> -                     if (len != to_write)
> > >> -                             goto err;
> > >> -             }
> > >>       }
> > >>
> > >>       rc = 0;
> > >> @@ -270,8 +238,7 @@ static void free_specs(struct saved_data *data)
> > >>               free(specs[i].lr.ctx_trans);
> > >>               free(specs[i].regex_str);
> > >>               free(specs[i].type_str);
> > >> -             pcre_free(specs[i].regex);
> > >> -             pcre_free_study(specs[i].sd);
> > >> +             regex_data_free(specs[i].regex);
> > >>       }
> > >>       free(specs);
> > >>
> > >>
> > >
> > > _______________________________________________
> > > Selinux mailing list
> > > Selinux@xxxxxxxxxxxxx
> > > To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
> > > To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.
> >
> >
> >
> > --
> > Respectfully,
> >
> > William C Roberts
> > _______________________________________________
> > Selinux mailing list
> > Selinux@xxxxxxxxxxxxx
> > To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
> > To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux