[PATCH 4/4] einj_mem_uc: add copy_mc_to_kernel() case
From: Ruidong Tian
Date: Tue Jun 16 2026 - 21:54:31 EST
From: Ruidong Tian <ruidong.trd@xxxxxxxxxxxxxxxxx>
add a coredump case to test copy_mc_to_kernel, call stack as follow:
[do_sea ] Fault PC (faulting insn): <__memcpy_mc> ffffb45742bee24c
[do_sea ] Call stack:
[do_sea ] <dump_user_range>
[do_sea ] <elf_core_dump>
[do_sea ] <coredump_write>
[do_sea ] <do_coredump>
[do_sea ] <vfs_coredump>
[do_sea ] <get_signal>
[extable ] Fault type: unknown(5)
[extable ] Recovery addr (fixup): <__memcpy_mc> ffffb45742bee328
Signed-off-by: Ruidong Tian <ruidong.trd@xxxxxxxxxxxxxxxxx>
---
einj_mem_uc_mm.c | 51 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 48 insertions(+), 3 deletions(-)
diff --git a/einj_mem_uc_mm.c b/einj_mem_uc_mm.c
index 3e23593..b495c22 100644
--- a/einj_mem_uc_mm.c
+++ b/einj_mem_uc_mm.c
@@ -2,12 +2,14 @@
/*
* einj_mem_uc_mm.c - tests that exercise the kernel's MC-safe page
- * copy primitives: copy_mc_user_highpage (COW / khugepaged / ksm) and
- * copy_mc_highpage (page migration).
+ * copy primitives: copy_mc_user_highpage (COW / khugepaged / ksm),
+ * copy_mc_highpage (page migration) and copy_mc_to_kernel (the ELF core
+ * dumper's dump_page_copy()).
*
* Each test allocates a page in a way that lets the kernel reach one of
* those primitives, and its trigger drives the operation synchronously
- * whenever possible (MADV_COLLAPSE, move_pages, mbind MOVE, MADV_PAGEOUT).
+ * whenever possible (MADV_COLLAPSE, move_pages, mbind MOVE, MADV_PAGEOUT,
+ * or a core dump).
*/
#define _GNU_SOURCE 1
@@ -26,6 +28,8 @@
#include <sys/syscall.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/prctl.h>
#include <sys/uio.h>
@@ -602,6 +606,45 @@ static int trigger_cow_anon_pinned(char *addr)
}
+/* ---------- core dump (copy_mc_to_kernel) ---------- */
+
+/*
+ * trigger_coredump - exercise copy_mc_to_kernel() via the ELF core dumper.
+ */
+static int trigger_coredump(char *addr)
+{
+ pid_t pid;
+
+ PRINT_TRIGGERING;
+ pid = fork();
+ if (pid == 0) {
+ struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
+
+ child_process = 1;
+ /* Allow a core dump regardless of inherited limits. */
+ setrlimit(RLIMIT_CORE, &rl);
+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ /*
+ * Do NOT touch *addr ourselves: the poisoned page must be
+ * consumed by the kernel core dumper (dump_user_range ->
+ * dump_page_copy -> copy_mc_to_kernel), not by a user read.
+ */
+ (void)addr;
+ abort(); /* SIGABRT -> core dump */
+ _exit(0); /* not reached */
+ }
+ if (pid > 0) {
+ int st;
+
+ waitpid(pid, &st, 0);
+ if (WIFSIGNALED(st))
+ printf("child killed by signal %d%s\n", WTERMSIG(st),
+ WCOREDUMP(st) ? " (core dumped)" : "");
+ }
+ return 0;
+}
+
+
/* ---------- test table ---------- */
#define MM(name, help, alloc_fn, trig_fn, fl) \
@@ -631,6 +674,8 @@ struct test mm_tests[] = {
MM("migrate_hugetlb", "move_pages(2) hugetlb file cross-node -> hugetlbfs_migrate_folio",
mm_hugetlb_file_alloc, trigger_move_pages_hugetlb, F_MCE|F_CMCI|F_SIGBUS|F_FATAL),
+ MM("coredump", "Core dump of a poisoned page -> dump_page_copy -> copy_mc_to_kernel",
+ mm_anon_private_alloc, trigger_coredump, F_MCE|F_CMCI|F_FATAL),
};
--
2.39.3