diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/Kconfig.debug | 25 | ||||
-rw-r--r-- | mm/Makefile | 2 | ||||
-rw-r--r-- | mm/page_alloc.c | 2 | ||||
-rw-r--r-- | mm/page_poison.c (renamed from mm/debug-pagealloc.c) | 60 |
4 files changed, 75 insertions, 14 deletions
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug index a0c136af9c91..1f99f9a0deae 100644 --- a/mm/Kconfig.debug +++ b/mm/Kconfig.debug | |||
@@ -41,4 +41,27 @@ config DEBUG_PAGEALLOC_ENABLE_DEFAULT | |||
41 | can be overridden by debug_pagealloc=off|on. | 41 | can be overridden by debug_pagealloc=off|on. |
42 | 42 | ||
43 | config PAGE_POISONING | 43 | config PAGE_POISONING |
44 | bool | 44 | bool "Poison pages after freeing" |
45 | select PAGE_EXTENSION | ||
46 | select PAGE_POISONING_NO_SANITY if HIBERNATION | ||
47 | ---help--- | ||
48 | Fill the pages with poison patterns after free_pages() and verify | ||
49 | the patterns before alloc_pages. The filling of the memory helps | ||
50 | reduce the risk of information leaks from freed data. This does | ||
51 | have a potential performance impact. | ||
52 | |||
53 | Note that "poison" here is not the same thing as the "HWPoison" | ||
54 | for CONFIG_MEMORY_FAILURE. This is software poisoning only. | ||
55 | |||
56 | If unsure, say N | ||
57 | |||
58 | config PAGE_POISONING_NO_SANITY | ||
59 | depends on PAGE_POISONING | ||
60 | bool "Only poison, don't sanity check" | ||
61 | ---help--- | ||
62 | Skip the sanity checking on alloc, only fill the pages with | ||
63 | poison on free. This reduces some of the overhead of the | ||
64 | poisoning feature. | ||
65 | |||
66 | If you are only interested in sanitization, say Y. Otherwise | ||
67 | say N. | ||
diff --git a/mm/Makefile b/mm/Makefile index 2ed43191fc3b..cfdd481d27a5 100644 --- a/mm/Makefile +++ b/mm/Makefile | |||
@@ -48,7 +48,7 @@ obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o | |||
48 | obj-$(CONFIG_SLOB) += slob.o | 48 | obj-$(CONFIG_SLOB) += slob.o |
49 | obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o | 49 | obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o |
50 | obj-$(CONFIG_KSM) += ksm.o | 50 | obj-$(CONFIG_KSM) += ksm.o |
51 | obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o | 51 | obj-$(CONFIG_PAGE_POISONING) += page_poison.o |
52 | obj-$(CONFIG_SLAB) += slab.o | 52 | obj-$(CONFIG_SLAB) += slab.o |
53 | obj-$(CONFIG_SLUB) += slub.o | 53 | obj-$(CONFIG_SLUB) += slub.o |
54 | obj-$(CONFIG_KMEMCHECK) += kmemcheck.o | 54 | obj-$(CONFIG_KMEMCHECK) += kmemcheck.o |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0691403aed93..2a08349fbab2 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -1025,6 +1025,7 @@ static bool free_pages_prepare(struct page *page, unsigned int order) | |||
1025 | PAGE_SIZE << order); | 1025 | PAGE_SIZE << order); |
1026 | } | 1026 | } |
1027 | arch_free_page(page, order); | 1027 | arch_free_page(page, order); |
1028 | kernel_poison_pages(page, 1 << order, 0); | ||
1028 | kernel_map_pages(page, 1 << order, 0); | 1029 | kernel_map_pages(page, 1 << order, 0); |
1029 | 1030 | ||
1030 | return true; | 1031 | return true; |
@@ -1420,6 +1421,7 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, | |||
1420 | 1421 | ||
1421 | arch_alloc_page(page, order); | 1422 | arch_alloc_page(page, order); |
1422 | kernel_map_pages(page, 1 << order, 1); | 1423 | kernel_map_pages(page, 1 << order, 1); |
1424 | kernel_poison_pages(page, 1 << order, 1); | ||
1423 | kasan_alloc_pages(page, order); | 1425 | kasan_alloc_pages(page, order); |
1424 | 1426 | ||
1425 | if (gfp_flags & __GFP_ZERO) | 1427 | if (gfp_flags & __GFP_ZERO) |
diff --git a/mm/debug-pagealloc.c b/mm/page_poison.c index 5bf5906ce13b..89d3bc773633 100644 --- a/mm/debug-pagealloc.c +++ b/mm/page_poison.c | |||
@@ -6,22 +6,48 @@ | |||
6 | #include <linux/poison.h> | 6 | #include <linux/poison.h> |
7 | #include <linux/ratelimit.h> | 7 | #include <linux/ratelimit.h> |
8 | 8 | ||
9 | static bool page_poisoning_enabled __read_mostly; | 9 | static bool __page_poisoning_enabled __read_mostly; |
10 | static bool want_page_poisoning __read_mostly; | ||
10 | 11 | ||
11 | static bool need_page_poisoning(void) | 12 | static int early_page_poison_param(char *buf) |
12 | { | 13 | { |
13 | if (!debug_pagealloc_enabled()) | 14 | if (!buf) |
14 | return false; | 15 | return -EINVAL; |
16 | |||
17 | if (strcmp(buf, "on") == 0) | ||
18 | want_page_poisoning = true; | ||
19 | else if (strcmp(buf, "off") == 0) | ||
20 | want_page_poisoning = false; | ||
15 | 21 | ||
16 | return true; | 22 | return 0; |
23 | } | ||
24 | early_param("page_poison", early_page_poison_param); | ||
25 | |||
26 | bool page_poisoning_enabled(void) | ||
27 | { | ||
28 | return __page_poisoning_enabled; | ||
29 | } | ||
30 | |||
31 | static bool need_page_poisoning(void) | ||
32 | { | ||
33 | return want_page_poisoning; | ||
17 | } | 34 | } |
18 | 35 | ||
19 | static void init_page_poisoning(void) | 36 | static void init_page_poisoning(void) |
20 | { | 37 | { |
21 | if (!debug_pagealloc_enabled()) | 38 | /* |
22 | return; | 39 | * page poisoning is debug page alloc for some arches. If either |
40 | * of those options are enabled, enable poisoning | ||
41 | */ | ||
42 | if (!IS_ENABLED(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC)) { | ||
43 | if (!want_page_poisoning && !debug_pagealloc_enabled()) | ||
44 | return; | ||
45 | } else { | ||
46 | if (!want_page_poisoning) | ||
47 | return; | ||
48 | } | ||
23 | 49 | ||
24 | page_poisoning_enabled = true; | 50 | __page_poisoning_enabled = true; |
25 | } | 51 | } |
26 | 52 | ||
27 | struct page_ext_operations page_poisoning_ops = { | 53 | struct page_ext_operations page_poisoning_ops = { |
@@ -83,6 +109,9 @@ static void check_poison_mem(unsigned char *mem, size_t bytes) | |||
83 | unsigned char *start; | 109 | unsigned char *start; |
84 | unsigned char *end; | 110 | unsigned char *end; |
85 | 111 | ||
112 | if (IS_ENABLED(CONFIG_PAGE_POISONING_NO_SANITY)) | ||
113 | return; | ||
114 | |||
86 | start = memchr_inv(mem, PAGE_POISON, bytes); | 115 | start = memchr_inv(mem, PAGE_POISON, bytes); |
87 | if (!start) | 116 | if (!start) |
88 | return; | 117 | return; |
@@ -95,9 +124,9 @@ static void check_poison_mem(unsigned char *mem, size_t bytes) | |||
95 | if (!__ratelimit(&ratelimit)) | 124 | if (!__ratelimit(&ratelimit)) |
96 | return; | 125 | return; |
97 | else if (start == end && single_bit_flip(*start, PAGE_POISON)) | 126 | else if (start == end && single_bit_flip(*start, PAGE_POISON)) |
98 | printk(KERN_ERR "pagealloc: single bit error\n"); | 127 | pr_err("pagealloc: single bit error\n"); |
99 | else | 128 | else |
100 | printk(KERN_ERR "pagealloc: memory corruption\n"); | 129 | pr_err("pagealloc: memory corruption\n"); |
101 | 130 | ||
102 | print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start, | 131 | print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start, |
103 | end - start + 1, 1); | 132 | end - start + 1, 1); |
@@ -125,9 +154,9 @@ static void unpoison_pages(struct page *page, int n) | |||
125 | unpoison_page(page + i); | 154 | unpoison_page(page + i); |
126 | } | 155 | } |
127 | 156 | ||
128 | void __kernel_map_pages(struct page *page, int numpages, int enable) | 157 | void kernel_poison_pages(struct page *page, int numpages, int enable) |
129 | { | 158 | { |
130 | if (!page_poisoning_enabled) | 159 | if (!page_poisoning_enabled()) |
131 | return; | 160 | return; |
132 | 161 | ||
133 | if (enable) | 162 | if (enable) |
@@ -135,3 +164,10 @@ void __kernel_map_pages(struct page *page, int numpages, int enable) | |||
135 | else | 164 | else |
136 | poison_pages(page, numpages); | 165 | poison_pages(page, numpages); |
137 | } | 166 | } |
167 | |||
168 | #ifndef CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC | ||
169 | void __kernel_map_pages(struct page *page, int numpages, int enable) | ||
170 | { | ||
171 | /* This function does nothing, all work is done via poison pages */ | ||
172 | } | ||
173 | #endif | ||