@@ -4254,6 +4254,10 @@
nopti [X86-64]
Equivalent to pti=off
+ nopkstables [X86-64] Disable PKS page table protection
+
+ pkstablessoft [X86-64] Warn instead of oops on pks tables violations
+
pty.legacy_count=
[KNL] Number of legacy pty's. Overwrites compiled-in
default number.
@@ -122,6 +122,7 @@ void pks_tables_check_boottime_disable(void);
void enable_pgtable_write(void);
void disable_pgtable_write(void);
bool pks_tables_inited(void);
+bool pks_tables_fault(unsigned long addr, bool write);
#else /* CONFIG_PKS_PG_TABLES */
static inline void pks_tables_check_boottime_disable(void) { }
static void enable_pgtable_write(void) { }
@@ -40,7 +40,7 @@ pgtable_t pte_alloc_one(struct mm_struct *mm)
#ifdef CONFIG_PKS_PG_TABLES
static struct grouped_page_cache gpc_pks;
static bool __ro_after_init pks_tables_inited_val;
-
+static bool __ro_after_init pks_tables_soft;
struct page *alloc_table_node(gfp_t gfp, int node)
{
@@ -971,6 +971,16 @@ bool pks_tables_inited(void)
return pks_tables_inited_val;
}
+bool pks_tables_fault(unsigned long addr, bool write)
+{
+ WARN(1, "Write to protected page table, exploit attempt?");
+ if (!pks_tables_soft)
+ return 0;
+
+ pks_abandon_protections(PKS_KEY_PG_TABLES);
+ return 1;
+}
+
static int __init pks_page_init(void)
{
/*
@@ -999,6 +1009,10 @@ __init void pks_tables_check_boottime_disable(void)
if (cmdline_find_option_bool(boot_command_line, "nopkstables"))
return;
+ if (IS_ENABLED(CONFIG_PKS_PG_TABLES_SOFT_ALWAYS) ||
+ cmdline_find_option_bool(boot_command_line, "pkstablessoft"))
+ pks_tables_soft = true;
+
/*
* PTI will want to allocate higher order page table pages, which the
* PKS table allocator doesn't support. So don't attempt to enable PKS
@@ -247,6 +247,9 @@ static const pks_key_callback pks_key_callbacks[PKS_KEY_NR_CONSUMERS] = {
#ifdef CONFIG_DEVMAP_ACCESS_PROTECTION
[PKS_KEY_PGMAP_PROTECTION] = pgmap_pks_fault_callback,
#endif
+#ifdef CONFIG_PKS_PG_TABLES
+ [PKS_KEY_PG_TABLES] = pks_tables_fault,
+#endif
};
bool handle_pks_key_callback(unsigned long address, bool write, u16 key)
@@ -851,6 +851,18 @@ config PKS_PG_TABLES
depends on !HIGHMEM && !X86_PAE && SPARSEMEM_VMEMMAP
depends on ARCH_HAS_SUPERVISOR_PKEYS
+config PKS_PG_TABLES_SOFT_ALWAYS
+ bool
+ default y
+ depends on PKS_PG_TABLES
+ help
+ This features enables PKS tables "soft" mode by default, such that
+ the first PKS table violation is logged and after that protections
+ are disabled. This is useful for cases where users would not like
+ to treat bugs that incorrectly modify page tables as fatal, but would
+ still like to get notifications of illegitimate attempts to modify
+ them.
+
config PERCPU_STATS
bool "Collect percpu memory statistics"
help
Some users may not want to treat errant page table writes as fatal, and would prefer to just log the invalid access and continue. Add a "soft" mode for this. Add a config to make always make this the default behavior, and a config to enable it at boot in the absence of the new config. After a single warning, the page tables will be writable, so no warnings will be reported until the next reboot. Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com> --- Documentation/admin-guide/kernel-parameters.txt | 4 ++++ arch/x86/include/asm/pgtable.h | 1 + arch/x86/mm/pgtable.c | 16 +++++++++++++++- arch/x86/mm/pkeys.c | 3 +++ mm/Kconfig | 12 ++++++++++++ 5 files changed, 35 insertions(+), 1 deletion(-)