Skip to content

Commit 89b83f2

Browse files
keestorvalds
authored andcommitted
slub: avoid redzone when choosing freepointer location
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. Fixes: 3202fa6 ("slub: relocate freelist pointer to middle of object") Reported-by: Marco Elver <[email protected]> Signed-off-by: Kees Cook <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Tested-by: Marco Elver <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: David Rientjes <[email protected]> Cc: Joonsoo Kim <[email protected]> Link: http://lkml.kernel.org/r/202004151054.BD695840@keescook Link: https://lore.kernel.org/linux-mm/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1eb64c0 commit 89b83f2

File tree

1 file changed

+10
-2
lines changed

1 file changed

+10
-2
lines changed

mm/slub.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3533,6 +3533,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
35333533
{
35343534
slab_flags_t flags = s->flags;
35353535
unsigned int size = s->object_size;
3536+
unsigned int freepointer_area;
35363537
unsigned int order;
35373538

35383539
/*
@@ -3541,6 +3542,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
35413542
* the possible location of the free pointer.
35423543
*/
35433544
size = ALIGN(size, sizeof(void *));
3545+
/*
3546+
* This is the area of the object where a freepointer can be
3547+
* safely written. If redzoning adds more to the inuse size, we
3548+
* can't use that portion for writing the freepointer, so
3549+
* s->offset must be limited within this for the general case.
3550+
*/
3551+
freepointer_area = size;
35443552

35453553
#ifdef CONFIG_SLUB_DEBUG
35463554
/*
@@ -3582,13 +3590,13 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
35823590
*/
35833591
s->offset = size;
35843592
size += sizeof(void *);
3585-
} else if (size > sizeof(void *)) {
3593+
} else if (freepointer_area > sizeof(void *)) {
35863594
/*
35873595
* Store freelist pointer near middle of object to keep
35883596
* it away from the edges of the object to avoid small
35893597
* sized over/underflows from neighboring allocations.
35903598
*/
3591-
s->offset = ALIGN(size / 2, sizeof(void *));
3599+
s->offset = ALIGN(freepointer_area / 2, sizeof(void *));
35923600
}
35933601

35943602
#ifdef CONFIG_SLUB_DEBUG

0 commit comments

Comments
 (0)