All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] libselinux: Add architecture string to file_context.bin
@ 2016-09-28 10:28 Janis Danisevskis
  2016-09-28 10:28 ` [PATCH 2/3] libselinux: sefcontext_compile: Add "-i" flag Janis Danisevskis
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Janis Danisevskis @ 2016-09-28 10:28 UTC (permalink / raw)
  To: selinux, seandroid-list, sds, jwcart2, jdanis; +Cc: Janis Danisevskis

Serialized precompiled regular expressins are architecture
dependent when using PCRE2. This patch
- bumps the SELINUX_COMPILED_FCONTEXT version to 5 and
- adds a field to the output indicating the architecture
  compatibility.

libselinux can cope with an architecture mismatch by
ignoring the precompiled data in the input file and recompiling
the regular expressions at runtime. It can also load older
versions of file_contexts.bin if they where built with
sefcontext_compile using the exact same version of the
pcre1/2 as selinux.

Signed-off-by: Janis Danisevskis <jdanis@android.com>
---
 libselinux/src/label_file.c           | 43 +++++++++++++++++++++++++++++-
 libselinux/src/label_file.h           |  4 ++-
 libselinux/src/regex.c                | 50 ++++++++++++++++++++++++++++++++---
 libselinux/src/regex.h                | 15 ++++++++++-
 libselinux/utils/sefcontext_compile.c | 13 +++++++++
 5 files changed, 119 insertions(+), 6 deletions(-)

diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 7156825..13e05c1 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -126,6 +126,8 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 	uint32_t i, magic, version;
 	uint32_t entry_len, stem_map_len, regex_array_len;
 	const char *reg_version;
+	const char *reg_arch;
+	char reg_arch_matches = 0;
 
 	mmap_area = malloc(sizeof(*mmap_area));
 	if (!mmap_area) {
@@ -159,6 +161,10 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 	if (!reg_version)
 		return -1;
 
+	reg_arch = regex_arch_string();
+	if (!reg_arch)
+		return -1;
+
 	if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
 
 		len = strlen(reg_version);
@@ -188,7 +194,42 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 			return -1;
 		}
 		free(str_buf);
+
+		if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
+			len = strlen(reg_arch);
+
+			rc = next_entry(&entry_len, mmap_area,
+					sizeof(uint32_t));
+			if (rc < 0)
+				return -1;
+
+			/* Check arch string lengths */
+			if (len != entry_len) {
+				/*
+				 * Skip the entry and conclude that we have
+				 * a mismatch, which is not fatal.
+				 */
+				next_entry(NULL, mmap_area, entry_len);
+				goto end_arch_check;
+			}
+
+			/* Check if arch string mismatch */
+			str_buf = malloc(entry_len + 1);
+			if (!str_buf)
+				return -1;
+
+			rc = next_entry(str_buf, mmap_area, entry_len);
+			if (rc < 0) {
+				free(str_buf);
+				return -1;
+			}
+
+			str_buf[entry_len] = '\0';
+			reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
+			free(str_buf);
+		}
 	}
+end_arch_check:
 
 	/* allocate the stems_data array */
 	rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
@@ -349,7 +390,7 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 			spec->prefix_len = prefix_len;
 		}
 
-		rc = regex_load_mmap(mmap_area, &spec->regex);
+		rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches);
 		if (rc < 0)
 			goto out;
 
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index 88f4294..00c0a5c 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -24,8 +24,10 @@
 #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS	2
 #define SELINUX_COMPILED_FCONTEXT_MODE		3
 #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN	4
+#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH	5
 
-#define SELINUX_COMPILED_FCONTEXT_MAX_VERS	SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
+#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
+	SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
 
 /* A file security context specification. */
 struct spec {
diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
index 750088e..a3b427b 100644
--- a/libselinux/src/regex.c
+++ b/libselinux/src/regex.c
@@ -7,6 +7,44 @@
 #include "label_file.h"
 
 #ifdef USE_PCRE2
+#define REGEX_ARCH_SIZE_T PCRE2_SIZE
+#else
+#define REGEX_ARCH_SIZE_T size_t
+#endif
+
+#ifndef __BYTE_ORDER__
+#error __BYTE_ORDER__ not defined. Unable to determine endianness.
+#endif
+
+#ifdef USE_PCRE2
+char const *regex_arch_string(void)
+{
+	static char arch_string_buffer[32];
+	static char const *arch_string = "";
+	char const *endianness = NULL;
+	int rc;
+
+	if (arch_string[0] == '\0') {
+		if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+			endianness = "el";
+		else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+			endianness = "eb";
+
+		if (!endianness)
+			return NULL;
+
+		rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer),
+				"%zu-%zu-%s", sizeof(void *),
+				sizeof(REGEX_ARCH_SIZE_T),
+				endianness);
+		if (rc < 0)
+			abort();
+
+		arch_string = &arch_string_buffer[0];
+	}
+	return arch_string;
+}
+
 struct regex_data {
 	pcre2_code *regex; /* compiled regular expression */
 	/*
@@ -56,7 +94,8 @@ char const *regex_version(void)
 	return version_buf;
 }
 
-int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
+int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
+		    int do_load_precompregex)
 {
 	int rc;
 	uint32_t entry_len;
@@ -65,7 +104,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
 	if (rc < 0)
 		return -1;
 
-	if (entry_len) {
+	if (entry_len && do_load_precompregex) {
 		/*
 		 * this should yield exactly one because we store one pattern at
 		 * a time
@@ -195,6 +234,10 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
 }
 
 #else // !USE_PCRE2
+char const *regex_arch_string(void)
+{
+	return "N/A";
+}
 
 /* Prior to version 8.20, libpcre did not have pcre_free_study() */
 #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
@@ -247,7 +290,8 @@ char const *regex_version(void)
 	return pcre_version();
 }
 
-int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
+int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
+		    int unused __attribute__((unused)))
 {
 	int rc;
 	uint32_t entry_len;
diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
index 810b3c5..186c5ec 100644
--- a/libselinux/src/regex.h
+++ b/libselinux/src/regex.h
@@ -34,6 +34,16 @@ struct regex_error_data {
 struct mmap_area;
 
 /**
+ * regex_arch_string return a string that represents the pointer width, the
+ * width of what the backend considers a size type, and the endianness of the
+ * system that this library was build for. (e.g. for x86_64: "8-8-el").
+ * This is required when loading stored regular espressions. PCRE2 regular
+ * expressions are not portable across architectures that do not have a
+ * matching arch-string.
+ */
+char const *regex_arch_string(void) hidden;
+
+/**
  * 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
@@ -86,12 +96,15 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
  *               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.
+ * @arg do_load_precompregex If non-zero precompiled patterns get loaded from
+ *			     the mmap region (ignored by PCRE1 back-end).
  *
  * @retval 0 on success
  * @retval -1 on error
  */
 int regex_load_mmap(struct mmap_area *map_area,
-		    struct regex_data **regex) hidden;
+		    struct regex_data **regex,
+		    int do_load_precompregex) hidden;
 /**
  * This function stores a precompiled regular expression to a file.
  * In the case of PCRE, it just dumps the binary representation of the
diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
index 70853e7..d91db9a 100644
--- a/libselinux/utils/sefcontext_compile.c
+++ b/libselinux/utils/sefcontext_compile.c
@@ -103,6 +103,7 @@ static int write_binary_file(struct saved_data *data, int fd,
 	uint32_t i;
 	int rc;
 	const char *reg_version;
+	const char *reg_arch;
 
 	bin_file = fdopen(fd, "w");
 	if (!bin_file) {
@@ -133,6 +134,18 @@ static int write_binary_file(struct saved_data *data, int fd,
 	if (len != section_len)
 		goto err;
 
+	/* write regex arch string */
+	reg_arch = regex_arch_string();
+	if (!reg_arch)
+		goto err;
+	section_len = strlen(reg_arch);
+	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
+	if (len != 1)
+		goto err;
+	len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
+	if (len != section_len)
+		goto err;
+
 	/* write the number of stems coming */
 	section_len = data->num_stems;
 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] libselinux: sefcontext_compile: Add "-i" flag
  2016-09-28 10:28 [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
@ 2016-09-28 10:28 ` Janis Danisevskis
  2016-09-28 10:28 ` [PATCH 3/3] libselinux: sefcontext_compile invert semantics of "-r" flag Janis Danisevskis
  2016-09-28 10:31 ` [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
  2 siblings, 0 replies; 8+ messages in thread
From: Janis Danisevskis @ 2016-09-28 10:28 UTC (permalink / raw)
  To: selinux, seandroid-list, sds, jwcart2, jdanis; +Cc: Janis Danisevskis

Adds the "-i" flag, which prints the version and
architecture identifier of the regular expression back end.

Signed-off-by: Janis Danisevskis <jdanis@android.com>
---
 libselinux/utils/sefcontext_compile.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
index d91db9a..8c48d32 100644
--- a/libselinux/utils/sefcontext_compile.c
+++ b/libselinux/utils/sefcontext_compile.c
@@ -280,6 +280,11 @@ static void usage(const char *progname)
 	    "         (PCRE2 only. Compiled PCRE2 regular expressions are\n\t"
 	    "         not portable across architectures. When linked against\n\t"
 	    "         PCRE this flag is ignored)\n\t"
+	    "-i       Print regular expression info end exit. That is, back\n\t"
+	    "         end version and architecture identifier.\n\t"
+	    "         Arch identifier format (PCRE2):\n\t"
+	    "         <pointer width>-<size type width>-<endianness>, e.g.,\n\t"
+	    "         \"8-8-el\" for x86_64.\n\t"
 	    "fc_file  The text based file contexts file to be processed.\n",
 	    progname);
 		exit(EXIT_FAILURE);
