[RFC PATCH v3 3/8] x86/pti: create the pti_adjust sysctl

From: Willy Tarreau
Date: Wed Jan 10 2018 - 14:29:54 EST


This sysctl supports a value from -1 to 1 which will let the administrator
decide whether or not to adjust the PTI behaviour per process.

Signed-off-by: Willy Tarreau <w@xxxxxx>
Cc: Andy Lutomirski <luto@xxxxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxxxx>
Cc: Brian Gerst <brgerst@xxxxxxxxx>
Cc: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
Cc: Kees Cook <keescook@xxxxxxxxxxxx>
---
arch/x86/include/asm/pti.h | 5 +++++
arch/x86/mm/pti.c | 19 +++++++++++++++++++
kernel/sysctl.c | 12 ++++++++++++
3 files changed, 36 insertions(+)

diff --git a/arch/x86/include/asm/pti.h b/arch/x86/include/asm/pti.h
index 0b5ef05..cc8e0d0e 100644
--- a/arch/x86/include/asm/pti.h
+++ b/arch/x86/include/asm/pti.h
@@ -6,6 +6,11 @@
#ifdef CONFIG_PAGE_TABLE_ISOLATION
extern void pti_init(void);
extern void pti_check_boottime_disable(void);
+# ifdef CONFIG_PER_PROCESS_PTI
+extern int pti_adjust;
+int pti_adjust_sysctl_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+# endif
#else
static inline void pti_check_boottime_disable(void) { }
#endif
diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c
index 43d4a4a..8166686f 100644
--- a/arch/x86/mm/pti.c
+++ b/arch/x86/mm/pti.c
@@ -54,6 +54,10 @@
#define __GFP_NOTRACK 0
#endif

+# ifdef CONFIG_PER_PROCESS_PTI
+int pti_adjust;
+#endif
+
static void __init pti_print_if_insecure(const char *reason)
{
if (boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN))
@@ -371,6 +375,21 @@ static void __init pti_clone_entry_text(void)
_PAGE_RW | _PAGE_GLOBAL);
}

+#ifdef CONFIG_PER_PROCESS_PTI
+/*
+ * sysctl handler for pti_adjust which decides whether or not to accept a
+ * change to the value. 0 and 1 may be interchanged, but -1 is definitive.
+ */
+int pti_adjust_sysctl_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ if (write && (!capable(CAP_SYS_RAWIO) || pti_adjust == -1))
+ return -EPERM;
+
+ return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+}
+#endif
+
/*
* Initialize kernel page table isolation
*/
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 557d467..a37a5e1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -34,6 +34,7 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/pti.h>
#include <linux/kobject.h>
#include <linux/net.h>
#include <linux/sysrq.h>
@@ -1572,6 +1573,17 @@ static int sysrq_sysctl_handler(struct ctl_table *table, int write,
.proc_handler = numa_zonelist_order_handler,
},
#endif
+#ifdef CONFIG_PER_PROCESS_PTI
+ {
+ .procname = "pti_adjust",
+ .data = &pti_adjust,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = pti_adjust_sysctl_handler,
+ .extra1 = &neg_one,
+ .extra2 = &one,
+ },
+#endif
#if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \
(defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
{
--
1.7.12.1