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:
 "A laundry list of changes: KASAN improvements/fixes for ptdump, a
  self-test fix, PAT cleanup and wbinvd() avoidance, removal of stale
  code and documentation updates"

* 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mm/ptdump: Add address marker for KASAN shadow region
  x86/mm/ptdump: Optimize check for W+X mappings for CONFIG_KASAN=y
  x86/mm/pat: Use rb_entry()
  x86/mpx: Re-add MPX to selftests Makefile
  x86/mm: Remove CONFIG_DEBUG_NX_TEST
  x86/mm/cpa: Avoid wbinvd() for PREEMPT
  x86/mm: Improve documentation for low-level device I/O functions
This commit is contained in:
Linus Torvalds 2017-02-20 15:57:19 -08:00
commit 8b5abde16b
8 changed files with 79 additions and 201 deletions

View File

@ -120,14 +120,6 @@ config DEBUG_SET_MODULE_RONX
against certain classes of kernel exploits.
If in doubt, say "N".
config DEBUG_NX_TEST
tristate "Testcase for the NX non-executable stack feature"
depends on DEBUG_KERNEL && m
---help---
This option enables a testcase for the CPU NX capability
and the software setup of this feature.
If in doubt, say "N"
config DOUBLEFAULT
default y
bool "Enable doublefault exception handler" if EXPERT

View File

