Skip to content

Commit aea4df4

Browse files
labbotttorvalds
authored andcommitted
mm: slub: really fix slab walking for init_on_free
Commit 1b7e816 ("mm: slub: Fix slab walking for init_on_free") fixed one problem with the slab walking but missed a key detail: When walking the list, the head and tail pointers need to be updated since we end up reversing the list as a result. Without doing this, bulk free is broken. One way this is exposed is a NULL pointer with slub_debug=F: ============================================================================= BUG skbuff_head_cache (Tainted: G T): Object already free ----------------------------------------------------------------------------- INFO: Slab 0x000000000d2d2f8f objects=16 used=3 fp=0x0000000064309071 flags=0x3fff00000000201 BUG: kernel NULL pointer dereference, address: 0000000000000000 Oops: 0000 [#1] PREEMPT SMP PTI RIP: 0010:print_trailer+0x70/0x1d5 Call Trace: <IRQ> free_debug_processing.cold.37+0xc9/0x149 __slab_free+0x22a/0x3d0 kmem_cache_free_bulk+0x415/0x420 __kfree_skb_flush+0x30/0x40 net_rx_action+0x2dd/0x480 __do_softirq+0xf0/0x246 irq_exit+0x93/0xb0 do_IRQ+0xa0/0x110 common_interrupt+0xf/0xf </IRQ> Given we're now almost identical to the existing debugging code which correctly walks the list, combine with that. Link: https://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Fixes: 1b7e816 ("mm: slub: Fix slab walking for init_on_free") Signed-off-by: Laura Abbott <[email protected]> Reported-by: Thibaut Sautereau <[email protected]> Acked-by: David Rientjes <[email protected]> Tested-by: Alexander Potapenko <[email protected]> Acked-by: Alexander Potapenko <[email protected]> Cc: Kees Cook <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: Joonsoo Kim <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 0362f32 commit aea4df4

File tree

1 file changed

+9
-30
lines changed

1 file changed

+9
-30
lines changed

mm/slub.c

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,12 +1433,15 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
14331433
void *old_tail = *tail ? *tail : *head;
14341434
int rsize;
14351435

1436-
if (slab_want_init_on_free(s)) {
1437-
void *p = NULL;
1436+
/* Head and tail of the reconstructed freelist */
1437+
*head = NULL;
1438+
*tail = NULL;
14381439

1439-
do {
1440-
object = next;
1441-
next = get_freepointer(s, object);
1440+
do {
1441+
object = next;
1442+
next = get_freepointer(s, object);
1443+
1444+
if (slab_want_init_on_free(s)) {
14421445
/*
14431446
* Clear the object and the metadata, but don't touch
14441447
* the redzone.
@@ -1448,29 +1451,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
14481451
: 0;
14491452
memset((char *)object + s->inuse, 0,
14501453
s->size - s->inuse - rsize);
1451-
set_freepointer(s, object, p);
1452-
p = object;
1453-
} while (object != old_tail);
1454-
}
1455-
1456-
/*
1457-
* Compiler cannot detect this function can be removed if slab_free_hook()
1458-
* evaluates to nothing. Thus, catch all relevant config debug options here.
1459-
*/
1460-
#if defined(CONFIG_LOCKDEP) || \
1461-
defined(CONFIG_DEBUG_KMEMLEAK) || \
1462-
defined(CONFIG_DEBUG_OBJECTS_FREE) || \
1463-
defined(CONFIG_KASAN)
14641454

1465-
next = *head;
1466-
1467-
/* Head and tail of the reconstructed freelist */
1468-
*head = NULL;
1469-
*tail = NULL;
1470-
1471-
do {
1472-
object = next;
1473-
next = get_freepointer(s, object);
1455+
}
14741456
/* If object's reuse doesn't have to be delayed */
14751457
if (!slab_free_hook(s, object)) {
14761458
/* Move object to the new freelist */
@@ -1485,9 +1467,6 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
14851467
*tail = NULL;
14861468

14871469
return *head != NULL;
1488-
#else
1489-
return true;
1490-
#endif
14911470
}
14921471

14931472
static void *setup_object(struct kmem_cache *s, struct page *page,

0 commit comments

Comments
 (0)