summaryrefslogtreecommitdiff
path: root/sys-kernel/cairn-sources/files/5.10.4/hardened-patches/0057-slub-add-multi-purpose-random-canaries.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sys-kernel/cairn-sources/files/5.10.4/hardened-patches/0057-slub-add-multi-purpose-random-canaries.patch')
-rw-r--r--sys-kernel/cairn-sources/files/5.10.4/hardened-patches/0057-slub-add-multi-purpose-random-canaries.patch264
1 files changed, 264 insertions, 0 deletions
diff --git a/sys-kernel/cairn-sources/files/5.10.4/hardened-patches/0057-slub-add-multi-purpose-random-canaries.patch b/sys-kernel/cairn-sources/files/5.10.4/hardened-patches/0057-slub-add-multi-purpose-random-canaries.patch
new file mode 100644
index 000000000000..1c38e4733107
--- /dev/null
+++ b/sys-kernel/cairn-sources/files/5.10.4/hardened-patches/0057-slub-add-multi-purpose-random-canaries.patch
@@ -0,0 +1,264 @@
+From 551722a13257966781dad52618ad54ba9cc6427c Mon Sep 17 00:00:00 2001
+From: Daniel Micay <danielmicay@gmail.com>
+Date: Wed, 3 May 2017 16:16:58 -0400
+Subject: [PATCH 057/112] slub: add multi-purpose random canaries
+
+From the configuration option:
+
+ Place canaries at the end of kernel slab allocations, sacrificing
+ some performance and memory usage for security.
+
+ Canaries can detect some forms of heap corruption when allocations
+ are freed and as part of the HARDENED_USERCOPY feature. It provides
+ basic use-after-free detection for HARDENED_USERCOPY.
+
+ Canaries absorb small overflows (rendering them harmless), mitigate
+ non-NUL terminated C string overflows on 64-bit via a guaranteed zero
+ byte and provide basic double-free detection.
+
+Signed-off-by: Daniel Micay <danielmicay@gmail.com>
+---
+ include/linux/slub_def.h | 5 +++
+ init/Kconfig | 17 ++++++++++
+ mm/slab.h | 2 +-
+ mm/slub.c | 69 ++++++++++++++++++++++++++++++++++++++--
+ 4 files changed, 89 insertions(+), 4 deletions(-)
+
+diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
+index 1be0ed5befa1..c71cf30b5987 100644
+--- a/include/linux/slub_def.h
++++ b/include/linux/slub_def.h
+@@ -113,6 +113,11 @@ struct kmem_cache {
+ unsigned long random;
+ #endif
+
++#ifdef CONFIG_SLAB_CANARY
++ unsigned long random_active;
++ unsigned long random_inactive;
++#endif
++
+ #ifdef CONFIG_NUMA
+ /*
+ * Defragmentation by allocating from a remote node.
+diff --git a/init/Kconfig b/init/Kconfig
+index 9b75a4921575..f15109e7b111 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1945,6 +1945,23 @@ config SLAB_FREELIST_HARDENED
+ sanity-checking than others. This option is most effective with
+ CONFIG_SLUB.
+
++config SLAB_CANARY
++ depends on SLUB
++ depends on !SLAB_MERGE_DEFAULT
++ bool "SLAB canaries"
++ default y
++ help
++ Place canaries at the end of kernel slab allocations, sacrificing
++ some performance and memory usage for security.
++
++ Canaries can detect some forms of heap corruption when allocations
++ are freed and as part of the HARDENED_USERCOPY feature. It provides
++ basic use-after-free detection for HARDENED_USERCOPY.
++
++ Canaries absorb small overflows (rendering them harmless), mitigate
++ non-NUL terminated C string overflows on 64-bit via a guaranteed zero
++ byte and provide basic double-free detection.
++
+ config SHUFFLE_PAGE_ALLOCATOR
+ bool "Page allocator randomization"
+ default SLAB_FREELIST_RANDOM && ACPI_NUMA
+diff --git a/mm/slab.h b/mm/slab.h
+index 0fcd97a4eb6f..105dba485a7e 100644
+--- a/mm/slab.h
++++ b/mm/slab.h
+@@ -504,7 +504,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s)
+ * back there or track user information then we can
+ * only use the space before that information.
+ */
+- if (s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER))
++ if ((s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER)) || IS_ENABLED(CONFIG_SLAB_CANARY))
+ return s->inuse;
+ /*
+ * Else we can use all the padding etc for the allocation
+diff --git a/mm/slub.c b/mm/slub.c
+index d42d2709526a..c949d918dc7f 100644
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -569,6 +569,33 @@ static inline unsigned int get_info_end(struct kmem_cache *s)
+ return s->inuse;
+ }
+
++#ifdef CONFIG_SLAB_CANARY
++static inline unsigned long *get_canary(struct kmem_cache *s, void *object)
++{
++ return object + get_info_end(s);
++}
++
++static inline unsigned long get_canary_value(const void *canary, unsigned long value)
++{
++ return (value ^ (unsigned long)canary) & CANARY_MASK;
++}
++
++static inline void set_canary(struct kmem_cache *s, void *object, unsigned long value)
++{
++ unsigned long *canary = get_canary(s, object);
++ *canary = get_canary_value(canary, value);
++}
++
++static inline void check_canary(struct kmem_cache *s, void *object, unsigned long value)
++{
++ unsigned long *canary = get_canary(s, object);
++ BUG_ON(*canary != get_canary_value(canary, value));
++}
++#else
++#define set_canary(s, object, value)
++#define check_canary(s, object, value)
++#endif
++
+ static struct track *get_track(struct kmem_cache *s, void *object,
+ enum track_item alloc)
+ {
+@@ -576,6 +603,9 @@ static struct track *get_track(struct kmem_cache *s, void *object,
+
+ p = object + get_info_end(s);
+
++ if (IS_ENABLED(CONFIG_SLAB_CANARY))
++ p = (void *)p + sizeof(void *);
++
+ return p + alloc;
+ }
+
+@@ -717,6 +747,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
+
+ off = get_info_end(s);
+
++ if (IS_ENABLED(CONFIG_SLAB_CANARY))
++ off += sizeof(void *);
++
+ if (s->flags & SLAB_STORE_USER)
+ off += 2 * sizeof(struct track);
+
+@@ -825,8 +858,9 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
+ * Meta data starts here.
+ *
+ * A. Free pointer (if we cannot overwrite object on free)
+- * B. Tracking data for SLAB_STORE_USER
+- * C. Padding to reach required alignment boundary or at mininum
++ * B. Canary for SLAB_CANARY
++ * C. Tracking data for SLAB_STORE_USER
++ * D. Padding to reach required alignment boundary or at mininum
+ * one word if debugging is on to be able to detect writes
+ * before the word boundary.
+ *
+@@ -844,6 +878,9 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
+ {
+ unsigned long off = get_info_end(s); /* The end of info */
+
++ if (IS_ENABLED(CONFIG_SLAB_CANARY))
++ off += sizeof(void *);
++
+ if (s->flags & SLAB_STORE_USER)
+ /* We also have user information there */
+ off += 2 * sizeof(struct track);
+@@ -1567,6 +1604,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
+ object = next;
+ next = get_freepointer(s, object);
+
++ check_canary(s, object, s->random_active);
++
+ if (slab_want_init_on_free(s)) {
+ /*
+ * Clear the object and the metadata, but don't touch
+@@ -1580,6 +1619,9 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s,
+ if (!IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && s->ctor)
+ s->ctor(object);
+ }
++
++ set_canary(s, object, s->random_inactive);
++
+ /* If object's reuse doesn't have to be delayed */
+ if (!slab_free_hook(s, object)) {
+ /* Move object to the new freelist */
+@@ -1611,6 +1653,7 @@ static void *setup_object(struct kmem_cache *s, struct page *page,
+ void *object)
+ {
+ setup_object_debug(s, page, object);
++ set_canary(s, object, s->random_inactive);
+ object = kasan_init_slab_obj(s, object);
+ if (unlikely(s->ctor) && !has_sanitize_verify(s)) {
+ kasan_unpoison_object_data(s, object);
+@@ -2915,6 +2958,11 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
+ } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object)
+ memset(object, 0, s->object_size);
+
++ if (object) {
++ check_canary(s, object, s->random_inactive);
++ set_canary(s, object, s->random_active);
++ }
++
+ slab_post_alloc_hook(s, objcg, gfpflags, 1, &object);
+
+ return object;
+@@ -3302,7 +3350,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+ void **p)
+ {
+ struct kmem_cache_cpu *c;
+- int i;
++ int i, k;
+ struct obj_cgroup *objcg = NULL;
+
+ /* memcg and kmem_cache debug support */
+@@ -3372,6 +3420,11 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+ memset(p[j], 0, s->object_size);
+ }
+
++ for (k = 0; k < i; k++) {
++ check_canary(s, p[k], s->random_inactive);
++ set_canary(s, p[k], s->random_active);
++ }
++
+ /* memcg and kmem_cache debug support */
+ slab_post_alloc_hook(s, objcg, flags, size, p);
+ return i;
+@@ -3573,6 +3626,7 @@ static void early_kmem_cache_node_alloc(int node)
+ init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
+ init_tracking(kmem_cache_node, n);
+ #endif
++ set_canary(kmem_cache_node, n, kmem_cache_node->random_active);
+ n = kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node),
+ GFP_KERNEL);
+ page->freelist = get_freepointer(kmem_cache_node, n);
+@@ -3753,6 +3807,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
+ s->offset = ALIGN(freepointer_area / 2, sizeof(void *));
+ }
+
++ if (IS_ENABLED(CONFIG_SLAB_CANARY))
++ size += sizeof(void *);
++
+ #ifdef CONFIG_SLUB_DEBUG
+ if (flags & SLAB_STORE_USER)
+ /*
+@@ -3826,6 +3883,10 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags)
+ #ifdef CONFIG_SLAB_FREELIST_HARDENED
+ s->random = get_random_long();
+ #endif
++#ifdef CONFIG_SLAB_CANARY
++ s->random_active = get_random_long();
++ s->random_inactive = get_random_long();
++#endif
+
+ if (!calculate_sizes(s, -1))
+ goto error;
+@@ -4099,6 +4160,8 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page,
+ offset -= s->red_left_pad;
+ }
+
++ check_canary(s, (void *)ptr - offset, s->random_active);
++
+ /* Allow address range falling entirely within usercopy region. */
+ if (offset >= s->useroffset &&
+ offset - s->useroffset <= s->usersize &&
+--
+2.30.0
+