@ -164,6 +164,17 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
#define virt_to_bus virt_to_phys
#define bus_to_virt phys_to_virt
/*
* The default ioremap() behavior is non-cached; if you need something
* else, you probably want one of the following.
*/
extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size);
extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size);
#define ioremap_uc ioremap_uc
extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size);
extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size, unsigned long prot_val);
/**
* ioremap - map bus memory into CPU space
* @offset: bus address of the memory
@ -178,17 +189,6 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
* If the area you are trying to map is a PCI BAR you should have a
* look at pci_iomap().
*/
extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size);
extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size);
#define ioremap_uc ioremap_uc
extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size);
extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size,
unsigned long prot_val);
/*
* The default ioremap() behavior is non-cached:
*/
static inline void __iomem *ioremap(resource_size_t offset, unsigned long size)
{
return ioremap_nocache(offset, size);
@ -207,18 +207,42 @@ extern void set_iounmap_nonlazy(void);
*/
#define xlate_dev_kmem_ptr(p) p
/**
* memset_io Set a range of I/O memory to a constant value
* @addr: The beginning of the I/O-memory range to set
* @val: The value to set the memory to
* @count: The number of bytes to set
*
* Set a range of I/O memory to a given value.
*/
static inline void
memset_io(volatile void __iomem *addr, unsigned char val, size_t count)
{
memset((void __force *)addr, val, count);
}
/**
* memcpy_fromio Copy a block of data from I/O memory
* @dst: The (RAM) destination for the copy
* @src: The (I/O memory) source for the data
* @count: The number of bytes to copy
*
* Copy a block of data from I/O memory.
*/
static inline void
memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count)
{
memcpy(dst, (const void __force *)src, count);
}
/**
* memcpy_toio Copy a block of data into I/O memory
* @dst: The (I/O memory) destination for the copy
* @src: The (RAM) source for the data
* @count: The number of bytes to copy
*
* Copy a block of data to I/O memory.
*/
static inline void
memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
{

View File

@ -101,7 +101,6 @@ obj-$(CONFIG_APB_TIMER) += apb_timer.o
obj-$(CONFIG_AMD_NB) += amd_nb.o
obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o
obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o
obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o
obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o

View File

@ -1,173 +0,0 @@
/*
* test_nx.c: functional test for NX functionality
*
* (C) Copyright 2008 Intel Corporation
* Author: Arjan van de Ven <arjan@linux.intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License.
*/
#include <linux/module.h>
#include <linux/sort.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/asm.h>
extern int rodata_test_data;
/*
* This file checks 4 things:
* 1) Check if the stack is not executable
* 2) Check if kmalloc memory is not executable
* 3) Check if the .rodata section is not executable
* 4) Check if the .data section of a module is not executable
*
* To do this, the test code tries to execute memory in stack/kmalloc/etc,
* and then checks if the expected trap happens.
*
* Sadly, this implies having a dynamic exception handling table entry.
* ... which can be done (and will make Rusty cry)... but it can only
* be done in a stand-alone module with only 1 entry total.
* (otherwise we'd have to sort and that's just too messy)
*/
/*
* We want to set up an exception handling point on our stack,
* which means a variable value. This function is rather dirty
* and walks the exception table of the module, looking for a magic
* marker and replaces it with a specific function.
*/
static void fudze_exception_table(void *marker, void *new)
{
struct module *mod = THIS_MODULE;
struct exception_table_entry *extable;
/*
* Note: This module has only 1 exception table entry,
* so searching and sorting is not needed. If that changes,
* this would be the place to search and re-sort the exception
* table.
*/
if (mod->num_exentries > 1) {
printk(KERN_ERR "test_nx: too many exception table entries!\n");
printk(KERN_ERR "test_nx: test results are not reliable.\n");
return;
}
extable = (struct exception_table_entry *)mod->extable;
extable[0].insn = (unsigned long)new;
}
/*
* exception tables get their symbols translated so we need
* to use a fake function to put in there, which we can then
* replace at runtime.
*/
void foo_label(void);
/*
* returns 0 for not-executable, negative for executable
*
* Note: we cannot allow this function to be inlined, because
* that would give us more than 1 exception table entry.
* This in turn would break the assumptions above.
*/
static noinline int test_address(void *address)
{
unsigned long result;
/* Set up an exception table entry for our address */
fudze_exception_table(&foo_label, address);
result = 1;
asm volatile(
"foo_label:\n"
"0: call *%[fake_code]\n"
"1:\n"
".section .fixup,\"ax\"\n"
"2: mov %[zero], %[rslt]\n"
" ret\n"
".previous\n"
_ASM_EXTABLE(0b,2b)
: [rslt] "=r" (result)
: [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
);
/* change the exception table back for the next round */
fudze_exception_table(address, &foo_label);
if (result)
return -ENODEV;
return 0;
}
static unsigned char test_data = 0xC3; /* 0xC3 is the opcode for "ret" */
static int test_NX(void)
{
int ret = 0;
/* 0xC3 is the opcode for "ret" */
char stackcode[] = {0xC3, 0x90, 0 };
char *heap;
test_data = 0xC3;
printk(KERN_INFO "Testing NX protection\n");
/* Test 1: check if the stack is not executable */
if (test_address(&stackcode)) {
printk(KERN_ERR "test_nx: stack was executable\n");
ret = -ENODEV;
}
/* Test 2: Check if the heap is executable */
heap = kmalloc(64, GFP_KERNEL);
if (!heap)
return -ENOMEM;
heap[0] = 0xC3; /* opcode for "ret" */
if (test_address(heap)) {
printk(KERN_ERR "test_nx: heap was executable\n");
ret = -ENODEV;
}
kfree(heap);
/*
* The following 2 tests currently fail, this needs to get fixed
* Until then, don't run them to avoid too many people getting scared
* by the error message
*/
/* Test 3: Check if the .rodata section is executable */
if (rodata_test_data != 0xC3) {
printk(KERN_ERR "test_nx: .rodata marker has invalid value\n");
ret = -ENODEV;
} else if (test_address(&rodata_test_data)) {
printk(KERN_ERR "test_nx: .rodata section is executable\n");
ret = -ENODEV;
}
#if 0
/* Test 4: Check if the .data section of a module is executable */
if (test_address(&test_data)) {
printk(KERN_ERR "test_nx: .data section is executable\n");
ret = -ENODEV;
}
#endif
return ret;
}
static void test_exit(void)
{
}
module_init(test_NX);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Testcase for the NX infrastructure");
MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");

View File

@ -18,6 +18,7 @@
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <asm/kasan.h>
#include <asm/pgtable.h>
/*
@ -51,6 +52,10 @@ enum address_markers_idx {
LOW_KERNEL_NR,
VMALLOC_START_NR,
VMEMMAP_START_NR,
#ifdef CONFIG_KASAN
KASAN_SHADOW_START_NR,
KASAN_SHADOW_END_NR,
#endif
# ifdef CONFIG_X86_ESPFIX64
ESPFIX_START_NR,
# endif
@ -76,6 +81,10 @@ static struct addr_marker address_markers[] = {
{ 0/* PAGE_OFFSET */, "Low Kernel Mapping" },
{ 0/* VMALLOC_START */, "vmalloc() Area" },
{ 0/* VMEMMAP_START */, "Vmemmap" },
#ifdef CONFIG_KASAN
{ KASAN_SHADOW_START, "KASAN shadow" },
{ KASAN_SHADOW_END, "KASAN shadow end" },
#endif
# ifdef CONFIG_X86_ESPFIX64
{ ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
# endif
@ -327,18 +336,31 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr,
#if PTRS_PER_PUD > 1
/*
* This is an optimization for CONFIG_DEBUG_WX=y + CONFIG_KASAN=y
* KASAN fills page tables with the same values. Since there is no
* point in checking page table more than once we just skip repeated
* entries. This saves us dozens of seconds during boot.
*/
static bool pud_already_checked(pud_t *prev_pud, pud_t *pud, bool checkwx)
{
return checkwx && prev_pud && (pud_val(*prev_pud) == pud_val(*pud));
}
static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
unsigned long P)
{
int i;
pud_t *start;
pgprotval_t prot;
pud_t *prev_pud = NULL;
start = (pud_t *) pgd_page_vaddr(addr);
for (i = 0; i < PTRS_PER_PUD; i++) {
st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT);
if (!pud_none(*start)) {
if (!pud_none(*start) &&
!pud_already_checked(prev_pud, start, st->check_wx)) {
if (pud_large(*start) || !pud_present(*start)) {
prot = pud_flags(*start);
note_page(m, st, __pgprot(prot), 2);
@ -349,6 +371,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
} else
note_page(m, st, __pgprot(0), 2);
prev_pud = start;
start++;
}
}

View File

@ -214,7 +214,20 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache,
int in_flags, struct page **pages)
{
unsigned int i, level;
#ifdef CONFIG_PREEMPT
/*
* Avoid wbinvd() because it causes latencies on all CPUs,
* regardless of any CPU isolation that may be in effect.
*
* This should be extended for CAT enabled systems independent of
* PREEMPT because wbinvd() does not respect the CAT partitions and
* this is exposed to unpriviledged users through the graphics
* subsystem.
*/
unsigned long do_wbinvd = 0;
#else
unsigned long do_wbinvd = cache && numpages >= 1024; /* 4M threshold */
#endif
BUG_ON(irqs_disabled());

View File

@ -47,7 +47,7 @@ static u64 get_subtree_max_end(struct rb_node *node)
{
u64 ret = 0;
if (node) {
struct memtype *data = container_of(node, struct memtype, rb);
struct memtype *data = rb_entry(node, struct memtype, rb);
ret = data->subtree_max_end;
}
return ret;
@ -79,7 +79,7 @@ static struct memtype *memtype_rb_lowest_match(struct rb_root *root,
struct memtype *last_lower = NULL;
while (node) {
struct memtype *data = container_of(node, struct memtype, rb);
struct memtype *data = rb_entry(node, struct memtype, rb);
if (get_subtree_max_end(node->rb_left) > start) {
/* Lowest overlap if any must be on left side */
@ -121,7 +121,7 @@ static struct memtype *memtype_rb_match(struct rb_root *root,
node = rb_next(&match->rb);
if (node)
match = container_of(node, struct memtype, rb);
match = rb_entry(node, struct memtype, rb);
else
match = NULL;
}
@ -150,7 +150,7 @@ static int memtype_rb_check_conflict(struct rb_root *root,
node = rb_next(&match->rb);
while (node) {
match = container_of(node, struct memtype, rb);
match = rb_entry(node, struct memtype, rb);
if (match->start >= end) /* Checked all possible matches */
goto success;
@ -181,7 +181,7 @@ static void memtype_rb_insert(struct rb_root *root, struct memtype *newdata)
struct rb_node *parent = NULL;
while (*node) {
struct memtype *data = container_of(*node, struct memtype, rb);
struct memtype *data = rb_entry(*node, struct memtype, rb);
parent = *node;
if (data->subtree_max_end < newdata->end)
@ -270,7 +270,7 @@ int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos)
}
if (node) { /* pos == i */
struct memtype *this = container_of(node, struct memtype, rb);
struct memtype *this = rb_entry(node, struct memtype, rb);
*out = *this;
return 0;
} else {

View File

@ -5,7 +5,7 @@ include ../lib.mk
.PHONY: all all_32 all_64 warn_32bit_failure clean
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \
check_initial_reg_state sigreturn ldt_gdt iopl \
check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test \
protection_keys test_vdso
TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
test_FCMOV test_FCOMI test_FISTTP \