summaryrefslogtreecommitdiffstats
path: root/mm/debug-pagealloc.c
diff options
context:
space:
mode:
authorLaura Abbott <labbott@fedoraproject.org>2016-03-15 17:56:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-15 19:55:16 -0400
commit8823b1dbc05fab1a8bec275eeae4709257c2661d (patch)
treea7d6683189c1656ac0879a0a7e9f39c695abfeee /mm/debug-pagealloc.c
parentff8e81163889ac4c7f59e7f7db6377d0c5d8d69c (diff)
mm/page_poison.c: enable PAGE_POISONING as a separate option
Page poisoning is currently set up as a feature if architectures don't have architecture debug page_alloc to allow unmapping of pages. It has uses apart from that though. Clearing of the pages on free provides an increase in security as it helps to limit the risk of information leaks. Allow page poisoning to be enabled as a separate option independent of kernel_map pages since the two features do separate work. Because of how hiberanation is implemented, the checks on alloc cannot occur if hibernation is enabled. The runtime alloc checks can also be enabled with an option when !HIBERNATION. Credit to Grsecurity/PaX team for inspiring this work Signed-off-by: Laura Abbott <labbott@fedoraproject.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Michal Hocko <mhocko@suse.com> Cc: Kees Cook <keescook@chromium.org> Cc: Mathias Krause <minipli@googlemail.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Jianyu Zhan <nasa4836@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/debug-pagealloc.c')
-rw-r--r--mm/debug-pagealloc.c137
1 files changed, 0 insertions, 137 deletions
diff --git a/mm/debug-pagealloc.c b/mm/debug-pagealloc.c
deleted file mode 100644
index 5bf5906ce13b..000000000000
--- a/mm/debug-pagealloc.c
+++ /dev/null
@@ -1,137 +0,0 @@
1#include <linux/kernel.h>
2#include <linux/string.h>
3#include <linux/mm.h>
4#include <linux/highmem.h>
5#include <linux/page_ext.h>
6#include <linux/poison.h>
7#include <linux/ratelimit.h>
8
9static bool page_poisoning_enabled __read_mostly;
10
11static bool need_page_poisoning(void)
12{
13 if (!debug_pagealloc_enabled())
14 return false;
15
16 return true;
17}
18
19static void init_page_poisoning(void)
20{
21 if (!debug_pagealloc_enabled())
22 return;
23
24 page_poisoning_enabled = true;
25}
26
27struct page_ext_operations page_poisoning_ops = {
28 .need = need_page_poisoning,
29 .init = init_page_poisoning,
30};
31
32static inline void set_page_poison(struct page *page)
33{
34 struct page_ext *page_ext;
35
36 page_ext = lookup_page_ext(page);
37 __set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
38}
39
40static inline void clear_page_poison(struct page *page)
41{
42 struct page_ext *page_ext;
43
44 page_ext = lookup_page_ext(page);
45 __clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
46}
47
48static inline bool page_poison(struct page *page)
49{
50 struct page_ext *page_ext;
51
52 page_ext = lookup_page_ext(page);
53 return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
54}
55
56static void poison_page(struct page *page)
57{
58 void *addr = kmap_atomic(page);
59
60 set_page_poison(page);
61 memset(addr, PAGE_POISON, PAGE_SIZE);
62 kunmap_atomic(addr);
63}
64
65static void poison_pages(struct page *page, int n)
66{
67 int i;
68
69 for (i = 0; i < n; i++)
70 poison_page(page + i);
71}
72
73static bool single_bit_flip(unsigned char a, unsigned char b)
74{
75 unsigned char error = a ^ b;
76
77 return error && !(error & (error - 1));
78}
79
80static void check_poison_mem(unsigned char *mem, size_t bytes)
81{
82 static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 10);
83 unsigned char *start;
84 unsigned char *end;
85
86 start = memchr_inv(mem, PAGE_POISON, bytes);
87 if (!start)
88 return;
89
90 for (end = mem + bytes - 1; end > start; end--) {
91 if (*end != PAGE_POISON)
92 break;
93 }
94
95 if (!__ratelimit(&ratelimit))
96 return;
97 else if (start == end && single_bit_flip(*start, PAGE_POISON))
98 printk(KERN_ERR "pagealloc: single bit error\n");
99 else
100 printk(KERN_ERR "pagealloc: memory corruption\n");
101
102 print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
103 end - start + 1, 1);
104 dump_stack();
105}
106
107static void unpoison_page(struct page *page)
108{
109 void *addr;
110
111 if (!page_poison(page))
112 return;
113
114 addr = kmap_atomic(page);
115 check_poison_mem(addr, PAGE_SIZE);
116 clear_page_poison(page);
117 kunmap_atomic(addr);
118}
119
120static void unpoison_pages(struct page *page, int n)
121{
122 int i;
123
124 for (i = 0; i < n; i++)
125 unpoison_page(page + i);
126}
127
128void __kernel_map_pages(struct page *page, int numpages, int enable)
129{
130 if (!page_poisoning_enabled)
131 return;
132
133 if (enable)
134 unpoison_pages(page, numpages);
135 else
136 poison_pages(page, numpages);
137}