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 9:25 AM, William Roberts
<bill.c.roberts@xxxxxxxxx> wrote:
> 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?

Looks like Stephen tried that to see what would happen, and it incorrectly
passed indicating we need more tests:
https://github.com/SELinuxProject/selinux/pull/67

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

Looks like we need to add whatever your doing.

>
>>> +                             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.



-- 
Respectfully,

William C Roberts




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

  Powered by Linux