diff options
| -rw-r--r-- | arch/x86/Kconfig.debug | 11 | ||||
| -rw-r--r-- | arch/x86/include/asm/pci.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/ftrace.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/vmlinux.lds.S | 8 | ||||
| -rw-r--r-- | arch/x86/mm/init.c | 3 | ||||
| -rw-r--r-- | arch/x86/mm/init_32.c | 20 | ||||
| -rw-r--r-- | arch/x86/mm/pageattr.c | 33 | ||||
| -rw-r--r-- | arch/x86/pci/pcbios.c | 23 | ||||
| -rw-r--r-- | include/linux/module.h | 11 | ||||
| -rw-r--r-- | kernel/module.c | 171 |
10 files changed, 266 insertions, 18 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index b59ee765414..45143bbcfe5 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -117,6 +117,17 @@ config DEBUG_RODATA_TEST | |||
| 117 | feature as well as for the change_page_attr() infrastructure. | 117 | feature as well as for the change_page_attr() infrastructure. |
| 118 | If in doubt, say "N" | 118 | If in doubt, say "N" |
| 119 | 119 | ||
| 120 | config DEBUG_SET_MODULE_RONX | ||
| 121 | bool "Set loadable kernel module data as NX and text as RO" | ||
| 122 | depends on MODULES | ||
| 123 | ---help--- | ||
| 124 | This option helps catch unintended modifications to loadable | ||
| 125 | kernel module's text and read-only data. It also prevents execution | ||
| 126 | of module data. Such protection may interfere with run-time code | ||
| 127 | patching and dynamic kernel tracing - and they might also protect | ||
| 128 | against certain classes of kernel exploits. | ||
| 129 | If in doubt, say "N". | ||
| 130 | |||
| 120 | config DEBUG_NX_TEST | 131 | config DEBUG_NX_TEST |
| 121 | tristate "Testcase for the NX non-executable stack feature" | 132 | tristate "Testcase for the NX non-executable stack feature" |
| 122 | depends on DEBUG_KERNEL && m | 133 | depends on DEBUG_KERNEL && m |
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index ca0437c714b..67612922963 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h | |||
| @@ -65,6 +65,7 @@ extern unsigned long pci_mem_start; | |||
| 65 | 65 | ||
| 66 | #define PCIBIOS_MIN_CARDBUS_IO 0x4000 | 66 | #define PCIBIOS_MIN_CARDBUS_IO 0x4000 |
| 67 | 67 | ||
| 68 | extern int pcibios_enabled; | ||
| 68 | void pcibios_config_init(void); | 69 | void pcibios_config_init(void); |
| 69 | struct pci_bus *pcibios_scan_root(int bus); | 70 | struct pci_bus *pcibios_scan_root(int bus); |
| 70 | 71 | ||
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 3afb33f14d2..298448656b6 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
| 22 | #include <linux/module.h> | ||
| 22 | 23 | ||
| 23 | #include <trace/syscall.h> | 24 | #include <trace/syscall.h> |
| 24 | 25 | ||
| @@ -49,6 +50,7 @@ static DEFINE_PER_CPU(int, save_modifying_code); | |||
| 49 | int ftrace_arch_code_modify_prepare(void) | 50 | int ftrace_arch_code_modify_prepare(void) |
| 50 | { | 51 | { |
| 51 | set_kernel_text_rw(); | 52 | set_kernel_text_rw(); |
| 53 | set_all_modules_text_rw(); | ||
| 52 | modifying_code = 1; | 54 | modifying_code = 1; |
| 53 | return 0; | 55 | return 0; |
| 54 | } | 56 | } |
| @@ -56,6 +58,7 @@ int ftrace_arch_code_modify_prepare(void) | |||
| 56 | int ftrace_arch_code_modify_post_process(void) | 58 | int ftrace_arch_code_modify_post_process(void) |
| 57 | { | 59 | { |
| 58 | modifying_code = 0; | 60 | modifying_code = 0; |
| 61 | set_all_modules_text_ro(); | ||
| 59 | set_kernel_text_ro(); | 62 | set_kernel_text_ro(); |
| 60 | return 0; | 63 | return 0; |
| 61 | } | 64 | } |
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index e03530aebfd..bf470075518 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S | |||
| @@ -69,7 +69,7 @@ jiffies_64 = jiffies; | |||
| 69 | 69 | ||
| 70 | PHDRS { | 70 | PHDRS { |
| 71 | text PT_LOAD FLAGS(5); /* R_E */ | 71 | text PT_LOAD FLAGS(5); /* R_E */ |
| 72 | data PT_LOAD FLAGS(7); /* RWE */ | 72 | data PT_LOAD FLAGS(6); /* RW_ */ |
| 73 | #ifdef CONFIG_X86_64 | 73 | #ifdef CONFIG_X86_64 |
| 74 | user PT_LOAD FLAGS(5); /* R_E */ | 74 | user PT_LOAD FLAGS(5); /* R_E */ |
| 75 | #ifdef CONFIG_SMP | 75 | #ifdef CONFIG_SMP |
| @@ -116,6 +116,10 @@ SECTIONS | |||
| 116 | 116 | ||
| 117 | EXCEPTION_TABLE(16) :text = 0x9090 | 117 | EXCEPTION_TABLE(16) :text = 0x9090 |
| 118 | 118 | ||
| 119 | #if defined(CONFIG_DEBUG_RODATA) | ||
| 120 | /* .text should occupy whole number of pages */ | ||
| 121 | . = ALIGN(PAGE_SIZE); | ||
| 122 | #endif | ||
| 119 | X64_ALIGN_DEBUG_RODATA_BEGIN | 123 | X64_ALIGN_DEBUG_RODATA_BEGIN |
| 120 | RO_DATA(PAGE_SIZE) | 124 | RO_DATA(PAGE_SIZE) |
| 121 | X64_ALIGN_DEBUG_RODATA_END | 125 | X64_ALIGN_DEBUG_RODATA_END |
| @@ -335,7 +339,7 @@ SECTIONS | |||
| 335 | __bss_start = .; | 339 | __bss_start = .; |
| 336 | *(.bss..page_aligned) | 340 | *(.bss..page_aligned) |
| 337 | *(.bss) | 341 | *(.bss) |
| 338 | . = ALIGN(4); | 342 | . = ALIGN(PAGE_SIZE); |
| 339 | __bss_stop = .; | 343 | __bss_stop = .; |
| 340 | } | 344 | } |
| 341 | 345 | ||
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index c0e28a13de7..947f42abe82 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c | |||
| @@ -364,8 +364,9 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end) | |||
| 364 | /* | 364 | /* |
| 365 | * We just marked the kernel text read only above, now that | 365 | * We just marked the kernel text read only above, now that |
| 366 | * we are going to free part of that, we need to make that | 366 | * we are going to free part of that, we need to make that |
| 367 | * writeable first. | 367 | * writeable and non-executable first. |
| 368 | */ | 368 | */ |
| 369 | set_memory_nx(begin, (end - begin) >> PAGE_SHIFT); | ||
| 369 | set_memory_rw(begin, (end - begin) >> PAGE_SHIFT); | 370 | set_memory_rw(begin, (end - begin) >> PAGE_SHIFT); |
| 370 | 371 | ||
| 371 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); | 372 | printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); |
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 0e969f9f401..f89b5bb4e93 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
| @@ -226,7 +226,7 @@ page_table_range_init(unsigned long start, unsigned long end, pgd_t *pgd_base) | |||
| 226 | 226 | ||
| 227 | static inline int is_kernel_text(unsigned long addr) | 227 | static inline int is_kernel_text(unsigned long addr) |
| 228 | { | 228 | { |
| 229 | if (addr >= PAGE_OFFSET && addr <= (unsigned long)__init_end) | 229 | if (addr >= (unsigned long)_text && addr <= (unsigned long)__init_end) |
| 230 | return 1; | 230 | return 1; |
| 231 | return 0; | 231 | return 0; |
| 232 | } | 232 | } |
| @@ -912,6 +912,23 @@ void set_kernel_text_ro(void) | |||
| 912 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); | 912 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); |
| 913 | } | 913 | } |
| 914 | 914 | ||
| 915 | static void mark_nxdata_nx(void) | ||
| 916 | { | ||
| 917 | /* | ||
| 918 | * When this called, init has already been executed and released, | ||
| 919 | * so everything past _etext sould be NX. | ||
| 920 | */ | ||
| 921 | unsigned long start = PFN_ALIGN(_etext); | ||
| 922 | /* | ||
| 923 | * This comes from is_kernel_text upper limit. Also HPAGE where used: | ||
| 924 | */ | ||
| 925 | unsigned long size = (((unsigned long)__init_end + HPAGE_SIZE) & HPAGE_MASK) - start; | ||
| 926 | |||
| 927 | if (__supported_pte_mask & _PAGE_NX) | ||
| 928 | printk(KERN_INFO "NX-protecting the kernel data: %luk\n", size >> 10); | ||
| 929 | set_pages_nx(virt_to_page(start), size >> PAGE_SHIFT); | ||
| 930 | } | ||
| 931 | |||
| 915 | void mark_rodata_ro(void) | 932 | void mark_rodata_ro(void) |
| 916 | { | 933 | { |
| 917 | unsigned long start = PFN_ALIGN(_text); | 934 | unsigned long start = PFN_ALIGN(_text); |
| @@ -946,6 +963,7 @@ void mark_rodata_ro(void) | |||
| 946 | printk(KERN_INFO "Testing CPA: write protecting again\n"); | 963 | printk(KERN_INFO "Testing CPA: write protecting again\n"); |
| 947 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); | 964 | set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); |
| 948 | #endif | 965 | #endif |
| 966 | mark_nxdata_nx(); | ||
| 949 | } | 967 | } |
| 950 | #endif | 968 | #endif |
| 951 | 969 | ||
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 532e7933d60..8b830ca14ac 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/pfn.h> | 13 | #include <linux/pfn.h> |
| 14 | #include <linux/percpu.h> | 14 | #include <linux/percpu.h> |
| 15 | #include <linux/gfp.h> | 15 | #include <linux/gfp.h> |
| 16 | #include <linux/pci.h> | ||
| 16 | 17 | ||
| 17 | #include <asm/e820.h> | 18 | #include <asm/e820.h> |
| 18 | #include <asm/processor.h> | 19 | #include <asm/processor.h> |
| @@ -255,13 +256,16 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, | |||
| 255 | unsigned long pfn) | 256 | unsigned long pfn) |
| 256 | { | 257 | { |
| 257 | pgprot_t forbidden = __pgprot(0); | 258 | pgprot_t forbidden = __pgprot(0); |
| 259 | pgprot_t required = __pgprot(0); | ||
| 258 | 260 | ||
| 259 | /* | 261 | /* |
| 260 | * The BIOS area between 640k and 1Mb needs to be executable for | 262 | * The BIOS area between 640k and 1Mb needs to be executable for |
| 261 | * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support. | 263 | * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support. |
| 262 | */ | 264 | */ |
| 263 | if (within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT)) | 265 | #ifdef CONFIG_PCI_BIOS |
| 266 | if (pcibios_enabled && within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT)) | ||
| 264 | pgprot_val(forbidden) |= _PAGE_NX; | 267 | pgprot_val(forbidden) |= _PAGE_NX; |
| 268 | #endif | ||
| 265 | 269 | ||
| 266 | /* | 270 | /* |
| 267 | * The kernel text needs to be executable for obvious reasons | 271 | * The kernel text needs to be executable for obvious reasons |
| @@ -278,6 +282,12 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, | |||
| 278 | if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT, | 282 | if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT, |
| 279 | __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) | 283 | __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) |
| 280 | pgprot_val(forbidden) |= _PAGE_RW; | 284 | pgprot_val(forbidden) |= _PAGE_RW; |
| 285 | /* | ||
| 286 | * .data and .bss should always be writable. | ||
| 287 | */ | ||
| 288 | if (within(address, (unsigned long)_sdata, (unsigned long)_edata) || | ||
| 289 | within(address, (unsigned long)__bss_start, (unsigned long)__bss_stop)) | ||
| 290 | pgprot_val(required) |= _PAGE_RW; | ||
| 281 | 291 | ||
| 282 | #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) | 292 | #if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) |
| 283 | /* | 293 | /* |
| @@ -317,6 +327,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, | |||
| 317 | #endif | 327 | #endif |
| 318 | 328 | ||
| 319 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); | 329 | prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); |
| 330 | prot = __pgprot(pgprot_val(prot) | pgprot_val(required)); | ||
| 320 | 331 | ||
| 321 | return prot; | 332 | return prot; |
| 322 | } | 333 | } |
| @@ -393,7 +404,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 393 | { | 404 | { |
| 394 | unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn; | 405 | unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn; |
| 395 | pte_t new_pte, old_pte, *tmp; | 406 | pte_t new_pte, old_pte, *tmp; |
| 396 | pgprot_t old_prot, new_prot; | 407 | pgprot_t old_prot, new_prot, req_prot; |
| 397 | int i, do_split = 1; | 408 | int i, do_split = 1; |
| 398 | unsigned int level; | 409 | unsigned int level; |
| 399 | 410 | ||
| @@ -438,10 +449,10 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 438 | * We are safe now. Check whether the new pgprot is the same: | 449 | * We are safe now. Check whether the new pgprot is the same: |
| 439 | */ | 450 | */ |
| 440 | old_pte = *kpte; | 451 | old_pte = *kpte; |
| 441 | old_prot = new_prot = pte_pgprot(old_pte); | 452 | old_prot = new_prot = req_prot = pte_pgprot(old_pte); |
| 442 | 453 | ||
| 443 | pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); | 454 | pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr); |
| 444 | pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); | 455 | pgprot_val(req_prot) |= pgprot_val(cpa->mask_set); |
| 445 | 456 | ||
| 446 | /* | 457 | /* |
| 447 | * old_pte points to the large page base address. So we need | 458 | * old_pte points to the large page base address. So we need |
| @@ -450,17 +461,17 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 450 | pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT); | 461 | pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT); |
| 451 | cpa->pfn = pfn; | 462 | cpa->pfn = pfn; |
| 452 | 463 | ||
| 453 | new_prot = static_protections(new_prot, address, pfn); | 464 | new_prot = static_protections(req_prot, address, pfn); |
| 454 | 465 | ||
| 455 | /* | 466 | /* |
| 456 | * We need to check the full range, whether | 467 | * We need to check the full range, whether |
| 457 | * static_protection() requires a different pgprot for one of | 468 | * static_protection() requires a different pgprot for one of |
| 458 | * the pages in the range we try to preserve: | 469 | * the pages in the range we try to preserve: |
| 459 | */ | 470 | */ |
| 460 | addr = address + PAGE_SIZE; | 471 | addr = address & pmask; |
| 461 | pfn++; | 472 | pfn = pte_pfn(old_pte); |
| 462 | for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) { | 473 | for (i = 0; i < (psize >> PAGE_SHIFT); i++, addr += PAGE_SIZE, pfn++) { |
| 463 | pgprot_t chk_prot = static_protections(new_prot, addr, pfn); | 474 | pgprot_t chk_prot = static_protections(req_prot, addr, pfn); |
| 464 | 475 | ||
| 465 | if (pgprot_val(chk_prot) != pgprot_val(new_prot)) | 476 | if (pgprot_val(chk_prot) != pgprot_val(new_prot)) |
| 466 | goto out_unlock; | 477 | goto out_unlock; |
| @@ -483,7 +494,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
| 483 | * that we limited the number of possible pages already to | 494 | * that we limited the number of possible pages already to |
| 484 | * the number of pages in the large page. | 495 | * the number of pages in the large page. |
| 485 | */ | 496 | */ |
| 486 | if (address == (nextpage_addr - psize) && cpa->numpages == numpages) { | 497 | if (address == (address & pmask) && cpa->numpages == (psize >> PAGE_SHIFT)) { |
| 487 | /* | 498 | /* |
| 488 | * The address is aligned and the number of pages | 499 | * The address is aligned and the number of pages |
| 489 | * covers the full page. | 500 | * covers the full page. |
diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c index 2492d165096..a5f7d0d63de 100644 --- a/arch/x86/pci/pcbios.c +++ b/arch/x86/pci/pcbios.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
| 10 | #include <asm/pci_x86.h> | 10 | #include <asm/pci_x86.h> |
| 11 | #include <asm/pci-functions.h> | 11 | #include <asm/pci-functions.h> |
| 12 | #include <asm/cacheflush.h> | ||
| 12 | 13 | ||
| 13 | /* BIOS32 signature: "_32_" */ | 14 | /* BIOS32 signature: "_32_" */ |
| 14 | #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) | 15 | #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) |
| @@ -25,6 +26,27 @@ | |||
| 25 | #define PCIBIOS_HW_TYPE1_SPEC 0x10 | 26 | #define PCIBIOS_HW_TYPE1_SPEC 0x10 |
| 26 | #define PCIBIOS_HW_TYPE2_SPEC 0x20 | 27 | #define PCIBIOS_HW_TYPE2_SPEC 0x20 |
| 27 | 28 | ||
| 29 | int pcibios_enabled; | ||
| 30 | |||
| 31 | /* According to the BIOS specification at: | ||
| 32 | * http://members.datafast.net.au/dft0802/specs/bios21.pdf, we could | ||
| 33 | * restrict the x zone to some pages and make it ro. But this may be | ||
| 34 | * broken on some bios, complex to handle with static_protections. | ||
| 35 | * We could make the 0xe0000-0x100000 range rox, but this can break | ||
| 36 | * some ISA mapping. | ||
| 37 | * | ||
| 38 | * So we let's an rw and x hole when pcibios is used. This shouldn't | ||
| 39 | * happen for modern system with mmconfig, and if you don't want it | ||
| 40 | * you could disable pcibios... | ||
| 41 | */ | ||
| 42 | static inline void set_bios_x(void) | ||
| 43 | { | ||
| 44 | pcibios_enabled = 1; | ||
| 45 | set_memory_x(PAGE_OFFSET + BIOS_BEGIN, (BIOS_END - BIOS_BEGIN) >> PAGE_SHIFT); | ||
| 46 | if (__supported_pte_mask & _PAGE_NX) | ||
| 47 | printk(KERN_INFO "PCI : PCI BIOS aera is rw and x. Use pci=nobios if you want it NX.\n"); | ||
| 48 | } | ||
| 49 | |||
| 28 | /* | 50 | /* |
| 29 | * This is the standard structure used to identify the entry point | 51 | * This is the standard structure used to identify the entry point |
| 30 | * to the BIOS32 Service Directory, as documented in | 52 | * to the BIOS32 Service Directory, as documented in |
| @@ -332,6 +354,7 @@ static struct pci_raw_ops * __devinit pci_find_bios(void) | |||
| 332 | DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", | 354 | DBG("PCI: BIOS32 Service Directory entry at 0x%lx\n", |
| 333 | bios32_entry); | 355 | bios32_entry); |
| 334 | bios32_indirect.address = bios32_entry + PAGE_OFFSET; | 356 | bios32_indirect.address = bios32_entry + PAGE_OFFSET; |
| 357 | set_bios_x(); | ||
| 335 | if (check_pcibios()) | 358 | if (check_pcibios()) |
| 336 | return &pci_bios_access; | 359 | return &pci_bios_access; |
| 337 | } | 360 | } |
diff --git a/include/linux/module.h b/include/linux/module.h index 7575bbbdf2a..8b17fd8c790 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
| @@ -308,6 +308,9 @@ struct module | |||
| 308 | /* The size of the executable code in each section. */ | 308 | /* The size of the executable code in each section. */ |
| 309 | unsigned int init_text_size, core_text_size; | 309 | unsigned int init_text_size, core_text_size; |
| 310 | 310 | ||
| 311 | /* Size of RO sections of the module (text+rodata) */ | ||
| 312 | unsigned int init_ro_size, core_ro_size; | ||
| 313 | |||
| 311 | /* Arch-specific module values */ | 314 | /* Arch-specific module values */ |
| 312 | struct mod_arch_specific arch; | 315 | struct mod_arch_specific arch; |
| 313 | 316 | ||
| @@ -672,7 +675,6 @@ static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter) | |||
| 672 | { | 675 | { |
| 673 | return 0; | 676 | return 0; |
| 674 | } | 677 | } |
| 675 | |||
| 676 | #endif /* CONFIG_MODULES */ | 678 | #endif /* CONFIG_MODULES */ |
| 677 | 679 | ||
| 678 | #ifdef CONFIG_SYSFS | 680 | #ifdef CONFIG_SYSFS |
| @@ -687,6 +689,13 @@ extern int module_sysfs_initialized; | |||
| 687 | 689 | ||
| 688 | #define __MODULE_STRING(x) __stringify(x) | 690 | #define __MODULE_STRING(x) __stringify(x) |
| 689 | 691 | ||
| 692 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | ||
| 693 | extern void set_all_modules_text_rw(void); | ||
| 694 | extern void set_all_modules_text_ro(void); | ||
| 695 | #else | ||
| 696 | static inline void set_all_modules_text_rw(void) { } | ||
| 697 | static inline void set_all_modules_text_ro(void) { } | ||
| 698 | #endif | ||
| 690 | 699 | ||
| 691 | #ifdef CONFIG_GENERIC_BUG | 700 | #ifdef CONFIG_GENERIC_BUG |
| 692 | void module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *, | 701 | void module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *, |
diff --git a/kernel/module.c b/kernel/module.c index d190664f25f..562f665c721 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include <linux/percpu.h> | 56 | #include <linux/percpu.h> |
| 57 | #include <linux/kmemleak.h> | 57 | #include <linux/kmemleak.h> |
| 58 | #include <linux/jump_label.h> | 58 | #include <linux/jump_label.h> |
| 59 | #include <linux/pfn.h> | ||
| 59 | 60 | ||
| 60 | #define CREATE_TRACE_POINTS | 61 | #define CREATE_TRACE_POINTS |
| 61 | #include <trace/events/module.h> | 62 | #include <trace/events/module.h> |
| @@ -70,6 +71,26 @@ | |||
| 70 | #define ARCH_SHF_SMALL 0 | 71 | #define ARCH_SHF_SMALL 0 |
| 71 | #endif | 72 | #endif |
| 72 | 73 | ||
| 74 | /* | ||
| 75 | * Modules' sections will be aligned on page boundaries | ||
| 76 | * to ensure complete separation of code and data, but | ||
| 77 | * only when CONFIG_DEBUG_SET_MODULE_RONX=y | ||
| 78 | */ | ||
| 79 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | ||
| 80 | # define debug_align(X) ALIGN(X, PAGE_SIZE) | ||
| 81 | #else | ||
| 82 | # define debug_align(X) (X) | ||
| 83 | #endif | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Given BASE and SIZE this macro calculates the number of pages the | ||
| 87 | * memory regions occupies | ||
| 88 | */ | ||
| 89 | #define MOD_NUMBER_OF_PAGES(BASE, SIZE) (((SIZE) > 0) ? \ | ||
| 90 | (PFN_DOWN((unsigned long)(BASE) + (SIZE) - 1) - \ | ||
| 91 | PFN_DOWN((unsigned long)BASE) + 1) \ | ||
| 92 | : (0UL)) | ||
| 93 | |||
| 73 | /* If this is set, the section belongs in the init part of the module */ | 94 | /* If this is set, the section belongs in the init part of the module */ |
| 74 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) | 95 | #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) |
| 75 | 96 | ||
| @@ -1542,6 +1563,115 @@ static int __unlink_module(void *_mod) | |||
| 1542 | return 0; | 1563 | return 0; |
| 1543 | } | 1564 | } |
| 1544 | 1565 | ||
| 1566 | #ifdef CONFIG_DEBUG_SET_MODULE_RONX | ||
| 1567 | /* | ||
| 1568 | * LKM RO/NX protection: protect module's text/ro-data | ||
| 1569 | * from modification and any data from execution. | ||
| 1570 | */ | ||
| 1571 | void set_page_attributes(void *start, void *end, int (*set)(unsigned long start, int num_pages)) | ||
| 1572 | { | ||
| 1573 | unsigned long begin_pfn = PFN_DOWN((unsigned long)start); | ||
| 1574 | unsigned long end_pfn = PFN_DOWN((unsigned long)end); | ||
| 1575 | |||
| 1576 | if (end_pfn > begin_pfn) | ||
| 1577 | set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn); | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | static void set_section_ro_nx(void *base, | ||
| 1581 | unsigned long text_size, | ||
| 1582 | unsigned long ro_size, | ||
| 1583 | unsigned long total_size) | ||
| 1584 | { | ||
| 1585 | /* begin and end PFNs of the current subsection */ | ||
| 1586 | unsigned long begin_pfn; | ||
| 1587 | unsigned long end_pfn; | ||
| 1588 | |||
| 1589 | /* | ||
| 1590 | * Set RO for module text and RO-data: | ||
| 1591 | * - Always protect first page. | ||
| 1592 | * - Do not protect last partial page. | ||
| 1593 | */ | ||
| 1594 | if (ro_size > 0) | ||
| 1595 | set_page_attributes(base, base + ro_size, set_memory_ro); | ||
| 1596 | |||
| 1597 | /* | ||
| 1598 | * Set NX permissions for module data: | ||
| 1599 | * - Do not protect first partial page. | ||
| 1600 | * - Always protect last page. | ||
| 1601 | */ | ||
| 1602 | if (total_size > text_size) { | ||
| 1603 | begin_pfn = PFN_UP((unsigned long)base + text_size); | ||
| 1604 | end_pfn = PFN_UP((unsigned long)base + total_size); | ||
| 1605 | if (end_pfn > begin_pfn) | ||
| 1606 | set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn); | ||
| 1607 | } | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | /* Setting memory back to RW+NX before releasing it */ | ||
| 1611 | void unset_section_ro_nx(struct module *mod, void *module_region) | ||
| 1612 | { | ||
| 1613 | unsigned long total_pages; | ||
| 1614 | |||
| 1615 | if (mod->module_core == module_region) { | ||
| 1616 | /* Set core as NX+RW */ | ||
| 1617 | total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size); | ||
| 1618 | set_memory_nx((unsigned long)mod->module_core, total_pages); | ||
| 1619 | set_memory_rw((unsigned long)mod->module_core, total_pages); | ||
| 1620 | |||
| 1621 | } else if (mod->module_init == module_region) { | ||
| 1622 | /* Set init as NX+RW */ | ||
| 1623 | total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size); | ||
| 1624 | set_memory_nx((unsigned long)mod->module_init, total_pages); | ||
| 1625 | set_memory_rw((unsigned long)mod->module_init, total_pages); | ||
| 1626 | } | ||
| 1627 | } | ||
| 1628 | |||
| 1629 | /* Iterate through all modules and set each module's text as RW */ | ||
| 1630 | void set_all_modules_text_rw() | ||
| 1631 | { | ||
| 1632 | struct module *mod; | ||
| 1633 | |||
| 1634 | mutex_lock(&module_mutex); | ||
| 1635 | list_for_each_entry_rcu(mod, &modules, list) { | ||
| 1636 | if ((mod->module_core) && (mod->core_text_size)) { | ||
| 1637 | set_page_attributes(mod->module_core, | ||
| 1638 | mod->module_core + mod->core_text_size, | ||
| 1639 | set_memory_rw); | ||
| 1640 | } | ||
| 1641 | if ((mod->module_init) && (mod->init_text_size)) { | ||
| 1642 | set_page_attributes(mod->module_init, | ||
| 1643 | mod->module_init + mod->init_text_size, | ||
| 1644 | set_memory_rw); | ||
| 1645 | } | ||
| 1646 | } | ||
| 1647 | mutex_unlock(&module_mutex); | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | /* Iterate through all modules and set each module's text as RO */ | ||
| 1651 | void set_all_modules_text_ro() | ||
| 1652 | { | ||
| 1653 | struct module *mod; | ||
| 1654 | |||
| 1655 | mutex_lock(&module_mutex); | ||
| 1656 | list_for_each_entry_rcu(mod, &modules, list) { | ||
| 1657 | if ((mod->module_core) && (mod->core_text_size)) { | ||
| 1658 | set_page_attributes(mod->module_core, | ||
| 1659 | mod->module_core + mod->core_text_size, | ||
| 1660 | set_memory_ro); | ||
| 1661 | } | ||
| 1662 | if ((mod->module_init) && (mod->init_text_size)) { | ||
| 1663 | set_page_attributes(mod->module_init, | ||
| 1664 | mod->module_init + mod->init_text_size, | ||
| 1665 | set_memory_ro); | ||
| 1666 | } | ||
| 1667 | } | ||
| 1668 | mutex_unlock(&module_mutex); | ||
| 1669 | } | ||
| 1670 | #else | ||
| 1671 | static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { } | ||
| 1672 | static inline void unset_section_ro_nx(struct module *mod, void *module_region) { } | ||
| 1673 | #endif | ||
| 1674 | |||
| 1545 | /* Free a module, remove from lists, etc. */ | 1675 | /* Free a module, remove from lists, etc. */ |
| 1546 | static void free_module(struct module *mod) | 1676 | static void free_module(struct module *mod) |
| 1547 | { | 1677 | { |
| @@ -1566,6 +1696,7 @@ static void free_module(struct module *mod) | |||
| 1566 | destroy_params(mod->kp, mod->num_kp); | 1696 | destroy_params(mod->kp, mod->num_kp); |
| 1567 | 1697 | ||
| 1568 | /* This may be NULL, but that's OK */ | 1698 | /* This may be NULL, but that's OK */ |
| 1699 | unset_section_ro_nx(mod, mod->module_init); | ||
| 1569 | module_free(mod, mod->module_init); | 1700 | module_free(mod, mod->module_init); |
| 1570 | kfree(mod->args); | 1701 | kfree(mod->args); |
| 1571 | percpu_modfree(mod); | 1702 | percpu_modfree(mod); |
| @@ -1574,6 +1705,7 @@ static void free_module(struct module *mod) | |||
| 1574 | lockdep_free_key_range(mod->module_core, mod->core_size); | 1705 | lockdep_free_key_range(mod->module_core, mod->core_size); |
| 1575 | 1706 | ||
| 1576 | /* Finally, free the core (containing the module structure) */ | 1707 | /* Finally, free the core (containing the module structure) */ |
| 1708 | unset_section_ro_nx(mod, mod->module_core); | ||
| 1577 | module_free(mod, mod->module_core); | 1709 | module_free(mod, mod->module_core); |
| 1578 | 1710 | ||
| 1579 | #ifdef CONFIG_MPU | 1711 | #ifdef CONFIG_MPU |
| @@ -1777,8 +1909,19 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
| 1777 | s->sh_entsize = get_offset(mod, &mod->core_size, s, i); | 1909 | s->sh_entsize = get_offset(mod, &mod->core_size, s, i); |
| 1778 | DEBUGP("\t%s\n", name); | 1910 | DEBUGP("\t%s\n", name); |
| 1779 | } | 1911 | } |
| 1780 | if (m == 0) | 1912 | switch (m) { |
| 1913 | case 0: /* executable */ | ||
| 1914 | mod->core_size = debug_align(mod->core_size); | ||
| 1781 | mod->core_text_size = mod->core_size; | 1915 | mod->core_text_size = mod->core_size; |
| 1916 | break; | ||
| 1917 | case 1: /* RO: text and ro-data */ | ||
| 1918 | mod->core_size = debug_align(mod->core_size); | ||
| 1919 | mod->core_ro_size = mod->core_size; | ||
| 1920 | break; | ||
| 1921 | case 3: /* whole core */ | ||
| 1922 | mod->core_size = debug_align(mod->core_size); | ||
| 1923 | break; | ||
| 1924 | } | ||
| 1782 | } | 1925 | } |
| 1783 | 1926 | ||
| 1784 | DEBUGP("Init section allocation order:\n"); | 1927 | DEBUGP("Init section allocation order:\n"); |
| @@ -1796,8 +1939,19 @@ static void layout_sections(struct module *mod, struct load_info *info) | |||
| 1796 | | INIT_OFFSET_MASK); | 1939 | | INIT_OFFSET_MASK); |
| 1797 | DEBUGP("\t%s\n", sname); | 1940 | DEBUGP("\t%s\n", sname); |
| 1798 | } | 1941 | } |
| 1799 | if (m == 0) | 1942 | switch (m) { |
| 1943 | case 0: /* executable */ | ||
| 1944 | mod->init_size = debug_align(mod->init_size); | ||
| 1800 | mod->init_text_size = mod->init_size; | 1945 | mod->init_text_size = mod->init_size; |
| 1946 | break; | ||
| 1947 | case 1: /* RO: text and ro-data */ | ||
| 1948 | mod->init_size = debug_align(mod->init_size); | ||
| 1949 | mod->init_ro_size = mod->init_size; | ||
| 1950 | break; | ||
| 1951 | case 3: /* whole init */ | ||
| 1952 | mod->init_size = debug_align(mod->init_size); | ||
| 1953 | break; | ||
| 1954 | } | ||
| 1801 | } | 1955 | } |
| 1802 | } | 1956 | } |
| 1803 | 1957 | ||
| @@ -2662,6 +2816,18 @@ static struct module *load_module(void __user *umod, | |||
| 2662 | kfree(info.strmap); | 2816 | kfree(info.strmap); |
| 2663 | free_copy(&info); | 2817 | free_copy(&info); |
| 2664 | 2818 | ||
| 2819 | /* Set RO and NX regions for core */ | ||
| 2820 | set_section_ro_nx(mod->module_core, | ||
| 2821 | mod->core_text_size, | ||
| 2822 | mod->core_ro_size, | ||
| 2823 | mod->core_size); | ||
| 2824 | |||
| 2825 | /* Set RO and NX regions for init */ | ||
| 2826 | set_section_ro_nx(mod->module_init, | ||
| 2827 | mod->init_text_size, | ||
| 2828 | mod->init_ro_size, | ||
| 2829 | mod->init_size); | ||
| 2830 | |||
| 2665 | /* Done! */ | 2831 | /* Done! */ |
| 2666 | trace_module_load(mod); | 2832 | trace_module_load(mod); |
| 2667 | return mod; | 2833 | return mod; |
| @@ -2765,6 +2931,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod, | |||
| 2765 | mod->symtab = mod->core_symtab; | 2931 | mod->symtab = mod->core_symtab; |
| 2766 | mod->strtab = mod->core_strtab; | 2932 | mod->strtab = mod->core_strtab; |
| 2767 | #endif | 2933 | #endif |
| 2934 | unset_section_ro_nx(mod, mod->module_init); | ||
| 2768 | module_free(mod, mod->module_init); | 2935 | module_free(mod, mod->module_init); |
| 2769 | mod->module_init = NULL; | 2936 | mod->module_init = NULL; |
| 2770 | mod->init_size = 0; | 2937 | mod->init_size = 0; |
