linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] slub: Avoid redzone when choosing freepointer location
@ 2020-04-15 17:55 Kees Cook
  2020-04-15 18:07 ` Marco Elver
  0 siblings, 1 reply; 2+ messages in thread
From: Kees Cook @ 2020-04-15 17:55 UTC (permalink / raw)
  To: Andrew Morton, Marco Elver
  Cc: Christoph Lameter, Pekka Enberg, David Rientjes, Joonsoo Kim,
	linux-mm, linux-kernel

Marco Elver reported system crashes when booting with "slub_debug=Z".
The freepointer location (s->offset) was not taking into account that
the "inuse" size that includes the redzone area should not be used by
the freelist pointer. Change the calculation to save the area of the
object that an inline freepointer may be written into.

Reported-by: Marco Elver <elver@google.com>
Link: https://lore.kernel.org/linux-mm/20200415164726.GA234932@google.com
Fixes: 3202fa62fb43 ("slub: relocate freelist pointer to middle of object")
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 mm/slub.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/mm/slub.c b/mm/slub.c
index 332d4b459a90..9bf44955c4f1 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3533,6 +3533,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
 	slab_flags_t flags = s->flags;
 	unsigned int size = s->object_size;
+	unsigned int freepointer_area;
 	unsigned int order;
 
 	/*
@@ -3541,6 +3542,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 	 * the possible location of the free pointer.
 	 */
 	size = ALIGN(size, sizeof(void *));
+	/*
+	 * This is the area of the object where a freepointer can be
+	 * safely written. If redzoning adds more to the inuse size, we
+	 * can't use that portion for writing the freepointer, so
+	 * s->offset must be limited within this for the general case.
+	 */
+	freepointer_area = size;
 
 #ifdef CONFIG_SLUB_DEBUG
 	/*
@@ -3582,13 +3590,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 		 */
 		s->offset = size;
 		size += sizeof(void *);
-	} else if (size > sizeof(void *)) {
+	} else if (freepointer_area > sizeof(void *)) {
 		/*
 		 * Store freelist pointer near middle of object to keep
 		 * it away from the edges of the object to avoid small
 		 * sized over/underflows from neighboring allocations.
 		 */
-		s->offset = ALIGN(size / 2, sizeof(void *));
+		s->offset = ALIGN(freepointer_area / 2, sizeof(void *));
 	}
 
 #ifdef CONFIG_SLUB_DEBUG
-- 
2.20.1


-- 
Kees Cook


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

* Re: [PATCH] slub: Avoid redzone when choosing freepointer location
  2020-04-15 17:55 [PATCH] slub: Avoid redzone when choosing freepointer location Kees Cook
@ 2020-04-15 18:07 ` Marco Elver
  0 siblings, 0 replies; 2+ messages in thread
From: Marco Elver @ 2020-04-15 18:07 UTC (permalink / raw)
  To: Kees Cook
  Cc: Andrew Morton, Christoph Lameter, Pekka Enberg, David Rientjes,
	Joonsoo Kim, Linux Memory Management List, LKML

On Wed, 15 Apr 2020 at 19:55, Kees Cook <keescook@chromium.org> wrote:
>
> Marco Elver reported system crashes when booting with "slub_debug=Z".
> The freepointer location (s->offset) was not taking into account that
> the "inuse" size that includes the redzone area should not be used by
> the freelist pointer. Change the calculation to save the area of the
> object that an inline freepointer may be written into.
>
> Reported-by: Marco Elver <elver@google.com>
> Link: https://lore.kernel.org/linux-mm/20200415164726.GA234932@google.com
> Fixes: 3202fa62fb43 ("slub: relocate freelist pointer to middle of object")
> Signed-off-by: Kees Cook <keescook@chromium.org>

Works for me, thank you!

Tested-by: Marco Elver <elver@google.com>

> ---
>  mm/slub.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/mm/slub.c b/mm/slub.c
> index 332d4b459a90..9bf44955c4f1 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -3533,6 +3533,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
>  {
>         slab_flags_t flags = s->flags;
>         unsigned int size = s->object_size;
> +       unsigned int freepointer_area;
>         unsigned int order;
>
>         /*
> @@ -3541,6 +3542,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
>          * the possible location of the free pointer.
>          */
>         size = ALIGN(size, sizeof(void *));
> +       /*
> +        * This is the area of the object where a freepointer can be
> +        * safely written. If redzoning adds more to the inuse size, we
> +        * can't use that portion for writing the freepointer, so
> +        * s->offset must be limited within this for the general case.
> +        */
> +       freepointer_area = size;
>
>  #ifdef CONFIG_SLUB_DEBUG
>         /*
> @@ -3582,13 +3590,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
>                  */
>                 s->offset = size;
>                 size += sizeof(void *);
> -       } else if (size > sizeof(void *)) {
> +       } else if (freepointer_area > sizeof(void *)) {
>                 /*
>                  * Store freelist pointer near middle of object to keep
>                  * it away from the edges of the object to avoid small
>                  * sized over/underflows from neighboring allocations.
>                  */
> -               s->offset = ALIGN(size / 2, sizeof(void *));
> +               s->offset = ALIGN(freepointer_area / 2, sizeof(void *));
>         }
>
>  #ifdef CONFIG_SLUB_DEBUG
> --
> 2.20.1
>
>
> --
> Kees Cook


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

end of thread, other threads:[~2020-04-15 18:08 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-15 17:55 [PATCH] slub: Avoid redzone when choosing freepointer location Kees Cook
2020-04-15 18:07 ` Marco Elver

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).