Re: [PATCH v3 1/2] libselinux: support multiple spec_files

Stephen Smalley <[email protected]> Mon, 27 Jul 2026 09:30:00 -0400
Newsgroups org.kernel.vger.selinux
Message-ID <CAEjxPJ5vH0qm8_RduSnOX2EU_2fz-zAoCPNLsETdXf5X+NUOfA@mail.gmail.com>
On Sun, Jul 26, 2026 at 9:39 PM Thiébaud Weksteen <[email protected]> wrote:
>
> Update the existing backends to potentially allocate multiple
> spec_files. This commit simply adds a level of indirection but does not
> change any current behaviour. It will facilitate the gradual migration
> of backends to multiple context files.
>
> In selabel_fini(), compat_validate() is updated to use the first
> spec_file only, for legacy validation error reporting. selabel_open() is
> already performing context validation if requested against individual
> file paths (see insert_spec).
>
> Signed-off-by: Thiébaud Weksteen <[email protected]>

You can keep Acked-by/Reviewed-by/Tested-by when the patch is unchanged.

Acked-by: Stephen Smalley <[email protected]>

> ---
> No changes since v2
>
>  libselinux/src/label.c          | 10 ++++++++--
>  libselinux/src/label_db.c       | 11 +++++++++--
>  libselinux/src/label_file.c     |  8 ++++++--
>  libselinux/src/label_internal.h |  5 +++--
>  libselinux/src/label_media.c    |  8 +++++++-
>  libselinux/src/label_x.c        |  8 +++++++-
>  6 files changed, 40 insertions(+), 10 deletions(-)
>
> diff --git a/libselinux/src/label.c b/libselinux/src/label.c
> index 991b9769..4a97d3bc 100644
> --- a/libselinux/src/label.c
> +++ b/libselinux/src/label.c
> @@ -162,7 +162,7 @@ static int selabel_fini(const struct selabel_handle *rec,
>         char *ctx_trans;
>         int rc;
>
> -       if (compat_validate(rec, lr, rec->spec_file, lr->lineno))
> +       if (compat_validate(rec, lr, rec->spec_files[0], lr->lineno))
>                 return -1;
>
>         if (!translating)
> @@ -398,11 +398,17 @@ int selabel_digest(struct selabel_handle *rec, unsigned char **digest,
>
>  void selabel_close(struct selabel_handle *rec)
>  {
> +       size_t i;
> +
>         if (rec->digest)
>                 selabel_digest_fini(rec->digest);
>         if (rec->func_close)
>                 rec->func_close(rec);
> -       free(rec->spec_file);
> +       if (rec->spec_files) {
> +               for (i = 0; i < rec->spec_files_len; i++)
> +                       free(rec->spec_files[i]);
> +               free(rec->spec_files);
> +       }
>         free(rec);
>  }
>
> diff --git a/libselinux/src/label_db.c b/libselinux/src/label_db.c
> index bafa9328..53731470 100644
> --- a/libselinux/src/label_db.c
> +++ b/libselinux/src/label_db.c
> @@ -302,12 +302,19 @@ static catalog_t *db_init(const struct selinux_opt *opts, unsigned nopts,
>                 errno = EINVAL;
>                 return NULL;
>         }
> -       rec->spec_file = strdup(path);
> -       if (!rec->spec_file) {
> +       rec->spec_files = calloc(1, sizeof(*rec->spec_files));
> +       if (!rec->spec_files) {
>                 free(catalog);
>                 fclose(filp);
>                 return NULL;
>         }
> +       rec->spec_files[0] = strdup(path);
> +       if (!rec->spec_files[0]) {
> +               free(catalog);
> +               fclose(filp);
> +               return NULL;
> +       }
> +       rec->spec_files_len = 1;
>
>         /*
>          * Parse for each lines
> diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> index 0c0499eb..d91e1462 100644
> --- a/libselinux/src/label_file.c
> +++ b/libselinux/src/label_file.c
> @@ -1549,9 +1549,13 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
>                 goto finish;
>         }
>
> -       rec->spec_file = strdup(path);
> -       if (!rec->spec_file)
> +       rec->spec_files = calloc(1, sizeof(*rec->spec_files));
> +       if (!rec->spec_files)
>                 goto finish;
> +       rec->spec_files[0] = strdup(path);
> +       if (!rec->spec_files[0])
> +               goto finish;
> +       rec->spec_files_len = 1;
>
>         /*
>          * The do detailed validation of the input and fill the spec array
> diff --git a/libselinux/src/label_internal.h b/libselinux/src/label_internal.h
> index 4ff39d96..d54053df 100644
> --- a/libselinux/src/label_internal.h
> +++ b/libselinux/src/label_internal.h
> @@ -96,10 +96,11 @@ struct selabel_handle {
>         void *data;
>
>         /*
> -        * The main spec file used. Note for file contexts the local and/or
> +        * The spec files 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 957fcfd3..f315abc3 100644
> --- a/libselinux/src/label_media.c
> +++ b/libselinux/src/label_media.c
> @@ -109,7 +109,13 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
>                 errno = EINVAL;
>                 goto finish;
>         }
> -       rec->spec_file = strdup(path);
> +       rec->spec_files = calloc(1, sizeof(*rec->spec_files));
> +       if (!rec->spec_files)
> +               goto finish;
> +       rec->spec_files[0] = strdup(path);
> +       if (!rec->spec_files[0])
> +               goto finish;
> +       rec->spec_files_len = 1;
>
>         /*
>          * Perform two passes over the specification file.
> diff --git a/libselinux/src/label_x.c b/libselinux/src/label_x.c
> index 0c525bfc..b528a019 100644
> --- a/libselinux/src/label_x.c
> +++ b/libselinux/src/label_x.c
> @@ -139,7 +139,13 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
>                 errno = EINVAL;
>                 goto finish;
>         }
> -       rec->spec_file = strdup(path);
> +       rec->spec_files = calloc(1, sizeof(*rec->spec_files));
> +       if (!rec->spec_files)
> +               goto finish;
> +       rec->spec_files[0] = strdup(path);
> +       if (!rec->spec_files[0])
> +               goto finish;
> +       rec->spec_files_len = 1;
>
>         /*
>          * Perform two passes over the specification file.
> --
> 2.55.0.229.g6434b31f56-goog
>