aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Windsor <dave@nullcore.net>2017-06-10 22:50:28 -0400
committerKees Cook <keescook@chromium.org>2018-01-15 15:07:47 -0500
commit8eb8284b412906181357c2b0110d879d5af95e52 (patch)
treefb1480a162d7999fbc739dc84ee3c44afc5f7b10
parent4229a470175be14e1d2648713be8a5e8e8fbea02 (diff)
usercopy: Prepare for usercopy whitelisting
This patch prepares the slab allocator to handle caches having annotations (useroffset and usersize) defining usercopy regions. This patch is modified from Brad Spengler/PaX Team's PAX_USERCOPY whitelisting code in the last public patch of grsecurity/PaX based on my understanding of the code. Changes or omissions from the original code are mine and don't reflect the original grsecurity/PaX code. Currently, hardened usercopy performs dynamic bounds checking on slab cache objects. This is good, but still leaves a lot of kernel memory available to be copied to/from userspace in the face of bugs. To further restrict what memory is available for copying, this creates a way to whitelist specific areas of a given slab cache object for copying to/from userspace, allowing much finer granularity of access control. Slab caches that are never exposed to userspace can declare no whitelist for their objects, thereby keeping them unavailable to userspace via dynamic copy operations. (Note, an implicit form of whitelisting is the use of constant sizes in usercopy operations and get_user()/put_user(); these bypass hardened usercopy checks since these sizes cannot change at runtime.) To support this whitelist annotation, usercopy region offset and size members are added to struct kmem_cache. The slab allocator receives a new function, kmem_cache_create_usercopy(), that creates a new cache with a usercopy region defined, suitable for declaring spans of fields within the objects that get copied to/from userspace. In this patch, the default kmem_cache_create() marks the entire allocation as whitelisted, leaving it semantically unchanged. Once all fine-grained whitelists have been added (in subsequent patches), this will be changed to a usersize of 0, making caches created with kmem_cache_create() not copyable to/from userspace. After the entire usercopy whitelist series is applied, less than 15% of the slab cache memory remains exposed to potential usercopy bugs after a fresh boot: Total Slab Memory: 48074720 Usercopyable Memory: 6367532 13.2% task_struct 0.2% 4480/1630720 RAW 0.3% 300/96000 RAWv6 2.1% 1408/64768 ext4_inode_cache 3.0% 269760/8740224 dentry 11.1% 585984/5273856 mm_struct 29.1% 54912/188448 kmalloc-8 100.0% 24576/24576 kmalloc-16 100.0% 28672/28672 kmalloc-32 100.0% 81920/81920 kmalloc-192 100.0% 96768/96768 kmalloc-128 100.0% 143360/143360 names_cache 100.0% 163840/163840 kmalloc-64 100.0% 167936/167936 kmalloc-256 100.0% 339968/339968 kmalloc-512 100.0% 350720/350720 kmalloc-96 100.0% 455616/455616 kmalloc-8192 100.0% 655360/655360 kmalloc-1024 100.0% 812032/812032 kmalloc-4096 100.0% 819200/819200 kmalloc-2048 100.0% 1310720/1310720 After some kernel build workloads, the percentage (mainly driven by dentry and inode caches expanding) drops under 10%: Total Slab Memory: 95516184 Usercopyable Memory: 8497452 8.8% task_struct 0.2% 4000/1456000 RAW 0.3% 300/96000 RAWv6 2.1% 1408/64768 ext4_inode_cache 3.0% 1217280/39439872 dentry 11.1% 1623200/14608800 mm_struct 29.1% 73216/251264 kmalloc-8 100.0% 24576/24576 kmalloc-16 100.0% 28672/28672 kmalloc-32 100.0% 94208/94208 kmalloc-192 100.0% 96768/96768 kmalloc-128 100.0% 143360/143360 names_cache 100.0% 163840/163840 kmalloc-64 100.0% 245760/245760 kmalloc-256 100.0% 339968/339968 kmalloc-512 100.0% 350720/350720 kmalloc-96 100.0% 563520/563520 kmalloc-8192 100.0% 655360/655360 kmalloc-1024 100.0% 794624/794624 kmalloc-4096 100.0% 819200/819200 kmalloc-2048 100.0% 1257472/1257472 Signed-off-by: David Windsor <dave@nullcore.net> [kees: adjust commit log, split out a few extra kmalloc hunks] [kees: add field names to function declarations] [kees: convert BUGs to WARNs and fail closed] [kees: add attack surface reduction analysis to commit log] Cc: Pekka Enberg <penberg@kernel.org> Cc: David Rientjes <rientjes@google.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: linux-mm@kvack.org Cc: linux-xfs@vger.kernel.org Signed-off-by: Kees Cook <keescook@chromium.org> Acked-by: Christoph Lameter <cl@linux.com>
-rw-r--r--include/linux/slab.h27
-rw-r--r--include/linux/slab_def.h3
-rw-r--r--include/linux/slub_def.h3
-rw-r--r--mm/slab.c2
-rw-r--r--mm/slab.h5
-rw-r--r--mm/slab_common.c46
-rw-r--r--mm/slub.c11
7 files changed, 79 insertions, 18 deletions
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 2dbeccdcb76b..8bf14d9762ec 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -135,9 +135,13 @@ struct mem_cgroup;
135void __init kmem_cache_init(void); 135void __init kmem_cache_init(void);
136bool slab_is_available(void); 136bool slab_is_available(void);
137 137
138struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, 138struct kmem_cache *kmem_cache_create(const char *name, size_t size,
139 slab_flags_t, 139 size_t align, slab_flags_t flags,
140 void (*)(void *)); 140 void (*ctor)(void *));
141struct kmem_cache *kmem_cache_create_usercopy(const char *name,
142 size_t size, size_t align, slab_flags_t flags,
143 size_t useroffset, size_t usersize,
144 void (*ctor)(void *));
141void kmem_cache_destroy(struct kmem_cache *); 145void kmem_cache_destroy(struct kmem_cache *);
142int kmem_cache_shrink(struct kmem_cache *); 146int kmem_cache_shrink(struct kmem_cache *);
143 147
@@ -153,9 +157,20 @@ void memcg_destroy_kmem_caches(struct mem_cgroup *);
153 * f.e. add ____cacheline_aligned_in_smp to the struct declaration 157 * f.e. add ____cacheline_aligned_in_smp to the struct declaration
154 * then the objects will be properly aligned in SMP configurations. 158 * then the objects will be properly aligned in SMP configurations.
155 */ 159 */
156#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ 160#define KMEM_CACHE(__struct, __flags) \
157 sizeof(struct __struct), __alignof__(struct __struct),\ 161 kmem_cache_create(#__struct, sizeof(struct __struct), \
158 (__flags), NULL) 162 __alignof__(struct __struct), (__flags), NULL)
163
164/*
165 * To whitelist a single field for copying to/from usercopy, use this
166 * macro instead for KMEM_CACHE() above.
167 */
168#define KMEM_CACHE_USERCOPY(__struct, __flags, __field) \
169 kmem_cache_create_usercopy(#__struct, \
170 sizeof(struct __struct), \
171 __alignof__(struct __struct), (__flags), \
172 offsetof(struct __struct, __field), \
173 sizeof_field(struct __struct, __field), NULL)
159 174
160/* 175/*
161 * Common kmalloc functions provided by all allocators 176 * Common kmalloc functions provided by all allocators
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index 072e46e9e1d5..7385547c04b1 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -85,6 +85,9 @@ struct kmem_cache {
85 unsigned int *random_seq; 85 unsigned int *random_seq;
86#endif 86#endif
87 87
88 size_t useroffset; /* Usercopy region offset */
89 size_t usersize; /* Usercopy region size */
90
88 struct kmem_cache_node *node[MAX_NUMNODES]; 91 struct kmem_cache_node *node[MAX_NUMNODES];
89}; 92};
90 93
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 0adae162dc8f..8ad99c47b19c 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -135,6 +135,9 @@ struct kmem_cache {
135 struct kasan_cache kasan_info; 135 struct kasan_cache kasan_info;
136#endif 136#endif
137 137
138 size_t useroffset; /* Usercopy region offset */
139 size_t usersize; /* Usercopy region size */
140
138 struct kmem_cache_node *node[MAX_NUMNODES]; 141 struct kmem_cache_node *node[MAX_NUMNODES];
139}; 142};
140 143
diff --git a/mm/slab.c b/mm/slab.c
index b2beb2cc15e2..47acfe54e1ae 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1281,7 +1281,7 @@ void __init kmem_cache_init(void)
1281 create_boot_cache(kmem_cache, "kmem_cache", 1281 create_boot_cache(kmem_cache, "kmem_cache",
1282 offsetof(struct kmem_cache, node) + 1282 offsetof(struct kmem_cache, node) +
1283 nr_node_ids * sizeof(struct kmem_cache_node *), 1283 nr_node_ids * sizeof(struct kmem_cache_node *),
1284 SLAB_HWCACHE_ALIGN); 1284 SLAB_HWCACHE_ALIGN, 0, 0);
1285 list_add(&kmem_cache->list, &slab_caches); 1285 list_add(&kmem_cache->list, &slab_caches);
1286 slab_state = PARTIAL; 1286 slab_state = PARTIAL;
1287 1287
diff --git a/mm/slab.h b/mm/slab.h
index ad657ffa44e5..8f3030788e01 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -22,6 +22,8 @@ struct kmem_cache {
22 unsigned int size; /* The aligned/padded/added on size */ 22 unsigned int size; /* The aligned/padded/added on size */
23 unsigned int align; /* Alignment as calculated */ 23 unsigned int align; /* Alignment as calculated */
24 slab_flags_t flags; /* Active flags on the slab */ 24 slab_flags_t flags; /* Active flags on the slab */
25 size_t useroffset; /* Usercopy region offset */
26 size_t usersize; /* Usercopy region size */
25 const char *name; /* Slab name for sysfs */ 27 const char *name; /* Slab name for sysfs */
26 int refcount; /* Use counter */ 28 int refcount; /* Use counter */
27 void (*ctor)(void *); /* Called on object slot creation */ 29 void (*ctor)(void *); /* Called on object slot creation */
@@ -97,7 +99,8 @@ int __kmem_cache_create(struct kmem_cache *, slab_flags_t flags);
97extern struct kmem_cache *create_kmalloc_cache(const char *name, size_t size, 99extern struct kmem_cache *create_kmalloc_cache(const char *name, size_t size,
98 slab_flags_t flags); 100 slab_flags_t flags);
99extern void create_boot_cache(struct kmem_cache *, const char *name, 101extern void create_boot_cache(struct kmem_cache *, const char *name,
100 size_t size, slab_flags_t flags); 102 size_t size, slab_flags_t flags, size_t useroffset,
103 size_t usersize);
101 104
102int slab_unmergeable(struct kmem_cache *s); 105int slab_unmergeable(struct kmem_cache *s);
103struct kmem_cache *find_mergeable(size_t size, size_t align, 106struct kmem_cache *find_mergeable(size_t size, size_t align,
diff --git a/mm/slab_common.c b/mm/slab_common.c
index c8cb36774ba1..fc3e66bdce75 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -281,6 +281,9 @@ int slab_unmergeable(struct kmem_cache *s)
281 if (s->ctor) 281 if (s->ctor)
282 return 1; 282 return 1;
283 283
284 if (s->usersize)
285 return 1;
286
284 /* 287 /*
285 * We may have set a slab to be unmergeable during bootstrap. 288 * We may have set a slab to be unmergeable during bootstrap.
286 */ 289 */
@@ -366,12 +369,16 @@ unsigned long calculate_alignment(slab_flags_t flags,
366 369
367static struct kmem_cache *create_cache(const char *name, 370static struct kmem_cache *create_cache(const char *name,
368 size_t object_size, size_t size, size_t align, 371 size_t object_size, size_t size, size_t align,
369 slab_flags_t flags, void (*ctor)(void *), 372 slab_flags_t flags, size_t useroffset,
373 size_t usersize, void (*ctor)(void *),
370 struct mem_cgroup *memcg, struct kmem_cache *root_cache) 374 struct mem_cgroup *memcg, struct kmem_cache *root_cache)
371{ 375{
372 struct kmem_cache *s; 376 struct kmem_cache *s;
373 int err; 377 int err;
374 378
379 if (WARN_ON(useroffset + usersize > object_size))
380 useroffset = usersize = 0;
381
375 err = -ENOMEM; 382 err = -ENOMEM;
376 s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL); 383 s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
377 if (!s) 384 if (!s)
@@ -382,6 +389,8 @@ static struct kmem_cache *create_cache(const char *name,
382 s->size = size; 389 s->size = size;
383 s->align = align; 390 s->align = align;
384 s->ctor = ctor; 391 s->ctor = ctor;
392 s->useroffset = useroffset;
393 s->usersize = usersize;
385 394
386 err = init_memcg_params(s, memcg, root_cache); 395 err = init_memcg_params(s, memcg, root_cache);
387 if (err) 396 if (err)
@@ -406,11 +415,13 @@ out_free_cache:
406} 415}
407 416
408/* 417/*
409 * kmem_cache_create - Create a cache. 418 * kmem_cache_create_usercopy - Create a cache.
410 * @name: A string which is used in /proc/slabinfo to identify this cache. 419 * @name: A string which is used in /proc/slabinfo to identify this cache.
411 * @size: The size of objects to be created in this cache. 420 * @size: The size of objects to be created in this cache.
412 * @align: The required alignment for the objects. 421 * @align: The required alignment for the objects.
413 * @flags: SLAB flags 422 * @flags: SLAB flags
423 * @useroffset: Usercopy region offset
424 * @usersize: Usercopy region size
414 * @ctor: A constructor for the objects. 425 * @ctor: A constructor for the objects.
415 * 426 *
416 * Returns a ptr to the cache on success, NULL on failure. 427 * Returns a ptr to the cache on success, NULL on failure.
@@ -430,8 +441,9 @@ out_free_cache:
430 * as davem. 441 * as davem.
431 */ 442 */
432struct kmem_cache * 443struct kmem_cache *
433kmem_cache_create(const char *name, size_t size, size_t align, 444kmem_cache_create_usercopy(const char *name, size_t size, size_t align,
434 slab_flags_t flags, void (*ctor)(void *)) 445 slab_flags_t flags, size_t useroffset, size_t usersize,
446 void (*ctor)(void *))
435{ 447{
436 struct kmem_cache *s = NULL; 448 struct kmem_cache *s = NULL;
437 const char *cache_name; 449 const char *cache_name;
@@ -462,7 +474,13 @@ kmem_cache_create(const char *name, size_t size, size_t align,
462 */ 474 */
463 flags &= CACHE_CREATE_MASK; 475 flags &= CACHE_CREATE_MASK;
464 476
465 s = __kmem_cache_alias(name, size, align, flags, ctor); 477 /* Fail closed on bad usersize of useroffset values. */
478 if (WARN_ON(!usersize && useroffset) ||
479 WARN_ON(size < usersize || size - usersize < useroffset))
480 usersize = useroffset = 0;
481
482 if (!usersize)
483 s = __kmem_cache_alias(name, size, align, flags, ctor);
466 if (s) 484 if (s)
467 goto out_unlock; 485 goto out_unlock;
468 486
@@ -474,7 +492,7 @@ kmem_cache_create(const char *name, size_t size, size_t align,
474 492
475 s = create_cache(cache_name, size, size, 493 s = create_cache(cache_name, size, size,
476 calculate_alignment(flags, align, size), 494 calculate_alignment(flags, align, size),
477 flags, ctor, NULL, NULL); 495 flags, useroffset, usersize, ctor, NULL, NULL);
478 if (IS_ERR(s)) { 496 if (IS_ERR(s)) {
479 err = PTR_ERR(s); 497 err = PTR_ERR(s);
480 kfree_const(cache_name); 498 kfree_const(cache_name);
@@ -500,6 +518,15 @@ out_unlock:
500 } 518 }
501 return s; 519 return s;
502} 520}
521EXPORT_SYMBOL(kmem_cache_create_usercopy);
522
523struct kmem_cache *
524kmem_cache_create(const char *name, size_t size, size_t align,
525 slab_flags_t flags, void (*ctor)(void *))
526{
527 return kmem_cache_create_usercopy(name, size, align, flags, 0, size,
528 ctor);
529}
503EXPORT_SYMBOL(kmem_cache_create); 530EXPORT_SYMBOL(kmem_cache_create);
504 531
505static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work) 532static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work)
@@ -612,6 +639,7 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg,
612 s = create_cache(cache_name, root_cache->object_size, 639 s = create_cache(cache_name, root_cache->object_size,
613 root_cache->size, root_cache->align, 640 root_cache->size, root_cache->align,
614 root_cache->flags & CACHE_CREATE_MASK, 641 root_cache->flags & CACHE_CREATE_MASK,
642 root_cache->useroffset, root_cache->usersize,
615 root_cache->ctor, memcg, root_cache); 643 root_cache->ctor, memcg, root_cache);
616 /* 644 /*
617 * If we could not create a memcg cache, do not complain, because 645 * If we could not create a memcg cache, do not complain, because
@@ -879,13 +907,15 @@ bool slab_is_available(void)
879#ifndef CONFIG_SLOB 907#ifndef CONFIG_SLOB
880/* Create a cache during boot when no slab services are available yet */ 908/* Create a cache during boot when no slab services are available yet */
881void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size, 909void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size,
882 slab_flags_t flags) 910 slab_flags_t flags, size_t useroffset, size_t usersize)
883{ 911{
884 int err; 912 int err;
885 913
886 s->name = name; 914 s->name = name;
887 s->size = s->object_size = size; 915 s->size = s->object_size = size;
888 s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size); 916 s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size);
917 s->useroffset = useroffset;
918 s->usersize = usersize;
889 919
890 slab_init_memcg_params(s); 920 slab_init_memcg_params(s);
891 921
@@ -906,7 +936,7 @@ struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,
906 if (!s) 936 if (!s)
907 panic("Out of memory when creating slab %s\n", name); 937 panic("Out of memory when creating slab %s\n", name);
908 938
909 create_boot_cache(s, name, size, flags); 939 create_boot_cache(s, name, size, flags, 0, size);
910 list_add(&s->list, &slab_caches); 940 list_add(&s->list, &slab_caches);
911 memcg_link_cache(s); 941 memcg_link_cache(s);
912 s->refcount = 1; 942 s->refcount = 1;
diff --git a/mm/slub.c b/mm/slub.c
index bcd22332300a..f40a57164dd6 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -4183,7 +4183,7 @@ void __init kmem_cache_init(void)
4183 kmem_cache = &boot_kmem_cache; 4183 kmem_cache = &boot_kmem_cache;
4184 4184
4185 create_boot_cache(kmem_cache_node, "kmem_cache_node", 4185 create_boot_cache(kmem_cache_node, "kmem_cache_node",
4186 sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN); 4186 sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN, 0, 0);
4187 4187
4188 register_hotmemory_notifier(&slab_memory_callback_nb); 4188 register_hotmemory_notifier(&slab_memory_callback_nb);
4189 4189
@@ -4193,7 +4193,7 @@ void __init kmem_cache_init(void)
4193 create_boot_cache(kmem_cache, "kmem_cache", 4193 create_boot_cache(kmem_cache, "kmem_cache",
4194 offsetof(struct kmem_cache, node) + 4194 offsetof(struct kmem_cache, node) +
4195 nr_node_ids * sizeof(struct kmem_cache_node *), 4195 nr_node_ids * sizeof(struct kmem_cache_node *),
4196 SLAB_HWCACHE_ALIGN); 4196 SLAB_HWCACHE_ALIGN, 0, 0);
4197 4197
4198 kmem_cache = bootstrap(&boot_kmem_cache); 4198 kmem_cache = bootstrap(&boot_kmem_cache);
4199 4199
@@ -5063,6 +5063,12 @@ static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
5063SLAB_ATTR_RO(cache_dma); 5063SLAB_ATTR_RO(cache_dma);
5064#endif 5064#endif
5065 5065
5066static ssize_t usersize_show(struct kmem_cache *s, char *buf)
5067{
5068 return sprintf(buf, "%zu\n", s->usersize);
5069}
5070SLAB_ATTR_RO(usersize);
5071
5066static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf) 5072static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
5067{ 5073{
5068 return sprintf(buf, "%d\n", !!(s->flags & SLAB_TYPESAFE_BY_RCU)); 5074 return sprintf(buf, "%d\n", !!(s->flags & SLAB_TYPESAFE_BY_RCU));
@@ -5437,6 +5443,7 @@ static struct attribute *slab_attrs[] = {
5437#ifdef CONFIG_FAILSLAB 5443#ifdef CONFIG_FAILSLAB
5438 &failslab_attr.attr, 5444 &failslab_attr.attr,
5439#endif 5445#endif
5446 &usersize_attr.attr,
5440 5447
5441 NULL 5448 NULL
5442}; 5449};