Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 mm updates from Ingo Molnar: "The changes in here are: - text_poke() fixes and an extensive set of executability lockdowns, to (hopefully) eliminate the last residual circumstances under which we are using W|X mappings even temporarily on x86 kernels. This required a broad range of surgery in text patching facilities, module loading, trampoline handling and other bits. - tweak page fault messages to be more informative and more structured. - remove DISCONTIGMEM support on x86-32 and make SPARSEMEM the default. - reduce KASLR granularity on 5-level paging kernels from 512 GB to 1 GB. - misc other changes and updates" * 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (36 commits) x86/mm: Initialize PGD cache during mm initialization x86/alternatives: Add comment about module removal races x86/kprobes: Use vmalloc special flag x86/ftrace: Use vmalloc special flag bpf: Use vmalloc special flag modules: Use vmalloc special flag mm/vmalloc: Add flag for freeing of special permsissions mm/hibernation: Make hibernation handle unmapped pages x86/mm/cpa: Add set_direct_map_*() functions x86/alternatives: Remove the return value of text_poke_*() x86/jump-label: Remove support for custom text poker x86/modules: Avoid breaking W^X while loading modules x86/kprobes: Set instruction page as executable x86/ftrace: Set trampoline pages as executable x86/kgdb: Avoid redundant comparison of patched code x86/alternatives: Use temporary mm for text poking x86/alternatives: Initialize temporary mm for patching fork: Provide a function for copying init_mm uprobes: Initialize uprobes earlier x86/mm: Save debug registers when loading a temporary mm ...
This commit is contained in:
@@ -1144,7 +1144,9 @@ static __always_inline bool free_pages_prepare(struct page *page,
|
||||
}
|
||||
arch_free_page(page, order);
|
||||
kernel_poison_pages(page, 1 << order, 0);
|
||||
kernel_map_pages(page, 1 << order, 0);
|
||||
if (debug_pagealloc_enabled())
|
||||
kernel_map_pages(page, 1 << order, 0);
|
||||
|
||||
kasan_free_nondeferred_pages(page, order);
|
||||
|
||||
return true;
|
||||
@@ -2014,7 +2016,8 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
|
||||
set_page_refcounted(page);
|
||||
|
||||
arch_alloc_page(page, order);
|
||||
kernel_map_pages(page, 1 << order, 1);
|
||||
if (debug_pagealloc_enabled())
|
||||
kernel_map_pages(page, 1 << order, 1);
|
||||
kasan_alloc_pages(page, order);
|
||||
kernel_poison_pages(page, 1 << order, 1);
|
||||
set_page_owner(page, order, gfp_flags);
|
||||
|
113
mm/vmalloc.c
113
mm/vmalloc.c
@@ -18,6 +18,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/set_memory.h>
|
||||
#include <linux/debugobjects.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/list.h>
|
||||
@@ -1059,24 +1060,9 @@ static void vb_free(const void *addr, unsigned long size)
|
||||
spin_unlock(&vb->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* vm_unmap_aliases - unmap outstanding lazy aliases in the vmap layer
|
||||
*
|
||||
* The vmap/vmalloc layer lazily flushes kernel virtual mappings primarily
|
||||
* to amortize TLB flushing overheads. What this means is that any page you
|
||||
* have now, may, in a former life, have been mapped into kernel virtual
|
||||
* address by the vmap layer and so there might be some CPUs with TLB entries
|
||||
* still referencing that page (additional to the regular 1:1 kernel mapping).
|
||||
*
|
||||
* vm_unmap_aliases flushes all such lazy mappings. After it returns, we can
|
||||
* be sure that none of the pages we have control over will have any aliases
|
||||
* from the vmap layer.
|
||||
*/
|
||||
void vm_unmap_aliases(void)
|
||||
static void _vm_unmap_aliases(unsigned long start, unsigned long end, int flush)
|
||||
{
|
||||
unsigned long start = ULONG_MAX, end = 0;
|
||||
int cpu;
|
||||
int flush = 0;
|
||||
|
||||
if (unlikely(!vmap_initialized))
|
||||
return;
|
||||
@@ -1113,6 +1099,27 @@ void vm_unmap_aliases(void)
|
||||
flush_tlb_kernel_range(start, end);
|
||||
mutex_unlock(&vmap_purge_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* vm_unmap_aliases - unmap outstanding lazy aliases in the vmap layer
|
||||
*
|
||||
* The vmap/vmalloc layer lazily flushes kernel virtual mappings primarily
|
||||
* to amortize TLB flushing overheads. What this means is that any page you
|
||||
* have now, may, in a former life, have been mapped into kernel virtual
|
||||
* address by the vmap layer and so there might be some CPUs with TLB entries
|
||||
* still referencing that page (additional to the regular 1:1 kernel mapping).
|
||||
*
|
||||
* vm_unmap_aliases flushes all such lazy mappings. After it returns, we can
|
||||
* be sure that none of the pages we have control over will have any aliases
|
||||
* from the vmap layer.
|
||||
*/
|
||||
void vm_unmap_aliases(void)
|
||||
{
|
||||
unsigned long start = ULONG_MAX, end = 0;
|
||||
int flush = 0;
|
||||
|
||||
_vm_unmap_aliases(start, end, flush);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vm_unmap_aliases);
|
||||
|
||||
/**
|
||||
@@ -1505,6 +1512,72 @@ struct vm_struct *remove_vm_area(const void *addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void set_area_direct_map(const struct vm_struct *area,
|
||||
int (*set_direct_map)(struct page *page))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < area->nr_pages; i++)
|
||||
if (page_address(area->pages[i]))
|
||||
set_direct_map(area->pages[i]);
|
||||
}
|
||||
|
||||
/* Handle removing and resetting vm mappings related to the vm_struct. */
|
||||
static void vm_remove_mappings(struct vm_struct *area, int deallocate_pages)
|
||||
{
|
||||
unsigned long addr = (unsigned long)area->addr;
|
||||
unsigned long start = ULONG_MAX, end = 0;
|
||||
int flush_reset = area->flags & VM_FLUSH_RESET_PERMS;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The below block can be removed when all architectures that have
|
||||
* direct map permissions also have set_direct_map_() implementations.
|
||||
* This is concerned with resetting the direct map any an vm alias with
|
||||
* execute permissions, without leaving a RW+X window.
|
||||
*/
|
||||
if (flush_reset && !IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
|
||||
set_memory_nx(addr, area->nr_pages);
|
||||
set_memory_rw(addr, area->nr_pages);
|
||||
}
|
||||
|
||||
remove_vm_area(area->addr);
|
||||
|
||||
/* If this is not VM_FLUSH_RESET_PERMS memory, no need for the below. */
|
||||
if (!flush_reset)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If not deallocating pages, just do the flush of the VM area and
|
||||
* return.
|
||||
*/
|
||||
if (!deallocate_pages) {
|
||||
vm_unmap_aliases();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If execution gets here, flush the vm mapping and reset the direct
|
||||
* map. Find the start and end range of the direct mappings to make sure
|
||||
* the vm_unmap_aliases() flush includes the direct map.
|
||||
*/
|
||||
for (i = 0; i < area->nr_pages; i++) {
|
||||
if (page_address(area->pages[i])) {
|
||||
start = min(addr, start);
|
||||
end = max(addr, end);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set direct map to something invalid so that it won't be cached if
|
||||
* there are any accesses after the TLB flush, then flush the TLB and
|
||||
* reset the direct map permissions to the default.
|
||||
*/
|
||||
set_area_direct_map(area, set_direct_map_invalid_noflush);
|
||||
_vm_unmap_aliases(start, end, 1);
|
||||
set_area_direct_map(area, set_direct_map_default_noflush);
|
||||
}
|
||||
|
||||
static void __vunmap(const void *addr, int deallocate_pages)
|
||||
{
|
||||
struct vm_struct *area;
|
||||
@@ -1526,7 +1599,8 @@ static void __vunmap(const void *addr, int deallocate_pages)
|
||||
debug_check_no_locks_freed(area->addr, get_vm_area_size(area));
|
||||
debug_check_no_obj_freed(area->addr, get_vm_area_size(area));
|
||||
|
||||
remove_vm_area(addr);
|
||||
vm_remove_mappings(area, deallocate_pages);
|
||||
|
||||
if (deallocate_pages) {
|
||||
int i;
|
||||
|
||||
@@ -1961,8 +2035,9 @@ EXPORT_SYMBOL(vzalloc_node);
|
||||
*/
|
||||
void *vmalloc_exec(unsigned long size)
|
||||
{
|
||||
return __vmalloc_node(size, 1, GFP_KERNEL, PAGE_KERNEL_EXEC,
|
||||
NUMA_NO_NODE, __builtin_return_address(0));
|
||||
return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
|
||||
GFP_KERNEL, PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS,
|
||||
NUMA_NO_NODE, __builtin_return_address(0));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
|
||||
|
Reference in New Issue
Block a user