linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot
@ 2020-01-30  6:44 Walter Wu
  2020-01-30 12:03 ` Alexander Potapenko
  0 siblings, 1 reply; 6+ messages in thread
From: Walter Wu @ 2020-01-30  6:44 UTC (permalink / raw)
  To: Dmitry Vyukov, Matthias Brugger, Thomas Gleixner,
	Alexander Potapenko, Josh Poimboeuf, Greg Kroah-Hartman,
	Kate Stewart
  Cc: linux-kernel, linux-arm-kernel, linux-mediatek, wsd_upstream, Walter Wu

If the depot_index = STACK_ALLOC_MAX_SLABS - 2 and next_slab_inited = 0,
then it will cause array out-of-bounds access, so that we should modify
the detection to avoid this array out-of-bounds bug.

Assume depot_index = STACK_ALLOC_MAX_SLABS - 3
Consider following call flow sequence:

stack_depot_save()
   depot_alloc_stack()
      if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
      depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 2
      if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) //enter
         smp_store_release(&next_slab_inited, 0); //next_slab_inited = 0
      init_stack_slab()
         if (stack_slabs[depot_index] == NULL) //enter and exit

stack_depot_save()
   depot_alloc_stack()
      if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
      depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 1
      init_stack_slab(&prealloc)
         stack_slabs[depot_index + 1]  //here get global out-of-bounds

Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Matthias Brugger <matthias.bgg@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Alexander Potapenko <glider@google.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kate Stewart <kstewart@linuxfoundation.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Kate Stewart <kstewart@linuxfoundation.org>
Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
---
changes in v2:
modify call flow sequence and preconditon

changes in v3:
add some reviewers
---
 lib/stackdepot.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index ed717dd08ff3..7e8a15e41600 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -106,7 +106,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
 	required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
 
 	if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
-		if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
+		if (unlikely(depot_index + 2 >= STACK_ALLOC_MAX_SLABS)) {
 			WARN_ONCE(1, "Stack depot reached limit capacity");
 			return NULL;
 		}
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot
  2020-01-30  6:44 [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot Walter Wu
@ 2020-01-30 12:03 ` Alexander Potapenko
  2020-01-31  2:05   ` Walter Wu
  0 siblings, 1 reply; 6+ messages in thread
From: Alexander Potapenko @ 2020-01-30 12:03 UTC (permalink / raw)
  To: Walter Wu
  Cc: Dmitry Vyukov, Matthias Brugger, Thomas Gleixner, Josh Poimboeuf,
	Greg Kroah-Hartman, Kate Stewart, LKML, linux-arm-kernel,
	linux-mediatek, wsd_upstream

On Thu, Jan 30, 2020 at 7:44 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:

Hi Walter,

> If the depot_index = STACK_ALLOC_MAX_SLABS - 2 and next_slab_inited = 0,
> then it will cause array out-of-bounds access, so that we should modify
> the detection to avoid this array out-of-bounds bug.
>
> Assume depot_index = STACK_ALLOC_MAX_SLABS - 3
> Consider following call flow sequence:
>
> stack_depot_save()
>    depot_alloc_stack()
>       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
>       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 2
>       if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) //enter
>          smp_store_release(&next_slab_inited, 0); //next_slab_inited = 0
>       init_stack_slab()
>          if (stack_slabs[depot_index] == NULL) //enter and exit
>
> stack_depot_save()
>    depot_alloc_stack()
>       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
>       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 1
>       init_stack_slab(&prealloc)
>          stack_slabs[depot_index + 1]  //here get global out-of-bounds
>
> Cc: Dmitry Vyukov <dvyukov@google.com>
> Cc: Matthias Brugger <matthias.bgg@gmail.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Alexander Potapenko <glider@google.com>
> Cc: Josh Poimboeuf <jpoimboe@redhat.com>
> Cc: Kate Stewart <kstewart@linuxfoundation.org>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Kate Stewart <kstewart@linuxfoundation.org>
> Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
> ---
> changes in v2:
> modify call flow sequence and preconditon
>
> changes in v3:
> add some reviewers
> ---
>  lib/stackdepot.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> index ed717dd08ff3..7e8a15e41600 100644
> --- a/lib/stackdepot.c
> +++ b/lib/stackdepot.c
> @@ -106,7 +106,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
>         required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
>
>         if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
> -               if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
> +               if (unlikely(depot_index + 2 >= STACK_ALLOC_MAX_SLABS)) {

I don't think this is the right way to fix the problem.
You're basically throwing away the last element of stack_slabs[], as
we won't allocate anything from it.

How about we set |next_slab_inited| to 1 here:

diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 2e7d2232ed3c..943a51eb746d 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -105,6 +105,8 @@ static bool init_stack_slab(void **prealloc)
                return true;
        if (stack_slabs[depot_index] == NULL) {
                stack_slabs[depot_index] = *prealloc;
+               if (depot_index + 1 == STACK_ALLOC_MAX_SLABS)
+                       smp_store_release(&next_slab_inited, 1);
        } else {
                stack_slabs[depot_index + 1] = *prealloc;
                /*

This will ensure we won't be preallocating pages once |depot_index|
reaches the last element, and we won't attempt to write those pages
anywhere either.

Could you please check if this fixes the problem for you?

>                         WARN_ONCE(1, "Stack depot reached limit capacity");
>                         return NULL;
>                 }
> --
> 2.18.0



-- 
Alexander Potapenko
Software Engineer

Google Germany GmbH
Erika-Mann-Straße, 33
80636 München

Geschäftsführer: Paul Manicle, Halimah DeLaine Prado
Registergericht und -nummer: Hamburg, HRB 86891
Sitz der Gesellschaft: Hamburg

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot
  2020-01-30 12:03 ` Alexander Potapenko