@@ -301,7 +306,7 @@ int main(int argc, char *argv[])
 	if (argc < 2)
 		usage(argv[0]);
 
-	while ((opt = getopt(argc, argv, "o:p:r")) > 0) {
+	while ((opt = getopt(argc, argv, "io:p:r")) > 0) {
 		switch (opt) {
 		case 'o':
 			out_file = optarg;
@@ -312,6 +317,10 @@ int main(int argc, char *argv[])
 		case 'r':
 			do_write_precompregex = 1;
 			break;
+		case 'i':
+			printf("%s (%s)\n", regex_version(),
+					regex_arch_string());
+			return 0;
 		default:
 			usage(argv[0]);
 		}
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] libselinux: sefcontext_compile invert semantics of "-r" flag
  2016-09-28 10:28 [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
  2016-09-28 10:28 ` [PATCH 2/3] libselinux: sefcontext_compile: Add "-i" flag Janis Danisevskis
@ 2016-09-28 10:28 ` Janis Danisevskis
  2016-09-28 12:10   ` Stephen Smalley
  2016-09-28 10:31 ` [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
  2 siblings, 1 reply; 8+ messages in thread
From: Janis Danisevskis @ 2016-09-28 10:28 UTC (permalink / raw)
  To: selinux, seandroid-list, sds, jwcart2, jdanis; +Cc: Janis Danisevskis

The "-r" flag of sefcontext_compile now causes it to omit the
precompiled regular expressions from the output.

Signed-off-by: Janis Danisevskis <jdanis@android.com>
---
 libselinux/utils/sefcontext_compile.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
index 8c48d32..b2746c7 100644
--- a/libselinux/utils/sefcontext_compile.c
+++ b/libselinux/utils/sefcontext_compile.c
@@ -276,10 +276,12 @@ static void usage(const char *progname)
 	    "         will be fc_file with the .bin suffix appended.\n\t"
 	    "-p       Optional binary policy file that will be used to\n\t"
 	    "         validate contexts defined in the fc_file.\n\t"
-	    "-r       Include precompiled regular expressions in the output.\n\t"
+	    "-r       Omit precompiled regular expressions from the output.\n\t"
 	    "         (PCRE2 only. Compiled PCRE2 regular expressions are\n\t"
-	    "         not portable across architectures. When linked against\n\t"
-	    "         PCRE this flag is ignored)\n\t"
+	    "         not portable across architectures. Use this flag\n\t"
+	    "         if you know that you build for an incompatible\n\t"
+	    "         architecture to save space. When linked against\n\t"
+	    "         PCRE1 this flag is ignored.)\n\t"
 	    "-i       Print regular expression info end exit. That is, back\n\t"
 	    "         end version and architecture identifier.\n\t"
 	    "         Arch identifier format (PCRE2):\n\t"
@@ -294,7 +296,7 @@ int main(int argc, char *argv[])
 {
 	const char *path = NULL;
 	const char *out_file = NULL;
-	int do_write_precompregex = 0;
+	int do_write_precompregex = 1;
 	char stack_path[PATH_MAX + 1];
 	char *tmp = NULL;
 	int fd, rc, opt;
@@ -315,7 +317,7 @@ int main(int argc, char *argv[])
 			policy_file = optarg;
 			break;
 		case 'r':
-			do_write_precompregex = 1;
+			do_write_precompregex = 0;
 			break;
 		case 'i':
 			printf("%s (%s)\n", regex_version(),
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] libselinux: Add architecture string to file_context.bin
  2016-09-28 10:28 [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
  2016-09-28 10:28 ` [PATCH 2/3] libselinux: sefcontext_compile: Add "-i" flag Janis Danisevskis
  2016-09-28 10:28 ` [PATCH 3/3] libselinux: sefcontext_compile invert semantics of "-r" flag Janis Danisevskis
@ 2016-09-28 10:31 ` Janis Danisevskis
  2 siblings, 0 replies; 8+ messages in thread
From: Janis Danisevskis @ 2016-09-28 10:31 UTC (permalink / raw)
  To: selinux, seandroid-list, Stephen Smalley, James Carter,
	Janis Danisevskis
  Cc: Janis Danisevskis

[-- Attachment #1: Type: text/plain, Size: 11043 bytes --]

The only change with respect to the first set of patches is the new default
"reg_arch_matches = 0".


On Wed, Sep 28, 2016 at 11:28 AM, Janis Danisevskis <jdanis@android.com>
wrote:

> Serialized precompiled regular expressins are architecture
> dependent when using PCRE2. This patch
> - bumps the SELINUX_COMPILED_FCONTEXT version to 5 and
> - adds a field to the output indicating the architecture
>   compatibility.
>
> libselinux can cope with an architecture mismatch by
> ignoring the precompiled data in the input file and recompiling
> the regular expressions at runtime. It can also load older
> versions of file_contexts.bin if they where built with
> sefcontext_compile using the exact same version of the
> pcre1/2 as selinux.
>
> Signed-off-by: Janis Danisevskis <jdanis@android.com>
> ---
>  libselinux/src/label_file.c           | 43 +++++++++++++++++++++++++++++-
>  libselinux/src/label_file.h           |  4 ++-
>  libselinux/src/regex.c                | 50 ++++++++++++++++++++++++++++++
> ++---
>  libselinux/src/regex.h                | 15 ++++++++++-
>  libselinux/utils/sefcontext_compile.c | 13 +++++++++
>  5 files changed, 119 insertions(+), 6 deletions(-)
>
> diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> index 7156825..13e05c1 100644
> --- a/libselinux/src/label_file.c
> +++ b/libselinux/src/label_file.c
> @@ -126,6 +126,8 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
>         uint32_t i, magic, version;
>         uint32_t entry_len, stem_map_len, regex_array_len;
>         const char *reg_version;
> +       const char *reg_arch;
> +       char reg_arch_matches = 0;
>
>         mmap_area = malloc(sizeof(*mmap_area));
>         if (!mmap_area) {
> @@ -159,6 +161,10 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
>         if (!reg_version)
>                 return -1;
>
> +       reg_arch = regex_arch_string();
> +       if (!reg_arch)
> +               return -1;
> +
>         if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
>
>                 len = strlen(reg_version);
> @@ -188,7 +194,42 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
>                         return -1;
>                 }
>                 free(str_buf);
> +
> +               if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
> +                       len = strlen(reg_arch);
> +
> +                       rc = next_entry(&entry_len, mmap_area,
> +                                       sizeof(uint32_t));
> +                       if (rc < 0)
> +                               return -1;
> +
> +                       /* Check arch string lengths */
> +                       if (len != entry_len) {
> +                               /*
> +                                * Skip the entry and conclude that we have
> +                                * a mismatch, which is not fatal.
> +                                */
> +                               next_entry(NULL, mmap_area, entry_len);
> +                               goto end_arch_check;
> +                       }
> +
> +                       /* Check if arch string mismatch */
> +                       str_buf = malloc(entry_len + 1);
> +                       if (!str_buf)
> +                               return -1;
> +
> +                       rc = next_entry(str_buf, mmap_area, entry_len);
> +                       if (rc < 0) {
> +                               free(str_buf);
> +                               return -1;
> +                       }
> +
> +                       str_buf[entry_len] = '\0';
> +                       reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
> +                       free(str_buf);
> +               }
>         }
> +end_arch_check:
>
>         /* allocate the stems_data array */
>         rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
> @@ -349,7 +390,7 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
>                         spec->prefix_len = prefix_len;
>                 }
>
> -               rc = regex_load_mmap(mmap_area, &spec->regex);
> +               rc = regex_load_mmap(mmap_area, &spec->regex,
> reg_arch_matches);
>                 if (rc < 0)
>                         goto out;
>
> diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
> index 88f4294..00c0a5c 100644
> --- a/libselinux/src/label_file.h
> +++ b/libselinux/src/label_file.h
> @@ -24,8 +24,10 @@
>  #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS    2
>  #define SELINUX_COMPILED_FCONTEXT_MODE         3
>  #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN   4
> +#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH   5
>
> -#define SELINUX_COMPILED_FCONTEXT_MAX_VERS     SELINUX_COMPILED_FCONTEXT_
> PREFIX_LEN
> +#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
> +       SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
>
>  /* A file security context specification. */
>  struct spec {
> diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
> index 750088e..a3b427b 100644
> --- a/libselinux/src/regex.c
> +++ b/libselinux/src/regex.c
> @@ -7,6 +7,44 @@
>  #include "label_file.h"
>
>  #ifdef USE_PCRE2
> +#define REGEX_ARCH_SIZE_T PCRE2_SIZE
> +#else
> +#define REGEX_ARCH_SIZE_T size_t
> +#endif
> +
> +#ifndef __BYTE_ORDER__
> +#error __BYTE_ORDER__ not defined. Unable to determine endianness.
> +#endif
> +
> +#ifdef USE_PCRE2
> +char const *regex_arch_string(void)
> +{
> +       static char arch_string_buffer[32];
> +       static char const *arch_string = "";
> +       char const *endianness = NULL;
> +       int rc;
> +
> +       if (arch_string[0] == '\0') {
> +               if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
> +                       endianness = "el";
> +               else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
> +                       endianness = "eb";
> +
> +               if (!endianness)
> +                       return NULL;
> +
> +               rc = snprintf(arch_string_buffer,
> sizeof(arch_string_buffer),
> +                               "%zu-%zu-%s", sizeof(void *),
> +                               sizeof(REGEX_ARCH_SIZE_T),
> +                               endianness);
> +               if (rc < 0)
> +                       abort();
> +
> +               arch_string = &arch_string_buffer[0];
> +       }
> +       return arch_string;
> +}
> +
>  struct regex_data {
>         pcre2_code *regex; /* compiled regular expression */
>         /*
> @@ -56,7 +94,8 @@ char const *regex_version(void)
>         return version_buf;
>  }
>
> -int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex)
> +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex,
> +                   int do_load_precompregex)
>  {
>         int rc;
>         uint32_t entry_len;
> @@ -65,7 +104,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct
> regex_data **regex)
>         if (rc < 0)
>                 return -1;
>
> -       if (entry_len) {
> +       if (entry_len && do_load_precompregex) {
>                 /*
>                  * this should yield exactly one because we store one
> pattern at
>                  * a time
> @@ -195,6 +234,10 @@ int regex_cmp(struct regex_data *regex1, struct
> regex_data *regex2)
>  }
>
>  #else // !USE_PCRE2
> +char const *regex_arch_string(void)
> +{
> +       return "N/A";
> +}
>
>  /* Prior to version 8.20, libpcre did not have pcre_free_study() */
>  #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
> @@ -247,7 +290,8 @@ char const *regex_version(void)
>         return pcre_version();
>  }
>
> -int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex)
> +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex,
> +                   int unused __attribute__((unused)))
>  {
>         int rc;
>         uint32_t entry_len;
> diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
> index 810b3c5..186c5ec 100644
> --- a/libselinux/src/regex.h
> +++ b/libselinux/src/regex.h
> @@ -34,6 +34,16 @@ struct regex_error_data {
>  struct mmap_area;
>
>  /**
> + * regex_arch_string return a string that represents the pointer width,
> the
> + * width of what the backend considers a size type, and the endianness of
> the
> + * system that this library was build for. (e.g. for x86_64: "8-8-el").
> + * This is required when loading stored regular espressions. PCRE2 regular
> + * expressions are not portable across architectures that do not have a
> + * matching arch-string.
> + */
> +char const *regex_arch_string(void) hidden;
> +
> +/**
>   * 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
> @@ -86,12 +96,15 @@ int regex_prepare_data(struct regex_data **regex, char
> const *pattern_string,
>   *               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.
> + * @arg do_load_precompregex If non-zero precompiled patterns get loaded
> from
> + *                          the mmap region (ignored by PCRE1 back-end).
>   *
>   * @retval 0 on success
>   * @retval -1 on error
>   */
>  int regex_load_mmap(struct mmap_area *map_area,
> -                   struct regex_data **regex) hidden;
> +                   struct regex_data **regex,
> +                   int do_load_precompregex) hidden;
>  /**
>   * This function stores a precompiled regular expression to a file.
>   * In the case of PCRE, it just dumps the binary representation of the
> diff --git a/libselinux/utils/sefcontext_compile.c
> b/libselinux/utils/sefcontext_compile.c
> index 70853e7..d91db9a 100644
> --- a/libselinux/utils/sefcontext_compile.c
> +++ b/libselinux/utils/sefcontext_compile.c
> @@ -103,6 +103,7 @@ static int write_binary_file(struct saved_data *data,
> int fd,
>         uint32_t i;
>         int rc;
>         const char *reg_version;
> +       const char *reg_arch;
>
>         bin_file = fdopen(fd, "w");
>         if (!bin_file) {
> @@ -133,6 +134,18 @@ static int write_binary_file(struct saved_data *data,
> int fd,
>         if (len != section_len)
>                 goto err;
>
> +       /* write regex arch string */
> +       reg_arch = regex_arch_string();
> +       if (!reg_arch)
> +               goto err;
> +       section_len = strlen(reg_arch);
> +       len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> +       if (len != 1)
> +               goto err;
> +       len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
> +       if (len != section_len)
> +               goto err;
> +
>         /* write the number of stems coming */
>         section_len = data->num_stems;
>         len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> --
> 2.8.0.rc3.226.g39d4020
>
>

[-- Attachment #2: Type: text/html, Size: 13570 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] libselinux: sefcontext_compile invert semantics of "-r" flag
  2016-09-28 10:28 ` [PATCH 3/3] libselinux: sefcontext_compile invert semantics of "-r" flag Janis Danisevskis
@ 2016-09-28 12:10   ` Stephen Smalley
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Smalley @ 2016-09-28 12:10 UTC (permalink / raw)
  To: Janis Danisevskis, selinux, seandroid-list, jwcart2, jdanis

On 09/28/2016 06:28 AM, Janis Danisevskis wrote:
> The "-r" flag of sefcontext_compile now causes it to omit the
> precompiled regular expressions from the output.
> 
> Signed-off-by: Janis Danisevskis <jdanis@android.com>

Thanks, all 3 applied.

> ---
>  libselinux/utils/sefcontext_compile.c | 12 +++++++-----
>  1 file changed, 7 insertions(+), 5 deletions(-)
> 
> diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
> index 8c48d32..b2746c7 100644
> --- a/libselinux/utils/sefcontext_compile.c
> +++ b/libselinux/utils/sefcontext_compile.c
> @@ -276,10 +276,12 @@ static void usage(const char *progname)
>  	    "         will be fc_file with the .bin suffix appended.\n\t"
>  	    "-p       Optional binary policy file that will be used to\n\t"
>  	    "         validate contexts defined in the fc_file.\n\t"
> -	    "-r       Include precompiled regular expressions in the output.\n\t"
> +	    "-r       Omit precompiled regular expressions from the output.\n\t"
>  	    "         (PCRE2 only. Compiled PCRE2 regular expressions are\n\t"
> -	    "         not portable across architectures. When linked against\n\t"
> -	    "         PCRE this flag is ignored)\n\t"
> +	    "         not portable across architectures. Use this flag\n\t"
> +	    "         if you know that you build for an incompatible\n\t"
> +	    "         architecture to save space. When linked against\n\t"
> +	    "         PCRE1 this flag is ignored.)\n\t"
>  	    "-i       Print regular expression info end exit. That is, back\n\t"
>  	    "         end version and architecture identifier.\n\t"
>  	    "         Arch identifier format (PCRE2):\n\t"
> @@ -294,7 +296,7 @@ int main(int argc, char *argv[])
>  {
>  	const char *path = NULL;
>  	const char *out_file = NULL;
> -	int do_write_precompregex = 0;
> +	int do_write_precompregex = 1;
>  	char stack_path[PATH_MAX + 1];
>  	char *tmp = NULL;
>  	int fd, rc, opt;
> @@ -315,7 +317,7 @@ int main(int argc, char *argv[])
>  			policy_file = optarg;
>  			break;
>  		case 'r':
> -			do_write_precompregex = 1;
> +			do_write_precompregex = 0;
>  			break;
>  		case 'i':
>  			printf("%s (%s)\n", regex_version(),
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] libselinux: Add architecture string to file_context.bin
  2016-09-26 16:29 ` William Roberts
@ 2016-09-26 17:15   ` Janis Danisevskis
  0 siblings, 0 replies; 8+ messages in thread
From: Janis Danisevskis @ 2016-09-26 17:15 UTC (permalink / raw)
  To: William Roberts, Janis Danisevskis
  Cc: selinux, seandroid-list, Stephen Smalley, James Carter

[-- Attachment #1: Type: text/plain, Size: 12569 bytes --]

My line of thought was that all pre version 5 .bin files should load the
regexes from the file. However, given that the PCRE back end ignores the
flag and that only .bin files of version < 5 that where build with
sefcompile_context that was linked against PCRE2 would be affected, I would
agree that reg_arch_matches = 0 would be the saner default setting. I'll
modify the patch accordingly.

Thanks

On Mon, 26 Sep 2016, 17:29 William Roberts, <bill.c.roberts@gmail.com>
wrote:

> On Mon, Sep 26, 2016 at 7:22 AM, Janis Danisevskis <jdanis@android.com>
> wrote:
> > Serialized precompiled regular expressins are architecture
> > dependent when using PCRE2. This patch
> > - bumps the SELINUX_COMPILED_FCONTEXT version to 5 and
> > - adds a field to the output indicating the architecture
> >   compatibility.
> >
> > libselinux can cope with an architecture mismatch by
> > ignoring the precompiled data in the input file and recompiling
> > the regular expressions at runtime. It can also load older
> > versions of file_contexts.bin if they where built with
> > sefcontext_compile using the exact same version of the
> > pcre1/2 as selinux.
> >
> > Signed-off-by: Janis Danisevskis <jdanis@android.com>
> > ---
> >  libselinux/src/label_file.c           | 44
> +++++++++++++++++++++++++++++-
> >  libselinux/src/label_file.h           |  4 ++-
> >  libselinux/src/regex.c                | 50
> ++++++++++++++++++++++++++++++++---
> >  libselinux/src/regex.h                | 15 ++++++++++-
> >  libselinux/utils/sefcontext_compile.c | 13 +++++++++
> >  5 files changed, 120 insertions(+), 6 deletions(-)
> >
> > diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> > index 7156825..9abc1d6 100644
> > --- a/libselinux/src/label_file.c
> > +++ b/libselinux/src/label_file.c
> > @@ -126,6 +126,8 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
> >         uint32_t i, magic, version;
> >         uint32_t entry_len, stem_map_len, regex_array_len;
> >         const char *reg_version;
> > +       const char *reg_arch;
> > +       char reg_arch_matches = 1;
>
> It appears all the patchs would reset this to 0 properly, but is their
> any reason you
> chose the default to be that it matches? I would assume it would be
> safer to mark
> this as its not a match.
>
> >
> >         mmap_area = malloc(sizeof(*mmap_area));
> >         if (!mmap_area) {
> > @@ -159,6 +161,10 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
> >         if (!reg_version)
> >                 return -1;
> >
> > +       reg_arch = regex_arch_string();
> > +       if (!reg_arch)
> > +               return -1;
> > +
> >         if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
> >
> >                 len = strlen(reg_version);
> > @@ -188,7 +194,43 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
> >                         return -1;
> >                 }
> >                 free(str_buf);
> > +
> > +               if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
> > +                       len = strlen(reg_arch);
> > +
> > +                       rc = next_entry(&entry_len, mmap_area,
> > +                                       sizeof(uint32_t));
> > +                       if (rc < 0)
> > +                               return -1;
> > +
> > +                       /* Check arch string lengths */
> > +                       if (len != entry_len) {
> > +                               /*
> > +                                * Skip the entry and conclude that we
> have
> > +                                * a mismatch, which is not fatal.
> > +                                */
> > +                               next_entry(NULL, mmap_area, entry_len);
> > +                               reg_arch_matches = 0;
> > +                               goto end_arch_check;
> > +                       }
> > +
> > +                       /* Check if arch string mismatch */
> > +                       str_buf = malloc(entry_len + 1);
> > +                       if (!str_buf)
> > +                               return -1;
> > +
> > +                       rc = next_entry(str_buf, mmap_area, entry_len);
> > +                       if (rc < 0) {
> > +                               free(str_buf);
> > +                               return -1;
> > +                       }
> > +
> > +                       str_buf[entry_len] = '\0';
> > +                       reg_arch_matches = strcmp(str_buf, reg_arch) ==
> 0;
> > +                       free(str_buf);
> > +               }
> >         }
> > +end_arch_check:
> >
> >         /* allocate the stems_data array */
> >         rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
> > @@ -349,7 +391,7 @@ static int load_mmap(FILE *fp, size_t len, struct
> selabel_handle *rec,
> >                         spec->prefix_len = prefix_len;
> >                 }
> >
> > -               rc = regex_load_mmap(mmap_area, &spec->regex);
> > +               rc = regex_load_mmap(mmap_area, &spec->regex,
> reg_arch_matches);
> >                 if (rc < 0)
> >                         goto out;
> >
> > diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
> > index 88f4294..00c0a5c 100644
> > --- a/libselinux/src/label_file.h
> > +++ b/libselinux/src/label_file.h
> > @@ -24,8 +24,10 @@
> >  #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS    2
> >  #define SELINUX_COMPILED_FCONTEXT_MODE         3
> >  #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN   4
> > +#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH   5
> >
> > -#define SELINUX_COMPILED_FCONTEXT_MAX_VERS
>  SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
> > +#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
> > +       SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
> >
> >  /* A file security context specification. */
> >  struct spec {
> > diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
> > index 750088e..a3b427b 100644
> > --- a/libselinux/src/regex.c
> > +++ b/libselinux/src/regex.c
> > @@ -7,6 +7,44 @@
> >  #include "label_file.h"
> >
> >  #ifdef USE_PCRE2
> > +#define REGEX_ARCH_SIZE_T PCRE2_SIZE
> > +#else
> > +#define REGEX_ARCH_SIZE_T size_t
> > +#endif
> > +
> > +#ifndef __BYTE_ORDER__
> > +#error __BYTE_ORDER__ not defined. Unable to determine endianness.
> > +#endif
> > +
> > +#ifdef USE_PCRE2
> > +char const *regex_arch_string(void)
> > +{
> > +       static char arch_string_buffer[32];
> > +       static char const *arch_string = "";
> > +       char const *endianness = NULL;
> > +       int rc;
> > +
> > +       if (arch_string[0] == '\0') {
> > +               if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
> > +                       endianness = "el";
> > +               else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
> > +                       endianness = "eb";
> > +
> > +               if (!endianness)
> > +                       return NULL;
> > +
> > +               rc = snprintf(arch_string_buffer,
> sizeof(arch_string_buffer),
> > +                               "%zu-%zu-%s", sizeof(void *),
> > +                               sizeof(REGEX_ARCH_SIZE_T),
> > +                               endianness);
> > +               if (rc < 0)
> > +                       abort();
> > +
> > +               arch_string = &arch_string_buffer[0];
> > +       }
> > +       return arch_string;
> > +}
> > +
> >  struct regex_data {
> >         pcre2_code *regex; /* compiled regular expression */
> >         /*
> > @@ -56,7 +94,8 @@ char const *regex_version(void)
> >         return version_buf;
> >  }
> >
> > -int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex)
> > +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex,
> > +                   int do_load_precompregex)
> >  {
> >         int rc;
> >         uint32_t entry_len;
> > @@ -65,7 +104,7 @@ int regex_load_mmap(struct mmap_area *mmap_area,
> struct regex_data **regex)
> >         if (rc < 0)
> >                 return -1;
> >
> > -       if (entry_len) {
> > +       if (entry_len && do_load_precompregex) {
> >                 /*
> >                  * this should yield exactly one because we store one
> pattern at
> >                  * a time
> > @@ -195,6 +234,10 @@ int regex_cmp(struct regex_data *regex1, struct
> regex_data *regex2)
> >  }
> >
> >  #else // !USE_PCRE2
> > +char const *regex_arch_string(void)
> > +{
> > +       return "N/A";
> > +}
> >
> >  /* Prior to version 8.20, libpcre did not have pcre_free_study() */
> >  #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
> > @@ -247,7 +290,8 @@ char const *regex_version(void)
> >         return pcre_version();
> >  }
> >
> > -int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex)
> > +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data
> **regex,
> > +                   int unused __attribute__((unused)))
> >  {
> >         int rc;
> >         uint32_t entry_len;
> > diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
> > index 810b3c5..186c5ec 100644
> > --- a/libselinux/src/regex.h
> > +++ b/libselinux/src/regex.h
> > @@ -34,6 +34,16 @@ struct regex_error_data {
> >  struct mmap_area;
> >
> >  /**
> > + * regex_arch_string return a string that represents the pointer width,
> the
> > + * width of what the backend considers a size type, and the endianness
> of the
> > + * system that this library was build for. (e.g. for x86_64: "8-8-el").
> > + * This is required when loading stored regular espressions. PCRE2
> regular
> > + * expressions are not portable across architectures that do not have a
> > + * matching arch-string.
> > + */
> > +char const *regex_arch_string(void) hidden;
> > +
> > +/**
> >   * 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
> > @@ -86,12 +96,15 @@ int regex_prepare_data(struct regex_data **regex,
> char const *pattern_string,
> >   *               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.
> > + * @arg do_load_precompregex If non-zero precompiled patterns get
> loaded from
> > + *                          the mmap region (ignored by PCRE1 back-end).
> >   *
> >   * @retval 0 on success
> >   * @retval -1 on error
> >   */
> >  int regex_load_mmap(struct mmap_area *map_area,
> > -                   struct regex_data **regex) hidden;
> > +                   struct regex_data **regex,
> > +                   int do_load_precompregex) hidden;
> >  /**
> >   * This function stores a precompiled regular expression to a file.
> >   * In the case of PCRE, it just dumps the binary representation of the
> > diff --git a/libselinux/utils/sefcontext_compile.c
> b/libselinux/utils/sefcontext_compile.c
> > index 70853e7..d91db9a 100644
> > --- a/libselinux/utils/sefcontext_compile.c
> > +++ b/libselinux/utils/sefcontext_compile.c
> > @@ -103,6 +103,7 @@ static int write_binary_file(struct saved_data
> *data, int fd,
> >         uint32_t i;
> >         int rc;
> >         const char *reg_version;
> > +       const char *reg_arch;
> >
> >         bin_file = fdopen(fd, "w");
> >         if (!bin_file) {
> > @@ -133,6 +134,18 @@ static int write_binary_file(struct saved_data
> *data, int fd,
> >         if (len != section_len)
> >                 goto err;
> >
> > +       /* write regex arch string */
> > +       reg_arch = regex_arch_string();
> > +       if (!reg_arch)
> > +               goto err;
> > +       section_len = strlen(reg_arch);
> > +       len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> > +       if (len != 1)
> > +               goto err;
> > +       len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
> > +       if (len != section_len)
> > +               goto err;
> > +
> >         /* write the number of stems coming */
> >         section_len = data->num_stems;
> >         len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> > --
> > 2.8.0.rc3.226.g39d4020
> >
> > _______________________________________________
> > Seandroid-list mailing list
> > Seandroid-list@tycho.nsa.gov
> > To unsubscribe, send email to Seandroid-list-leave@tycho.nsa.gov.
> > To get help, send an email containing "help" to
> Seandroid-list-request@tycho.nsa.gov.
>
>
>
> --
> Respectfully,
>
> William C Roberts
>

[-- Attachment #2: Type: text/html, Size: 21588 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] libselinux: Add architecture string to file_context.bin
  2016-09-26 14:22 Janis Danisevskis
@ 2016-09-26 16:29 ` William Roberts
  2016-09-26 17:15   ` Janis Danisevskis
  0 siblings, 1 reply; 8+ messages in thread
From: William Roberts @ 2016-09-26 16:29 UTC (permalink / raw)
  To: Janis Danisevskis
  Cc: selinux, seandroid-list, Stephen Smalley, James Carter,
	Janis Danisevskis

On Mon, Sep 26, 2016 at 7:22 AM, Janis Danisevskis <jdanis@android.com> wrote:
> Serialized precompiled regular expressins are architecture
> dependent when using PCRE2. This patch
> - bumps the SELINUX_COMPILED_FCONTEXT version to 5 and
> - adds a field to the output indicating the architecture
>   compatibility.
>
> libselinux can cope with an architecture mismatch by
> ignoring the precompiled data in the input file and recompiling
> the regular expressions at runtime. It can also load older
> versions of file_contexts.bin if they where built with
> sefcontext_compile using the exact same version of the
> pcre1/2 as selinux.
>
> Signed-off-by: Janis Danisevskis <jdanis@android.com>
> ---
>  libselinux/src/label_file.c           | 44 +++++++++++++++++++++++++++++-
>  libselinux/src/label_file.h           |  4 ++-
>  libselinux/src/regex.c                | 50 ++++++++++++++++++++++++++++++++---
>  libselinux/src/regex.h                | 15 ++++++++++-
>  libselinux/utils/sefcontext_compile.c | 13 +++++++++
>  5 files changed, 120 insertions(+), 6 deletions(-)
>
> diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> index 7156825..9abc1d6 100644
> --- a/libselinux/src/label_file.c
> +++ b/libselinux/src/label_file.c
> @@ -126,6 +126,8 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
>         uint32_t i, magic, version;
>         uint32_t entry_len, stem_map_len, regex_array_len;
>         const char *reg_version;
> +       const char *reg_arch;
> +       char reg_arch_matches = 1;

It appears all the patchs would reset this to 0 properly, but is their
any reason you
chose the default to be that it matches? I would assume it would be
safer to mark
this as its not a match.

>
>         mmap_area = malloc(sizeof(*mmap_area));
>         if (!mmap_area) {
> @@ -159,6 +161,10 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
>         if (!reg_version)
>                 return -1;
>
> +       reg_arch = regex_arch_string();
> +       if (!reg_arch)
> +               return -1;
> +
>         if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
>
>                 len = strlen(reg_version);
> @@ -188,7 +194,43 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
>                         return -1;
>                 }
>                 free(str_buf);
> +
> +               if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
> +                       len = strlen(reg_arch);
> +
> +                       rc = next_entry(&entry_len, mmap_area,
> +                                       sizeof(uint32_t));
> +                       if (rc < 0)
> +                               return -1;
> +
> +                       /* Check arch string lengths */
> +                       if (len != entry_len) {
> +                               /*
> +                                * Skip the entry and conclude that we have
> +                                * a mismatch, which is not fatal.
> +                                */
> +                               next_entry(NULL, mmap_area, entry_len);
> +                               reg_arch_matches = 0;
> +                               goto end_arch_check;
> +                       }
> +
> +                       /* Check if arch string mismatch */
> +                       str_buf = malloc(entry_len + 1);
> +                       if (!str_buf)
> +                               return -1;
> +
> +                       rc = next_entry(str_buf, mmap_area, entry_len);
> +                       if (rc < 0) {
> +                               free(str_buf);
> +                               return -1;
> +                       }
> +
> +                       str_buf[entry_len] = '\0';
> +                       reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
> +                       free(str_buf);
> +               }
>         }
> +end_arch_check:
>
>         /* allocate the stems_data array */
>         rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
> @@ -349,7 +391,7 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
>                         spec->prefix_len = prefix_len;
>                 }
>
> -               rc = regex_load_mmap(mmap_area, &spec->regex);
> +               rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches);
>                 if (rc < 0)
>                         goto out;
>
> diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
> index 88f4294..00c0a5c 100644
> --- a/libselinux/src/label_file.h
> +++ b/libselinux/src/label_file.h
> @@ -24,8 +24,10 @@
>  #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS    2
>  #define SELINUX_COMPILED_FCONTEXT_MODE         3
>  #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN   4
> +#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH   5
>
> -#define SELINUX_COMPILED_FCONTEXT_MAX_VERS     SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
> +#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
> +       SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
>
>  /* A file security context specification. */
>  struct spec {
> diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
> index 750088e..a3b427b 100644
> --- a/libselinux/src/regex.c
> +++ b/libselinux/src/regex.c
> @@ -7,6 +7,44 @@
>  #include "label_file.h"
>
>  #ifdef USE_PCRE2
> +#define REGEX_ARCH_SIZE_T PCRE2_SIZE
> +#else
> +#define REGEX_ARCH_SIZE_T size_t
> +#endif
> +
> +#ifndef __BYTE_ORDER__
> +#error __BYTE_ORDER__ not defined. Unable to determine endianness.
> +#endif
> +
> +#ifdef USE_PCRE2
> +char const *regex_arch_string(void)
> +{
> +       static char arch_string_buffer[32];
> +       static char const *arch_string = "";
> +       char const *endianness = NULL;
> +       int rc;
> +
> +       if (arch_string[0] == '\0') {
> +               if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
> +                       endianness = "el";
> +               else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
> +                       endianness = "eb";
> +
> +               if (!endianness)
> +                       return NULL;
> +
> +               rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer),
> +                               "%zu-%zu-%s", sizeof(void *),
> +                               sizeof(REGEX_ARCH_SIZE_T),
> +                               endianness);
> +               if (rc < 0)
> +                       abort();
> +
> +               arch_string = &arch_string_buffer[0];
> +       }
> +       return arch_string;
> +}
> +
>  struct regex_data {
>         pcre2_code *regex; /* compiled regular expression */
>         /*
> @@ -56,7 +94,8 @@ char const *regex_version(void)
>         return version_buf;
>  }
>
> -int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
> +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
> +                   int do_load_precompregex)
>  {
>         int rc;
>         uint32_t entry_len;
> @@ -65,7 +104,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
>         if (rc < 0)
>                 return -1;
>
> -       if (entry_len) {
> +       if (entry_len && do_load_precompregex) {
>                 /*
>                  * this should yield exactly one because we store one pattern at
>                  * a time
> @@ -195,6 +234,10 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
>  }
>
>  #else // !USE_PCRE2
> +char const *regex_arch_string(void)
> +{
> +       return "N/A";
> +}
>
>  /* Prior to version 8.20, libpcre did not have pcre_free_study() */
>  #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
> @@ -247,7 +290,8 @@ char const *regex_version(void)
>         return pcre_version();
>  }
>
> -int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
> +int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
> +                   int unused __attribute__((unused)))
>  {
>         int rc;
>         uint32_t entry_len;
> diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
> index 810b3c5..186c5ec 100644
> --- a/libselinux/src/regex.h
> +++ b/libselinux/src/regex.h
> @@ -34,6 +34,16 @@ struct regex_error_data {
>  struct mmap_area;
>
>  /**
> + * regex_arch_string return a string that represents the pointer width, the
> + * width of what the backend considers a size type, and the endianness of the
> + * system that this library was build for. (e.g. for x86_64: "8-8-el").
> + * This is required when loading stored regular espressions. PCRE2 regular
> + * expressions are not portable across architectures that do not have a
> + * matching arch-string.
> + */
> +char const *regex_arch_string(void) hidden;
> +
> +/**
>   * 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
> @@ -86,12 +96,15 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
>   *               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.
> + * @arg do_load_precompregex If non-zero precompiled patterns get loaded from
> + *                          the mmap region (ignored by PCRE1 back-end).
>   *
>   * @retval 0 on success
>   * @retval -1 on error
>   */
>  int regex_load_mmap(struct mmap_area *map_area,
> -                   struct regex_data **regex) hidden;
> +                   struct regex_data **regex,
> +                   int do_load_precompregex) hidden;
>  /**
>   * This function stores a precompiled regular expression to a file.
>   * In the case of PCRE, it just dumps the binary representation of the
> diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
> index 70853e7..d91db9a 100644
> --- a/libselinux/utils/sefcontext_compile.c
> +++ b/libselinux/utils/sefcontext_compile.c
> @@ -103,6 +103,7 @@ static int write_binary_file(struct saved_data *data, int fd,
>         uint32_t i;
>         int rc;
>         const char *reg_version;
> +       const char *reg_arch;
>
>         bin_file = fdopen(fd, "w");
>         if (!bin_file) {
> @@ -133,6 +134,18 @@ static int write_binary_file(struct saved_data *data, int fd,
>         if (len != section_len)
>                 goto err;
>
> +       /* write regex arch string */
> +       reg_arch = regex_arch_string();
> +       if (!reg_arch)
> +               goto err;
> +       section_len = strlen(reg_arch);
> +       len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> +       if (len != 1)
> +               goto err;
> +       len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
> +       if (len != section_len)
> +               goto err;
> +
>         /* write the number of stems coming */
>         section_len = data->num_stems;
>         len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
> --
> 2.8.0.rc3.226.g39d4020
>
> _______________________________________________
> Seandroid-list mailing list
> Seandroid-list@tycho.nsa.gov
> To unsubscribe, send email to Seandroid-list-leave@tycho.nsa.gov.
> To get help, send an email containing "help" to Seandroid-list-request@tycho.nsa.gov.



-- 
Respectfully,

William C Roberts

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] libselinux: Add architecture string to file_context.bin
@ 2016-09-26 14:22 Janis Danisevskis
  2016-09-26 16:29 ` William Roberts
  0 siblings, 1 reply; 8+ messages in thread
From: Janis Danisevskis @ 2016-09-26 14:22 UTC (permalink / raw)
  To: selinux, seandroid-list, sds, jwcart2, jdanis; +Cc: Janis Danisevskis

Serialized precompiled regular expressins are architecture
dependent when using PCRE2. This patch
- bumps the SELINUX_COMPILED_FCONTEXT version to 5 and
- adds a field to the output indicating the architecture
  compatibility.

libselinux can cope with an architecture mismatch by
ignoring the precompiled data in the input file and recompiling
the regular expressions at runtime. It can also load older
versions of file_contexts.bin if they where built with
sefcontext_compile using the exact same version of the
pcre1/2 as selinux.

Signed-off-by: Janis Danisevskis <jdanis@android.com>
---
 libselinux/src/label_file.c           | 44 +++++++++++++++++++++++++++++-
 libselinux/src/label_file.h           |  4 ++-
 libselinux/src/regex.c                | 50 ++++++++++++++++++++++++++++++++---
 libselinux/src/regex.h                | 15 ++++++++++-
 libselinux/utils/sefcontext_compile.c | 13 +++++++++
 5 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
index 7156825..9abc1d6 100644
--- a/libselinux/src/label_file.c
+++ b/libselinux/src/label_file.c
@@ -126,6 +126,8 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 	uint32_t i, magic, version;
 	uint32_t entry_len, stem_map_len, regex_array_len;
 	const char *reg_version;
+	const char *reg_arch;
+	char reg_arch_matches = 1;
 
 	mmap_area = malloc(sizeof(*mmap_area));
 	if (!mmap_area) {
@@ -159,6 +161,10 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 	if (!reg_version)
 		return -1;
 
+	reg_arch = regex_arch_string();
+	if (!reg_arch)
+		return -1;
+
 	if (version >= SELINUX_COMPILED_FCONTEXT_PCRE_VERS) {
 
 		len = strlen(reg_version);
@@ -188,7 +194,43 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 			return -1;
 		}
 		free(str_buf);
+
+		if (version >= SELINUX_COMPILED_FCONTEXT_REGEX_ARCH) {
+			len = strlen(reg_arch);
+
+			rc = next_entry(&entry_len, mmap_area,
+					sizeof(uint32_t));
+			if (rc < 0)
+				return -1;
+
+			/* Check arch string lengths */
+			if (len != entry_len) {
+				/*
+				 * Skip the entry and conclude that we have
+				 * a mismatch, which is not fatal.
+				 */
+				next_entry(NULL, mmap_area, entry_len);
+				reg_arch_matches = 0;
+				goto end_arch_check;
+			}
+
+			/* Check if arch string mismatch */
+			str_buf = malloc(entry_len + 1);
+			if (!str_buf)
+				return -1;
+
+			rc = next_entry(str_buf, mmap_area, entry_len);
+			if (rc < 0) {
+				free(str_buf);
+				return -1;
+			}
+
+			str_buf[entry_len] = '\0';
+			reg_arch_matches = strcmp(str_buf, reg_arch) == 0;
+			free(str_buf);
+		}
 	}
+end_arch_check:
 
 	/* allocate the stems_data array */
 	rc = next_entry(&stem_map_len, mmap_area, sizeof(uint32_t));
@@ -349,7 +391,7 @@ static int load_mmap(FILE *fp, size_t len, struct selabel_handle *rec,
 			spec->prefix_len = prefix_len;
 		}
 
-		rc = regex_load_mmap(mmap_area, &spec->regex);
+		rc = regex_load_mmap(mmap_area, &spec->regex, reg_arch_matches);
 		if (rc < 0)
 			goto out;
 
diff --git a/libselinux/src/label_file.h b/libselinux/src/label_file.h
index 88f4294..00c0a5c 100644
--- a/libselinux/src/label_file.h
+++ b/libselinux/src/label_file.h
@@ -24,8 +24,10 @@
 #define SELINUX_COMPILED_FCONTEXT_PCRE_VERS	2
 #define SELINUX_COMPILED_FCONTEXT_MODE		3
 #define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN	4
+#define SELINUX_COMPILED_FCONTEXT_REGEX_ARCH	5
 
-#define SELINUX_COMPILED_FCONTEXT_MAX_VERS	SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
+#define SELINUX_COMPILED_FCONTEXT_MAX_VERS \
+	SELINUX_COMPILED_FCONTEXT_REGEX_ARCH
 
 /* A file security context specification. */
 struct spec {
diff --git a/libselinux/src/regex.c b/libselinux/src/regex.c
index 750088e..a3b427b 100644
--- a/libselinux/src/regex.c
+++ b/libselinux/src/regex.c
@@ -7,6 +7,44 @@
 #include "label_file.h"
 
 #ifdef USE_PCRE2
+#define REGEX_ARCH_SIZE_T PCRE2_SIZE
+#else
+#define REGEX_ARCH_SIZE_T size_t
+#endif
+
+#ifndef __BYTE_ORDER__
+#error __BYTE_ORDER__ not defined. Unable to determine endianness.
+#endif
+
+#ifdef USE_PCRE2
+char const *regex_arch_string(void)
+{
+	static char arch_string_buffer[32];
+	static char const *arch_string = "";
+	char const *endianness = NULL;
+	int rc;
+
+	if (arch_string[0] == '\0') {
+		if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+			endianness = "el";
+		else if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+			endianness = "eb";
+
+		if (!endianness)
+			return NULL;
+
+		rc = snprintf(arch_string_buffer, sizeof(arch_string_buffer),
+				"%zu-%zu-%s", sizeof(void *),
+				sizeof(REGEX_ARCH_SIZE_T),
+				endianness);
+		if (rc < 0)
+			abort();
+
+		arch_string = &arch_string_buffer[0];
+	}
+	return arch_string;
+}
+
 struct regex_data {
 	pcre2_code *regex; /* compiled regular expression */
 	/*
@@ -56,7 +94,8 @@ char const *regex_version(void)
 	return version_buf;
 }
 
-int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
+int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
+		    int do_load_precompregex)
 {
 	int rc;
 	uint32_t entry_len;
@@ -65,7 +104,7 @@ int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
 	if (rc < 0)
 		return -1;
 
-	if (entry_len) {
+	if (entry_len && do_load_precompregex) {
 		/*
 		 * this should yield exactly one because we store one pattern at
 		 * a time
@@ -195,6 +234,10 @@ int regex_cmp(struct regex_data *regex1, struct regex_data *regex2)
 }
 
 #else // !USE_PCRE2
+char const *regex_arch_string(void)
+{
+	return "N/A";
+}
 
 /* Prior to version 8.20, libpcre did not have pcre_free_study() */
 #if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
@@ -247,7 +290,8 @@ char const *regex_version(void)
 	return pcre_version();
 }
 
-int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex)
+int regex_load_mmap(struct mmap_area *mmap_area, struct regex_data **regex,
+		    int unused __attribute__((unused)))
 {
 	int rc;
 	uint32_t entry_len;
diff --git a/libselinux/src/regex.h b/libselinux/src/regex.h
index 810b3c5..186c5ec 100644
--- a/libselinux/src/regex.h
+++ b/libselinux/src/regex.h
@@ -34,6 +34,16 @@ struct regex_error_data {
 struct mmap_area;
 
 /**
+ * regex_arch_string return a string that represents the pointer width, the
+ * width of what the backend considers a size type, and the endianness of the
+ * system that this library was build for. (e.g. for x86_64: "8-8-el").
+ * This is required when loading stored regular espressions. PCRE2 regular
+ * expressions are not portable across architectures that do not have a
+ * matching arch-string.
+ */
+char const *regex_arch_string(void) hidden;
+
+/**
  * 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
@@ -86,12 +96,15 @@ int regex_prepare_data(struct regex_data **regex, char const *pattern_string,
  *               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.
+ * @arg do_load_precompregex If non-zero precompiled patterns get loaded from
+ *			     the mmap region (ignored by PCRE1 back-end).
  *
  * @retval 0 on success
  * @retval -1 on error
  */
 int regex_load_mmap(struct mmap_area *map_area,
-		    struct regex_data **regex) hidden;
+		    struct regex_data **regex,
+		    int do_load_precompregex) hidden;
 /**
  * This function stores a precompiled regular expression to a file.
  * In the case of PCRE, it just dumps the binary representation of the
diff --git a/libselinux/utils/sefcontext_compile.c b/libselinux/utils/sefcontext_compile.c
index 70853e7..d91db9a 100644
--- a/libselinux/utils/sefcontext_compile.c
+++ b/libselinux/utils/sefcontext_compile.c
@@ -103,6 +103,7 @@ static int write_binary_file(struct saved_data *data, int fd,
 	uint32_t i;
 	int rc;
 	const char *reg_version;
+	const char *reg_arch;
 
 	bin_file = fdopen(fd, "w");
 	if (!bin_file) {
@@ -133,6 +134,18 @@ static int write_binary_file(struct saved_data *data, int fd,
 	if (len != section_len)
 		goto err;
 
+	/* write regex arch string */
+	reg_arch = regex_arch_string();
+	if (!reg_arch)
+		goto err;
+	section_len = strlen(reg_arch);
+	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
+	if (len != 1)
+		goto err;
+	len = fwrite(reg_arch, sizeof(char), section_len, bin_file);
+	if (len != section_len)
+		goto err;
+
 	/* write the number of stems coming */
 	section_len = data->num_stems;
 	len = fwrite(&section_len, sizeof(uint32_t), 1, bin_file);
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2016-09-28 12:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-28 10:28 [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
2016-09-28 10:28 ` [PATCH 2/3] libselinux: sefcontext_compile: Add "-i" flag Janis Danisevskis
2016-09-28 10:28 ` [PATCH 3/3] libselinux: sefcontext_compile invert semantics of "-r" flag Janis Danisevskis
2016-09-28 12:10   ` Stephen Smalley
2016-09-28 10:31 ` [PATCH 1/3] libselinux: Add architecture string to file_context.bin Janis Danisevskis
  -- strict thread matches above, loose matches on Subject: below --
2016-09-26 14:22 Janis Danisevskis
2016-09-26 16:29 ` William Roberts
2016-09-26 17:15   ` Janis Danisevskis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.