diff mbox series

[RFC,v2,10/36] libsepol: add checks for read sizes

Message ID 20211105154542.38434-11-cgzones@googlemail.com (mailing list archive)
State Superseded
Headers show
Series libsepol: add fuzzer for reading binary policies | expand

Commit Message

Christian Göttsche Nov. 5, 2021, 3:45 p.m. UTC
Add checks for invalid read sizes from a binary policy to guard
allocations.

The common and class permission counts needs to be limited more strict
otherwise a too high count of common or class permissions can lead to
permission values with a too high value, which can lead to overflows
in shift operations.

In the fuzzer build the value will also be bounded to avoid oom reports.

    ==29857== ERROR: libFuzzer: out-of-memory (malloc(17179868160))
       To change the out-of-memory limit use -rss_limit_mb=<N>

        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
        #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
        #8 0x580b5d in mallocarray ./libsepol/src/./private.h:93:9
        #9 0x57c2ed in scope_read ./libsepol/src/policydb.c:4120:7
        #10 0x576b0d in policydb_read ./libsepol/src/policydb.c:4462:9
        #11 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
        #12 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #13 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #14 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #15 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #16 0x7ffad6e107ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #17 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

    ==19462== ERROR: libFuzzer: out-of-memory (malloc(18253611008))
       To change the out-of-memory limit use -rss_limit_mb=<N>

        #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
        #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
        #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
        #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
        #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
        #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
        #6 0x4aa999 in __asan::asan_calloc(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa999)
        #7 0x525b63 in __interceptor_calloc (./out/binpolicy-fuzzer+0x525b63)
        #8 0x570938 in policydb_index_others ./libsepol/src/policydb.c:1245:6
        #9 0x5771f3 in policydb_read ./src/policydb.c:4481:6
        #10 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
        #11 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
        #12 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
        #13 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
        #14 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
        #15 0x7f4d933157ec in __libc_start_main csu/../csu/libc-start.c:332:16
        #16 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
 libsepol/src/policydb.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Comments

James Carter Nov. 9, 2021, 6:46 p.m. UTC | #1
On Fri, Nov 5, 2021 at 12:11 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> Add checks for invalid read sizes from a binary policy to guard
> allocations.
>
> The common and class permission counts needs to be limited more strict
> otherwise a too high count of common or class permissions can lead to
> permission values with a too high value, which can lead to overflows
> in shift operations.
>
> In the fuzzer build the value will also be bounded to avoid oom reports.
>
>     ==29857== ERROR: libFuzzer: out-of-memory (malloc(17179868160))
>        To change the out-of-memory limit use -rss_limit_mb=<N>
>
>         #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
>         #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
>         #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
>         #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
>         #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
>         #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
>         #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
>         #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
>         #8 0x580b5d in mallocarray ./libsepol/src/./private.h:93:9
>         #9 0x57c2ed in scope_read ./libsepol/src/policydb.c:4120:7
>         #10 0x576b0d in policydb_read ./libsepol/src/policydb.c:4462:9
>         #11 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
>         #12 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
>         #13 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
>         #14 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
>         #15 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
>         #16 0x7ffad6e107ec in __libc_start_main csu/../csu/libc-start.c:332:16
>         #17 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)
>
>     ==19462== ERROR: libFuzzer: out-of-memory (malloc(18253611008))
>        To change the out-of-memory limit use -rss_limit_mb=<N>
>
>         #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
>         #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
>         #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
>         #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
>         #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
>         #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
>         #6 0x4aa999 in __asan::asan_calloc(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa999)
>         #7 0x525b63 in __interceptor_calloc (./out/binpolicy-fuzzer+0x525b63)
>         #8 0x570938 in policydb_index_others ./libsepol/src/policydb.c:1245:6
>         #9 0x5771f3 in policydb_read ./src/policydb.c:4481:6
>         #10 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
>         #11 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
>         #12 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
>         #13 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
>         #14 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
>         #15 0x7f4d933157ec in __libc_start_main csu/../csu/libc-start.c:332:16
>         #16 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)
>
> Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> ---
>  libsepol/src/policydb.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> index dcea1807..1408405d 100644
> --- a/libsepol/src/policydb.c
> +++ b/libsepol/src/policydb.c
> @@ -2103,6 +2103,8 @@ static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
>         if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
>                 goto bad;
>         comdatum->permissions.nprim = le32_to_cpu(buf[2]);
> +       if (comdatum->permissions.nprim > 32)