@ 2020-01-31  2:05   ` Walter Wu
  2020-01-31 18:11     ` Alexander Potapenko
  0 siblings, 1 reply; 6+ messages in thread
From: Walter Wu @ 2020-01-31  2:05 UTC (permalink / raw)
  To: Alexander Potapenko
  Cc: Dmitry Vyukov, Matthias Brugger, Thomas Gleixner, Josh Poimboeuf,
	Greg Kroah-Hartman, Kate Stewart, LKML, linux-arm-kernel,
	linux-mediatek, wsd_upstream

On Thu, 2020-01-30 at 13:03 +0100, Alexander Potapenko wrote:
> On Thu, Jan 30, 2020 at 7:44 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
> 
> Hi Walter,
> 
> > If the depot_index = STACK_ALLOC_MAX_SLABS - 2 and next_slab_inited = 0,
> > then it will cause array out-of-bounds access, so that we should modify
> > the detection to avoid this array out-of-bounds bug.
> >
> > Assume depot_index = STACK_ALLOC_MAX_SLABS - 3
> > Consider following call flow sequence:
> >
> > stack_depot_save()
> >    depot_alloc_stack()
> >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 2
> >       if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) //enter
> >          smp_store_release(&next_slab_inited, 0); //next_slab_inited = 0
> >       init_stack_slab()
> >          if (stack_slabs[depot_index] == NULL) //enter and exit
> >
> > stack_depot_save()
> >    depot_alloc_stack()
> >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 1
> >       init_stack_slab(&prealloc)
> >          stack_slabs[depot_index + 1]  //here get global out-of-bounds
> >
> > Cc: Dmitry Vyukov <dvyukov@google.com>
> > Cc: Matthias Brugger <matthias.bgg@gmail.com>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Alexander Potapenko <glider@google.com>
> > Cc: Josh Poimboeuf <jpoimboe@redhat.com>
> > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
> > ---
> > changes in v2:
> > modify call flow sequence and preconditon
> >
> > changes in v3:
> > add some reviewers
> > ---
> >  lib/stackdepot.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> > index ed717dd08ff3..7e8a15e41600 100644
> > --- a/lib/stackdepot.c
> > +++ b/lib/stackdepot.c
> > @@ -106,7 +106,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
> >         required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
> >
> >         if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
> > -               if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
> > +               if (unlikely(depot_index + 2 >= STACK_ALLOC_MAX_SLABS)) {
> 
> I don't think this is the right way to fix the problem.
> You're basically throwing away the last element of stack_slabs[], as
> we won't allocate anything from it.
> 
ok, I agree.
 
> How about we set |next_slab_inited| to 1 here:
> 
> diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> index 2e7d2232ed3c..943a51eb746d 100644
> --- a/lib/stackdepot.c
> +++ b/lib/stackdepot.c
> @@ -105,6 +105,8 @@ static bool init_stack_slab(void **prealloc)
>                 return true;
>         if (stack_slabs[depot_index] == NULL) {
>                 stack_slabs[depot_index] = *prealloc;
> +               if (depot_index + 1 == STACK_ALLOC_MAX_SLABS)
> +                       smp_store_release(&next_slab_inited, 1);
>         } else {
>                 stack_slabs[depot_index + 1] = *prealloc;
>                 /*
> 
> This will ensure we won't be preallocating pages once |depot_index|
> reaches the last element, and we won't attempt to write those pages
> anywhere either.
> 
> Could you please check if this fixes the problem for you?
> 
Consider above call flow sequence at first stack_depot_save(),
depot_index = STACK_ALLOC_MAX_SLABS - 2 before enter init_stack_slab(),
so the fixes should be below.

--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -83,6 +83,8 @@ static bool init_stack_slab(void **prealloc)
                return true;
        if (stack_slabs[depot_index] == NULL) {
                stack_slabs[depot_index] = *prealloc;
+               if (depot_index + 2 == STACK_ALLOC_MAX_SLABS)
+                       smp_store_release(&next_slab_inited, 1);
        } else {
                stack_slabs[depot_index + 1] = *prealloc;
                /*


> >                         WARN_ONCE(1, "Stack depot reached limit capacity");
> >                         return NULL;
> >                 }
> > --
> > 2.18.0
> 
> 
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot
  2020-01-31  2:05   ` Walter Wu
@ 2020-01-31 18:11     ` Alexander Potapenko
  2020-02-03  2:05       ` Walter Wu
  0 siblings, 1 reply; 6+ messages in thread
From: Alexander Potapenko @ 2020-01-31 18:11 UTC (permalink / raw)
  To: Walter Wu
  Cc: Dmitry Vyukov, Matthias Brugger, Thomas Gleixner, Josh Poimboeuf,
	Greg Kroah-Hartman, Kate Stewart, LKML, linux-arm-kernel,
	linux-mediatek, wsd_upstream

On Fri, Jan 31, 2020 at 3:05 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
>
> On Thu, 2020-01-30 at 13:03 +0100, Alexander Potapenko wrote:
> > On Thu, Jan 30, 2020 at 7:44 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
> >
> > Hi Walter,
> >
> > > If the depot_index = STACK_ALLOC_MAX_SLABS - 2 and next_slab_inited = 0,
> > > then it will cause array out-of-bounds access, so that we should modify
> > > the detection to avoid this array out-of-bounds bug.
> > >
> > > Assume depot_index = STACK_ALLOC_MAX_SLABS - 3
> > > Consider following call flow sequence:
> > >
> > > stack_depot_save()
> > >    depot_alloc_stack()
> > >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> > >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 2
> > >       if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) //enter
> > >          smp_store_release(&next_slab_inited, 0); //next_slab_inited = 0
> > >       init_stack_slab()
> > >          if (stack_slabs[depot_index] == NULL) //enter and exit
> > >
> > > stack_depot_save()
> > >    depot_alloc_stack()
> > >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> > >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 1
> > >       init_stack_slab(&prealloc)
> > >          stack_slabs[depot_index + 1]  //here get global out-of-bounds
> > >
> > > Cc: Dmitry Vyukov <dvyukov@google.com>
> > > Cc: Matthias Brugger <matthias.bgg@gmail.com>
> > > Cc: Thomas Gleixner <tglx@linutronix.de>
> > > Cc: Alexander Potapenko <glider@google.com>
> > > Cc: Josh Poimboeuf <jpoimboe@redhat.com>
> > > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > > Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
> > > ---
> > > changes in v2:
> > > modify call flow sequence and preconditon
> > >
> > > changes in v3:
> > > add some reviewers
> > > ---
> > >  lib/stackdepot.c | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> > > index ed717dd08ff3..7e8a15e41600 100644
> > > --- a/lib/stackdepot.c
> > > +++ b/lib/stackdepot.c
> > > @@ -106,7 +106,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
> > >         required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
> > >
> > >         if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
> > > -               if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
> > > +               if (unlikely(depot_index + 2 >= STACK_ALLOC_MAX_SLABS)) {

This again means stack_slabs[STACK_ALLOC_MAX_SLABS - 2] gets
initialized, but stack_slabs[STACK_ALLOC_MAX_SLABS - 1] doesn't,
because we'll be bailing out from init_stack_slab() from now on.
Does this patch actually fix the problem (do you have a reliable reproducer?)
This addition of 2 is also counterintuitive, I don't think further
readers will understand the logic behind it.

What if we just check that depot_index + 1 is a valid index before accessing it?

diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 2e7d2232ed3c..c2e6ff18d716 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -106,7 +106,9 @@ static bool init_stack_slab(void **prealloc)
        if (stack_slabs[depot_index] == NULL) {
                stack_slabs[depot_index] = *prealloc;
        } else {
-               stack_slabs[depot_index + 1] = *prealloc;
+               /* If this is the last depot slab, do not touch the next one. */
+               if (depot_index + 1 < STACK_ALLOC_MAX_SLABS)
+                       stack_slabs[depot_index + 1] = *prealloc;
                /*
                 * This smp_store_release pairs with smp_load_acquire() from
                 * |next_slab_inited| above and in stack_depot_save().

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot
  2020-01-31 18:11     ` Alexander Potapenko
@ 2020-02-03  2:05       ` Walter Wu
  2020-02-03 10:30         ` Alexander Potapenko
  0 siblings, 1 reply; 6+ messages in thread
From: Walter Wu @ 2020-02-03  2:05 UTC (permalink / raw)
  To: Alexander Potapenko
  Cc: Dmitry Vyukov, Matthias Brugger, Thomas Gleixner, Josh Poimboeuf,
	Greg Kroah-Hartman, Kate Stewart, LKML, linux-arm-kernel,
	linux-mediatek, wsd_upstream

On Fri, 2020-01-31 at 19:11 +0100, Alexander Potapenko wrote:
> On Fri, Jan 31, 2020 at 3:05 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
> >
> > On Thu, 2020-01-30 at 13:03 +0100, Alexander Potapenko wrote:
> > > On Thu, Jan 30, 2020 at 7:44 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
> > >
> > > Hi Walter,
> > >
> > > > If the depot_index = STACK_ALLOC_MAX_SLABS - 2 and next_slab_inited = 0,
> > > > then it will cause array out-of-bounds access, so that we should modify
> > > > the detection to avoid this array out-of-bounds bug.
> > > >
> > > > Assume depot_index = STACK_ALLOC_MAX_SLABS - 3
> > > > Consider following call flow sequence:
> > > >
> > > > stack_depot_save()
> > > >    depot_alloc_stack()
> > > >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> > > >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 2
> > > >       if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) //enter
> > > >          smp_store_release(&next_slab_inited, 0); //next_slab_inited = 0
> > > >       init_stack_slab()
> > > >          if (stack_slabs[depot_index] == NULL) //enter and exit
> > > >
> > > > stack_depot_save()
> > > >    depot_alloc_stack()
> > > >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> > > >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 1
> > > >       init_stack_slab(&prealloc)
> > > >          stack_slabs[depot_index + 1]  //here get global out-of-bounds
> > > >
> > > > Cc: Dmitry Vyukov <dvyukov@google.com>
> > > > Cc: Matthias Brugger <matthias.bgg@gmail.com>
> > > > Cc: Thomas Gleixner <tglx@linutronix.de>
> > > > Cc: Alexander Potapenko <glider@google.com>
> > > > Cc: Josh Poimboeuf <jpoimboe@redhat.com>
> > > > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > > > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > > > Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
> > > > ---
> > > > changes in v2:
> > > > modify call flow sequence and preconditon
> > > >
> > > > changes in v3:
> > > > add some reviewers
> > > > ---
> > > >  lib/stackdepot.c | 2 +-
> > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > >
> > > > diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> > > > index ed717dd08ff3..7e8a15e41600 100644
> > > > --- a/lib/stackdepot.c
> > > > +++ b/lib/stackdepot.c
> > > > @@ -106,7 +106,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
> > > >         required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
> > > >
> > > >         if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
> > > > -               if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
> > > > +               if (unlikely(depot_index + 2 >= STACK_ALLOC_MAX_SLABS)) {
> 
> This again means stack_slabs[STACK_ALLOC_MAX_SLABS - 2] gets
> initialized, but stack_slabs[STACK_ALLOC_MAX_SLABS - 1] doesn't,
> because we'll be bailing out from init_stack_slab() from now on.
> Does this patch actually fix the problem (do you have a reliable reproducer?)
We get it by reviewing code, because Kasan doesn't scan it and we catch
another bug internally, we found it unintentionally.

> This addition of 2 is also counterintuitive, I don't think further
> readers will understand the logic behind it.
> 
Yes

> What if we just check that depot_index + 1 is a valid index before accessing it?
> 
It should fix the problem, do you want to send this patch?

> diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> index 2e7d2232ed3c..c2e6ff18d716 100644
> --- a/lib/stackdepot.c
> +++ b/lib/stackdepot.c
> @@ -106,7 +106,9 @@ static bool init_stack_slab(void **prealloc)
>         if (stack_slabs[depot_index] == NULL) {
>                 stack_slabs[depot_index] = *prealloc;
>         } else {
> -               stack_slabs[depot_index + 1] = *prealloc;
> +               /* If this is the last depot slab, do not touch the next one. */
> +               if (depot_index + 1 < STACK_ALLOC_MAX_SLABS)
> +                       stack_slabs[depot_index + 1] = *prealloc;
>                 /*
>                  * This smp_store_release pairs with smp_load_acquire() from
>                  * |next_slab_inited| above and in stack_depot_save().


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot
  2020-02-03  2:05       ` Walter Wu
@ 2020-02-03 10:30         ` Alexander Potapenko
  0 siblings, 0 replies; 6+ messages in thread
From: Alexander Potapenko @ 2020-02-03 10:30 UTC (permalink / raw)
  To: Walter Wu
  Cc: Dmitry Vyukov, Matthias Brugger, Thomas Gleixner, Josh Poimboeuf,
	Greg Kroah-Hartman, Kate Stewart, LKML, linux-arm-kernel,
	linux-mediatek, wsd_upstream

On Mon, Feb 3, 2020 at 3:05 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
>
> On Fri, 2020-01-31 at 19:11 +0100, Alexander Potapenko wrote:
> > On Fri, Jan 31, 2020 at 3:05 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
> > >
> > > On Thu, 2020-01-30 at 13:03 +0100, Alexander Potapenko wrote:
> > > > On Thu, Jan 30, 2020 at 7:44 AM Walter Wu <walter-zh.wu@mediatek.com> wrote:
> > > >
> > > > Hi Walter,
> > > >
> > > > > If the depot_index = STACK_ALLOC_MAX_SLABS - 2 and next_slab_inited = 0,
> > > > > then it will cause array out-of-bounds access, so that we should modify
> > > > > the detection to avoid this array out-of-bounds bug.
> > > > >
> > > > > Assume depot_index = STACK_ALLOC_MAX_SLABS - 3
> > > > > Consider following call flow sequence:
> > > > >
> > > > > stack_depot_save()
> > > > >    depot_alloc_stack()
> > > > >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> > > > >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 2
> > > > >       if (depot_index + 1 < STACK_ALLOC_MAX_SLABS) //enter
> > > > >          smp_store_release(&next_slab_inited, 0); //next_slab_inited = 0
> > > > >       init_stack_slab()
> > > > >          if (stack_slabs[depot_index] == NULL) //enter and exit
> > > > >
> > > > > stack_depot_save()
> > > > >    depot_alloc_stack()
> > > > >       if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) //pass
> > > > >       depot_index++  //depot_index = STACK_ALLOC_MAX_SLABS - 1
> > > > >       init_stack_slab(&prealloc)
> > > > >          stack_slabs[depot_index + 1]  //here get global out-of-bounds
> > > > >
> > > > > Cc: Dmitry Vyukov <dvyukov@google.com>
> > > > > Cc: Matthias Brugger <matthias.bgg@gmail.com>
> > > > > Cc: Thomas Gleixner <tglx@linutronix.de>
> > > > > Cc: Alexander Potapenko <glider@google.com>
> > > > > Cc: Josh Poimboeuf <jpoimboe@redhat.com>
> > > > > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > > > > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > > > > Cc: Kate Stewart <kstewart@linuxfoundation.org>
> > > > > Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
> > > > > ---
> > > > > changes in v2:
> > > > > modify call flow sequence and preconditon
> > > > >
> > > > > changes in v3:
> > > > > add some reviewers
> > > > > ---
> > > > >  lib/stackdepot.c | 2 +-
> > > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> > > > > index ed717dd08ff3..7e8a15e41600 100644
> > > > > --- a/lib/stackdepot.c
> > > > > +++ b/lib/stackdepot.c
> > > > > @@ -106,7 +106,7 @@ static struct stack_record *depot_alloc_stack(unsigned long *entries, int size,
> > > > >         required_size = ALIGN(required_size, 1 << STACK_ALLOC_ALIGN);
> > > > >
> > > > >         if (unlikely(depot_offset + required_size > STACK_ALLOC_SIZE)) {
> > > > > -               if (unlikely(depot_index + 1 >= STACK_ALLOC_MAX_SLABS)) {
> > > > > +               if (unlikely(depot_index + 2 >= STACK_ALLOC_MAX_SLABS)) {
> >
> > This again means stack_slabs[STACK_ALLOC_MAX_SLABS - 2] gets
> > initialized, but stack_slabs[STACK_ALLOC_MAX_SLABS - 1] doesn't,
> > because we'll be bailing out from init_stack_slab() from now on.
> > Does this patch actually fix the problem (do you have a reliable reproducer?)
> We get it by reviewing code, because Kasan doesn't scan it and we catch
> another bug internally, we found it unintentionally.
>
> > This addition of 2 is also counterintuitive, I don't think further
> > readers will understand the logic behind it.
> >
> Yes
>
> > What if we just check that depot_index + 1 is a valid index before accessing it?
> >
> It should fix the problem, do you want to send this patch?

I've sent the patch. Thanks for the report!

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-02-03 10:30 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-30  6:44 [PATCH v3] lib/stackdepot: Fix global out-of-bounds in stackdepot Walter Wu
2020-01-30 12:03 ` Alexander Potapenko
2020-01-31  2:05   ` Walter Wu
2020-01-31 18:11     ` Alexander Potapenko
2020-02-03  2:05       ` Walter Wu
2020-02-03 10:30         ` Alexander Potapenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).