Re: [PATCH 5/6 v7] libsepol: Add overflow checks to strs_* family of functions

Stephen Smalley <[email protected]>
Newsgroups org.kernel.vger.selinux
Message-ID <CAEjxPJ66ymZa93AgxV9jFHqKURJxcJX5N72zfEeGf0nDqXFq=Q@mail.gmail.com>
On Mon, Jul 6, 2026 at 10:39 AM James Carter <[email protected]> wrote:
>
> The strs_* family of functions provide convenient functions for
> handling an array of strings which is used in kernel_to_conf and
> kernel_to_cil. It uses the common idiom of "*= 2" to grow the
> array without any checks for overflow. There is also the function
> strs_add_at_index() which can cause multiple iterations of the
> "*= 2" idiom.
>
> Use the __builtin_mul_overflow() function that will do the
> multiplication while checking for overflow.
>
> In addition, the function strs_len_items() adds up the lengths
> of all the strings in the array which can overflow.
>
> Use the __builtin_add_overflow() function that will do the addition
> while checking for overflow.
>
> Signed-off-by: James Carter <[email protected]>

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

> ---
> v7: Remove uneccessary check for len > 0 before subtracting 1
>
>  libsepol/src/kernel_to_common.c | 29 ++++++++++++++++++++++-------
>  libsepol/src/kernel_to_conf.c   | 10 +++++++++-
>  2 files changed, 31 insertions(+), 8 deletions(-)
>
> diff --git a/libsepol/src/kernel_to_common.c b/libsepol/src/kernel_to_common.c
> index adb7b661..c7b6d73a 100644
> --- a/libsepol/src/kernel_to_common.c
> +++ b/libsepol/src/kernel_to_common.c
> @@ -117,13 +117,18 @@ int strs_add(struct strs *strs, char *s)
>         if (strs->num + 1 > strs->size) {
>                 char **new;
>                 size_t i = strs->size;
> -               strs->size *= 2;
> -               new = reallocarray(strs->list, strs->size, sizeof(char *));
> +               size_t new_size;
> +               if (__builtin_mul_overflow(strs->size, 2, &new_size)) {
> +                       ERR(NULL, "Overflow");
> +                       return -1;
> +               }
> +               new = reallocarray(strs->list, new_size, sizeof(char *));
>                 if (!new) {
>                         ERR(NULL, "Out of memory");
>                         return -1;
>                 }
>                 strs->list = new;
> +               strs->size = new_size;
>                 memset(&strs->list[i], 0, sizeof(char *) * (strs->size - i));
>         }
>
> @@ -172,15 +177,20 @@ int strs_add_at_index(struct strs *strs, char *s, size_t index)
>         if (index >= strs->size) {
>                 char **new;
>                 size_t i = strs->size;
> -               while (index >= strs->size) {
> -                       strs->size *= 2;
> +               size_t new_size = strs->size;
> +               while (index >= new_size) {
> +                       if (__builtin_mul_overflow(new_size, 2, &new_size)) {
> +                               ERR(NULL, "Overflow");
> +                               return -1;
> +                       }
>                 }
> -               new = reallocarray(strs->list, strs->size, sizeof(char *));
> +               new = reallocarray(strs->list, new_size, sizeof(char *));
>                 if (!new) {
>                         ERR(NULL, "Out of memory");
>                         return -1;
>                 }
>                 strs->list = new;
> +               strs->size = new_size;
>                 memset(&strs->list[i], 0, sizeof(char *) * (strs->size - i));
>         }
>
> @@ -229,7 +239,9 @@ size_t strs_len_items(const struct strs *strs)
>         for (i = 0; i < strs->num; i++) {
>                 if (!strs->list[i])
>                         continue;
> -               len += strlen(strs->list[i]);
> +               if (__builtin_add_overflow(len, strlen(strs->list[i]), &len)) {
> +                       return SIZE_MAX;
> +               }
>         }
>
>         return len;
> @@ -248,7 +260,10 @@ char *strs_to_str(const struct strs *strs)
>         }
>
>         /* strs->num added because either ' ' or '\0' follows each item */
> -       len = strs_len_items(strs) + strs->num;
> +       if (__builtin_add_overflow(strs_len_items(strs), strs->num, &len)) {
> +               ERR(NULL, "Overflow");
> +               goto exit;
> +       }
>         str = malloc(len);
>         if (!str) {
>                 ERR(NULL, "Out of memory");
> diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c
> index 3e6bcb33..9bfe5b38 100644
> --- a/libsepol/src/kernel_to_conf.c
> +++ b/libsepol/src/kernel_to_conf.c
> @@ -1663,7 +1663,15 @@ static char *attr_strs_to_str(struct strs *strs)
>         }
>
>         /* 2*strs->num - 1 because ", " follows all but last attr (followed by '\0') */
> -       len = strs_len_items(strs) + 2 * strs->num - 1;
> +       if (__builtin_mul_overflow(strs->num, 2, &len)) {
> +               ERR(NULL, "Overflow");
> +               goto exit;
> +       }
> +       len -= 1;
> +       if (__builtin_add_overflow(len, strs_len_items(strs), &len)) {
> +               ERR(NULL, "Overflow");
> +               goto exit;
> +       }
>         str = malloc(len);
>         if (!str) {
>                 ERR(NULL, "Out of memory");
> --
> 2.55.0
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.