mm: Mark free pages as read only

Drivers have a tendency to scribble on everything, including free
pages. Make life easier by marking free pages as read only when
on the buddy list and re-marking as read/write when allocating.

Change-Id: I978ed2921394919917307b9c99217fdc22f82c59
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
This commit is contained in:
Laura Abbott 2014-04-14 20:09:44 -07:00
parent 853075183f
commit a21cc73659
3 changed files with 30 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -6,6 +6,14 @@
#include <linux/poison.h>
#include <linux/ratelimit.h>
#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);
}