Re: [PATCH] libsepol: Cap max depth and processed nodes for cil_tree_walk()

James Carter <[email protected]> Mon, 3 Aug 2026 11:12:39 -0400
Newsgroups org.kernel.vger.selinux
Message-ID <CAP+JOzQ5n-5S4BpMfZD7d7jWQZw6fw4iON6oV+dboc==+mibCg@mail.gmail.com>
On Mon, Aug 3, 2026 at 10:24=E2=80=AFAM Stephen Smalley
<[email protected]> wrote:
>
> Cap the max tree depth and number of processed nodes for
> cil_tree_walk() to avoid stack overflows and OOM conditions.
>
> Reported-by: oss-fuzz (issue 471608794)
> Signed-off-by: Stephen Smalley <[email protected]>

Acked-by: James Carter <[email protected]>

> ---
>  libsepol/cil/src/cil_tree.c | 65 ++++++++++++++++++++++++++++++-------
>  1 file changed, 53 insertions(+), 12 deletions(-)
>
> diff --git a/libsepol/cil/src/cil_tree.c b/libsepol/cil/src/cil_tree.c
> index 63dd33dd..17f19256 100644
> --- a/libsepol/cil/src/cil_tree.c
> +++ b/libsepol/cil/src/cil_tree.c
> @@ -41,6 +41,9 @@
>  #include "cil_parser.h"
>  #include "cil_strpool.h"
>
> +#define MAX_DEPTH (256)
> +#define MAX_NODES (1U << 20)
> +
>  struct cil_tree_node *cil_tree_get_next_path(struct cil_tree_node *node,
>                                              char **info_kind,
>                                              uint32_t *hll_line, char **p=
ath)
> @@ -311,25 +314,41 @@ void cil_tree_node_remove(struct cil_tree_node *nod=
e)
>     extra_args:               any additional data to be passed to the hel=
per functions
>  */
>
> +static int cil_tree_walk_helper(
> +       struct cil_tree_node *node,
> +       int (*process_node)(struct cil_tree_node *node, uint32_t *finishe=
d,
> +                           void *extra_args),
> +       int (*first_child)(struct cil_tree_node *node, void *extra_args),
> +       int (*last_child)(struct cil_tree_node *node, void *extra_args),
> +       void *extra_args, unsigned depth, unsigned *processed);
> +
>  static int cil_tree_walk_core(
>         struct cil_tree_node *node,
>         int (*process_node)(struct cil_tree_node *node, uint32_t *finishe=
d,
>                             void *extra_args),
>         int (*first_child)(struct cil_tree_node *node, void *extra_args),
>         int (*last_child)(struct cil_tree_node *node, void *extra_args),
> -       void *extra_args)
> +       void *extra_args, unsigned depth, unsigned *processed)
>  {
>         int rc =3D SEPOL_ERR;
>
>         while (node) {
>                 uint32_t finished =3D CIL_TREE_SKIP_NOTHING;
>
> +               if (*processed >=3D MAX_NODES) {
> +                       cil_tree_log(node, CIL_ERR,
> +                                    "Exceeded max tree processed nodes (=
%u)",
> +                                    MAX_NODES);
> +                       return SEPOL_ERR;
> +               }
> +
>                 if (process_node !=3D NULL) {
>                         rc =3D (*process_node)(node, &finished, extra_arg=
s);
>                         if (rc !=3D SEPOL_OK) {
>                                 cil_tree_log(node, CIL_INFO, "Problem");
>                                 return rc;
>                         }
> +                       (*processed)++;
>                 }
>
>                 if (finished & CIL_TREE_SKIP_NEXT) {
> @@ -337,8 +356,10 @@ static int cil_tree_walk_core(
>                 }
>
>                 if (node->cl_head !=3D NULL && !(finished & CIL_TREE_SKIP=
_HEAD)) {
> -                       rc =3D cil_tree_walk(node, process_node, first_ch=
ild,
> -                                          last_child, extra_args);
> +                       rc =3D cil_tree_walk_helper(node, process_node,
> +                                                 first_child, last_child=
,
> +                                                 extra_args, depth + 1,
> +                                                 processed);
>                         if (rc !=3D SEPOL_OK) {
>                                 return rc;
>                         }
> @@ -350,17 +371,22 @@ static int cil_tree_walk_core(
>         return SEPOL_OK;
>  }
>
> -int cil_tree_walk(struct cil_tree_node *node,
> -                 int (*process_node)(struct cil_tree_node *node,
> -                                     uint32_t *finished, void *extra_arg=
s),
> -                 int (*first_child)(struct cil_tree_node *node,
> -                                    void *extra_args),
> -                 int (*last_child)(struct cil_tree_node *node,
> -                                   void *extra_args),
> -                 void *extra_args)
> +static int cil_tree_walk_helper(
> +       struct cil_tree_node *node,
> +       int (*process_node)(struct cil_tree_node *node, uint32_t *finishe=
d,
> +                           void *extra_args),
> +       int (*first_child)(struct cil_tree_node *node, void *extra_args),
> +       int (*last_child)(struct cil_tree_node *node, void *extra_args),
> +       void *extra_args, unsigned depth, unsigned *processed)
>  {
>         int rc =3D SEPOL_ERR;
>
> +       if (depth >=3D MAX_DEPTH) {
> +               cil_tree_log(node, CIL_ERR, "Exceeded max tree depth (%u)=
",
> +                            MAX_DEPTH);
> +               return SEPOL_ERR;
> +       }
> +
>         if (!node || !node->cl_head) {
>                 return SEPOL_OK;
>         }
> @@ -374,7 +400,7 @@ int cil_tree_walk(struct cil_tree_node *node,
>         }
>
>         rc =3D cil_tree_walk_core(node->cl_head, process_node, first_chil=
d,
> -                               last_child, extra_args);
> +                               last_child, extra_args, depth, processed)=
;
>         if (rc !=3D SEPOL_OK) {
>                 return rc;
>         }
> @@ -389,3 +415,18 @@ int cil_tree_walk(struct cil_tree_node *node,
>
>         return SEPOL_OK;
>  }
> +
> +int cil_tree_walk(struct cil_tree_node *node,
> +                 int (*process_node)(struct cil_tree_node *node,
> +                                     uint32_t *finished, void *extra_arg=
s),
> +                 int (*first_child)(struct cil_tree_node *node,
> +                                    void *extra_args),
> +                 int (*last_child)(struct cil_tree_node *node,
> +                                   void *extra_args),
> +                 void *extra_args)
> +{
> +       unsigned processed =3D 0;
> +
> +       return cil_tree_walk_helper(node, process_node, first_child, last=
_child,
> +                                   extra_args, 0, &processed);
> +}
> --
> 2.55.0
>