From: Yang Yingliang yangyingliang@huawei.com
hulk inclusion category: bugfix bugzilla: 47452 CVE: NA
-------------------------------------------------
Change control methods of check validity of freelist and connector debug to sysctl.
Signed-off-by: Yang Yingliang yangyingliang@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com Signed-off-by: Cheng Jian cj.chengjian@huawei.com --- drivers/connector/connector.c | 1 + include/linux/slab.h | 4 --- kernel/sysctl.c | 20 +++++++++++ mm/slub.c | 63 ++++++++++++++--------------------- 4 files changed, 46 insertions(+), 42 deletions(-)
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index a8df9ecbf42b..b5cdd0b99736 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -42,6 +42,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR); static struct cn_dev cdev;
static int cn_already_initialized; +int sysctl_connector_debug = 0;
/* * Sends mult (multiple) cn_msg at a time. diff --git a/include/linux/slab.h b/include/linux/slab.h index 1ab5fd97dec8..d6393413ef09 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -24,8 +24,6 @@ */ /* DEBUG: Perform (expensive) checks on alloc/free */ #define SLAB_CONSISTENCY_CHECKS ((slab_flags_t __force)0x00000100U) -/* Check if freelist is valid */ -#define SLAB_NO_FREELIST_CHECKS ((slab_flags_t __force)0x00000200U) /* DEBUG: Red zone objs in a cache */ #define SLAB_RED_ZONE ((slab_flags_t __force)0x00000400U) /* DEBUG: Poison objects */ @@ -113,8 +111,6 @@ #define SLAB_KASAN 0 #endif
-#define SLAB_CONNECTOR_DEBUG ((slab_flags_t __force)0x10000000U) - /* The following flags affect the page allocator grouping pages by mobility */ /* Objects are reclaimable */ #define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0x00020000U) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 665c9e2a8802..c921ee10615a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1245,6 +1245,7 @@ static struct ctl_table kern_table[] = { { } };
+extern int sysctl_isolate_corrupted_freelist; static struct ctl_table vm_table[] = { { .procname = "overcommit_memory", @@ -1714,6 +1715,15 @@ static struct ctl_table vm_table[] = { .extra2 = (void *)&mmap_rnd_compat_bits_max, }, #endif + { + .procname = "isolate_corrupted_freelist", + .data = &sysctl_isolate_corrupted_freelist, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { } };
@@ -1925,6 +1935,7 @@ static struct ctl_table fs_table[] = { { } };
+extern int sysctl_connector_debug; static struct ctl_table debug_table[] = { #ifdef CONFIG_SYSCTL_EXCEPTION_TRACE { @@ -1946,6 +1957,15 @@ static struct ctl_table debug_table[] = { .extra2 = &one, }, #endif + { + .procname = "connector-debug", + .data = &sysctl_connector_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { } };
diff --git a/mm/slub.c b/mm/slub.c index ee0d18699bde..2301c04353d0 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1221,30 +1221,6 @@ static noinline int free_debug_processing( return ret; }
-/* - * Check if the next object in freechain is - * valid, then isolate the corrupted freelist. - */ -int isolate_cnt = 0; -static bool isolate_corrupted_freelist(struct kmem_cache *s, struct page *page, - void **freelist, void *next) -{ - if (!(slub_debug & SLAB_NO_FREELIST_CHECKS) && - (!check_valid_pointer(s, page, next))) { - /* Need caller make sure freelist is not NULL */ - *freelist = NULL; - isolate_cnt++; - - slab_fix(s, "Freelist corrupt,isolate corrupted freechain."); - pr_info("freelist=%lx object=%lx, page->base=%lx, page->objects=%u, objsize=%u, s->offset=%d page:%llx\n", - (long)freelist, (long)next, (long)page_address(page), page->objects, s->size, s->offset, (u64)page); - - return true; - } - - return false; -} - static int __init setup_slub_debug(char *str) { slub_debug = DEBUG_DEFAULT_FLAGS; @@ -1291,14 +1267,6 @@ static int __init setup_slub_debug(char *str) case 'a': slub_debug |= SLAB_FAILSLAB; break; - case 'n': - slub_debug |= SLAB_NO_FREELIST_CHECKS; - pr_info("Freelist pointer check disabled."); - break; - case 'd': - slub_debug |= SLAB_CONNECTOR_DEBUG; - pr_info("Connector debug enabled.\n"); - break; case 'o': /* * Avoid enabling debugging on caches if its minimum @@ -1311,8 +1279,6 @@ static int __init setup_slub_debug(char *str) *str); } } - if (!(slub_debug & SLAB_NO_FREELIST_CHECKS)) - pr_info("Freelist pointer check enabled.");
check_slabs: if (*str == ',') @@ -1380,12 +1346,33 @@ static bool freelist_corrupted(struct kmem_cache *s, struct page *page, { return false; } +#endif /* CONFIG_SLUB_DEBUG */ + +extern int sysctl_connector_debug; +/* + * Check if the next object in freechain is + * valid, then isolate the corrupted freelist. + */ +int isolate_cnt = 0; +int sysctl_isolate_corrupted_freelist = 1; static bool isolate_corrupted_freelist(struct kmem_cache *s, struct page *page, - void **freelist, void *nextfree) + void **freelist, void *next) { + if (sysctl_isolate_corrupted_freelist && + (!check_valid_pointer(s, page, next))) { + /* Need caller make sure freelist is not NULL */ + *freelist = NULL; + isolate_cnt++; + + slab_fix(s, "Freelist corrupt,isolate corrupted freechain."); + pr_info("freelist=%lx object=%lx, page->base=%lx, page->objects=%u, objsize=%u, s->offset=%d page:%llx\n", + (long)freelist, (long)next, (long)page_address(page), page->objects, s->size, s->offset, (u64)page); + + return true; + } + return false; } -#endif /* CONFIG_SLUB_DEBUG */
/* * Hooks for other subsystems that check memory allocations. In a typical @@ -2798,7 +2785,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, if (unlikely(gfpflags & __GFP_ZERO) && object) memset(object, 0, s->object_size);
- if ((slub_debug & SLAB_CONNECTOR_DEBUG) && + if (sysctl_connector_debug && unlikely(gfpflags & __GFP_CONNECTOR) && object) { if (s->object_size == 512) memset(object + 504, 0xad, 8); @@ -4015,7 +4002,7 @@ void kfree(const void *x) __free_pages(page, compound_order(page)); return; } - if ((slub_debug & SLAB_CONNECTOR_DEBUG) && + if (sysctl_connector_debug && unlikely(page->slab_cache->object_size == 512)) { u64 *tail = (u64 *)(x + 504);