Skip to content

Commit e43518a

Browse files
committed
mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory
jira KERNEL-249 cve CVE-2025-39883 Rebuild_History Non-Buildable kernel-4.18.0-553.87.1.el8_10 commit-author Miaohe Lin <linmiaohe@huawei.com> commit d613f53 Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-4.18.0-553.87.1.el8_10/d613f53c.failed When I did memory failure tests, below panic occurs: page dumped because: VM_BUG_ON_PAGE(PagePoisoned(page)) kernel BUG at include/linux/page-flags.h:616! Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI CPU: 3 PID: 720 Comm: bash Not tainted 6.10.0-rc1-00195-g148743902568 #40 RIP: 0010:unpoison_memory+0x2f3/0x590 RSP: 0018:ffffa57fc8787d60 EFLAGS: 00000246 RAX: 0000000000000037 RBX: 0000000000000009 RCX: ffff9be25fcdc9c8 RDX: 0000000000000000 RSI: 0000000000000027 RDI: ffff9be25fcdc9c0 RBP: 0000000000300000 R08: ffffffffb4956f88 R09: 0000000000009ffb R10: 0000000000000284 R11: ffffffffb4926fa0 R12: ffffe6b00c000000 R13: ffff9bdb453dfd00 R14: 0000000000000000 R15: fffffffffffffffe FS: 00007f08f04e4740(0000) GS:ffff9be25fcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000564787a30410 CR3: 000000010d4e2000 CR4: 00000000000006f0 Call Trace: <TASK> unpoison_memory+0x2f3/0x590 simple_attr_write_xsigned.constprop.0.isra.0+0xb3/0x110 debugfs_attr_write+0x42/0x60 full_proxy_write+0x5b/0x80 vfs_write+0xd5/0x540 ksys_write+0x64/0xe0 do_syscall_64+0xb9/0x1d0 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f08f0314887 RSP: 002b:00007ffece710078 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000009 RCX: 00007f08f0314887 RDX: 0000000000000009 RSI: 0000564787a30410 RDI: 0000000000000001 RBP: 0000564787a30410 R08: 000000000000fefe R09: 000000007fffffff R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000009 R13: 00007f08f041b780 R14: 00007f08f0417600 R15: 00007f08f0416a00 </TASK> Modules linked in: hwpoison_inject ---[ end trace 0000000000000000 ]--- RIP: 0010:unpoison_memory+0x2f3/0x590 RSP: 0018:ffffa57fc8787d60 EFLAGS: 00000246 RAX: 0000000000000037 RBX: 0000000000000009 RCX: ffff9be25fcdc9c8 RDX: 0000000000000000 RSI: 0000000000000027 RDI: ffff9be25fcdc9c0 RBP: 0000000000300000 R08: ffffffffb4956f88 R09: 0000000000009ffb R10: 0000000000000284 R11: ffffffffb4926fa0 R12: ffffe6b00c000000 R13: ffff9bdb453dfd00 R14: 0000000000000000 R15: fffffffffffffffe FS: 00007f08f04e4740(0000) GS:ffff9be25fcc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000564787a30410 CR3: 000000010d4e2000 CR4: 00000000000006f0 Kernel panic - not syncing: Fatal exception Kernel Offset: 0x31c00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff) ---[ end Kernel panic - not syncing: Fatal exception ]--- The root cause is that unpoison_memory() tries to check the PG_HWPoison flags of an uninitialized page. So VM_BUG_ON_PAGE(PagePoisoned(page)) is triggered. This can be reproduced by below steps: 1.Offline memory block: echo offline > /sys/devices/system/memory/memory12/state 2.Get offlined memory pfn: page-types -b n -rlN 3.Write pfn to unpoison-pfn echo <pfn> > /sys/kernel/debug/hwpoison/unpoison-pfn This scenario can be identified by pfn_to_online_page() returning NULL. And ZONE_DEVICE pages are never expected, so we can simply fail if pfn_to_online_page() == NULL to fix the bug. Link: https://lkml.kernel.org/r/20250828024618.1744895-1-linmiaohe@huawei.com Fixes: f1dd2cd ("mm, memory_hotplug: do not associate hotadded memory to zones until online") Signed-off-by: Miaohe Lin <linmiaohe@huawei.com> Suggested-by: David Hildenbrand <david@redhat.com> Acked-by: David Hildenbrand <david@redhat.com> Cc: Naoya Horiguchi <nao.horiguchi@gmail.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> (cherry picked from commit d613f53) Signed-off-by: Jonathan Maple <jmaple@ciq.com> # Conflicts: # mm/memory-failure.c
1 parent 46e3dae commit e43518a

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory
2+
3+
jira KERNEL-249
4+
cve CVE-2025-39883
5+
Rebuild_History Non-Buildable kernel-4.18.0-553.87.1.el8_10
6+
commit-author Miaohe Lin <linmiaohe@huawei.com>
7+
commit d613f53c83ec47089c4e25859d5e8e0359f6f8da
8+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
9+
Will be included in final tarball splat. Ref for failed cherry-pick at:
10+
ciq/ciq_backports/kernel-4.18.0-553.87.1.el8_10/d613f53c.failed
11+
12+
When I did memory failure tests, below panic occurs:
13+
14+
page dumped because: VM_BUG_ON_PAGE(PagePoisoned(page))
15+
kernel BUG at include/linux/page-flags.h:616!
16+
Oops: invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
17+
CPU: 3 PID: 720 Comm: bash Not tainted 6.10.0-rc1-00195-g148743902568 #40
18+
RIP: 0010:unpoison_memory+0x2f3/0x590
19+
RSP: 0018:ffffa57fc8787d60 EFLAGS: 00000246
20+
RAX: 0000000000000037 RBX: 0000000000000009 RCX: ffff9be25fcdc9c8
21+
RDX: 0000000000000000 RSI: 0000000000000027 RDI: ffff9be25fcdc9c0
22+
RBP: 0000000000300000 R08: ffffffffb4956f88 R09: 0000000000009ffb
23+
R10: 0000000000000284 R11: ffffffffb4926fa0 R12: ffffe6b00c000000
24+
R13: ffff9bdb453dfd00 R14: 0000000000000000 R15: fffffffffffffffe
25+
FS: 00007f08f04e4740(0000) GS:ffff9be25fcc0000(0000) knlGS:0000000000000000
26+
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
27+
CR2: 0000564787a30410 CR3: 000000010d4e2000 CR4: 00000000000006f0
28+
Call Trace:
29+
<TASK>
30+
unpoison_memory+0x2f3/0x590
31+
simple_attr_write_xsigned.constprop.0.isra.0+0xb3/0x110
32+
debugfs_attr_write+0x42/0x60
33+
full_proxy_write+0x5b/0x80
34+
vfs_write+0xd5/0x540
35+
ksys_write+0x64/0xe0
36+
do_syscall_64+0xb9/0x1d0
37+
entry_SYSCALL_64_after_hwframe+0x77/0x7f
38+
RIP: 0033:0x7f08f0314887
39+
RSP: 002b:00007ffece710078 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
40+
RAX: ffffffffffffffda RBX: 0000000000000009 RCX: 00007f08f0314887
41+
RDX: 0000000000000009 RSI: 0000564787a30410 RDI: 0000000000000001
42+
RBP: 0000564787a30410 R08: 000000000000fefe R09: 000000007fffffff
43+
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000009
44+
R13: 00007f08f041b780 R14: 00007f08f0417600 R15: 00007f08f0416a00
45+
</TASK>
46+
Modules linked in: hwpoison_inject
47+
---[ end trace 0000000000000000 ]---
48+
RIP: 0010:unpoison_memory+0x2f3/0x590
49+
RSP: 0018:ffffa57fc8787d60 EFLAGS: 00000246
50+
RAX: 0000000000000037 RBX: 0000000000000009 RCX: ffff9be25fcdc9c8
51+
RDX: 0000000000000000 RSI: 0000000000000027 RDI: ffff9be25fcdc9c0
52+
RBP: 0000000000300000 R08: ffffffffb4956f88 R09: 0000000000009ffb
53+
R10: 0000000000000284 R11: ffffffffb4926fa0 R12: ffffe6b00c000000
54+
R13: ffff9bdb453dfd00 R14: 0000000000000000 R15: fffffffffffffffe
55+
FS: 00007f08f04e4740(0000) GS:ffff9be25fcc0000(0000) knlGS:0000000000000000
56+
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
57+
CR2: 0000564787a30410 CR3: 000000010d4e2000 CR4: 00000000000006f0
58+
Kernel panic - not syncing: Fatal exception
59+
Kernel Offset: 0x31c00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
60+
---[ end Kernel panic - not syncing: Fatal exception ]---
61+
62+
The root cause is that unpoison_memory() tries to check the PG_HWPoison
63+
flags of an uninitialized page. So VM_BUG_ON_PAGE(PagePoisoned(page)) is
64+
triggered. This can be reproduced by below steps:
65+
66+
1.Offline memory block:
67+
68+
echo offline > /sys/devices/system/memory/memory12/state
69+
70+
2.Get offlined memory pfn:
71+
72+
page-types -b n -rlN
73+
74+
3.Write pfn to unpoison-pfn
75+
76+
echo <pfn> > /sys/kernel/debug/hwpoison/unpoison-pfn
77+
78+
This scenario can be identified by pfn_to_online_page() returning NULL.
79+
And ZONE_DEVICE pages are never expected, so we can simply fail if
80+
pfn_to_online_page() == NULL to fix the bug.
81+
82+
Link: https://lkml.kernel.org/r/20250828024618.1744895-1-linmiaohe@huawei.com
83+
Fixes: f1dd2cd13c4b ("mm, memory_hotplug: do not associate hotadded memory to zones until online")
84+
Signed-off-by: Miaohe Lin <linmiaohe@huawei.com>
85+
Suggested-by: David Hildenbrand <david@redhat.com>
86+
Acked-by: David Hildenbrand <david@redhat.com>
87+
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
88+
Cc: <stable@vger.kernel.org>
89+
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
90+
(cherry picked from commit d613f53c83ec47089c4e25859d5e8e0359f6f8da)
91+
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
92+
93+
# Conflicts:
94+
# mm/memory-failure.c
95+
diff --cc mm/memory-failure.c
96+
index 5f584fb174dc,df6ee59527dd..000000000000
97+
--- a/mm/memory-failure.c
98+
+++ b/mm/memory-failure.c
99+
@@@ -1776,75 -2568,98 +1776,98 @@@ int unpoison_memory(unsigned long pfn
100+
static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
101+
DEFAULT_RATELIMIT_BURST);
102+
103+
++<<<<<<< HEAD
104+
+ if (!pfn_valid(pfn))
105+
+ return -ENXIO;
106+
+
107+
+ p = pfn_to_page(pfn);
108+
+ page = compound_head(p);
109+
++=======
110+
+ p = pfn_to_online_page(pfn);
111+
+ if (!p)
112+
+ return -EIO;
113+
+ folio = page_folio(p);
114+
+
115+
+ mutex_lock(&mf_mutex);
116+
+
117+
+ if (hw_memory_failure) {
118+
+ unpoison_pr_info("%#lx: disabled after HW memory failure\n",
119+
+ pfn, &unpoison_rs);
120+
+ ret = -EOPNOTSUPP;
121+
+ goto unlock_mutex;
122+
+ }
123+
+
124+
+ if (is_huge_zero_folio(folio)) {
125+
+ unpoison_pr_info("%#lx: huge zero page is not supported\n",
126+
+ pfn, &unpoison_rs);
127+
+ ret = -EOPNOTSUPP;
128+
+ goto unlock_mutex;
129+
+ }
130+
++>>>>>>> d613f53c83ec (mm/memory-failure: fix VM_BUG_ON_PAGE(PagePoisoned(page)) when unpoison memory)
131+
132+
if (!PageHWPoison(p)) {
133+
- unpoison_pr_info("%#lx: page was already unpoisoned\n",
134+
+ unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n",
135+
pfn, &unpoison_rs);
136+
- goto unlock_mutex;
137+
+ return 0;
138+
}
139+
140+
- if (folio_ref_count(folio) > 1) {
141+
- unpoison_pr_info("%#lx: someone grabs the hwpoison page\n",
142+
+ if (page_count(page) > 1) {
143+
+ unpoison_pr_info("Unpoison: Someone grabs the hwpoison page %#lx\n",
144+
pfn, &unpoison_rs);
145+
- goto unlock_mutex;
146+
+ return 0;
147+
}
148+
149+
- if (folio_test_slab(folio) || folio_test_pgtable(folio) ||
150+
- folio_test_reserved(folio) || folio_test_offline(folio))
151+
- goto unlock_mutex;
152+
-
153+
- if (folio_mapped(folio)) {
154+
- unpoison_pr_info("%#lx: someone maps the hwpoison page\n",
155+
+ if (page_mapped(page)) {
156+
+ unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n",
157+
pfn, &unpoison_rs);
158+
- goto unlock_mutex;
159+
+ return 0;
160+
}
161+
162+
- if (folio_mapping(folio)) {
163+
- unpoison_pr_info("%#lx: the hwpoison page has non-NULL mapping\n",
164+
+ if (page_mapping(page)) {
165+
+ unpoison_pr_info("Unpoison: the hwpoison page has non-NULL mapping %#lx\n",
166+
pfn, &unpoison_rs);
167+
- goto unlock_mutex;
168+
+ return 0;
169+
}
170+
171+
- ghp = get_hwpoison_page(p, MF_UNPOISON);
172+
- if (!ghp) {
173+
- if (folio_test_hugetlb(folio)) {
174+
- huge = true;
175+
- count = folio_free_raw_hwp(folio, false);
176+
- if (count == 0)
177+
- goto unlock_mutex;
178+
- }
179+
- ret = folio_test_clear_hwpoison(folio) ? 0 : -EBUSY;
180+
- } else if (ghp < 0) {
181+
- if (ghp == -EHWPOISON) {
182+
- ret = put_page_back_buddy(p) ? 0 : -EBUSY;
183+
- } else {
184+
- ret = ghp;
185+
- unpoison_pr_info("%#lx: failed to grab page\n",
186+
- pfn, &unpoison_rs);
187+
- }
188+
- } else {
189+
- if (folio_test_hugetlb(folio)) {
190+
- huge = true;
191+
- count = folio_free_raw_hwp(folio, false);
192+
- if (count == 0) {
193+
- folio_put(folio);
194+
- goto unlock_mutex;
195+
- }
196+
- }
197+
+ /*
198+
+ * unpoison_memory() can encounter thp only when the thp is being
199+
+ * worked by memory_failure() and the page lock is not held yet.
200+
+ * In such case, we yield to memory_failure() and make unpoison fail.
201+
+ */
202+
+ if (!PageHuge(page) && PageTransHuge(page)) {
203+
+ unpoison_pr_info("Unpoison: Memory failure is now running on %#lx\n",
204+
+ pfn, &unpoison_rs);
205+
+ return 0;
206+
+ }
207+
208+
- folio_put(folio);
209+
- if (TestClearPageHWPoison(p)) {
210+
- folio_put(folio);
211+
- ret = 0;
212+
- }
213+
+ if (!get_hwpoison_page(p, flags, 0)) {
214+
+ if (TestClearPageHWPoison(p))
215+
+ num_poisoned_pages_dec();
216+
+ unpoison_pr_info("Unpoison: Software-unpoisoned free page %#lx\n",
217+
+ pfn, &unpoison_rs);
218+
+ return 0;
219+
}
220+
221+
-unlock_mutex:
222+
- mutex_unlock(&mf_mutex);
223+
- if (!ret) {
224+
- if (!huge)
225+
- num_poisoned_pages_sub(pfn, 1);
226+
- unpoison_pr_info("%#lx: software-unpoisoned page\n",
227+
- page_to_pfn(p), &unpoison_rs);
228+
+ lock_page(page);
229+
+ /*
230+
+ * This test is racy because PG_hwpoison is set outside of page lock.
231+
+ * That's acceptable because that won't trigger kernel panic. Instead,
232+
+ * the PG_hwpoison page will be caught and isolated on the entrance to
233+
+ * the free buddy page pool.
234+
+ */
235+
+ if (TestClearPageHWPoison(page)) {
236+
+ unpoison_pr_info("Unpoison: Software-unpoisoned page %#lx\n",
237+
+ pfn, &unpoison_rs);
238+
+ num_poisoned_pages_dec();
239+
+ freeit = 1;
240+
}
241+
- return ret;
242+
+ unlock_page(page);
243+
+
244+
+ put_page(page);
245+
+ if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1))
246+
+ put_page(page);
247+
+
248+
+ return 0;
249+
}
250+
EXPORT_SYMBOL(unpoison_memory);
251+
252+
* Unmerged path mm/memory-failure.c

0 commit comments

Comments
 (0)