| From: Imran Khan <imran.f.khan@oracle.com> |
| Subject: kfence: add sysfs interface to disable kfence for selected slabs. |
| Date: Mon, 15 Aug 2022 05:53:53 +1000 |
| |
| By default kfence allocation can happen for any slab object, whose size is |
| up to PAGE_SIZE, as long as that allocation is the first allocation after |
| expiration of kfence sample interval. But in certain debugging scenarios |
| we may be interested in debugging corruptions involving some specific slub |
| objects like dentry or ext4_* etc. In such cases limiting kfence for |
| allocations involving only specific slub objects will increase the |
| probablity of catching the issue since kfence pool will not be consumed by |
| other slab objects. |
| |
| This patch introduces a sysfs interface |
| '/sys/kernel/slab/<name>/skip_kfence' to disable kfence for specific |
| slabs. Having the interface work in this way does not impact |
| current/default behavior of kfence and allows us to use kfence for |
| specific slabs (when needed) as well. The decision to skip/use kfence is |
| taken depending on whether kmem_cache.flags has (newly introduced) |
| SLAB_SKIP_KFENCE flag set or not. |
| |
| Link: https://lkml.kernel.org/r/20220814195353.2540848-1-imran.f.khan@oracle.com |
| Signed-off-by: Imran Khan <imran.f.khan@oracle.com> |
| Reviewed-by: Vlastimil Babka <vbabka@suse.cz> |
| Reviewed-by: Marco Elver <elver@google.com> |
| Reviewed-by: Hyeonggon Yoo <42.hyeyoo@gmail.com> |
| Cc: Alexander Potapenko <glider@google.com> |
| Cc: Dmitry Vyukov <dvyukov@google.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> |
| Cc: Roman Gushchin <roman.gushchin@linux.dev> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| include/linux/slab.h | 6 ++++++ |
| mm/kfence/core.c | 7 +++++++ |
| mm/slub.c | 26 ++++++++++++++++++++++++++ |
| 3 files changed, 39 insertions(+) |
| |
| --- a/include/linux/slab.h~kfence-add-sysfs-interface-to-disable-kfence-for-selected-slabs |
| +++ a/include/linux/slab.h |
| @@ -119,6 +119,12 @@ |
| */ |
| #define SLAB_NO_USER_FLAGS ((slab_flags_t __force)0x10000000U) |
| |
| +#ifdef CONFIG_KFENCE |
| +#define SLAB_SKIP_KFENCE ((slab_flags_t __force)0x20000000U) |
| +#else |
| +#define SLAB_SKIP_KFENCE 0 |
| +#endif |
| + |
| /* The following flags affect the page allocator grouping pages by mobility */ |
| /* Objects are reclaimable */ |
| #define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0x00020000U) |
| --- a/mm/kfence/core.c~kfence-add-sysfs-interface-to-disable-kfence-for-selected-slabs |
| +++ a/mm/kfence/core.c |
| @@ -1003,6 +1003,13 @@ void *__kfence_alloc(struct kmem_cache * |
| return NULL; |
| } |
| |
| + /* |
| + * Skip allocations for this slab, if KFENCE has been disabled for |
| + * this slab. |
| + */ |
| + if (s->flags & SLAB_SKIP_KFENCE) |
| + return NULL; |
| + |
| if (atomic_inc_return(&kfence_allocation_gate) > 1) |
| return NULL; |
| #ifdef CONFIG_KFENCE_STATIC_KEYS |
| --- a/mm/slub.c~kfence-add-sysfs-interface-to-disable-kfence-for-selected-slabs |
| +++ a/mm/slub.c |
| @@ -5745,6 +5745,29 @@ STAT_ATTR(CPU_PARTIAL_NODE, cpu_partial_ |
| STAT_ATTR(CPU_PARTIAL_DRAIN, cpu_partial_drain); |
| #endif /* CONFIG_SLUB_STATS */ |
| |
| +#ifdef CONFIG_KFENCE |
| +static ssize_t skip_kfence_show(struct kmem_cache *s, char *buf) |
| +{ |
| + return sysfs_emit(buf, "%d\n", !!(s->flags & SLAB_SKIP_KFENCE)); |
| +} |
| + |
| +static ssize_t skip_kfence_store(struct kmem_cache *s, |
| + const char *buf, size_t length) |
| +{ |
| + int ret = length; |
| + |
| + if (buf[0] == '0') |
| + s->flags &= ~SLAB_SKIP_KFENCE; |
| + else if (buf[0] == '1') |
| + s->flags |= SLAB_SKIP_KFENCE; |
| + else |
| + ret = -EINVAL; |
| + |
| + return ret; |
| +} |
| +SLAB_ATTR(skip_kfence); |
| +#endif |
| + |
| static struct attribute *slab_attrs[] = { |
| &slab_size_attr.attr, |
| &object_size_attr.attr, |
| @@ -5812,6 +5835,9 @@ static struct attribute *slab_attrs[] = |
| &failslab_attr.attr, |
| #endif |
| &usersize_attr.attr, |
| +#ifdef CONFIG_KFENCE |
| + &skip_kfence_attr.attr, |
| +#endif |
| |
| NULL |
| }; |
| _ |