mm, slab: ignore hardened usercopy parameters when disabled
authorVlastimil Babka <vbabka@suse.cz>
Wed, 16 Nov 2022 14:56:32 +0000 (15:56 +0100)
committerVlastimil Babka <vbabka@suse.cz>
Sun, 27 Nov 2022 22:35:04 +0000 (23:35 +0100)
With CONFIG_HARDENED_USERCOPY not enabled, there are no
__check_heap_object() checks happening that would use the struct
kmem_cache useroffset and usersize fields. Yet the fields are still
initialized, preventing merging of otherwise compatible caches.

Also the fields contribute to struct kmem_cache size unnecessarily when
unused. Thus #ifdef them out completely when CONFIG_HARDENED_USERCOPY is
disabled. In kmem_dump_obj() print object_size instead of usersize, as
that's actually the intention.

In a quick virtme boot test, this has reduced the number of caches in
/proc/slabinfo from 131 to 111.

Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Acked-by: Mike Rapoport <rppt@linux.ibm.com>
Reviewed-by: Christoph Lameter <cl@linux.com>
include/linux/slab_def.h
include/linux/slub_def.h
mm/slab.h
mm/slab_common.c
mm/slub.c

index f0ffad6a336531e0383cc2162b481241ef1ad440..5834bad8ad78bc38a28946bd04a038e0b28e8b9e 100644 (file)
@@ -80,8 +80,10 @@ struct kmem_cache {
        unsigned int *random_seq;
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
        unsigned int useroffset;        /* Usercopy region offset */
        unsigned int usersize;          /* Usercopy region size */
+#endif
 
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
index f9c68a9dac04293fcb077fe30c80514b0e517b7c..7ed5e455cbf4e3afff47c5bad8022926fdda31b1 100644 (file)
@@ -136,8 +136,10 @@ struct kmem_cache {
        struct kasan_cache kasan_info;
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
        unsigned int useroffset;        /* Usercopy region offset */
        unsigned int usersize;          /* Usercopy region size */
+#endif
 
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
index 0202a8c2f0d25dc4d00ae339e0d1ab06d6f4518b..db9a7984e22ef13d525291e9aec4f5f5dfe5c10c 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -207,8 +207,6 @@ struct kmem_cache {
        unsigned int size;      /* The aligned/padded/added on size  */
        unsigned int align;     /* Alignment as calculated */
        slab_flags_t flags;     /* Active flags on the slab */
-       unsigned int useroffset;/* Usercopy region offset */
-       unsigned int usersize;  /* Usercopy region size */
        const char *name;       /* Slab name for sysfs */
        int refcount;           /* Use counter */
        void (*ctor)(void *);   /* Called on object slot creation */
index 0042fb2730d1e1ef107a213627716b149ae96cb7..af0f370fe7a28a492462af700aa03c474bef606e 100644 (file)
@@ -143,8 +143,10 @@ int slab_unmergeable(struct kmem_cache *s)
        if (s->ctor)
                return 1;
 
+#ifdef CONFIG_HARDENED_USERCOPY
        if (s->usersize)
                return 1;
+#endif
 
        /*
         * We may have set a slab to be unmergeable during bootstrap.
@@ -223,8 +225,10 @@ static struct kmem_cache *create_cache(const char *name,
        s->size = s->object_size = object_size;
        s->align = align;
        s->ctor = ctor;
+#ifdef CONFIG_HARDENED_USERCOPY
        s->useroffset = useroffset;
        s->usersize = usersize;
+#endif
 
        err = __kmem_cache_create(s, flags);
        if (err)
@@ -317,7 +321,8 @@ kmem_cache_create_usercopy(const char *name,
        flags &= CACHE_CREATE_MASK;
 
        /* Fail closed on bad usersize of useroffset values. */
-       if (WARN_ON(!usersize && useroffset) ||
+       if (!IS_ENABLED(CONFIG_HARDENED_USERCOPY) ||
+           WARN_ON(!usersize && useroffset) ||
            WARN_ON(size < usersize || size - usersize < useroffset))
                usersize = useroffset = 0;
 
@@ -595,8 +600,8 @@ void kmem_dump_obj(void *object)
                ptroffset = ((char *)object - (char *)kp.kp_objp) - kp.kp_data_offset;
                pr_cont(" pointer offset %lu", ptroffset);
        }
-       if (kp.kp_slab_cache && kp.kp_slab_cache->usersize)
-               pr_cont(" size %u", kp.kp_slab_cache->usersize);
+       if (kp.kp_slab_cache && kp.kp_slab_cache->object_size)
+               pr_cont(" size %u", kp.kp_slab_cache->object_size);
        if (kp.kp_ret)
                pr_cont(" allocated at %pS\n", kp.kp_ret);
        else
@@ -640,8 +645,10 @@ void __init create_boot_cache(struct kmem_cache *s, const char *name,
                align = max(align, size);
        s->align = calculate_alignment(flags, align, size);
 
+#ifdef CONFIG_HARDENED_USERCOPY
        s->useroffset = useroffset;
        s->usersize = usersize;
+#endif
 
        err = __kmem_cache_create(s, flags);
 
index 157527d7101be0da54026376ff4f4095deb9ec2d..e32db854076794cf3cc6d8b61f42c1b40ce76dcd 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -5502,11 +5502,13 @@ static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
 SLAB_ATTR_RO(cache_dma);
 #endif
 
+#ifdef CONFIG_HARDENED_USERCOPY
 static ssize_t usersize_show(struct kmem_cache *s, char *buf)
 {
        return sysfs_emit(buf, "%u\n", s->usersize);
 }
 SLAB_ATTR_RO(usersize);
+#endif
 
 static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
 {
@@ -5803,7 +5805,9 @@ static struct attribute *slab_attrs[] = {
 #ifdef CONFIG_FAILSLAB
        &failslab_attr.attr,
 #endif
+#ifdef CONFIG_HARDENED_USERCOPY
        &usersize_attr.attr,
+#endif
 #ifdef CONFIG_KFENCE
        &skip_kfence_attr.attr,
 #endif