Re: [PATCH v3] selinux: libselinux: Enable multiple input files to selabel_open.

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

 



On Thu, Oct 19, 2017 at 7:26 AM, Stephen Smalley <sds@xxxxxxxxxxxxx> wrote:
> On Tue, 2017-10-17 at 09:33 -0700, Daniel Cashman wrote:
>> From: Dan Cashman <dcashman@xxxxxxxxxx>
>>
>> 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.
>>
>> Signed-off-by: Dan Cashman <dcashman@xxxxxxxxxxx>
>> ---
>>  libselinux/src/label.c          |  21 +++++---
>>  libselinux/src/label_db.c       |  13 ++++-
>>  libselinux/src/label_file.c     | 104 +++++++++++++++++++++++++++++-
>> ----------
>>  libselinux/src/label_internal.h |   5 +-
>>  libselinux/src/label_media.c    |  10 +++-
>>  libselinux/src/label_x.c        |  10 +++-
>>  6 files changed, 124 insertions(+), 39 deletions(-)
>>
>> diff --git a/libselinux/src/label.c b/libselinux/src/label.c
>> index 48f4d2d6..0dfa054c 100644
>> --- a/libselinux/src/label.c
>> +++ b/libselinux/src/label.c
>> @@ -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);
>>  }
>>
>> diff --git a/libselinux/src/label_db.c b/libselinux/src/label_db.c
>> index c46d0a1d..9a35abea 100644
>> --- a/libselinux/src/label_db.c
>> +++ b/libselinux/src/label_db.c
>> @@ -290,7 +290,18 @@ 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(rec-
>> >spec_files[0]));
>> +     if (!rec->spec_files) {
>> +             free(catalog);
>> +             return NULL;
>> +     }
>> +     rec->spec_files[0] = strdup(path);
>> +     if (!rec->spec_files[0]) {
>> +             free(catalog);
>> +             free(rec->spec_files);
>> +             return NULL;
>> +     }
>>
>>       /*
>>        * Parse for each lines
>> diff --git a/libselinux/src/label_file.c
>> b/libselinux/src/label_file.c
>> index 560d8c3d..b3b36bc2 100644
>> --- a/libselinux/src/label_file.c
>> +++ b/libselinux/src/label_file.c
>> @@ -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);
>
> Perhaps surprisingly, opts[i].value can be NULL here and some callers
> rely on that.  After applying your patch, coreutils, selabel_lookup,
> and other userspace programs all seg fault as a result.  The use case
> is programs where the selinux_opt structure is declared with a
> SELABEL_OPT_PATH entry whose value is subsequently filled in, and left
> NULL if they want to use the default path for file_contexts.
> Internally, libselinux also does this from the
> matchpathcon_init_prefix() function.
>
> In any event, you need to handle this case.
>

Poor Stephen has turned into your test bot :-)

Does any of the test suite exercise this? Maybe make a PR
on github first to get Travis to test these?

Stephen can you share with how your testing this so Dan can follow
suit?


>> +                             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);
>>
>> diff --git a/libselinux/src/label_internal.h
>> b/libselinux/src/label_internal.h
>> index c55efb75..43b63513 100644
>> --- a/libselinux/src/label_internal.h
>> +++ b/libselinux/src/label_internal.h
>> @@ -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;
>> diff --git a/libselinux/src/label_media.c
>> b/libselinux/src/label_media.c
>> index d202e5d5..34260cbb 100644
>> --- a/libselinux/src/label_media.c
>> +++ b/libselinux/src/label_media.c
>> @@ -100,7 +100,15 @@ 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(rec-
>> >spec_files[0]));
>> +     if (!rec->spec_files)
>> +             return -1;
>> +     rec->spec_files[0] = strdup(path);
>> +     if (!rec->spec_files[0]) {
>> +             free(rec->spec_files);
>> +             return -1;
>> +     }
>>
>>       /*
>>        * Perform two passes over the specification file.
>> diff --git a/libselinux/src/label_x.c b/libselinux/src/label_x.c
>> index 96745299..fafe034a 100644
>> --- a/libselinux/src/label_x.c
>> +++ b/libselinux/src/label_x.c
>> @@ -127,7 +127,15 @@ 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(rec-
>> >spec_files[0]));
>> +     if (!rec->spec_files)
>> +             return -1;
>> +     rec->spec_files[0] = strdup(path);
>> +     if (!rec->spec_files[0]) {
>> +             free(rec->spec_files);
>> +             return -1;
>> +     }
>>
>>       /*
>>        * Perform two passes over the specification file.




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

  Powered by Linux