]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.9.45/mm-discard-memblock-data-later.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.9.45 / mm-discard-memblock-data-later.patch
1 From 3010f876500f9ba921afaeccec30c45ca6584dc8 Mon Sep 17 00:00:00 2001
2 From: Pavel Tatashin <pasha.tatashin@oracle.com>
3 Date: Fri, 18 Aug 2017 15:16:05 -0700
4 Subject: mm: discard memblock data later
5
6 From: Pavel Tatashin <pasha.tatashin@oracle.com>
7
8 commit 3010f876500f9ba921afaeccec30c45ca6584dc8 upstream.
9
10 There is existing use after free bug when deferred struct pages are
11 enabled:
12
13 The memblock_add() allocates memory for the memory array if more than
14 128 entries are needed. See comment in e820__memblock_setup():
15
16 * The bootstrap memblock region count maximum is 128 entries
17 * (INIT_MEMBLOCK_REGIONS), but EFI might pass us more E820 entries
18 * than that - so allow memblock resizing.
19
20 This memblock memory is freed here:
21 free_low_memory_core_early()
22
23 We access the freed memblock.memory later in boot when deferred pages
24 are initialized in this path:
25
26 deferred_init_memmap()
27 for_each_mem_pfn_range()
28 __next_mem_pfn_range()
29 type = &memblock.memory;
30
31 One possible explanation for why this use-after-free hasn't been hit
32 before is that the limit of INIT_MEMBLOCK_REGIONS has never been
33 exceeded at least on systems where deferred struct pages were enabled.
34
35 Tested by reducing INIT_MEMBLOCK_REGIONS down to 4 from the current 128,
36 and verifying in qemu that this code is getting excuted and that the
37 freed pages are sane.
38
39 Link: http://lkml.kernel.org/r/1502485554-318703-2-git-send-email-pasha.tatashin@oracle.com
40 Fixes: 7e18adb4f80b ("mm: meminit: initialise remaining struct pages in parallel with kswapd")
41 Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
42 Reviewed-by: Steven Sistare <steven.sistare@oracle.com>
43 Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com>
44 Reviewed-by: Bob Picco <bob.picco@oracle.com>
45 Acked-by: Michal Hocko <mhocko@suse.com>
46 Cc: Mel Gorman <mgorman@techsingularity.net>
47 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
48 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
49 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
50
51 ---
52 include/linux/memblock.h | 6 ++++--
53 mm/memblock.c | 40 ++++++++++++++++++----------------------
54 mm/nobootmem.c | 16 ----------------
55 mm/page_alloc.c | 4 ++++
56 4 files changed, 26 insertions(+), 40 deletions(-)
57
58 --- a/include/linux/memblock.h
59 +++ b/include/linux/memblock.h
60 @@ -64,6 +64,7 @@ extern bool movable_node_enabled;
61 #ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
62 #define __init_memblock __meminit
63 #define __initdata_memblock __meminitdata
64 +void memblock_discard(void);
65 #else
66 #define __init_memblock
67 #define __initdata_memblock
68 @@ -77,8 +78,6 @@ phys_addr_t memblock_find_in_range_node(
69 int nid, ulong flags);
70 phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end,
71 phys_addr_t size, phys_addr_t align);
72 -phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr);
73 -phys_addr_t get_allocated_memblock_memory_regions_info(phys_addr_t *addr);
74 void memblock_allow_resize(void);
75 int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid);
76 int memblock_add(phys_addr_t base, phys_addr_t size);
77 @@ -112,6 +111,9 @@ void __next_mem_range_rev(u64 *idx, int
78 void __next_reserved_mem_region(u64 *idx, phys_addr_t *out_start,
79 phys_addr_t *out_end);
80
81 +void __memblock_free_early(phys_addr_t base, phys_addr_t size);
82 +void __memblock_free_late(phys_addr_t base, phys_addr_t size);
83 +
84 /**
85 * for_each_mem_range - iterate through memblock areas from type_a and not
86 * included in type_b. Or just type_a if type_b is NULL.
87 --- a/mm/memblock.c
88 +++ b/mm/memblock.c
89 @@ -297,31 +297,27 @@ static void __init_memblock memblock_rem
90 }
91
92 #ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
93 -
94 -phys_addr_t __init_memblock get_allocated_memblock_reserved_regions_info(
95 - phys_addr_t *addr)
96 -{
97 - if (memblock.reserved.regions == memblock_reserved_init_regions)
98 - return 0;
99 -
100 - *addr = __pa(memblock.reserved.regions);
101 -
102 - return PAGE_ALIGN(sizeof(struct memblock_region) *
103 - memblock.reserved.max);
104 -}
105 -
106 -phys_addr_t __init_memblock get_allocated_memblock_memory_regions_info(
107 - phys_addr_t *addr)
108 +/**
109 + * Discard memory and reserved arrays if they were allocated
110 + */
111 +void __init memblock_discard(void)
112 {
113 - if (memblock.memory.regions == memblock_memory_init_regions)
114 - return 0;
115 + phys_addr_t addr, size;
116
117 - *addr = __pa(memblock.memory.regions);
118 -
119 - return PAGE_ALIGN(sizeof(struct memblock_region) *
120 - memblock.memory.max);
121 + if (memblock.reserved.regions != memblock_reserved_init_regions) {
122 + addr = __pa(memblock.reserved.regions);
123 + size = PAGE_ALIGN(sizeof(struct memblock_region) *
124 + memblock.reserved.max);
125 + __memblock_free_late(addr, size);
126 + }
127 +
128 + if (memblock.memory.regions == memblock_memory_init_regions) {
129 + addr = __pa(memblock.memory.regions);
130 + size = PAGE_ALIGN(sizeof(struct memblock_region) *
131 + memblock.memory.max);
132 + __memblock_free_late(addr, size);
133 + }
134 }
135 -
136 #endif
137
138 /**
139 --- a/mm/nobootmem.c
140 +++ b/mm/nobootmem.c
141 @@ -146,22 +146,6 @@ static unsigned long __init free_low_mem
142 NULL)
143 count += __free_memory_core(start, end);
144
145 -#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
146 - {
147 - phys_addr_t size;
148 -
149 - /* Free memblock.reserved array if it was allocated */
150 - size = get_allocated_memblock_reserved_regions_info(&start);
151 - if (size)
152 - count += __free_memory_core(start, start + size);
153 -
154 - /* Free memblock.memory array if it was allocated */
155 - size = get_allocated_memblock_memory_regions_info(&start);
156 - if (size)
157 - count += __free_memory_core(start, start + size);
158 - }
159 -#endif
160 -
161 return count;
162 }
163
164 --- a/mm/page_alloc.c
165 +++ b/mm/page_alloc.c
166 @@ -1587,6 +1587,10 @@ void __init page_alloc_init_late(void)
167 /* Reinit limits that are based on free pages after the kernel is up */
168 files_maxfiles_init();
169 #endif
170 +#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
171 + /* Discard memblock private memory */
172 + memblock_discard();
173 +#endif
174
175 for_each_populated_zone(zone)
176 set_zone_contiguous(zone);