| From 45e2a9d4701d8c624d4a4bcdd1084eae31e92f58 Mon Sep 17 00:00:00 2001 |
| From: Kees Cook <keescook@chromium.org> |
| Date: Fri, 14 Nov 2014 11:47:37 -0800 |
| Subject: x86, mm: Set NX across entire PMD at boot |
| |
| From: Kees Cook <keescook@chromium.org> |
| |
| commit 45e2a9d4701d8c624d4a4bcdd1084eae31e92f58 upstream. |
| |
| When setting up permissions on kernel memory at boot, the end of the |
| PMD that was split from bss remained executable. It should be NX like |
| the rest. This performs a PMD alignment instead of a PAGE alignment to |
| get the correct span of memory. |
| |
| Before: |
| ---[ High Kernel Mapping ]--- |
| ... |
| 0xffffffff8202d000-0xffffffff82200000 1868K RW GLB NX pte |
| 0xffffffff82200000-0xffffffff82c00000 10M RW PSE GLB NX pmd |
| 0xffffffff82c00000-0xffffffff82df5000 2004K RW GLB NX pte |
| 0xffffffff82df5000-0xffffffff82e00000 44K RW GLB x pte |
| 0xffffffff82e00000-0xffffffffc0000000 978M pmd |
| |
| After: |
| ---[ High Kernel Mapping ]--- |
| ... |
| 0xffffffff8202d000-0xffffffff82200000 1868K RW GLB NX pte |
| 0xffffffff82200000-0xffffffff82e00000 12M RW PSE GLB NX pmd |
| 0xffffffff82e00000-0xffffffffc0000000 978M pmd |
| |
| [ tglx: Changed it to roundup(_brk_end, PMD_SIZE) and added a comment. |
| We really should unmap the reminder along with the holes |
| caused by init,initdata etc. but thats a different issue ] |
| |
| Signed-off-by: Kees Cook <keescook@chromium.org> |
| Cc: Andy Lutomirski <luto@amacapital.net> |
| Cc: Toshi Kani <toshi.kani@hp.com> |
| Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> |
| Cc: David Vrabel <david.vrabel@citrix.com> |
| Cc: Wang Nan <wangnan0@huawei.com> |
| Cc: Yinghai Lu <yinghai@kernel.org> |
| Link: http://lkml.kernel.org/r/20141114194737.GA3091@www.outflux.net |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/mm/init_64.c | 11 ++++++++++- |
| 1 file changed, 10 insertions(+), 1 deletion(-) |
| |
| --- a/arch/x86/mm/init_64.c |
| +++ b/arch/x86/mm/init_64.c |
| @@ -1111,7 +1111,7 @@ void mark_rodata_ro(void) |
| unsigned long end = (unsigned long) &__end_rodata_hpage_align; |
| unsigned long text_end = PFN_ALIGN(&__stop___ex_table); |
| unsigned long rodata_end = PFN_ALIGN(&__end_rodata); |
| - unsigned long all_end = PFN_ALIGN(&_end); |
| + unsigned long all_end; |
| |
| printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", |
| (end - start) >> 10); |
| @@ -1122,7 +1122,16 @@ void mark_rodata_ro(void) |
| /* |
| * The rodata/data/bss/brk section (but not the kernel text!) |
| * should also be not-executable. |
| + * |
| + * We align all_end to PMD_SIZE because the existing mapping |
| + * is a full PMD. If we would align _brk_end to PAGE_SIZE we |
| + * split the PMD and the reminder between _brk_end and the end |
| + * of the PMD will remain mapped executable. |
| + * |
| + * Any PMD which was setup after the one which covers _brk_end |
| + * has been zapped already via cleanup_highmem(). |
| */ |
| + all_end = roundup((unsigned long)_brk_end, PMD_SIZE); |
| set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT); |
| |
| rodata_test(); |