From: Arjan van de Ven x86-64 specific parts to make the .rodata section read only Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Cc: Andi Kleen Signed-off-by: Andrew Morton --- arch/x86_64/Kconfig.debug | 10 ++++++++++ arch/x86_64/mm/init.c | 23 +++++++++++++++++++++++ include/asm-x86_64/cacheflush.h | 1 + 3 files changed, 34 insertions(+) diff -puN arch/x86_64/Kconfig.debug~mark-rodata-section-read-only-x86-64-support arch/x86_64/Kconfig.debug --- devel/arch/x86_64/Kconfig.debug~mark-rodata-section-read-only-x86-64-support 2005-11-10 02:19:44.000000000 -0800 +++ devel-akpm/arch/x86_64/Kconfig.debug 2005-11-10 02:19:44.000000000 -0800 @@ -9,6 +9,16 @@ config INIT_DEBUG Fill __init and __initdata at the end of boot. This helps debugging illegal uses of __init and __initdata after initialization. +config DEBUG_RODATA + bool "Write protect kernel read-only data structures" + depends on DEBUG_KERNEL + help + Mark the kernel read-only data as write-protected in the pagetables, + in order to catch accidental (and incorrect) writes to such const data. + This option may have a slight performance impact because a portion + of the kernel code won't be covered by a 2MB TLB anymore. + If in doubt, say "N". + config IOMMU_DEBUG depends on GART_IOMMU && DEBUG_KERNEL bool "Enable IOMMU debugging" diff -puN arch/x86_64/mm/init.c~mark-rodata-section-read-only-x86-64-support arch/x86_64/mm/init.c --- devel/arch/x86_64/mm/init.c~mark-rodata-section-read-only-x86-64-support 2005-11-10 02:19:44.000000000 -0800 +++ devel-akpm/arch/x86_64/mm/init.c 2005-11-10 02:19:44.000000000 -0800 @@ -498,6 +498,29 @@ void free_initmem(void) printk ("Freeing unused kernel memory: %luk freed\n", (__init_end - __init_begin) >> 10); } +#ifdef CONFIG_DEBUG_RODATA + +extern char __start_rodata, __end_rodata; +void mark_rodata_ro(void) +{ + unsigned long addr = (unsigned long)&__start_rodata; + + for (; addr < (unsigned long)&__end_rodata; addr += PAGE_SIZE) + change_page_attr_addr(addr, 1, PAGE_KERNEL_RO); + + printk ("Write protecting the kernel read-only data: %luk\n", + (&__end_rodata - &__start_rodata) >> 10); + + /* + * change_page_attr_addr() requires a global_flush_tlb() call after it. + * We do this after the printk so that if something went wrong in the + * change, the printk gets out at least to give a better debug hint + * of who is the culprit. + */ + global_flush_tlb(); +} +#endif + #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { diff -puN include/asm-x86_64/cacheflush.h~mark-rodata-section-read-only-x86-64-support include/asm-x86_64/cacheflush.h --- devel/include/asm-x86_64/cacheflush.h~mark-rodata-section-read-only-x86-64-support 2005-11-10 02:19:44.000000000 -0800 +++ devel-akpm/include/asm-x86_64/cacheflush.h 2005-11-10 02:19:44.000000000 -0800 @@ -26,5 +26,6 @@ void global_flush_tlb(void); int change_page_attr(struct page *page, int numpages, pgprot_t prot); int change_page_attr_addr(unsigned long addr, int numpages, pgprot_t prot); +void mark_rodata_ro(void); #endif /* _X8664_CACHEFLUSH_H */ _