Re: [PATCH v2 2/2] libselinux: support multiple context files for the file backend

Stephen Smalley <[email protected]> Thu, 23 Jul 2026 10:03:38 -0400
Newsgroups org.kernel.vger.selinux
Message-ID <CAEjxPJ6_ZBTP=wVnF3=cW1NNQAAsnDLFG7FiA0rv0r_-nLCZUA@mail.gmail.com>
On Wed, Jul 22, 2026 at 11:11 PM Thiébaud Weksteen <[email protected]> wrote:
>
> Update the file labeling backend to support specifying multiple
> SELABEL_OPT_PATH options in selabel_open().
>
> All provided paths are stored in rec->spec_files and processed during
> initialization. Derived files, such as substitutions (.subs, .subs_dist)
> and auxiliary contexts (.homedirs, .local), continue to be based on the
> first path (or default selinux_file_context_path()) when enabled.
>
> Duplicate checking is only performed within each context file. The current
> behavior expects the ability for a later file to overwrite a previous
> declaration (e.g., .local).
>
> Signed-off-by: Thiébaud Weksteen <[email protected]>
> ---
> Changes since v1:
> - Restore nodups_spec_node, ignore duplicates across files.
> - Change num_paths type to uint8_t and check for overflow.
> - Check for NULL before strdup any path.
> - Use num_paths and num_paths+1 for homedirs and local.
>
>  libselinux/src/label_file.c | 139 ++++++++++++++++++++++++------------
>  1 file changed, 92 insertions(+), 47 deletions(-)
>
> diff --git a/libselinux/src/label_file.c b/libselinux/src/label_file.c
> index d91e1462..02bd6f5d 100644
> --- a/libselinux/src/label_file.c
> +++ b/libselinux/src/label_file.c
> @@ -126,13 +127,16 @@ static int nodups_spec_node(const struct spec_node *node, const char *path)
>                             node1->file_kind != node2->file_kind)
>                                 continue;
>
> +                       if (node1->inputno != node2->inputno)
> +                               continue;
> +
>                         rc = -1;
>                         errno = EINVAL;
>                         if (strcmp(node1->lr.ctx_raw, node2->lr.ctx_raw) != 0) {
>                                 COMPAT_LOG(
>                                         SELINUX_ERROR,
>                                         "%s: Multiple different specifications for %s %s  (%s and %s).\n",
> -                                       path,
> +                                       rec->spec_files[node1->inputno],

Here and below if we hit this error within .local or .homedirs we will
have an OOB read on rec->spec_files.

> @@ -1511,10 +1526,50 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
>                 }
>         }
>
> +       /* If no paths were provided, we will use the default path or fail,
> +        * depending on the target. */
> +       if (!path_provided) {
> +#if !defined(BUILD_HOST) && !defined(ANDROID)
> +               num_paths = 1;
> +#else
> +               selinux_log(SELINUX_ERROR,
> +                           "No path given to file labeling backend\n");
> +               errno = EINVAL;
> +               return -1;
> +#endif
> +       }
> +
> +       /* If !baseonly, we reserve the last 2 indexes for homedirs and local.
> +        * Let's make sure we don't wrap */
> +       if (!baseonly && num_paths > UINT8_MAX - 1) {

This is never true since you capped num_paths at 254 above (return on
UINT8_MAX).