Skip to contentSkip to conversation

selinux: libselinux: Enable multiple input files to selabel_open.

PATCH In review Daniel Cashman 3 participants 7 messages Sep 11, 2017 – Oct 17, 2017 SELinux security module

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 selinux: libselinux: Enable multiple input files to selabel_open.

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes that only one path will be specified as an option to selabel_open(). The split of platform and non-platform policy on device, however, will necessitate the loading of two disparate policy files. Rather than combining the files and then calling the existing API on a newly-formed file, just add the ability to specify multiple files to use. Order of opt specification to selabel_open matters.

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which lead to a fork with upstream, which we'd like to correct.

---
 libselinux/src/label.c          |  21 +++++---
 libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-----------
 libselinux/src/label_internal.h |   5 +-
 3 files changed, 94 insertions(+), 36 deletions(-)
libselinux/src/label.c +15 -6
index 48f4d2d6..0dfa054c 100644
@@ -143,7 +143,11 @@ static int selabel_fini(struct selabel_handle *rec,
 			    struct selabel_lookup_rec *lr,
 			    int translating)
 {
-	if (compat_validate(rec, lr, rec->spec_file, 0))
+	char *path = NULL;
+
+	if (rec->spec_files)
+		path = rec->spec_files[0];
+	if (compat_validate(rec, lr, path, 0))
 		return -1;
 
 	if (translating && !lr->ctx_trans &&
@@ -226,11 +230,9 @@ struct selabel_handle *selabel_open(unsigned int backend,
 	rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
 
 	if ((*initfuncs[backend])(rec, opts, nopts)) {
-		free(rec->spec_file);
-		free(rec);
+		selabel_close(rec);
 		rec = NULL;
 	}
-
 out:
 	return rec;
 }
@@ -337,10 +339,17 @@ int selabel_digest(struct selabel_handle *rec,
 
 void selabel_close(struct selabel_handle *rec)
 {
+	size_t i;
+
+	if (rec->spec_files) {
+		for (i = 0; i < rec->spec_files_len; i++)
+			free(rec->spec_files[i]);
+		free(rec->spec_files);
+	}
 	if (rec->digest)
 		selabel_digest_fini(rec->digest);
-	rec->func_close(rec);
-	free(rec->spec_file);
+	if (rec->func_close)
+		rec->func_close(rec);
 	free(rec);
 }
 
libselinux/src/label_file.c +76 -28

153 lines not on this page · raw message

libselinux/src/label_internal.h +3 -2
index c55efb75..43b63513 100644
@@ -98,10 +98,11 @@ struct selabel_handle {
 	void *data;
 
 	/*
-	 * The main spec file used. Note for file contexts the local and/or
+	 * The main spec file(s) used. Note for file contexts the local and/or
 	 * homedirs could also have been used to resolve a context.
 	 */
-	char *spec_file;
+	size_t spec_files_len;
+	char **spec_files;
 
 	/* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */
 	struct selabel_digest *digest;
Signature · 1 line
2.14.1.581.gf28d330327-goog
#1 lore raw
Quoted 124 lines · Daniel Cashman

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes
that only one path will be specified as an option to selabel_open(). The split
of platform and non-platform policy on device, however, will necessitate the
loading of two disparate policy files. Rather than combining the files and then
calling the existing API on a newly-formed file, just add the ability to specify
multiple files to use. Order of opt specification to selabel_open matters.

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which
lead to a fork with upstream, which we'd like to correct.

---
 libselinux/src/label.c          |  21 +++++---
 libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-
----------
 libselinux/src/label_internal.h |   5 +-
 3 files changed, 94 insertions(+), 36 deletions(-)
libselinux/src/label.c +6 -4
index 48f4d2d6..0dfa054c 100644
@@ -143,7 +143,11 @@ static int selabel_fini(struct selabel_handle *rec,
                            struct selabel_lookup_rec *lr,
                            int translating)
 {
-       if (compat_validate(rec, lr, rec->spec_file, 0))
+       char *path = NULL;
+
+       if (rec->spec_files)
+               path = rec->spec_files[0];
+       if (compat_validate(rec, lr, path, 0))
                return -1;
 
        if (translating && !lr->ctx_trans &&
@@ -226,11 +230,9 @@ struct selabel_handle *selabel_open(unsigned int
 backend,
        rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
 
        if ((*initfuncs[backend])(rec, opts, nopts)) {
-               free(rec->spec_file);
-               free(rec);
+               selabel_close(rec);
                rec = NULL;
        }
-
 out:
        return rec;

}

libselinux/src/label.c +9 -2
@@ -337,10 +339,17 @@ int selabel_digest(struct selabel_handle *rec,
 
 void selabel_close(struct selabel_handle *rec)
 {
+       size_t i;
+
+       if (rec->spec_files) {
+               for (i = 0; i < rec->spec_files_len; i++)
+                       free(rec->spec_files[i]);
+               free(rec->spec_files);
+       }
        if (rec->digest)
                selabel_digest_fini(rec->digest);
-       rec->func_close(rec);
-       free(rec->spec_file);
+       if (rec->func_close)
+               rec->func_close(rec);
        free(rec);
 }
 
libselinux/src/label_file.c +20 -7
index 560d8c3d..b3b36bc2 100644
@@ -709,28 +709,61 @@ static int init(struct selabel_handle *rec, const
 struct selinux_opt *opts,
                unsigned n)
 {
        struct saved_data *data = (struct saved_data *)rec->data;
-       const char *path = NULL;
+       size_t num_paths = 0;
+       char **path = NULL;
        const char *prefix = NULL;
-       int status = -1, baseonly = 0;
+       int status = -1;
+       size_t i;
+       bool baseonly = false;
+       bool path_provided;
 
        /* Process arguments */
-       while (n--)
-               switch(opts[n].type) {
+       i = n;
+       while (i--)
+               switch(opts[i].type) {
                case SELABEL_OPT_PATH:
-                       path = opts[n].value;
+                       num_paths++;
                        break;
                case SELABEL_OPT_SUBSET:
-                       prefix = opts[n].value;
+                       prefix = opts[i].value;
                        break;
                case SELABEL_OPT_BASEONLY:
-                       baseonly = !!opts[n].value;
+                       baseonly = !!opts[i].value;
                        break;
                }
 
+       if (!num_paths) {
+               num_paths = 1;
+               path_provided = false;
+       } else {
+               path_provided = true;
+       }
+
+       path = calloc(num_paths, sizeof(*path));

libselinux/src/label_file.c static int init(struct selabel_handle *rec, const · line 753

Quoted 10 lines
libselinux/src/label_file.c +9 -0
+       if (path == NULL) {
+               goto finish;
+       }
+       rec->spec_files = path;
+       rec->spec_files_len = num_paths;
+
+       if (path_provided) {
+               for (i = 0; i < n; i++) {
+                       switch(opts[i].type) {
 

Weird way to do an if/else?

Quoted 134 lines
libselinux/src/label_file.c +12 -1
+                       case SELABEL_OPT_PATH:
+                               *path = strdup(opts[i].value);
+                               if (*path == NULL)
+                                       goto finish;
+                               path++;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
 #if !defined(BUILD_HOST) && !defined(ANDROID)
        char subs_file[PATH_MAX + 1];
        /* Process local and distribution substitution files */
-       if (!path) {
+       if (!path_provided) {
                status = selabel_subs_init(
                        selinux_file_context_subs_dist_path(),
                        rec->digest, &data->dist_subs);
libselinux/src/label_file.c +28 -19
@@ -740,43 +773,52 @@ static int init(struct selabel_handle *rec, const
 struct selinux_opt *opts,
                        rec->digest, &data->subs);
                if (status)
                        goto finish;
-               path = selinux_file_context_path();
+               rec->spec_files[0] = strdup(selinux_file_context_path());
+               if (rec->spec_files[0] == NULL)
+                       goto finish;
        } else {
-               snprintf(subs_file, sizeof(subs_file), "%s.subs_dist",
 path);
-               status = selabel_subs_init(subs_file, rec->digest,
+               for (i = 0; i < num_paths; i++) {
+                       snprintf(subs_file, sizeof(subs_file),
 "%s.subs_dist", rec->spec_files[i]);
+                       status = selabel_subs_init(subs_file, rec->digest,
                                           &data->dist_subs);
-               if (status)
-                       goto finish;
-               snprintf(subs_file, sizeof(subs_file), "%s.subs", path);
-               status = selabel_subs_init(subs_file, rec->digest,
+                       if (status)
+                               goto finish;
+                       snprintf(subs_file, sizeof(subs_file), "%s.subs",
 rec->spec_files[i]);
+                       status = selabel_subs_init(subs_file, rec->digest,
                                           &data->subs);
-               if (status)
-                       goto finish;
+                       if (status)
+                               goto finish;
+               }
+       }
+#else
+       if (!path_provided) {
+               selinux_log(SELINUX_ERROR, "No path given to file labeling
 backend\n");
+               goto finish;
        }
-
 #endif
-       rec->spec_file = strdup(path);
 
        /*
-        * The do detailed validation of the input and fill the spec array
+        * Do detailed validation of the input and fill the spec array
         */
-       status = process_file(path, NULL, rec, prefix, rec->digest);
-       if (status)
-               goto finish;
-
-       if (rec->validating) {
-               status = nodups_specs(data, path);
+       for (i = 0; i < num_paths; i++) {
+               status = process_file(rec->spec_files[i], NULL, rec,
 prefix, rec->digest);
                if (status)
                        goto finish;
+
+               if (rec->validating) {
+                       status = nodups_specs(data, rec->spec_files[i]);
+                       if (status)
+                               goto finish;
+               }
        }
 
        if (!baseonly) {
-               status = process_file(path, "homedirs", rec, prefix,
+               status = process_file(rec->spec_files[0], "homedirs",
 rec, prefix,
                                                            rec->digest);
                if (status && errno != ENOENT)
                        goto finish;
libselinux/src/label_file.c +1 -1
-               status = process_file(path, "local", rec, prefix,
+               status = process_file(rec->spec_files[0], "local", rec,

prefix,

                                                            rec->digest);
                if (status && errno != ENOENT)
                        goto finish;
libselinux/src/label_file.c +6 -0
@@ -804,6 +846,12 @@ static void closef(struct selabel_handle *rec)
        struct stem *stem;
        unsigned int i;
 
+       if (!data)
+               return;
+
+       /* make sure successive ->func_close() calls are harmless */
+       rec->data = NULL;
+
        selabel_subs_fini(data->subs);
        selabel_subs_fini(data->dist_subs);
 
libselinux/src/label_ renamed from libselinux/src/label_internal.h +0 -0

internal.h
index c55efb75..43b63513 100644

libselinux/src/label_internal.h +1 -1
@@ -98,10 +98,11 @@ struct selabel_handle {
        void *data;
 
        /*
-        * The main spec file used. Note for file contexts the local and/or
+        * The main spec file(s) used. Note for file contexts the local

and/or
* homedirs could also have been used to resolve a context. */

libselinux/src/label_internal.h +2 -2
-       char *spec_file;
+       size_t spec_files_len;
+       char **spec_files;
 
        /* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */
        struct selabel_digest *digest;
--
Quoted 3 lines

2.14.1.581.gf28d330327-goog

all in all, I have no major gripes with this. Ack.

#2 lore raw
In reply to Daniel Cashman
Quoted 15 lines · Daniel Cashman

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes
that only one path will be specified as an option to selabel_open().  The split
of platform and non-platform policy on device, however, will necessitate the
loading of two disparate policy files.  Rather than combining the files and then
calling the existing API on a newly-formed file, just add the ability to specify
multiple files to use.  Order of opt specification to selabel_open matters.

Quoted 3 lines

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which lead to a fork with upstream, which we'd like to correct.

We need to update the other label backends as well, at least sufficiently to still build, even if they only support a single path.

Quoted 262 lines

---
 libselinux/src/label.c          |  21 +++++--- libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-
----------
 libselinux/src/label_internal.h |   5 +-

 3 files changed, 94 insertions(+), 36 deletions(-)
libselinux/src/label.c +5 -1
index 48f4d2d6..0dfa054c 100644
@@ -143,7 +143,11 @@ static int selabel_fini(struct selabel_handle
 *rec,
  			    struct selabel_lookup_rec *lr,
  			    int translating)
  {
-	if (compat_validate(rec, lr, rec->spec_file, 0))
+	char *path = NULL;
+
+	if (rec->spec_files)
+		path = rec->spec_files[0];
+	if (compat_validate(rec, lr, path, 0))
  		return -1;


  if (translating && !lr->ctx_trans &&

libselinux/src/label.c +0 -0
@@ -226,11 +230,9 @@ struct selabel_handle *selabel_open(unsigned int
 backend,

  rec->digest = selabel_is_digest_set(opts, nopts, rec-

Quoted 1 line

digest);


  if ((*initfuncs[backend])(rec, opts, nopts)) {

libselinux/src/label.c +1 -2
-		free(rec->spec_file);
-		free(rec);
+		selabel_close(rec);

  rec = NULL;
  }
-
 out:
  return rec;
 }

libselinux/src/label.c +0 -0
@@ -337,10 +339,17 @@ int selabel_digest(struct selabel_handle *rec,


 void selabel_close(struct selabel_handle *rec)
 {

libselinux/src/label.c +7 -0
+	size_t i;
+
+	if (rec->spec_files) {
+		for (i = 0; i < rec->spec_files_len; i++)
+			free(rec->spec_files[i]);
+		free(rec->spec_files);
+	}

  if (rec->digest)
  selabel_digest_fini(rec->digest);

libselinux/src/label.c +2 -2
-	rec->func_close(rec);
-	free(rec->spec_file);
+	if (rec->func_close)
+		rec->func_close(rec);

  free(rec);
 }

libselinux/src/label_file.c +6 -2
index 560d8c3d..b3b36bc2 100644
@@ -709,28 +709,61 @@ static int init(struct selabel_handle *rec,
 const struct selinux_opt *opts,
  		unsigned n)
  {
  	struct saved_data *data = (struct saved_data *)rec->data;
-	const char *path = NULL;
+	size_t num_paths = 0;
+	char **path = NULL;
  	const char *prefix = NULL;
-	int status = -1, baseonly = 0;
+	int status = -1;
+	size_t i;
+	bool baseonly = false;
+	bool path_provided;


  /* Process arguments */

libselinux/src/label_file.c +3 -2
-	while (n--)
-		switch(opts[n].type) {
+	i = n;
+	while (i--)
+		switch(opts[i].type) {

  case SELABEL_OPT_PATH:

libselinux/src/label_file.c +1 -1
-			path = opts[n].value;
+			num_paths++;

  break;
  case SELABEL_OPT_SUBSET:

libselinux/src/label_file.c +1 -1
-			prefix = opts[n].value;
+			prefix = opts[i].value;

  break;
  case SELABEL_OPT_BASEONLY:

libselinux/src/label_file.c +1 -1
-			baseonly = !!opts[n].value;
+			baseonly = !!opts[i].value;

  break;
  }

libselinux/src/label_file.c +28 -0
+	if (!num_paths) {
+		num_paths = 1;
+		path_provided = false;
+	} else {
+		path_provided = true;
+	}
+
+	path = calloc(num_paths, sizeof(*path));
+	if (path == NULL) {
+		goto finish;
+	}
+	rec->spec_files = path;
+	rec->spec_files_len = num_paths;
+
+	if (path_provided) {
+		for (i = 0; i < n; i++) {
+			switch(opts[i].type) {
+			case SELABEL_OPT_PATH:
+				*path = strdup(opts[i].value);
+				if (*path == NULL)
+					goto finish;
+				path++;
+				break;
+			default:
+				break;
+			}
+		}
+	}

 #if !defined(BUILD_HOST) && !defined(ANDROID)
  char subs_file[PATH_MAX + 1];
  /* Process local and distribution substitution files */

libselinux/src/label_file.c +1 -1
-	if (!path) {
+	if (!path_provided) {

  status = selabel_subs_init( selinux_file_context_subs_dist_path(), rec->digest, &data->dist_subs);

libselinux/src/label_file.c +18 -11
@@ -740,43 +773,52 @@ static int init(struct selabel_handle *rec,
 const struct selinux_opt *opts,
  			rec->digest, &data->subs);
  		if (status)
  			goto finish;
-		path = selinux_file_context_path();
+		rec->spec_files[0] =
 strdup(selinux_file_context_path());
+		if (rec->spec_files[0] == NULL)
+			goto finish;
  	} else {
-		snprintf(subs_file, sizeof(subs_file),
 "%s.subs_dist", path);
-		status = selabel_subs_init(subs_file, rec->digest,
+		for (i = 0; i < num_paths; i++) {
+			snprintf(subs_file, sizeof(subs_file),
 "%s.subs_dist", rec->spec_files[i]);
+			status = selabel_subs_init(subs_file, rec-
 >digest,
  					   &data->dist_subs);
-		if (status)
-			goto finish;
-		snprintf(subs_file, sizeof(subs_file), "%s.subs",
 path);
-		status = selabel_subs_init(subs_file, rec->digest,
+			if (status)
+				goto finish;
+			snprintf(subs_file, sizeof(subs_file),
 "%s.subs", rec->spec_files[i]);
+			status = selabel_subs_init(subs_file, rec-
 >digest,
  					   &data->subs);
-		if (status)
-			goto finish;
+			if (status)
+				goto finish;
+		}
+	}
+#else
+	if (!path_provided) {
+		selinux_log(SELINUX_ERROR, "No path given to file
 labeling backend\n");
+		goto finish;
  	}
-
  #endif
-	rec->spec_file = strdup(path);


  /*

libselinux/src/label_file.c +0 -1
-	 * The do detailed validation of the input and fill the spec

array

libselinux/src/label_file.c +1 -0
+	 * Do detailed validation of the input and fill the spec

array
   */

libselinux/src/label_file.c +2 -6
-	status = process_file(path, NULL, rec, prefix, rec->digest);
-	if (status)
-		goto finish;
-
-	if (rec->validating) {
-		status = nodups_specs(data, path);
+	for (i = 0; i < num_paths; i++) {
+		status = process_file(rec->spec_files[i], NULL, rec,

prefix, rec->digest);
  if (status)
  goto finish;

libselinux/src/label_file.c +3 -0
+
+		if (rec->validating) {
+			status = nodups_specs(data, rec-
Quoted 1 line

spec_files[i]);

libselinux/src/label_file.c +3 -0
+			if (status)
+				goto finish;
+		}

  }

  if (!baseonly) {

libselinux/src/label_file.c +1 -1
-		status = process_file(path, "homedirs", rec, prefix,
+		status = process_file(rec->spec_files[0],

"homedirs", rec, prefix,
      rec-

Quoted 1 line

digest);

  if (status && errno != ENOENT)
  goto finish;

libselinux/src/label_file.c +1 -1
-		status = process_file(path, "local", rec, prefix,
+		status = process_file(rec->spec_files[0], "local",

rec, prefix,
      rec-

Quoted 1 line

digest);

  if (status && errno != ENOENT)
  goto finish;

libselinux/src/label_file.c +0 -0
@@ -804,6 +846,12 @@ static void closef(struct selabel_handle *rec)
  	struct stem *stem;
  	unsigned int i;

libselinux/src/label_file.c +6 -0
+	if (!data)
+		return;
+
+	/* make sure successive ->func_close() calls are harmless */
+	rec->data = NULL;
+

  selabel_subs_fini(data->subs);
  selabel_subs_fini(data->dist_subs);

libselinux/src/label_internal.h +0 -0
index c55efb75..43b63513 100644
@@ -98,10 +98,11 @@ struct selabel_handle {
  	void *data;


  /*

libselinux/src/label_internal.h +0 -1
-	 * The main spec file used. Note for file contexts the local

and/or

libselinux/src/label_internal.h +1 -0
+	 * The main spec file(s) used. Note for file contexts the

local and/or
   * homedirs could also have been used to resolve a context. */

libselinux/src/label_internal.h +2 -1
-	char *spec_file;
+	size_t spec_files_len;
+	char **spec_files;


  /* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */ struct selabel_digest *digest;

#3 lore raw

PATCH 1/1 selinux: libselinux: Enable multiple input files to selabel_open.

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes that only one path will be specified as an option to selabel_open(). The split of platform and non-platform policy on device, however, will necessitate the loading of two disparate policy files. Rather than combining the files and then calling the existing API on a newly-formed file, just add the ability to specify multiple files to use. Order of opt specification to selabel_open matters.

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which lead to a fork with upstream, which we'd like to correct.

---
 libselinux/src/label.c          |  21 +++++---
 libselinux/src/label_db.c       |   4 +-
 libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-----------
 libselinux/src/label_internal.h |   5 +-
 libselinux/src/label_media.c    |   4 +-
 libselinux/src/label_x.c        |   4 +-
 6 files changed, 103 insertions(+), 39 deletions(-)
libselinux/src/label.c +15 -6
index 48f4d2d6..0dfa054c 100644
@@ -143,7 +143,11 @@ static int selabel_fini(struct selabel_handle *rec,
 			    struct selabel_lookup_rec *lr,
 			    int translating)
 {
-	if (compat_validate(rec, lr, rec->spec_file, 0))
+	char *path = NULL;
+
+	if (rec->spec_files)
+		path = rec->spec_files[0];
+	if (compat_validate(rec, lr, path, 0))
 		return -1;
 
 	if (translating && !lr->ctx_trans &&
@@ -226,11 +230,9 @@ struct selabel_handle *selabel_open(unsigned int backend,
 	rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
 
 	if ((*initfuncs[backend])(rec, opts, nopts)) {
-		free(rec->spec_file);
-		free(rec);
+		selabel_close(rec);
 		rec = NULL;
 	}
-
 out:
 	return rec;
 }
@@ -337,10 +339,17 @@ int selabel_digest(struct selabel_handle *rec,
 
 void selabel_close(struct selabel_handle *rec)
 {
+	size_t i;
+
+	if (rec->spec_files) {
+		for (i = 0; i < rec->spec_files_len; i++)
+			free(rec->spec_files[i]);
+		free(rec->spec_files);
+	}
 	if (rec->digest)
 		selabel_digest_fini(rec->digest);
-	rec->func_close(rec);
-	free(rec->spec_file);
+	if (rec->func_close)
+		rec->func_close(rec);
 	free(rec);
 }
 
libselinux/src/label_db.c +3 -1
index c46d0a1d..205ff5f4 100644
@@ -290,7 +290,9 @@ db_init(const struct selinux_opt *opts, unsigned nopts,
 		errno = EINVAL;
 		return NULL;
 	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);
 
 	/*
 	 * Parse for each lines
libselinux/src/label_file.c +76 -28

153 lines not on this page · raw message

libselinux/src/label_internal.h +3 -2
index c55efb75..43b63513 100644
@@ -98,10 +98,11 @@ struct selabel_handle {
 	void *data;
 
 	/*
-	 * The main spec file used. Note for file contexts the local and/or
+	 * The main spec file(s) used. Note for file contexts the local and/or
 	 * homedirs could also have been used to resolve a context.
 	 */
-	char *spec_file;
+	size_t spec_files_len;
+	char **spec_files;
 
 	/* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */
 	struct selabel_digest *digest;
libselinux/src/label_media.c +3 -1
index d202e5d5..f4a46ffe 100644
@@ -100,7 +100,9 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
 		errno = EINVAL;
 		return -1;
 	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);
 
 	/* 
 	 * Perform two passes over the specification file.
libselinux/src/label_x.c +3 -1
index 96745299..54ebd2eb 100644
@@ -127,7 +127,9 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
 		errno = EINVAL;
 		return -1;
 	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);
 
 	/* 
 	 * Perform two passes over the specification file.
Signature · 1 line
2.14.2.920.gcf0c67979c-goog
#4 lore raw
Quoted 286 lines · Daniel Cashman

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes that only one path will be specified as an option to selabel_open(). The split of platform and non-platform policy on device, however, will necessitate the loading of two disparate policy files. Rather than combining the files and then calling the existing API on a newly-formed file, just add the ability to specify multiple files to use. Order of opt specification to selabel_open matters.

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which lead to a fork with upstream, which we'd like to correct.

---
  libselinux/src/label.c          |  21 +++++---
  libselinux/src/label_db.c       |   4 +-
  libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-----------
  libselinux/src/label_internal.h |   5 +-
  libselinux/src/label_media.c    |   4 +-
  libselinux/src/label_x.c        |   4 +-
  6 files changed, 103 insertions(+), 39 deletions(-)
libselinux/src/label.c +15 -6
index 48f4d2d6..0dfa054c 100644
@@ -143,7 +143,11 @@ static int selabel_fini(struct selabel_handle *rec,
  			    struct selabel_lookup_rec *lr,
  			    int translating)
  {
-	if (compat_validate(rec, lr, rec->spec_file, 0))
+	char *path = NULL;
+
+	if (rec->spec_files)
+		path = rec->spec_files[0];
+	if (compat_validate(rec, lr, path, 0))
  		return -1;
 
  	if (translating && !lr->ctx_trans &&
@@ -226,11 +230,9 @@ struct selabel_handle *selabel_open(unsigned int backend,
  	rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
 
  	if ((*initfuncs[backend])(rec, opts, nopts)) {
-		free(rec->spec_file);
-		free(rec);
+		selabel_close(rec);
  		rec = NULL;
  	}
-
  out:
  	return rec;
  }
@@ -337,10 +339,17 @@ int selabel_digest(struct selabel_handle *rec,
 
  void selabel_close(struct selabel_handle *rec)
  {
+	size_t i;
+
+	if (rec->spec_files) {
+		for (i = 0; i < rec->spec_files_len; i++)
+			free(rec->spec_files[i]);
+		free(rec->spec_files);
+	}
  	if (rec->digest)
  		selabel_digest_fini(rec->digest);
-	rec->func_close(rec);
-	free(rec->spec_file);
+	if (rec->func_close)
+		rec->func_close(rec);
  	free(rec);
  }
 
libselinux/src/label_db.c +3 -1
index c46d0a1d..205ff5f4 100644
@@ -290,7 +290,9 @@ db_init(const struct selinux_opt *opts, unsigned nopts,
  		errno = EINVAL;
  		return NULL;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);
 
  	/*
  	 * Parse for each lines
libselinux/src/label_file.c +76 -28
index 560d8c3d..b3b36bc2 100644
@@ -709,28 +709,61 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
  		unsigned n)
  {
  	struct saved_data *data = (struct saved_data *)rec->data;
-	const char *path = NULL;
+	size_t num_paths = 0;
+	char **path = NULL;
  	const char *prefix = NULL;
-	int status = -1, baseonly = 0;
+	int status = -1;
+	size_t i;
+	bool baseonly = false;
+	bool path_provided;
 
  	/* Process arguments */
-	while (n--)
-		switch(opts[n].type) {
+	i = n;
+	while (i--)
+		switch(opts[i].type) {
  		case SELABEL_OPT_PATH:
-			path = opts[n].value;
+			num_paths++;
  			break;
  		case SELABEL_OPT_SUBSET:
-			prefix = opts[n].value;
+			prefix = opts[i].value;
  			break;
  		case SELABEL_OPT_BASEONLY:
-			baseonly = !!opts[n].value;
+			baseonly = !!opts[i].value;
  			break;
  		}
 
+	if (!num_paths) {
+		num_paths = 1;
+		path_provided = false;
+	} else {
+		path_provided = true;
+	}
+
+	path = calloc(num_paths, sizeof(*path));
+	if (path == NULL) {
+		goto finish;
+	}
+	rec->spec_files = path;
+	rec->spec_files_len = num_paths;
+
+	if (path_provided) {
+		for (i = 0; i < n; i++) {
+			switch(opts[i].type) {
+			case SELABEL_OPT_PATH:
+				*path = strdup(opts[i].value);
+				if (*path == NULL)
+					goto finish;
+				path++;
+				break;
+			default:
+				break;
+			}
+		}
+	}
  #if !defined(BUILD_HOST) && !defined(ANDROID)
  	char subs_file[PATH_MAX + 1];
  	/* Process local and distribution substitution files */
-	if (!path) {
+	if (!path_provided) {
  		status = selabel_subs_init(
  			selinux_file_context_subs_dist_path(),
  			rec->digest, &data->dist_subs);
@@ -740,43 +773,52 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
  			rec->digest, &data->subs);
  		if (status)
  			goto finish;
-		path = selinux_file_context_path();
+		rec->spec_files[0] = strdup(selinux_file_context_path());
+		if (rec->spec_files[0] == NULL)
+			goto finish;
  	} else {
-		snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path);
-		status = selabel_subs_init(subs_file, rec->digest,
+		for (i = 0; i < num_paths; i++) {
+			snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", rec->spec_files[i]);
+			status = selabel_subs_init(subs_file, rec->digest,
  					   &data->dist_subs);
-		if (status)
-			goto finish;
-		snprintf(subs_file, sizeof(subs_file), "%s.subs", path);
-		status = selabel_subs_init(subs_file, rec->digest,
+			if (status)
+				goto finish;
+			snprintf(subs_file, sizeof(subs_file), "%s.subs", rec->spec_files[i]);
+			status = selabel_subs_init(subs_file, rec->digest,
  					   &data->subs);
-		if (status)
-			goto finish;
+			if (status)
+				goto finish;
+		}
+	}
+#else
+	if (!path_provided) {
+		selinux_log(SELINUX_ERROR, "No path given to file labeling backend\n");
+		goto finish;
  	}
-
  #endif
-	rec->spec_file = strdup(path);
 
  	/*
-	 * The do detailed validation of the input and fill the spec array
+	 * Do detailed validation of the input and fill the spec array
  	 */
-	status = process_file(path, NULL, rec, prefix, rec->digest);
-	if (status)
-		goto finish;
-
-	if (rec->validating) {
-		status = nodups_specs(data, path);
+	for (i = 0; i < num_paths; i++) {
+		status = process_file(rec->spec_files[i], NULL, rec, prefix, rec->digest);
  		if (status)
  			goto finish;
+
+		if (rec->validating) {
+			status = nodups_specs(data, rec->spec_files[i]);
+			if (status)
+				goto finish;
+		}
  	}
 
  	if (!baseonly) {
-		status = process_file(path, "homedirs", rec, prefix,
+		status = process_file(rec->spec_files[0], "homedirs", rec, prefix,
  							    rec->digest);
  		if (status && errno != ENOENT)
  			goto finish;
 
-		status = process_file(path, "local", rec, prefix,
+		status = process_file(rec->spec_files[0], "local", rec, prefix,
  							    rec->digest);
  		if (status && errno != ENOENT)
  			goto finish;
@@ -804,6 +846,12 @@ static void closef(struct selabel_handle *rec)
  	struct stem *stem;
  	unsigned int i;
 
+	if (!data)
+		return;
+
+	/* make sure successive ->func_close() calls are harmless */
+	rec->data = NULL;
+
  	selabel_subs_fini(data->subs);
  	selabel_subs_fini(data->dist_subs);
 
libselinux/src/label_internal.h +3 -2
index c55efb75..43b63513 100644
@@ -98,10 +98,11 @@ struct selabel_handle {
  	void *data;
 
  	/*
-	 * The main spec file used. Note for file contexts the local and/or
+	 * The main spec file(s) used. Note for file contexts the local and/or
  	 * homedirs could also have been used to resolve a context.
  	 */
-	char *spec_file;
+	size_t spec_files_len;
+	char **spec_files;
 
  	/* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */
  	struct selabel_digest *digest;
libselinux/src/label_media.c +3 -1
index d202e5d5..f4a46ffe 100644
@@ -100,7 +100,9 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
  		errno = EINVAL;
  		return -1;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);
 
  	/*
  	 * Perform two passes over the specification file.
libselinux/src/label_x.c +0 -0
index 96745299..54ebd2eb 100644

libselinux/src/label_x.c static int init(struct selabel_handle *rec, const struct selinux_opt *opts, · line 135

Quoted 10 lines
libselinux/src/label_x.c +3 -1
@@ -127,7 +127,9 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
  		errno = EINVAL;
  		return -1;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);
 
  	/*
  	 * Perform two passes over the specification file.

Sorry, I completely overlooked the non-compilation of the other backends. I actually would like to see us integrate the upstream
tests and build so that we're not just flying by the android build system, but for now I think this is all that is required. I'll be sending a follow-up patch for the android backends that is basically AOSP commit: c75d01302f68d7714235600bd5b237bae2e8b893.

Thanks,
Dan

#5 lore raw
In reply to Daniel Cashman
Quoted 36 lines · Daniel Cashman

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes
that only one path will be specified as an option to selabel_open().  The split
of platform and non-platform policy on device, however, will necessitate the
loading of two disparate policy files.  Rather than combining the files and then
calling the existing API on a newly-formed file, just add the ability to specify
multiple files to use.  Order of opt specification to selabel_open matters.

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which lead to a fork with upstream, which we'd like to correct.

---
 libselinux/src/label.c          |  21 +++++--- libselinux/src/label_db.c       |   4 +- libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-
----------
 libselinux/src/label_internal.h |   5 +- libselinux/src/label_media.c    |   4 +- libselinux/src/label_x.c        |   4 +-

 6 files changed, 103 insertions(+), 39 deletions(-)
libselinux/src/label_db.c +0 -0
index c46d0a1d..205ff5f4 100644

libselinux/src/label_db.c db_init(const struct selinux_opt *opts, unsigned · line 295

Quoted 7 lines
libselinux/src/label_db.c +2 -1
@@ -290,7 +290,9 @@ db_init(const struct selinux_opt *opts, unsigned
 nopts,
  		errno = EINVAL;
  		return NULL;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))

Missing semicolon, and a check for NULL. Also should likely be sizeof(rec->spec_files[0]) or sizeof(char *); path isn't really relevant here.

libselinux/src/label_db.c db_init(const struct selinux_opt *opts, unsigned · line 296

Quoted 1 line
libselinux/src/label_db.c +1 -0
+	rec->spec_files[0] = strdup(path);

Ditto, although I see you didn't introduce that per se; we ought to fix it anyway.

Quoted 6 lines
libselinux/src/label_media.c +0 -0
index d202e5d5..f4a46ffe 100644

libselinux/src/label_media.c static int init(struct selabel_handle *rec, const · line 106

Quoted 8 lines
libselinux/src/label_media.c +3 -1
@@ -100,7 +100,9 @@ static int init(struct selabel_handle *rec, const
 struct selinux_opt *opts,
  		errno = EINVAL;
  		return -1;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);

Same as for label_db.c.

Quoted 8 lines


  /*
   * Perform two passes over the specification file.

libselinux/src/label_x.c +0 -0
index 96745299..54ebd2eb 100644

libselinux/src/label_x.c static int init(struct selabel_handle *rec, const · line 133

Quoted 8 lines
libselinux/src/label_x.c +3 -1
@@ -127,7 +127,9 @@ static int init(struct selabel_handle *rec, const
 struct selinux_opt *opts,
  		errno = EINVAL;
  		return -1;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);

And again.

Quoted 3 lines


  /*
   * Perform two passes over the specification file.

#6 lore raw
Quoted 81 lines · Stephen Smalley
Quoted 36 lines · Daniel Cashman

From: Dan Cashman <[email protected]>

The file_contexts labeling backend, specified in label_file.c, currently assumes
that only one path will be specified as an option to selabel_open().  The split
of platform and non-platform policy on device, however, will necessitate the
loading of two disparate policy files.  Rather than combining the files and then
calling the existing API on a newly-formed file, just add the ability to specify
multiple files to use.  Order of opt specification to selabel_open matters.

This corresponds to AOSP commit 50400d38203e4db08314168e60c281cc61a717a8, which lead to a fork with upstream, which we'd like to correct.

---
  libselinux/src/label.c          |  21 +++++---
  libselinux/src/label_db.c       |   4 +-
  libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-
----------
  libselinux/src/label_internal.h |   5 +-
  libselinux/src/label_media.c    |   4 +-
  libselinux/src/label_x.c        |   4 +-
  6 files changed, 103 insertions(+), 39 deletions(-)
libselinux/src/label_db.c +0 -0
index c46d0a1d..205ff5f4 100644

libselinux/src/label_db.c db_init(const struct selinux_opt *opts, unsigned · line 295

Quoted 7 lines
libselinux/src/label_db.c +2 -1
@@ -290,7 +290,9 @@ db_init(const struct selinux_opt *opts, unsigned
 nopts,
  		errno = EINVAL;
  		return NULL;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))

Missing semicolon, and a check for NULL. Also should likely be sizeof(rec->spec_files[0]) or sizeof(char *); path isn't really relevant here.

libselinux/src/label_db.c db_init(const struct selinux_opt *opts, unsigned · line 296

Quoted 1 line
libselinux/src/label_db.c +1 -0
+	rec->spec_files[0] = strdup(path);

Ditto, although I see you didn't introduce that per se; we ought to fix it anyway.

Quoted 6 lines
libselinux/src/label_media.c +0 -0
index d202e5d5..f4a46ffe 100644

libselinux/src/label_media.c static int init(struct selabel_handle *rec, const · line 106

Quoted 8 lines
libselinux/src/label_media.c +3 -1
@@ -100,7 +100,9 @@ static int init(struct selabel_handle *rec, const
 struct selinux_opt *opts,
  		errno = EINVAL;
  		return -1;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);

Same as for label_db.c.

Quoted 10 lines
libselinux/src/label_media.c +0 -0
  	/*
  	 * Perform two passes over the specification file.
libselinux/src/label_x.c +0 -0
index 96745299..54ebd2eb 100644
@@ -127,7 +127,9 @@ static int init(struct selabel_handle *rec, const
 struct selinux_opt *opts,
  		errno = EINVAL;
Quoted 12 lines

libselinux/src/label_x.c static int init(struct selabel_handle *rec, const · line 133

Quoted 6 lines
libselinux/src/label_x.c +3 -1
  		return -1;
  	}
-	rec->spec_file = strdup(path);
+	rec->spec_files_len = 1;
+	rec->spec_files = calloc(rec->spec_files_len, sizeof(path))
+	rec->spec_files[0] = strdup(path);

And again.

Quoted 3 lines
libselinux/src/label_x.c +0 -0
  	/*
  	 * Perform two passes over the specification file.

Well that was embarrassing. Twice bitten, thrice shy? I've now setup a fedora vm to at least test whether or not patches will build, so that's a good outcome of this. Submitted v3 to the list (rather than continuing this thread). Thanks for the review!

-Dan