lkml.org 
[lkml]   [2020]   [Jul]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.7 024/112] mm/slub.c: fix corrupted freechain in deactivate_slab()
    Date
    From: Dongli Zhang <dongli.zhang@oracle.com>

    [ Upstream commit 52f23478081ae0dcdb95d1650ea1e7d52d586829 ]

    The slub_debug is able to fix the corrupted slab freelist/page.
    However, alloc_debug_processing() only checks the validity of current
    and next freepointer during allocation path. As a result, once some
    objects have their freepointers corrupted, deactivate_slab() may lead to
    page fault.

    Below is from a test kernel module when 'slub_debug=PUF,kmalloc-128
    slub_nomerge'. The test kernel corrupts the freepointer of one free
    object on purpose. Unfortunately, deactivate_slab() does not detect it
    when iterating the freechain.

    BUG: unable to handle page fault for address: 00000000123456f8
    #PF: supervisor read access in kernel mode
    #PF: error_code(0x0000) - not-present page
    PGD 0 P4D 0
    Oops: 0000 [#1] SMP PTI
    ... ...
    RIP: 0010:deactivate_slab.isra.92+0xed/0x490
    ... ...
    Call Trace:
    ___slab_alloc+0x536/0x570
    __slab_alloc+0x17/0x30
    __kmalloc+0x1d9/0x200
    ext4_htree_store_dirent+0x30/0xf0
    htree_dirblock_to_tree+0xcb/0x1c0
    ext4_htree_fill_tree+0x1bc/0x2d0
    ext4_readdir+0x54f/0x920
    iterate_dir+0x88/0x190
    __x64_sys_getdents+0xa6/0x140
    do_syscall_64+0x49/0x170
    entry_SYSCALL_64_after_hwframe+0x44/0xa9

    Therefore, this patch adds extra consistency check in deactivate_slab().
    Once an object's freepointer is corrupted, all following objects
    starting at this object are isolated.

    [akpm@linux-foundation.org: fix build with CONFIG_SLAB_DEBUG=n]
    Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Cc: Joe Jin <joe.jin@oracle.com>
    Cc: Christoph Lameter <cl@linux.com>
    Cc: Pekka Enberg <penberg@kernel.org>
    Cc: David Rientjes <rientjes@google.com>
    Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
    Link: http://lkml.kernel.org/r/20200331031450.12182-1-dongli.zhang@oracle.com
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    mm/slub.c | 27 +++++++++++++++++++++++++++
    1 file changed, 27 insertions(+)

    diff --git a/mm/slub.c b/mm/slub.c
    index 63bd39c476431..63f372366ec59 100644
    --- a/mm/slub.c
    +++ b/mm/slub.c
    @@ -679,6 +679,20 @@ static void slab_fix(struct kmem_cache *s, char *fmt, ...)
    va_end(args);
    }

    +static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
    + void *freelist, void *nextfree)
    +{
    + if ((s->flags & SLAB_CONSISTENCY_CHECKS) &&
    + !check_valid_pointer(s, page, nextfree)) {
    + object_err(s, page, freelist, "Freechain corrupt");
    + freelist = NULL;
    + slab_fix(s, "Isolate corrupted freechain");
    + return true;
    + }
    +
    + return false;
    +}
    +
    static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
    {
    unsigned int off; /* Offset of last byte */
    @@ -1410,6 +1424,11 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node,
    static inline void dec_slabs_node(struct kmem_cache *s, int node,
    int objects) {}

    +static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
    + void *freelist, void *nextfree)
    +{
    + return false;
    +}
    #endif /* CONFIG_SLUB_DEBUG */

    /*
    @@ -2093,6 +2112,14 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page,
    void *prior;
    unsigned long counters;

    + /*
    + * If 'nextfree' is invalid, it is possible that the object at
    + * 'freelist' is already corrupted. So isolate all objects
    + * starting at 'freelist'.
    + */
    + if (freelist_corrupted(s, page, freelist, nextfree))
    + break;
    +
    do {
    prior = page->freelist;
    counters = page->counters;
    --
    2.25.1


    \
     
     \ /
      Last update: 2020-07-07 17:24    [W:4.298 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site