Should use PERM_SYMTAB_SIZE here (like in patch 22).

> +               goto bad;
>         nel = le32_to_cpu(buf[3]);
>
>         key = malloc(len + 1);
> @@ -2251,6 +2253,8 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
>         if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
>                 goto bad;
>         cladatum->permissions.nprim = le32_to_cpu(buf[3]);
> +       if (cladatum->permissions.nprim > 32)

Same here.


> +               goto bad;
>         nel = le32_to_cpu(buf[4]);
>
>         ncons = le32_to_cpu(buf[5]);
> @@ -3980,6 +3984,8 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
>                 if (rc < 0)
>                         return -1;
>                 nprim = le32_to_cpu(buf[0]);
> +               if (is_saturated(nprim))
> +                       return -1;
>                 nel = le32_to_cpu(buf[1]);
>                 for (j = 0; j < nel; j++) {
>                         if (read_f[i] (p, decl->symtab[i].table, fp)) {
> @@ -4106,7 +4112,7 @@ static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
>                 goto cleanup;
>         scope->scope = le32_to_cpu(buf[0]);
>         scope->decl_ids_len = le32_to_cpu(buf[1]);
> -       if (scope->decl_ids_len == 0) {
> +       if (zero_or_saturated(scope->decl_ids_len)) {
>                 ERR(fp->handle, "invalid scope with no declaration");
>                 goto cleanup;
>         }
> @@ -4396,6 +4402,8 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
>                 if (rc < 0)
>                         goto bad;
>                 nprim = le32_to_cpu(buf[0]);
> +               if (is_saturated(nprim))
> +                       goto bad;
>                 nel = le32_to_cpu(buf[1]);
>                 if (nel && !nprim) {
>                         ERR(fp->handle, "unexpected items in symbol table with no symbol");
> --
> 2.33.1
>
Christian Göttsche Nov. 9, 2021, 6:58 p.m. UTC | #2
On Tue, 9 Nov 2021 at 19:46, James Carter <jwcart2@gmail.com> wrote:
>
> On Fri, Nov 5, 2021 at 12:11 PM Christian Göttsche
> <cgzones@googlemail.com> wrote:
> >
> > Add checks for invalid read sizes from a binary policy to guard
> > allocations.
> >
> > The common and class permission counts needs to be limited more strict
> > otherwise a too high count of common or class permissions can lead to
> > permission values with a too high value, which can lead to overflows
> > in shift operations.
> >
> > In the fuzzer build the value will also be bounded to avoid oom reports.
> >
> >     ==29857== ERROR: libFuzzer: out-of-memory (malloc(17179868160))
> >        To change the out-of-memory limit use -rss_limit_mb=<N>
> >
> >         #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
> >         #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
> >         #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
> >         #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
> >         #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
> >         #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
> >         #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
> >         #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
> >         #8 0x580b5d in mallocarray ./libsepol/src/./private.h:93:9
> >         #9 0x57c2ed in scope_read ./libsepol/src/policydb.c:4120:7
> >         #10 0x576b0d in policydb_read ./libsepol/src/policydb.c:4462:9
> >         #11 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
> >         #12 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
> >         #13 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
> >         #14 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
> >         #15 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
> >         #16 0x7ffad6e107ec in __libc_start_main csu/../csu/libc-start.c:332:16
> >         #17 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)
> >
> >     ==19462== ERROR: libFuzzer: out-of-memory (malloc(18253611008))
> >        To change the out-of-memory limit use -rss_limit_mb=<N>
> >
> >         #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
> >         #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
> >         #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
> >         #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
> >         #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
> >         #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
> >         #6 0x4aa999 in __asan::asan_calloc(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa999)
> >         #7 0x525b63 in __interceptor_calloc (./out/binpolicy-fuzzer+0x525b63)
> >         #8 0x570938 in policydb_index_others ./libsepol/src/policydb.c:1245:6
> >         #9 0x5771f3 in policydb_read ./src/policydb.c:4481:6
> >         #10 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
> >         #11 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
> >         #12 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
> >         #13 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
> >         #14 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
> >         #15 0x7f4d933157ec in __libc_start_main csu/../csu/libc-start.c:332:16
> >         #16 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)
> >
> > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> > ---
> >  libsepol/src/policydb.c | 10 +++++++++-
> >  1 file changed, 9 insertions(+), 1 deletion(-)
> >
> > diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> > index dcea1807..1408405d 100644
> > --- a/libsepol/src/policydb.c
> > +++ b/libsepol/src/policydb.c
> > @@ -2103,6 +2103,8 @@ static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
> >         if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
> >                 goto bad;
> >         comdatum->permissions.nprim = le32_to_cpu(buf[2]);
> > +       if (comdatum->permissions.nprim > 32)
>
> Should use PERM_SYMTAB_SIZE here (like in patch 22).

I thought about that, but it seemed a bit unrelated.
In patch 25 (https://patchwork.kernel.org/project/selinux/patch/20211105154542.38434-26-cgzones@googlemail.com/)
the number of permissions in commons and classes is checked against
the logical limit (which is imposed by the implementation via a bitset
on a 32 bit integer).
The check here is to prevent overflows on subsequent left-shifts by
the checked value on a 32 bit integer.
Maybe `sizeof(uint32_t)` is more expressive?
However I do not object your comment, so I fine to change to PERM_SYMTAB_SIZE.

> > +               goto bad;
> >         nel = le32_to_cpu(buf[3]);
> >
> >         key = malloc(len + 1);
> > @@ -2251,6 +2253,8 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
> >         if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
> >                 goto bad;
> >         cladatum->permissions.nprim = le32_to_cpu(buf[3]);
> > +       if (cladatum->permissions.nprim > 32)
>
> Same here.
>
>
> > +               goto bad;
> >         nel = le32_to_cpu(buf[4]);
> >
> >         ncons = le32_to_cpu(buf[5]);
> > @@ -3980,6 +3984,8 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
> >                 if (rc < 0)
> >                         return -1;
> >                 nprim = le32_to_cpu(buf[0]);
> > +               if (is_saturated(nprim))
> > +                       return -1;
> >                 nel = le32_to_cpu(buf[1]);
> >                 for (j = 0; j < nel; j++) {
> >                         if (read_f[i] (p, decl->symtab[i].table, fp)) {
> > @@ -4106,7 +4112,7 @@ static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
> >                 goto cleanup;
> >         scope->scope = le32_to_cpu(buf[0]);
> >         scope->decl_ids_len = le32_to_cpu(buf[1]);
> > -       if (scope->decl_ids_len == 0) {
> > +       if (zero_or_saturated(scope->decl_ids_len)) {
> >                 ERR(fp->handle, "invalid scope with no declaration");
> >                 goto cleanup;
> >         }
> > @@ -4396,6 +4402,8 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
> >                 if (rc < 0)
> >                         goto bad;
> >                 nprim = le32_to_cpu(buf[0]);
> > +               if (is_saturated(nprim))
> > +                       goto bad;
> >                 nel = le32_to_cpu(buf[1]);
> >                 if (nel && !nprim) {
> >                         ERR(fp->handle, "unexpected items in symbol table with no symbol");
> > --
> > 2.33.1
> >
James Carter Nov. 9, 2021, 7:17 p.m. UTC | #3
On Tue, Nov 9, 2021 at 1:59 PM Christian Göttsche
<cgzones@googlemail.com> wrote:
>
> On Tue, 9 Nov 2021 at 19:46, James Carter <jwcart2@gmail.com> wrote:
> >
> > On Fri, Nov 5, 2021 at 12:11 PM Christian Göttsche
> > <cgzones@googlemail.com> wrote:
> > >
> > > Add checks for invalid read sizes from a binary policy to guard
> > > allocations.
> > >
> > > The common and class permission counts needs to be limited more strict
> > > otherwise a too high count of common or class permissions can lead to
> > > permission values with a too high value, which can lead to overflows
> > > in shift operations.
> > >
> > > In the fuzzer build the value will also be bounded to avoid oom reports.
> > >
> > >     ==29857== ERROR: libFuzzer: out-of-memory (malloc(17179868160))
> > >        To change the out-of-memory limit use -rss_limit_mb=<N>
> > >
> > >         #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
> > >         #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
> > >         #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
> > >         #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
> > >         #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
> > >         #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
> > >         #6 0x4aa143 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa143)
> > >         #7 0x5259cb in malloc (./out/binpolicy-fuzzer+0x5259cb)
> > >         #8 0x580b5d in mallocarray ./libsepol/src/./private.h:93:9
> > >         #9 0x57c2ed in scope_read ./libsepol/src/policydb.c:4120:7
> > >         #10 0x576b0d in policydb_read ./libsepol/src/policydb.c:4462:9
> > >         #11 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
> > >         #12 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
> > >         #13 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
> > >         #14 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
> > >         #15 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
> > >         #16 0x7ffad6e107ec in __libc_start_main csu/../csu/libc-start.c:332:16
> > >         #17 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)
> > >
> > >     ==19462== ERROR: libFuzzer: out-of-memory (malloc(18253611008))
> > >        To change the out-of-memory limit use -rss_limit_mb=<N>
> > >
> > >         #0 0x52dc61 in __sanitizer_print_stack_trace (./out/binpolicy-fuzzer+0x52dc61)
> > >         #1 0x475618 in fuzzer::PrintStackTrace() fuzzer.o
> > >         #2 0x458855 in fuzzer::Fuzzer::HandleMalloc(unsigned long) fuzzer.o
> > >         #3 0x45876a in fuzzer::MallocHook(void const volatile*, unsigned long) fuzzer.o
> > >         #4 0x534557 in __sanitizer::RunMallocHooks(void const*, unsigned long) (./out/binpolicy-fuzzer+0x534557)
> > >         #5 0x4aa7d7 in __asan::Allocator::Allocate(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*, __asan::AllocType, bool) (./out/binpolicy-fuzzer+0x4aa7d7)
> > >         #6 0x4aa999 in __asan::asan_calloc(unsigned long, unsigned long, __sanitizer::BufferedStackTrace*) (./out/binpolicy-fuzzer+0x4aa999)
> > >         #7 0x525b63 in __interceptor_calloc (./out/binpolicy-fuzzer+0x525b63)
> > >         #8 0x570938 in policydb_index_others ./libsepol/src/policydb.c:1245:6
> > >         #9 0x5771f3 in policydb_read ./src/policydb.c:4481:6
> > >         #10 0x55a214 in LLVMFuzzerTestOneInput ./libsepol/fuzz/binpolicy-fuzzer.c:26:6
> > >         #11 0x45aed3 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) fuzzer.o
> > >         #12 0x446a12 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) fuzzer.o
> > >         #13 0x44c93b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) fuzzer.o
> > >         #14 0x475dd2 in main (./out/binpolicy-fuzzer+0x475dd2)
> > >         #15 0x7f4d933157ec in __libc_start_main csu/../csu/libc-start.c:332:16
> > >         #16 0x423689 in _start (./out/binpolicy-fuzzer+0x423689)
> > >
> > > Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
> > > ---
> > >  libsepol/src/policydb.c | 10 +++++++++-
> > >  1 file changed, 9 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
> > > index dcea1807..1408405d 100644
> > > --- a/libsepol/src/policydb.c
> > > +++ b/libsepol/src/policydb.c
> > > @@ -2103,6 +2103,8 @@ static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
> > >         if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
> > >                 goto bad;
> > >         comdatum->permissions.nprim = le32_to_cpu(buf[2]);
> > > +       if (comdatum->permissions.nprim > 32)
> >
> > Should use PERM_SYMTAB_SIZE here (like in patch 22).
>
> I thought about that, but it seemed a bit unrelated.
> In patch 25 (https://patchwork.kernel.org/project/selinux/patch/20211105154542.38434-26-cgzones@googlemail.com/)
> the number of permissions in commons and classes is checked against
> the logical limit (which is imposed by the implementation via a bitset
> on a 32 bit integer).
> The check here is to prevent overflows on subsequent left-shifts by
> the checked value on a 32 bit integer.
> Maybe `sizeof(uint32_t)` is more expressive?
> However I do not object your comment, so I fine to change to PERM_SYMTAB_SIZE.
>

I think that you make a good point, but I think that PERM_SYMTAB_SIZE,
while not perfect, is the best choice.

Thanks,
Jim


> > > +               goto bad;
> > >         nel = le32_to_cpu(buf[3]);
> > >
> > >         key = malloc(len + 1);
> > > @@ -2251,6 +2253,8 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
> > >         if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
> > >                 goto bad;
> > >         cladatum->permissions.nprim = le32_to_cpu(buf[3]);
> > > +       if (cladatum->permissions.nprim > 32)
> >
> > Same here.
> >
> >
> > > +               goto bad;
> > >         nel = le32_to_cpu(buf[4]);
> > >
> > >         ncons = le32_to_cpu(buf[5]);
> > > @@ -3980,6 +3984,8 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
> > >                 if (rc < 0)
> > >                         return -1;
> > >                 nprim = le32_to_cpu(buf[0]);
> > > +               if (is_saturated(nprim))
> > > +                       return -1;
> > >                 nel = le32_to_cpu(buf[1]);
> > >                 for (j = 0; j < nel; j++) {
> > >                         if (read_f[i] (p, decl->symtab[i].table, fp)) {
> > > @@ -4106,7 +4112,7 @@ static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
> > >                 goto cleanup;
> > >         scope->scope = le32_to_cpu(buf[0]);
> > >         scope->decl_ids_len = le32_to_cpu(buf[1]);
> > > -       if (scope->decl_ids_len == 0) {
> > > +       if (zero_or_saturated(scope->decl_ids_len)) {
> > >                 ERR(fp->handle, "invalid scope with no declaration");
> > >                 goto cleanup;
> > >         }
> > > @@ -4396,6 +4402,8 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
> > >                 if (rc < 0)
> > >                         goto bad;
> > >                 nprim = le32_to_cpu(buf[0]);
> > > +               if (is_saturated(nprim))
> > > +                       goto bad;
> > >                 nel = le32_to_cpu(buf[1]);
> > >                 if (nel && !nprim) {
> > >                         ERR(fp->handle, "unexpected items in symbol table with no symbol");
> > > --
> > > 2.33.1
> > >
diff mbox series

Patch

diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index dcea1807..1408405d 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -2103,6 +2103,8 @@  static int common_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
 	if (symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE))
 		goto bad;
 	comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+	if (comdatum->permissions.nprim > 32)
+		goto bad;
 	nel = le32_to_cpu(buf[3]);
 
 	key = malloc(len + 1);
@@ -2251,6 +2253,8 @@  static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp)
 	if (symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE))
 		goto bad;
 	cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+	if (cladatum->permissions.nprim > 32)
+		goto bad;
 	nel = le32_to_cpu(buf[4]);
 
 	ncons = le32_to_cpu(buf[5]);
@@ -3980,6 +3984,8 @@  static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl,
 		if (rc < 0) 
 			return -1;
 		nprim = le32_to_cpu(buf[0]);
+		if (is_saturated(nprim))
+			return -1;
 		nel = le32_to_cpu(buf[1]);
 		for (j = 0; j < nel; j++) {
 			if (read_f[i] (p, decl->symtab[i].table, fp)) {
@@ -4106,7 +4112,7 @@  static int scope_read(policydb_t * p, int symnum, struct policy_file *fp)
 		goto cleanup;
 	scope->scope = le32_to_cpu(buf[0]);
 	scope->decl_ids_len = le32_to_cpu(buf[1]);
-	if (scope->decl_ids_len == 0) {
+	if (zero_or_saturated(scope->decl_ids_len)) {
 		ERR(fp->handle, "invalid scope with no declaration");
 		goto cleanup;
 	}
@@ -4396,6 +4402,8 @@  int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
 		if (rc < 0)
 			goto bad;
 		nprim = le32_to_cpu(buf[0]);
+		if (is_saturated(nprim))
+			goto bad;
 		nel = le32_to_cpu(buf[1]);
 		if (nel && !nprim) {
 			ERR(fp->handle, "unexpected items in symbol table with no symbol");