diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 25e9e03dcd1e..2f69005437a5 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -85,6 +85,18 @@ config FORCE_PAGES If unsure say N. +config FREE_PAGES_RDONLY + bool "Set pages as read only while on the buddy list" + select FORCE_PAGES + select PAGE_POISONING + help + Pages are always mapped in the kernel. This means that anyone + can write to the page if they have the address. Enable this option + to mark pages as read only to trigger a fault if any code attempts + to write to a page on the buddy list. This may have a performance + impact. + + If unsure, say N. # These options are only for real kernel hackers who want to get their hands dirty. config DEBUG_LL diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 341057f74f74..da6d8adf975f 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -462,4 +462,12 @@ int set_memory_rw(unsigned long addr, int numpages); int set_memory_x(unsigned long addr, int numpages); int set_memory_nx(unsigned long addr, int numpages); +#ifdef CONFIG_FREE_PAGES_RDONLY +#define mark_addr_rdonly(a) set_memory_ro((unsigned long)a, 1); +#define mark_addr_rdwrite(a) set_memory_rw((unsigned long)a, 1); +#else +#define mark_addr_rdonly(a) +#define mark_addr_rdwrite(a) +#endif + #endif diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c index bc91cbab343a..87dde3682f5e 100644 --- a/mm/debug-pagealloc.c +++ b/mm/debug-pagealloc.c @@ -6,6 +6,14 @@ #include #include +#ifndef mark_addr_rdonly +#define mark_addr_rdonly(a) +#endif + +#ifndef mark_addr_rdwrite +#define mark_addr_rdwrite(a) +#endif + static inline void set_page_poison(struct page *page) { __set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags); @@ -27,6 +35,7 @@ static void poison_page(struct page *page) set_page_poison(page); memset(addr, PAGE_POISON, PAGE_SIZE); + mark_addr_rdonly(addr); kunmap_atomic(addr); } @@ -82,6 +91,7 @@ static void unpoison_page(struct page *page) addr = kmap_atomic(page); check_poison_mem(addr, PAGE_SIZE); + mark_addr_rdwrite(addr); clear_page_poison(page); kunmap_atomic(addr); }