| From 3f8fd02b1bf1d7ba964485a56f2f4b53ae88c167 Mon Sep 17 00:00:00 2001 |
| From: Joerg Roedel <jroedel@suse.de> |
| Date: Fri, 19 Jul 2019 20:46:52 +0200 |
| Subject: mm/vmalloc: Sync unmappings in __purge_vmap_area_lazy() |
| |
| From: Joerg Roedel <jroedel@suse.de> |
| |
| commit 3f8fd02b1bf1d7ba964485a56f2f4b53ae88c167 upstream. |
| |
| On x86-32 with PTI enabled, parts of the kernel page-tables are not shared |
| between processes. This can cause mappings in the vmalloc/ioremap area to |
| persist in some page-tables after the region is unmapped and released. |
| |
| When the region is re-used the processes with the old mappings do not fault |
| in the new mappings but still access the old ones. |
| |
| This causes undefined behavior, in reality often data corruption, kernel |
| oopses and panics and even spontaneous reboots. |
| |
| Fix this problem by activly syncing unmaps in the vmalloc/ioremap area to |
| all page-tables in the system before the regions can be re-used. |
| |
| References: https://bugzilla.suse.com/show_bug.cgi?id=1118689 |
| Fixes: 5d72b4fba40ef ('x86, mm: support huge I/O mapping capability I/F') |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> |
| Link: https://lkml.kernel.org/r/20190719184652.11391-4-joro@8bytes.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| mm/vmalloc.c | 9 +++++++++ |
| 1 file changed, 9 insertions(+) |
| |
| --- a/mm/vmalloc.c |
| +++ b/mm/vmalloc.c |
| @@ -1766,6 +1766,12 @@ void *__vmalloc_node_range(unsigned long |
| return NULL; |
| |
| /* |
| + * First make sure the mappings are removed from all page-tables |
| + * before they are freed. |
| + */ |
| + vmalloc_sync_all(); |
| + |
| + /* |
| * In this function, newly allocated vm_struct has VM_UNINITIALIZED |
| * flag. It means that vm_struct is not fully initialized. |
| * Now, it is fully initialized, so remove this flag here. |
| @@ -2314,6 +2320,9 @@ EXPORT_SYMBOL(remap_vmalloc_range); |
| /* |
| * Implement a stub for vmalloc_sync_all() if the architecture chose not to |
| * have one. |
| + * |
| + * The purpose of this function is to make sure the vmalloc area |
| + * mappings are identical in all page-tables in the system. |
| */ |
| void __weak vmalloc_sync_all(void) |
| { |