|
|
Message-Id: <20171122005432.4974-1-mjg59@google.com>
Date: Tue, 21 Nov 2017 16:54:32 -0800
From: Matthew Garrett <mjg59@...gle.com>
To: keescook@...omium.org
Cc: kernel-hardening@...ts.openwall.com, Matthew Garrett <mjg59@...gle.com>
Subject: [PATCH] usercopy: Allow runtime disabling of usercopy fallback
Distributions are likely to build with
CONFIG_HARDENED_USERCOPY_FALLBACK, but individual sites may wish to
disable that functionality. Add a sysctl that allows the fallback to be
disabled and then forbids any attempt to re-enable it.
Signed-off-by: Matthew Garrett <mjg59@...gle.com>
---
Documentation/sysctl/vm.txt | 9 +++++++++
include/linux/mm.h | 7 +++++++
kernel/sysctl.c | 11 +++++++++++
mm/memory.c | 17 +++++++++++++++++
mm/slab.c | 4 +---
mm/slub.c | 4 +---
6 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 9baf66a9ef4e..b494b292fd93 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -60,6 +60,7 @@ Currently, these files are in /proc/sys/vm:
- stat_refresh
- swappiness
- user_reserve_kbytes
+- usercopy_fallback
- vfs_cache_pressure
- watermark_scale_factor
- zone_reclaim_mode
@@ -822,6 +823,14 @@ Changing this takes effect whenever an application requests memory.
==============================================================
+usercopy_fallback
+
+If 1, attempts to copy data from userland will generate a kernel warning
+if the target has not been whitelisted, but will still be permitted. If 0,
+this will result in a kernel BUG(). This may be set from 1 to 0 at runtime,
+but may not be modified if 0.
+
+==============================================================
vfs_cache_pressure
------------------
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f8c10d336e42..511237addbf9 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2456,6 +2456,8 @@ int drop_caches_sysctl_handler(struct ctl_table *, int,
void drop_slab(void);
void drop_slab_node(int nid);
+extern bool usercopy_fallback;
+
#ifndef CONFIG_MMU
#define randomize_va_space 0
#else
@@ -2602,5 +2604,10 @@ void __init setup_nr_node_ids(void);
static inline void setup_nr_node_ids(void) {}
#endif
+#ifdef CONFIG_HARDENED_USERCOPY
+int usercopy_fallback_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos);
+#endif
+
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 423554ad3610..ba3366335b40 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1663,6 +1663,17 @@ static struct ctl_table vm_table[] = {
.extra1 = (void *)&mmap_rnd_compat_bits_min,
.extra2 = (void *)&mmap_rnd_compat_bits_max,
},
+#endif
+#ifdef CONFIG_HARDENED_USERCOPY
+ {
+ .procname = "usercopy_fallback",
+ .data = &usercopy_fallback,
+ .maxlen = sizeof(int),
+ .mode = 0600,
+ .proc_handler = usercopy_fallback_handler,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
#endif
{ }
};
diff --git a/mm/memory.c b/mm/memory.c
index ec4e15494901..29ed21083a8d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -104,6 +104,11 @@ EXPORT_SYMBOL(mem_map);
void *high_memory;
EXPORT_SYMBOL(high_memory);
+#ifdef CONFIG_HARDENED_USERCOPY
+/* Permit non-whitelisted usercopy targets */
+bool usercopy_fallback = IS_ENABLED(CONFIG_HARDENED_USERCOPY_FALLBACK);
+#endif
+
/*
* Randomize the address space (stacks, mmaps, brk, etc.).
*
@@ -4668,3 +4673,15 @@ void ptlock_free(struct page *page)
kmem_cache_free(page_ptl_cachep, page->ptl);
}
#endif
+
+#ifdef CONFIG_HARDENED_USERCOPY
+int usercopy_fallback_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ /* Don't allow re-enabling fallback if it's been disabled */
+ if (write && !usercopy_fallback)
+ return -EINVAL;
+
+ return proc_dointvec_minmax(table, write, buffer, length, ppos);
+}
+#endif
diff --git a/mm/slab.c b/mm/slab.c
index 23c53dc46cd6..6afcac1d8b97 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -4435,21 +4435,19 @@ const char *__check_heap_object(const void *ptr, unsigned long n,
if (offset < cachep->useroffset ||
offset - cachep->useroffset > cachep->usersize ||
n > cachep->useroffset - offset + cachep->usersize) {
-#ifdef CONFIG_HARDENED_USERCOPY_FALLBACK
/*
* If no whitelist exists, and FALLBACK is set, produce
* a warning instead of rejecting the copy. This is intended
* to be a temporary method to find any missing usercopy
* whitelists.
*/
- if (cachep->usersize == 0 &&
+ if (usercopy_fallback && cachep->usersize == 0 &&
offset <= cachep->object_size &&
n <= cachep->object_size - offset) {
WARN_ONCE(1, "unexpected usercopy without slab whitelist from %s offset %lu size %lu",
cachep->name, offset, n);
return NULL;
}
-#endif
return cachep->name;
}
diff --git a/mm/slub.c b/mm/slub.c
index 82e7f15162a8..e664c6e715e6 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3867,7 +3867,6 @@ const char *__check_heap_object(const void *ptr, unsigned long n,
if (offset < s->useroffset ||
offset - s->useroffset > s->usersize ||
n > s->useroffset - offset + s->usersize) {
-#ifdef CONFIG_HARDENED_USERCOPY_FALLBACK
size_t object_size;
object_size = slab_ksize(s);
@@ -3878,13 +3877,12 @@ const char *__check_heap_object(const void *ptr, unsigned long n,
* to be a temporary method to find any missing usercopy
* whitelists.
*/
- if (s->usersize == 0 &&
+ if (usercopy_fallback && s->usersize == 0 &&
(offset <= object_size && n <= object_size - offset)) {
WARN_ONCE(1, "unexpected usercopy without slab whitelist from %s offset %lu size %lu",
s->name, offset, n);
return NULL;
}
-#endif
return s->name;
}
--
2.15.0.448.gf294e3d99a-goog
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.