From c0ecfa66af961d3fce7e413a8b9c1d7246dd71b0 Mon Sep 17 00:00:00 2001 From: Filippo Arcidiacono Date: Thu, 19 Apr 2012 15:45:57 +0900 Subject: [PATCH] --- yaml --- r: 305225 b: refs/heads/master c: 5d920bb929a99446062a48cf90867bbca57b8e77 h: refs/heads/master i: 305223: 575056aafe4d791cd14117dc8cfbd51347511d65 v: v3 --- [refs] | 2 +- trunk/arch/sh/Kconfig | 14 +++ trunk/arch/sh/Makefile | 4 + trunk/arch/sh/boards/Kconfig | 4 +- trunk/arch/sh/include/asm/stackprotector.h | 27 ++++++ trunk/arch/sh/kernel/process.c | 7 ++ trunk/arch/sh/kernel/process_32.c | 5 ++ trunk/arch/sh/mm/fault_32.c | 99 ++++++---------------- 8 files changed, 84 insertions(+), 78 deletions(-) create mode 100644 trunk/arch/sh/include/asm/stackprotector.h diff --git a/[refs] b/[refs] index d0e81fd6d925..3fa61c5fa4c1 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9e7f60a37d1817460ffcdfc2001a00861ac3e121 +refs/heads/master: 5d920bb929a99446062a48cf90867bbca57b8e77 diff --git a/trunk/arch/sh/Kconfig b/trunk/arch/sh/Kconfig index ff9e033ce626..60ed3669979d 100644 --- a/trunk/arch/sh/Kconfig +++ b/trunk/arch/sh/Kconfig @@ -685,6 +685,20 @@ config SECCOMP If unsure, say N. +config CC_STACKPROTECTOR + bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" + depends on SUPERH32 && EXPERIMENTAL + help + This option turns on the -fstack-protector GCC feature. This + feature puts, at the beginning of functions, a canary value on + the stack just before the return address, and validates + the value just before actually returning. Stack based buffer + overflows (that need to overwrite this return address) now also + overwrite the canary, which gets detected and the attack is then + neutralized via a kernel panic. + + This feature requires gcc version 4.2 or above. + config SMP bool "Symmetric multi-processing support" depends on SYS_SUPPORTS_SMP diff --git a/trunk/arch/sh/Makefile b/trunk/arch/sh/Makefile index 3fc0f413777c..24875c8c1514 100644 --- a/trunk/arch/sh/Makefile +++ b/trunk/arch/sh/Makefile @@ -199,6 +199,10 @@ ifeq ($(CONFIG_DWARF_UNWINDER),y) KBUILD_CFLAGS += -fasynchronous-unwind-tables endif +ifeq ($(CONFIG_CC_STACKPROTECTOR),y) + KBUILD_CFLAGS += -fstack-protector +endif + libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) diff --git a/trunk/arch/sh/boards/Kconfig b/trunk/arch/sh/boards/Kconfig index 6c96daab499b..d893411022d5 100644 --- a/trunk/arch/sh/boards/Kconfig +++ b/trunk/arch/sh/boards/Kconfig @@ -338,6 +338,8 @@ config SH_APSH4AD0A help Select AP-SH4AD-0A if configuring for an ALPHAPROJECT AP-SH4AD-0A. +endmenu + source "arch/sh/boards/mach-r2d/Kconfig" source "arch/sh/boards/mach-highlander/Kconfig" source "arch/sh/boards/mach-sdk7780/Kconfig" @@ -357,5 +359,3 @@ config SH_MAGIC_PANEL_R2_VERSION endmenu endif - -endmenu diff --git a/trunk/arch/sh/include/asm/stackprotector.h b/trunk/arch/sh/include/asm/stackprotector.h new file mode 100644 index 000000000000..d9df3a76847c --- /dev/null +++ b/trunk/arch/sh/include/asm/stackprotector.h @@ -0,0 +1,27 @@ +#ifndef __ASM_SH_STACKPROTECTOR_H +#define __ASM_SH_STACKPROTECTOR_H + +#include +#include + +extern unsigned long __stack_chk_guard; + +/* + * Initialize the stackprotector canary value. + * + * NOTE: this must only be called from functions that never return, + * and it must always be inlined. + */ +static __always_inline void boot_init_stack_canary(void) +{ + unsigned long canary; + + /* Try to get a semi random initial value. */ + get_random_bytes(&canary, sizeof(canary)); + canary ^= LINUX_VERSION_CODE; + + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary; +} + +#endif /* __ASM_SH_STACKPROTECTOR_H */ diff --git a/trunk/arch/sh/kernel/process.c b/trunk/arch/sh/kernel/process.c index 325f98b1736d..f3f03e4c785d 100644 --- a/trunk/arch/sh/kernel/process.c +++ b/trunk/arch/sh/kernel/process.c @@ -2,10 +2,17 @@ #include #include #include +#include +#include struct kmem_cache *task_xstate_cachep = NULL; unsigned int xstate_size; +#ifdef CONFIG_CC_STACKPROTECTOR +unsigned long __stack_chk_guard __read_mostly; +EXPORT_SYMBOL(__stack_chk_guard); +#endif + int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) { *dst = *src; diff --git a/trunk/arch/sh/kernel/process_32.c b/trunk/arch/sh/kernel/process_32.c index 94273aaf78c1..f78cc421e665 100644 --- a/trunk/arch/sh/kernel/process_32.c +++ b/trunk/arch/sh/kernel/process_32.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,10 @@ __switch_to(struct task_struct *prev, struct task_struct *next) { struct thread_struct *next_t = &next->thread; +#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) + __stack_chk_guard = next->stack_canary; +#endif + unlazy_fpu(prev, task_pt_regs(prev)); /* we're going to use this soon, after a few expensive things */ diff --git a/trunk/arch/sh/mm/fault_32.c b/trunk/arch/sh/mm/fault_32.c index c5cd87868c73..324eef93c900 100644 --- a/trunk/arch/sh/mm/fault_32.c +++ b/trunk/arch/sh/mm/fault_32.c @@ -35,74 +35,6 @@ static inline int notify_page_fault(struct pt_regs *regs, int trap) return ret; } -/* - * This is useful to dump out the page tables associated with - * 'addr' in mm 'mm'. - */ -static void show_pte(struct mm_struct *mm, unsigned long addr) -{ - pgd_t *pgd; - - if (mm) - pgd = mm->pgd; - else - pgd = get_TTB(); - - printk(KERN_ALERT "pgd = %p\n", pgd); - pgd += pgd_index(addr); - printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr, - sizeof(*pgd) * 2, (u64)pgd_val(*pgd)); - - do { - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - if (pgd_none(*pgd)) - break; - - if (pgd_bad(*pgd)) { - printk("(bad)"); - break; - } - - pud = pud_offset(pgd, addr); - if (PTRS_PER_PUD != 1) - printk(", *pud=%0*Lx", sizeof(*pud) * 2, - (u64)pud_val(*pud)); - - if (pud_none(*pud)) - break; - - if (pud_bad(*pud)) { - printk("(bad)"); - break; - } - - pmd = pmd_offset(pud, addr); - if (PTRS_PER_PMD != 1) - printk(", *pmd=%0*Lx", sizeof(*pmd) * 2, - (u64)pmd_val(*pmd)); - - if (pmd_none(*pmd)) - break; - - if (pmd_bad(*pmd)) { - printk("(bad)"); - break; - } - - /* We must not map this if we have highmem enabled */ - if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT))) - break; - - pte = pte_offset_kernel(pmd, addr); - printk(", *pte=%0*Lx", sizeof(*pte) * 2, (u64)pte_val(*pte)); - } while (0); - - printk("\n"); -} - static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) { unsigned index = pgd_index(address); @@ -154,7 +86,7 @@ static noinline int vmalloc_fault(unsigned long address) pte_t *pte_k; /* Make sure we are in vmalloc/module/P3 area: */ - if (!(address >= P3SEG && address < P3_ADDR_MAX)) + if (!(address >= VMALLOC_START && address < P3_ADDR_MAX)) return -1; /* @@ -322,12 +254,29 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, bust_spinlocks(1); if (oops_may_print()) { - printk(KERN_ALERT - "Unable to handle kernel %s at virtual address %08lx\n", - (address < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", address); - - show_pte(mm, address); + unsigned long page; + + if (address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL " + "pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel paging " + "request"); + printk(" at virtual address %08lx\n", address); + printk(KERN_ALERT "pc = %08lx\n", regs->pc); + page = (unsigned long)get_TTB(); + if (page) { + page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT]; + printk(KERN_ALERT "*pde = %08lx\n", page); + if (page & _PAGE_PRESENT) { + page &= PAGE_MASK; + address &= 0x003ff000; + page = ((__typeof__(page) *) + __va(page))[address >> + PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); + } + } } die("Oops", regs, writeaccess);