* [LTP] [PATCH v3] coredump01: New core_pattern specifiers test
@ 2026-08-24 8:58 Andrea Cervesato
2026-08-24 9:49 ` [LTP] " linuxtestproject.agent
2026-08-31 14:52 ` [LTP] [PATCH v3] " Cyril Hrubis
0 siblings, 2 replies; 13+ messages in thread
From: Andrea Cervesato @ 2026-08-24 8:58 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Add a simple coredump01 test that simulate a coredump and verify that it
actually works. This is a small coverage that is missing inside LTP
testing suite.
---
Changes in v3:
- check for CONFIG_COREDUMP=y
- Link to v2: https://lore.kernel.org/20260824-coredump-v2-1-42428acf5216@suse.com
Changes in v2:
- fix CI agent spotted errors
- Link to v1: https://lore.kernel.org/20260820-coredump-v1-1-7ce51603cefb@suse.com
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 +
testcases/kernel/coredump/coredump01.c | 225 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 66 ++++++++
6 files changed, 302 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..96a7252da
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "tst_test.h"
+#include "tst_kconfig.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_dir[PATH_MAX];
+static char cwd[PATH_MAX];
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+}
+
+/* PID 2 is kthreadd only if we can see the initial PID namespace */
+static int have_init_pid_ns(void)
+{
+ char comm[16] = {0};
+ int fd, len;
+
+ fd = open("/proc/2/comm", O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ len = SAFE_READ(0, fd, comm, sizeof(comm) - 1);
+ SAFE_CLOSE(fd);
+
+ return len > 0 && !strncmp(comm, "kthreadd\n", 9);
+}
+
+/*
+ * The kernel resolves @path the way /proc/2/root (kthreadd lives in the
+ * initial namespaces) resolves it.
+ */
+static int same_in_init_mnt_ns(const char *path)
+{
+ char init_path[PATH_MAX + 32];
+ struct stat our_st, init_st;
+
+ SAFE_STAT(path, &our_st);
+
+ snprintf(init_path, sizeof(init_path), "/proc/2/root%s", path);
+
+ if (stat(init_path, &init_st))
+ return 0;
+
+ return init_st.st_dev == our_st.st_dev && init_st.st_ino == our_st.st_ino;
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX], helper[PATH_MAX + 32];
+ struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
+ int pid_seen, sig_seen, elf;
+ long long bytes;
+ pid_t pid;
+
+ tst_kconfig_read(&kconfig, 1);
+ if (kconfig.choice == 'y') {
+ tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
+ return;
+ }
+
+ snprintf(helper, sizeof(helper), "%s/%s", helper_dir, HELPER);
+
+ /*
+ * The kernel always execs the pipe helper in the initial mount
+ * namespace (core(5)), no matter where the crashing process lives.
+ * Skip unless both the helper and the result directory are the very
+ * same objects there, otherwise the kernel would not find them and
+ * the test would fail spuriously, e.g. inside a container.
+ */
+ if (!have_init_pid_ns() || !same_in_init_mnt_ns(helper) ||
+ !same_in_init_mnt_ns(cwd)) {
+ tst_res(TCONF, "Pipe helper or result dir not visible in the initial mount namespace");
+ return;
+ }
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s/%s %%e %%p %%s %s/res.%%p", helper_dir, HELPER, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+ ssize_t len;
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+
+ SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
+
+ SAFE_GETCWD(cwd, sizeof(cwd));
+
+ len = SAFE_READLINK("/proc/self/exe", helper_dir, sizeof(helper_dir) - 1);
+ helper_dir[len] = '\0';
+ *strrchr(helper_dir, '/') = '\0';
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char* []) {
+ "CONFIG_COREDUMP=y",
+ NULL,
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..41091b428
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ char buf[4096], tmp[PATH_MAX], magic[4];
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf = 0;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * A core dump embeds the ELF images it has mapped, so the magic is
+ * only meaningful at the very beginning of the stream. Collect it
+ * across reads, since a pipe read can return less than 4 bytes.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && bytes + i < 4; i++)
+ magic[bytes + i] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
+ elf = 1;
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
---
base-commit: e62b1a4731f9c458d65c2659d2f8bb58b93e6d6d
change-id: 20260820-coredump-22fc731bde08
Best regards,
--
Andrea Cervesato <andrea.cervesato@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-08-24 8:58 [LTP] [PATCH v3] coredump01: New core_pattern specifiers test Andrea Cervesato
@ 2026-08-24 9:49 ` linuxtestproject.agent
2026-08-31 14:52 ` [LTP] [PATCH v3] " Cyril Hrubis
1 sibling, 0 replies; 13+ messages in thread
From: linuxtestproject.agent @ 2026-08-24 9:49 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Mon, 24 Aug 2026, Andrea Cervesato wrote:
> coredump01: New core_pattern specifiers test
Verdict - Reviewed
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [LTP] [PATCH v3] coredump01: New core_pattern specifiers test
2026-08-24 8:58 [LTP] [PATCH v3] coredump01: New core_pattern specifiers test Andrea Cervesato
2026-08-24 9:49 ` [LTP] " linuxtestproject.agent
@ 2026-08-31 14:52 ` Cyril Hrubis
1 sibling, 0 replies; 13+ messages in thread
From: Cyril Hrubis @ 2026-08-31 14:52 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: Linux Test Project
Hi!
> LTP has no coverage for the core_pattern specifiers expansion, neither
> for the pipe flavor of core_pattern, where the kernel spawns a user
> space helper and writes the core dump into its standard input.
>
> The new test verifies that %e, %p and %s are expanded both in the core
> file name and in the arguments of a piped helper, checking also that
> the helper really receives an ELF core dump.
>
> Root is required to rewrite the system wide core_pattern, which is
> restored by the test library on all exit paths.
>
> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
> ---
> Add a simple coredump01 test that simulate a coredump and verify that it
> actually works. This is a small coverage that is missing inside LTP
> testing suite.
> ---
> Changes in v3:
> - check for CONFIG_COREDUMP=y
> - Link to v2: https://lore.kernel.org/20260824-coredump-v2-1-42428acf5216@suse.com
>
> Changes in v2:
> - fix CI agent spotted errors
> - Link to v1: https://lore.kernel.org/20260820-coredump-v1-1-7ce51603cefb@suse.com
> ---
> runtest/kernel_misc | 1 +
> testcases/kernel/Makefile | 1 +
> testcases/kernel/coredump/.gitignore | 2 +
> testcases/kernel/coredump/Makefile | 7 +
> testcases/kernel/coredump/coredump01.c | 225 ++++++++++++++++++++++++++
> testcases/kernel/coredump/coredump01_helper.c | 66 ++++++++
> 6 files changed, 302 insertions(+)
>
> diff --git a/runtest/kernel_misc b/runtest/kernel_misc
> index cc3562cb7..ecf9ee2a2 100644
> --- a/runtest/kernel_misc
> +++ b/runtest/kernel_misc
> @@ -17,3 +17,4 @@ zram02 zram02.sh
> zram03 zram03
> umip_basic_test umip_basic_test
> aslr01 aslr01
> +coredump01 coredump01
> diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
> index ac816e4e8..6b303c14b 100644
> --- a/testcases/kernel/Makefile
> +++ b/testcases/kernel/Makefile
> @@ -19,6 +19,7 @@ SUBDIRS += lib
> SUBDIRS += connectors \
> containers \
> controllers \
> + coredump \
> crypto \
> device-drivers \
> firmware \
> diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
> new file mode 100644
> index 000000000..cd0b51700
> --- /dev/null
> +++ b/testcases/kernel/coredump/.gitignore
> @@ -0,0 +1,2 @@
> +/coredump01
> +/coredump01_helper
> diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
> new file mode 100644
> index 000000000..951a3e976
> --- /dev/null
> +++ b/testcases/kernel/coredump/Makefile
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2026 Linux Test Project
> +
> +top_srcdir ?= ../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
> new file mode 100644
> index 000000000..96a7252da
> --- /dev/null
> +++ b/testcases/kernel/coredump/coredump01.c
> @@ -0,0 +1,225 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 Linux Test Project
> + */
> +
> +/*\
> + * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
> + * (executable name), %p (PID) and %s (signal number) when it creates a
> + * core dump.
> + *
> + * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
> + *
> + * - a plain file name, where the specifiers become part of the core file
> + * name
> + * - a pipe to a user space helper, where the specifiers are expanded in
> + * the helper arguments and the core dump is written to the helper
> + * standard input
> + *
> + * The test needs root because it rewrites the system wide core_pattern.
> + * The original value is saved and restored by the test library on all
> + * exit paths.
> + *
> + * [Algorithm]
> + *
> + * - Point core_pattern into the test temporary directory
> + * - Fork a child which aborts itself to produce a core dump
> + * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
> + * - For the pipe pattern check the arguments the helper was called with
> + * and that it received an ELF core dump on its standard input
> + */
> +
> +#include <sys/wait.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +#include "tst_test.h"
> +#include "tst_kconfig.h"
> +#include "lapi/prctl.h"
> +
> +#define PATTERN_MAX 128
> +#define HELPER "coredump01_helper"
> +#define HELPER_TIMEOUT 10
> +
> +static char helper_dir[PATH_MAX];
> +static char cwd[PATH_MAX];
> +
> +static void set_pattern(const char *fmt, ...)
> +{
> + char pattern[PATTERN_MAX];
> + va_list va;
> + int len;
> +
> + va_start(va, fmt);
> + len = vsnprintf(pattern, sizeof(pattern), fmt, va);
> + va_end(va);
> +
> + if (len >= PATTERN_MAX)
> + tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
> +
> + SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
> +
> + tst_res(TINFO, "core_pattern is '%s'", pattern);
Shouldn't we read the pattern back and make sure it's the same?
> +}
> +
> +static pid_t crash_child(void)
> +{
> + int status;
> + pid_t pid;
> +
> + pid = SAFE_FORK();
> + if (!pid)
> + abort();
> +
> + SAFE_WAITPID(pid, &status, 0);
> +
> + if (!WIFSIGNALED(status) || !WCOREDUMP(status))
> + tst_brk(TFAIL, "Child did not dump core");
> +
> + return pid;
> +}
> +
> +static void verify_file_pattern(void)
> +{
> + char dump[PATH_MAX + 32];
> + pid_t pid;
> +
> + tst_res(TINFO, "Testing file core_pattern");
> +
> + set_pattern("%s/core.%%e.%%p.%%s", cwd);
> +
> + pid = crash_child();
> +
> + snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
> +
> + TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
> + pid, SIGABRT);
> +}
> +
> +/* PID 2 is kthreadd only if we can see the initial PID namespace */
> +static int have_init_pid_ns(void)
> +{
> + char comm[16] = {0};
> + int fd, len;
> +
> + fd = open("/proc/2/comm", O_RDONLY);
> + if (fd < 0)
> + return 0;
> +
> + len = SAFE_READ(0, fd, comm, sizeof(comm) - 1);
> + SAFE_CLOSE(fd);
> +
> + return len > 0 && !strncmp(comm, "kthreadd\n", 9);
> +}
> +
> +/*
> + * The kernel resolves @path the way /proc/2/root (kthreadd lives in the
> + * initial namespaces) resolves it.
> + */
> +static int same_in_init_mnt_ns(const char *path)
> +{
> + char init_path[PATH_MAX + 32];
> + struct stat our_st, init_st;
> +
> + SAFE_STAT(path, &our_st);
> +
> + snprintf(init_path, sizeof(init_path), "/proc/2/root%s", path);
> +
> + if (stat(init_path, &init_st))
> + return 0;
> +
> + return init_st.st_dev == our_st.st_dev && init_st.st_ino == our_st.st_ino;
> +}
> +
> +static void verify_pipe_pattern(void)
> +{
> + char res[PATH_MAX + 32], exe[PATH_MAX], helper[PATH_MAX + 32];
> + struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
> + int pid_seen, sig_seen, elf;
> + long long bytes;
> + pid_t pid;
> +
> + tst_kconfig_read(&kconfig, 1);
> + if (kconfig.choice == 'y') {
> + tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
> + return;
> + }
This should be read once in the test setup so that we do not parse
.config on each -i iteration.
> + snprintf(helper, sizeof(helper), "%s/%s", helper_dir, HELPER);
> +
> + /*
> + * The kernel always execs the pipe helper in the initial mount
> + * namespace (core(5)), no matter where the crashing process lives.
> + * Skip unless both the helper and the result directory are the very
> + * same objects there, otherwise the kernel would not find them and
> + * the test would fail spuriously, e.g. inside a container.
> + */
> + if (!have_init_pid_ns() || !same_in_init_mnt_ns(helper) ||
> + !same_in_init_mnt_ns(cwd)) {
> + tst_res(TCONF, "Pipe helper or result dir not visible in the initial mount namespace");
> + return;
> + }
I'm not sure if these extensive tests aren't out of scope for the test.
Is it common for tests to be executed in a mount namespace?
> + tst_res(TINFO, "Testing pipe core_pattern");
> +
> + set_pattern("|%s/%s %%e %%p %%s %s/res.%%p", helper_dir, HELPER, cwd);
> +
> + pid = crash_child();
> +
> + snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
> +
> + /* the kernel spawns the helper asynchronously */
> + if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
> + tst_res(TFAIL, "%s did not report any core dump", HELPER);
> + return;
> + }
> +
> + SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d",
> + exe, &pid_seen, &sig_seen, &bytes, &elf);
> +
> + TST_EXP_EQ_STR(exe, "coredump01");
> + TST_EXP_EQ_LI(pid_seen, pid);
> + TST_EXP_EQ_LI(sig_seen, SIGABRT);
> + TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
> +}
> +
> +static void run(unsigned int n)
> +{
> + if (n)
> + verify_pipe_pattern();
> + else
> + verify_file_pattern();
> +}
> +
> +static void setup(void)
> +{
> + struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
> + ssize_t len;
> +
> + SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
> +
> + SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
> +
> + SAFE_GETCWD(cwd, sizeof(cwd));
> +
> + len = SAFE_READLINK("/proc/self/exe", helper_dir, sizeof(helper_dir) - 1);
> + helper_dir[len] = '\0';
> + *strrchr(helper_dir, '/') = '\0';
This looks like a hack. We do have tst_get_path() that could be used to
resolve the helper absolute path instead.
> +}
> +
> +static struct tst_test test = {
> + .test = run,
> + .tcnt = 2,
> + .setup = setup,
> + .needs_root = 1,
> + .needs_tmpdir = 1,
> + .forks_child = 1,
> + .needs_kconfigs = (const char* []) {
> + "CONFIG_COREDUMP=y",
> + NULL,
> + },
> + .save_restore = (const struct tst_path_val[]) {
> + {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
> + {}
> + },
> +};
> diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
> new file mode 100644
> index 000000000..41091b428
> --- /dev/null
> +++ b/testcases/kernel/coredump/coredump01_helper.c
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 Linux Test Project
> + */
> +
> +/*
> + * Core dump collector for the piped core_pattern tested by coredump01.
> + *
> + * Avoiding the LTP API here is correct, since the kernel spawns the helper
> + * through ``call_usermodehelper()`` without the LTP IPC environment.
> + *
> + * The helper is called as:
> + *
> + * coredump01_helper <exe> <pid> <signal> <result file>
> + *
> + * and stores what it received in the result file, which is published with
> + * :manpage:`rename()` so that the polling test never reads a partial line.
> + */
> +
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +int main(int argc, char *argv[])
> +{
> + char buf[4096], tmp[PATH_MAX], magic[4];
> + long long bytes = 0;
> + ssize_t rval, i;
> + int fd, elf = 0;
> +
> + if (argc < 5)
> + return 1;
> +
> + /*
> + * A core dump embeds the ELF images it has mapped, so the magic is
> + * only meaningful at the very beginning of the stream. Collect it
> + * across reads, since a pipe read can return less than 4 bytes.
> + */
> + while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
> + for (i = 0; i < rval && bytes + i < 4; i++)
> + magic[bytes + i] = buf[i];
> +
> + bytes += rval;
> + }
> +
> + if (rval < 0)
> + return 1;
> +
> + if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
> + elf = 1;
> +
> + snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
> +
> + fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
> + if (fd < 0)
> + return 1;
> +
> + dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
> + argv[1], argv[2], argv[3], bytes, elf);
> +
> + close(fd);
> +
> + return rename(tmp, argv[4]) ? 1 : 0;
> +}
>
> ---
> base-commit: e62b1a4731f9c458d65c2659d2f8bb58b93e6d6d
> change-id: 20260820-coredump-22fc731bde08
>
> Best regards,
> --
> Andrea Cervesato <andrea.cervesato@suse.com>
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
--
Cyril Hrubis
chrubis@suse.cz
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
* [LTP] [PATCH v8 1/2] coredump01: New core_pattern specifiers test
@ 2026-09-08 6:26 Andrea Cervesato
2026-09-08 6:48 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 13+ messages in thread
From: Andrea Cervesato @ 2026-09-08 6:26 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Reviewed-by: Li Wang <li.wang@linux.dev>
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 ++
testcases/kernel/coredump/coredump01.c | 158 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 73 ++++++++++++
testcases/kernel/coredump/coredump_common.h | 69 +++++++++++
7 files changed, 311 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..ad690e95c
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include "coredump_common.h"
+#include "tst_kconfig.h"
+
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_path[PATH_MAX];
+static int static_usermodehelper;
+
+/*
+ * e_ident[] and e_type live at the same file offset in ELF32 and ELF64,
+ * so we can validate both without picking a class.
+ */
+static void verify_elf_core(const char *path)
+{
+ unsigned char hdr[EI_NIDENT + sizeof(Elf32_Half)];
+ Elf32_Half e_type;
+ int fd;
+
+ fd = SAFE_OPEN(path, O_RDONLY);
+ SAFE_READ(1, fd, hdr, sizeof(hdr));
+ SAFE_CLOSE(fd);
+
+ memcpy(&e_type, hdr + EI_NIDENT, sizeof(e_type));
+
+ TST_EXP_EXPR(!memcmp(hdr, ELFMAG, SELFMAG), "%s starts with ELF magic", path);
+ TST_EXP_EQ_LI(e_type, ET_CORE);
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+ if (!TST_PASS)
+ return;
+
+ verify_elf_core(dump);
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX];
+ int pid_seen, sig_seen, elf, et_core;
+ long long bytes;
+ pid_t pid;
+
+ if (static_usermodehelper) {
+ tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
+ return;
+ }
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s %%e %%p %%s %s/res.%%p", helper_path, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d et_core=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf, &et_core);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+ TST_EXP_EQ_LI(et_core, 1);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ char path[PATH_MAX];
+ struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
+
+ coredump_setup();
+
+ tst_kconfig_read(&kconfig, 1);
+ static_usermodehelper = (kconfig.choice == 'y');
+
+ if (tst_get_path(HELPER, path, sizeof(path)))
+ tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
+
+ if (!realpath(path, helper_path))
+ tst_brk(TBROK | TERRNO, "realpath(%s) failed", path);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char* []) {
+ "CONFIG_COREDUMP=y",
+ NULL,
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..b454de476
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <elf.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ unsigned char buf[4096], hdr[EI_NIDENT + sizeof(Elf32_Half)];
+ char tmp[PATH_MAX];
+ unsigned int hdr_len = 0;
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf = 0, et_core = 0;
+ Elf32_Half e_type;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * The ELF header is only meaningful at the very beginning of the
+ * stream. Collect enough bytes to read e_ident and e_type.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && hdr_len < sizeof(hdr); i++)
+ hdr[hdr_len++] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (hdr_len >= sizeof(hdr)) {
+ if (!memcmp(hdr, ELFMAG, SELFMAG))
+ elf = 1;
+ memcpy(&e_type, hdr + EI_NIDENT, sizeof(e_type));
+ et_core = (e_type == ET_CORE);
+ }
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d et_core=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf, et_core);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
diff --git a/testcases/kernel/coredump/coredump_common.h b/testcases/kernel/coredump/coredump_common.h
new file mode 100644
index 000000000..7c04a659c
--- /dev/null
+++ b/testcases/kernel/coredump/coredump_common.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+#ifndef COREDUMP_COMMON_H
+#define COREDUMP_COMMON_H
+
+#include <elf.h>
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+
+static char cwd[PATH_MAX];
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ char readback[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+ SAFE_FILE_LINES_SCANF(PATH_KERN_CORE_PATTERN, "%127[^\n]", readback);
+
+ if (strcmp(pattern, readback))
+ tst_brk(TBROK, "core_pattern readback mismatch: wrote '%s', read '%s'",
+ pattern, readback);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+static void coredump_setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+ SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ SAFE_GETCWD(cwd, sizeof(cwd));
+}
+
+#endif /* COREDUMP_COMMON_H */
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* [LTP] [PATCH v7 1/2] coredump01: New core_pattern specifiers test
@ 2026-09-04 11:03 Andrea Cervesato
2026-09-04 12:20 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 13+ messages in thread
From: Andrea Cervesato @ 2026-09-04 11:03 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 ++
testcases/kernel/coredump/coredump01.c | 158 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 73 ++++++++++++
testcases/kernel/coredump/coredump_common.h | 69 +++++++++++
7 files changed, 311 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..ad690e95c
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include "coredump_common.h"
+#include "tst_kconfig.h"
+
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_path[PATH_MAX];
+static int static_usermodehelper;
+
+/*
+ * e_ident[] and e_type live at the same file offset in ELF32 and ELF64,
+ * so we can validate both without picking a class.
+ */
+static void verify_elf_core(const char *path)
+{
+ unsigned char hdr[EI_NIDENT + sizeof(Elf32_Half)];
+ Elf32_Half e_type;
+ int fd;
+
+ fd = SAFE_OPEN(path, O_RDONLY);
+ SAFE_READ(1, fd, hdr, sizeof(hdr));
+ SAFE_CLOSE(fd);
+
+ memcpy(&e_type, hdr + EI_NIDENT, sizeof(e_type));
+
+ TST_EXP_EXPR(!memcmp(hdr, ELFMAG, SELFMAG), "%s starts with ELF magic", path);
+ TST_EXP_EQ_LI(e_type, ET_CORE);
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+ if (!TST_PASS)
+ return;
+
+ verify_elf_core(dump);
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX];
+ int pid_seen, sig_seen, elf, et_core;
+ long long bytes;
+ pid_t pid;
+
+ if (static_usermodehelper) {
+ tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
+ return;
+ }
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s %%e %%p %%s %s/res.%%p", helper_path, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d et_core=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf, &et_core);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+ TST_EXP_EQ_LI(et_core, 1);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ char path[PATH_MAX];
+ struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
+
+ coredump_setup();
+
+ tst_kconfig_read(&kconfig, 1);
+ static_usermodehelper = (kconfig.choice == 'y');
+
+ if (tst_get_path(HELPER, path, sizeof(path)))
+ tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
+
+ if (!realpath(path, helper_path))
+ tst_brk(TBROK | TERRNO, "realpath(%s) failed", path);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char* []) {
+ "CONFIG_COREDUMP=y",
+ NULL,
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..b454de476
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <elf.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ unsigned char buf[4096], hdr[EI_NIDENT + sizeof(Elf32_Half)];
+ char tmp[PATH_MAX];
+ unsigned int hdr_len = 0;
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf = 0, et_core = 0;
+ Elf32_Half e_type;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * The ELF header is only meaningful at the very beginning of the
+ * stream. Collect enough bytes to read e_ident and e_type.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && hdr_len < sizeof(hdr); i++)
+ hdr[hdr_len++] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (hdr_len >= sizeof(hdr)) {
+ if (!memcmp(hdr, ELFMAG, SELFMAG))
+ elf = 1;
+ memcpy(&e_type, hdr + EI_NIDENT, sizeof(e_type));
+ et_core = (e_type == ET_CORE);
+ }
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d et_core=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf, et_core);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
diff --git a/testcases/kernel/coredump/coredump_common.h b/testcases/kernel/coredump/coredump_common.h
new file mode 100644
index 000000000..7c04a659c
--- /dev/null
+++ b/testcases/kernel/coredump/coredump_common.h
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+#ifndef COREDUMP_COMMON_H
+#define COREDUMP_COMMON_H
+
+#include <elf.h>
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+
+static char cwd[PATH_MAX];
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ char readback[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+ SAFE_FILE_LINES_SCANF(PATH_KERN_CORE_PATTERN, "%127[^\n]", readback);
+
+ if (strcmp(pattern, readback))
+ tst_brk(TBROK, "core_pattern readback mismatch: wrote '%s', read '%s'",
+ pattern, readback);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+static void coredump_setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+ SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ SAFE_GETCWD(cwd, sizeof(cwd));
+}
+
+#endif /* COREDUMP_COMMON_H */
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-09-04 11:03 [LTP] [PATCH v7 1/2] " Andrea Cervesato
@ 2026-09-04 12:20 ` linuxtestproject.agent
2026-09-04 12:26 ` Andrea Cervesato via ltp
2026-09-08 6:27 ` Andrea Cervesato via ltp
0 siblings, 2 replies; 13+ messages in thread
From: linuxtestproject.agent @ 2026-09-04 12:20 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Fri, 4 Sep 2026, Andrea Cervesato wrote:
> coredump01: New core_pattern specifiers test
--- [PATCH 1/2] ---
> static void run(unsigned int n)
> {
> if (n)
> verify_pipe_pattern();
> else
> verify_file_pattern();
> }
>
> static struct tst_test test = {
> .test = run,
> .tcnt = 2,
This manually dispatches separate functions for the two test cases. Use a
single struct tcase array and a generic .test callback, with
.tcnt = ARRAY_SIZE(tcases), as required for multi-case tests.
--- [PATCH 2/2] ---
> } else if (ph[i].p_type == PT_LOAD) {
> have_load = 1;
> }
This only proves that a PT_LOAD header exists, not that its data is present.
A short dump_emit() after the headers and notes leaves WCOREDUMP set, so a
truncated core can pass every check here. Validate p_offset + p_filesz against
core_len with overflow-safe arithmetic for every file-backed segment.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-09-04 12:20 ` [LTP] " linuxtestproject.agent
@ 2026-09-04 12:26 ` Andrea Cervesato via ltp
2026-09-08 6:27 ` Andrea Cervesato via ltp
1 sibling, 0 replies; 13+ messages in thread
From: Andrea Cervesato via ltp @ 2026-09-04 12:26 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: ltp
>
> This manually dispatches separate functions for the two test cases. Use a
> single struct tcase array and a generic .test callback, with
> .tcnt = ARRAY_SIZE(tcases), as required for multi-case tests.
no need for this.
>
> --- [PATCH 2/2] ---
>
> > } else if (ph[i].p_type == PT_LOAD) {
> > have_load = 1;
> > }
>
> This only proves that a PT_LOAD header exists, not that its data is present.
> A short dump_emit() after the headers and notes leaves WCOREDUMP set, so a
> truncated core can pass every check here. Validate p_offset + p_filesz against
> core_len with overflow-safe arithmetic for every file-backed segment.
>
this is valid
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-09-04 12:20 ` [LTP] " linuxtestproject.agent
2026-09-04 12:26 ` Andrea Cervesato via ltp
@ 2026-09-08 6:27 ` Andrea Cervesato via ltp
1 sibling, 0 replies; 13+ messages in thread
From: Andrea Cervesato via ltp @ 2026-09-08 6:27 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: ltp
> --- [PATCH 2/2] ---
>
> > } else if (ph[i].p_type == PT_LOAD) {
> > have_load = 1;
> > }
>
> This only proves that a PT_LOAD header exists, not that its data is present.
> A short dump_emit() after the headers and notes leaves WCOREDUMP set, so a
> truncated core can pass every check here. Validate p_offset + p_filesz against
> core_len with overflow-safe arithmetic for every file-backed segment.
Sent a v8 fixing this
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
* [LTP] [PATCH v6 1/2] coredump01: New core_pattern specifiers test
@ 2026-09-04 7:15 Andrea Cervesato
2026-09-04 7:52 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 13+ messages in thread
From: Andrea Cervesato @ 2026-09-04 7:15 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 +
testcases/kernel/coredump/coredump01.c | 212 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 73 +++++++++
6 files changed, 296 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..e2e3c8e47
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include <elf.h>
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "tst_kconfig.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_path[PATH_MAX];
+static char cwd[PATH_MAX];
+static int static_usermodehelper;
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ char readback[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+
+ SAFE_FILE_LINES_SCANF(PATH_KERN_CORE_PATTERN, "%127[^\n]", readback);
+
+ if (strcmp(pattern, readback))
+ tst_brk(TBROK, "core_pattern readback mismatch: wrote '%s', read '%s'",
+ pattern, readback);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+/*
+ * e_ident[] and e_type live at the same file offset in ELF32 and ELF64,
+ * so we can validate both without picking a class.
+ */
+static void verify_elf_core(const char *path)
+{
+ unsigned char hdr[EI_NIDENT + sizeof(Elf32_Half)];
+ Elf32_Half e_type;
+ int fd;
+
+ fd = SAFE_OPEN(path, O_RDONLY);
+ SAFE_READ(1, fd, hdr, sizeof(hdr));
+ SAFE_CLOSE(fd);
+
+ memcpy(&e_type, hdr + EI_NIDENT, sizeof(e_type));
+
+ TST_EXP_EXPR(!memcmp(hdr, ELFMAG, SELFMAG), "%s starts with ELF magic", path);
+ TST_EXP_EQ_LI(e_type, ET_CORE);
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+ if (!TST_PASS)
+ return;
+
+ verify_elf_core(dump);
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX];
+ int pid_seen, sig_seen, elf, et_core;
+ long long bytes;
+ pid_t pid;
+
+ if (static_usermodehelper) {
+ tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
+ return;
+ }
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s %%e %%p %%s %s/res.%%p", helper_path, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d et_core=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf, &et_core);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+ TST_EXP_EQ_LI(et_core, 1);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+ struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
+
+ tst_kconfig_read(&kconfig, 1);
+ static_usermodehelper = (kconfig.choice == 'y');
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+
+ SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
+
+ SAFE_GETCWD(cwd, sizeof(cwd));
+
+ char path[PATH_MAX];
+
+ if (tst_get_path(HELPER, path, sizeof(path)))
+ tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
+
+ if (!realpath(path, helper_path))
+ tst_brk(TBROK | TERRNO, "realpath(%s) failed", path);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char* []) {
+ "CONFIG_COREDUMP=y",
+ NULL,
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..b454de476
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <elf.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ unsigned char buf[4096], hdr[EI_NIDENT + sizeof(Elf32_Half)];
+ char tmp[PATH_MAX];
+ unsigned int hdr_len = 0;
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf = 0, et_core = 0;
+ Elf32_Half e_type;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * The ELF header is only meaningful at the very beginning of the
+ * stream. Collect enough bytes to read e_ident and e_type.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && hdr_len < sizeof(hdr); i++)
+ hdr[hdr_len++] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (hdr_len >= sizeof(hdr)) {
+ if (!memcmp(hdr, ELFMAG, SELFMAG))
+ elf = 1;
+ memcpy(&e_type, hdr + EI_NIDENT, sizeof(e_type));
+ et_core = (e_type == ET_CORE);
+ }
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d et_core=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf, et_core);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
--
2.51.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-09-04 7:15 [LTP] [PATCH v6 1/2] " Andrea Cervesato
@ 2026-09-04 7:52 ` linuxtestproject.agent
0 siblings, 0 replies; 13+ messages in thread
From: linuxtestproject.agent @ 2026-09-04 7:52 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Fri, Sep 4, 2026 at 09:15, Andrea Cervesato wrote:
> coredump01: New core_pattern specifiers test
--- [PATCH 2/2] ---
> Verify that a kernel-generated core dump contains a valid ELF header,
> expected program headers (PT_NOTE and PT_LOAD), and valid process
> metadata notes (NT_PRPSINFO and NT_PRSTATUS).
The commit message only restates what the test verifies. Please explain why
this coverage is needed or what problem it addresses.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
* [LTP] [PATCH v5] coredump01: New core_pattern specifiers test
@ 2026-09-03 7:21 Andrea Cervesato
2026-09-03 12:01 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 13+ messages in thread
From: Andrea Cervesato @ 2026-09-03 7:21 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Add a simple coredump01 test that simulate a coredump and verify that it
actually works. This is a small coverage that is missing inside LTP
testing suite.
---
Changes in v5:
- resolve path from root for helper
- Link to v4: https://lore.kernel.org/20260902-coredump-v4-1-3f511ea1c96a@suse.com
Changes in v4:
- read back core_pattern after writing and abort with TBROK on mismatch
- read CONFIG_STATIC_USERMODEHELPER once in setup() and cache the result
- remove namespace visibility scaffolding and skip logic from verify_pipe_pattern()
- resolve helper path with tst_get_path() instead of /proc/self/exe readlink
- Link to v3: https://lore.kernel.org/20260824-coredump-v3-1-6429da674718@suse.com
Changes in v3:
- check for CONFIG_COREDUMP=y
- Link to v2: https://lore.kernel.org/20260824-coredump-v2-1-42428acf5216@suse.com
Changes in v2:
- fix CI agent spotted errors
- Link to v1: https://lore.kernel.org/20260820-coredump-v1-1-7ce51603cefb@suse.com
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 +
testcases/kernel/coredump/coredump01.c | 186 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 66 +++++++++
6 files changed, 263 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..fcdffd625
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "tst_kconfig.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_path[PATH_MAX];
+static char cwd[PATH_MAX];
+static int static_usermodehelper;
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ char readback[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+
+ SAFE_FILE_LINES_SCANF(PATH_KERN_CORE_PATTERN, "%127[^\n]", readback);
+
+ if (strcmp(pattern, readback))
+ tst_brk(TBROK, "core_pattern readback mismatch: wrote '%s', read '%s'",
+ pattern, readback);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX];
+ int pid_seen, sig_seen, elf;
+ long long bytes;
+ pid_t pid;
+
+ if (static_usermodehelper) {
+ tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
+ return;
+ }
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s %%e %%p %%s %s/res.%%p", helper_path, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+ struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
+
+ tst_kconfig_read(&kconfig, 1);
+ static_usermodehelper = (kconfig.choice == 'y');
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+
+ SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
+
+ SAFE_GETCWD(cwd, sizeof(cwd));
+
+ char path[PATH_MAX];
+
+ if (tst_get_path(HELPER, path, sizeof(path)))
+ tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
+
+ if (!realpath(path, helper_path))
+ tst_brk(TBROK | TERRNO, "realpath(%s) failed", path);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char* []) {
+ "CONFIG_COREDUMP=y",
+ NULL,
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..41091b428
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ char buf[4096], tmp[PATH_MAX], magic[4];
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf = 0;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * A core dump embeds the ELF images it has mapped, so the magic is
+ * only meaningful at the very beginning of the stream. Collect it
+ * across reads, since a pipe read can return less than 4 bytes.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && bytes + i < 4; i++)
+ magic[bytes + i] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
+ elf = 1;
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
---
base-commit: 12724413534a6d4160ff9694ba6f09daa4ccb6bd
change-id: 20260820-coredump-22fc731bde08
Best regards,
--
Andrea Cervesato <andrea.cervesato@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* [LTP] [PATCH v4] coredump01: New core_pattern specifiers test
@ 2026-09-02 15:00 Andrea Cervesato
2026-09-02 17:44 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 13+ messages in thread
From: Andrea Cervesato @ 2026-09-02 15:00 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Add a simple coredump01 test that simulate a coredump and verify that it
actually works. This is a small coverage that is missing inside LTP
testing suite.
---
Changes in v4:
- read back core_pattern after writing and abort with TBROK on mismatch
- read CONFIG_STATIC_USERMODEHELPER once in setup() and cache the result
- remove namespace visibility scaffolding and skip logic from verify_pipe_pattern()
- resolve helper path with tst_get_path() instead of /proc/self/exe readlink
- Link to v3: https://lore.kernel.org/20260824-coredump-v3-1-6429da674718@suse.com
Changes in v3:
- check for CONFIG_COREDUMP=y
- Link to v2: https://lore.kernel.org/20260824-coredump-v2-1-42428acf5216@suse.com
Changes in v2:
- fix CI agent spotted errors
- Link to v1: https://lore.kernel.org/20260820-coredump-v1-1-7ce51603cefb@suse.com
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 +
testcases/kernel/coredump/coredump01.c | 181 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 66 ++++++++++
6 files changed, 258 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..9697578b7
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "tst_kconfig.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_path[PATH_MAX];
+static char cwd[PATH_MAX];
+static int static_usermodehelper;
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ char readback[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+
+ SAFE_FILE_LINES_SCANF(PATH_KERN_CORE_PATTERN, "%127[^\n]", readback);
+
+ if (strcmp(pattern, readback))
+ tst_brk(TBROK, "core_pattern readback mismatch: wrote '%s', read '%s'",
+ pattern, readback);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX];
+ int pid_seen, sig_seen, elf;
+ long long bytes;
+ pid_t pid;
+
+ if (static_usermodehelper) {
+ tst_res(TCONF, "CONFIG_STATIC_USERMODEHELPER is enabled, skipping pipe core_pattern");
+ return;
+ }
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s %%e %%p %%s %s/res.%%p", helper_path, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+ struct tst_kconfig_var kconfig = TST_KCONFIG_INIT("CONFIG_STATIC_USERMODEHELPER");
+
+ tst_kconfig_read(&kconfig, 1);
+ static_usermodehelper = (kconfig.choice == 'y');
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+
+ SAFE_PRCTL(PR_SET_DUMPABLE, 1, 0, 0, 0);
+
+ SAFE_GETCWD(cwd, sizeof(cwd));
+
+ if (tst_get_path(HELPER, helper_path, sizeof(helper_path)))
+ tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .needs_kconfigs = (const char* []) {
+ "CONFIG_COREDUMP=y",
+ NULL,
+ },
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..41091b428
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ char buf[4096], tmp[PATH_MAX], magic[4];
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf = 0;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * A core dump embeds the ELF images it has mapped, so the magic is
+ * only meaningful at the very beginning of the stream. Collect it
+ * across reads, since a pipe read can return less than 4 bytes.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && bytes + i < 4; i++)
+ magic[bytes + i] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
+ elf = 1;
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
---
base-commit: 12724413534a6d4160ff9694ba6f09daa4ccb6bd
change-id: 20260820-coredump-22fc731bde08
Best regards,
--
Andrea Cervesato <andrea.cervesato@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-09-02 15:00 [LTP] [PATCH v4] " Andrea Cervesato
@ 2026-09-02 17:44 ` linuxtestproject.agent
2026-09-03 7:22 ` Andrea Cervesato via ltp
0 siblings, 1 reply; 13+ messages in thread
From: linuxtestproject.agent @ 2026-09-02 17:44 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On September 2, 2026, Andrea Cervesato wrote:
> coredump01: New core_pattern specifiers test
> if (tst_get_path(HELPER, helper_path, sizeof(helper_path)))
> tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
`tst_get_path()` can return a relative path such as
`./coredump01_helper`, but a piped core_pattern helper is resolved from
the root directory. Canonicalize `helper_path` to an absolute path before
writing it to core_pattern, otherwise the helper may not start and the
test reports a false failure.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [LTP] coredump01: New core_pattern specifiers test
2026-09-02 17:44 ` [LTP] " linuxtestproject.agent
@ 2026-09-03 7:22 ` Andrea Cervesato via ltp
0 siblings, 0 replies; 13+ messages in thread
From: Andrea Cervesato via ltp @ 2026-09-03 7:22 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: ltp
> Hi Andrea,
>
> On September 2, 2026, Andrea Cervesato wrote:
> > coredump01: New core_pattern specifiers test
>
> > if (tst_get_path(HELPER, helper_path, sizeof(helper_path)))
> > tst_brk(TCONF, "'%s' not found in $PATH", HELPER);
>
> `tst_get_path()` can return a relative path such as
> `./coredump01_helper`, but a piped core_pattern helper is resolved from
> the root directory. Canonicalize `helper_path` to an absolute path before
> writing it to core_pattern, otherwise the helper may not start and the
> test reports a false failure.
>
> Verdict - Needs revision
>
> ---
> Note:
>
> The agent can sometimes produce false positives although often its
> findings are genuine. If you find issues with the review, please
> comment this email or ignore the suggestions.
>
> Regards,
> LTP AI Reviewer
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
This is valid. I sent a new version
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
* [LTP] [PATCH] coredump01: New core_pattern specifiers test
@ 2026-08-20 18:47 Andrea Cervesato
2026-08-20 19:35 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 13+ messages in thread
From: Andrea Cervesato @ 2026-08-20 18:47 UTC (permalink / raw)
To: Linux Test Project
From: Andrea Cervesato <andrea.cervesato@suse.com>
LTP has no coverage for the core_pattern specifiers expansion, neither
for the pipe flavor of core_pattern, where the kernel spawns a user
space helper and writes the core dump into its standard input.
The new test verifies that %e, %p and %s are expanded both in the core
file name and in the arguments of a piped helper, checking also that
the helper really receives an ELF core dump.
Root is required to rewrite the system wide core_pattern, which is
restored by the test library on all exit paths.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Add a simple coredump01 test that simulate a coredump and verify that it
actually works. This is a small coverage that is missing inside LTP
testing suite.
---
runtest/kernel_misc | 1 +
testcases/kernel/Makefile | 1 +
testcases/kernel/coredump/.gitignore | 2 +
testcases/kernel/coredump/Makefile | 7 ++
testcases/kernel/coredump/coredump01.c | 161 ++++++++++++++++++++++++++
testcases/kernel/coredump/coredump01_helper.c | 66 +++++++++++
6 files changed, 238 insertions(+)
diff --git a/runtest/kernel_misc b/runtest/kernel_misc
index cc3562cb7..ecf9ee2a2 100644
--- a/runtest/kernel_misc
+++ b/runtest/kernel_misc
@@ -17,3 +17,4 @@ zram02 zram02.sh
zram03 zram03
umip_basic_test umip_basic_test
aslr01 aslr01
+coredump01 coredump01
diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile
index ac816e4e8..6b303c14b 100644
--- a/testcases/kernel/Makefile
+++ b/testcases/kernel/Makefile
@@ -19,6 +19,7 @@ SUBDIRS += lib
SUBDIRS += connectors \
containers \
controllers \
+ coredump \
crypto \
device-drivers \
firmware \
diff --git a/testcases/kernel/coredump/.gitignore b/testcases/kernel/coredump/.gitignore
new file mode 100644
index 000000000..cd0b51700
--- /dev/null
+++ b/testcases/kernel/coredump/.gitignore
@@ -0,0 +1,2 @@
+/coredump01
+/coredump01_helper
diff --git a/testcases/kernel/coredump/Makefile b/testcases/kernel/coredump/Makefile
new file mode 100644
index 000000000..951a3e976
--- /dev/null
+++ b/testcases/kernel/coredump/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2026 Linux Test Project
+
+top_srcdir ?= ../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/coredump/coredump01.c b/testcases/kernel/coredump/coredump01.c
new file mode 100644
index 000000000..a6003ba10
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*\
+ * Verify that the kernel expands the :manpage:`core(5)` specifiers %e
+ * (executable name), %p (PID) and %s (signal number) when it creates a
+ * core dump.
+ *
+ * Both flavors of ``/proc/sys/kernel/core_pattern`` are tested:
+ *
+ * - a plain file name, where the specifiers become part of the core file
+ * name
+ * - a pipe to a user space helper, where the specifiers are expanded in
+ * the helper arguments and the core dump is written to the helper
+ * standard input
+ *
+ * The test needs root because it rewrites the system wide core_pattern.
+ * The original value is saved and restored by the test library on all
+ * exit paths.
+ *
+ * [Algorithm]
+ *
+ * - Point core_pattern into the test temporary directory
+ * - Fork a child which aborts itself to produce a core dump
+ * - For the file pattern check that ``core.<exe>.<pid>.<signal>`` was created
+ * - For the pipe pattern check the arguments the helper was called with
+ * and that it received an ELF core dump on its standard input
+ */
+
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "lapi/prctl.h"
+
+#define PATTERN_MAX 128
+#define HELPER "coredump01_helper"
+#define HELPER_TIMEOUT 10
+
+static char helper_dir[PATH_MAX];
+static char cwd[PATH_MAX];
+
+static void set_pattern(const char *fmt, ...)
+{
+ char pattern[PATTERN_MAX];
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(pattern, sizeof(pattern), fmt, va);
+ va_end(va);
+
+ if (len >= PATTERN_MAX)
+ tst_brk(TCONF, "core_pattern does not fit into %i bytes", PATTERN_MAX - 1);
+
+ SAFE_FILE_PRINTF(PATH_KERN_CORE_PATTERN, "%s", pattern);
+
+ tst_res(TINFO, "core_pattern is '%s'", pattern);
+}
+
+static pid_t crash_child(void)
+{
+ int status;
+ pid_t pid;
+
+ pid = SAFE_FORK();
+ if (!pid)
+ abort();
+
+ SAFE_WAITPID(pid, &status, 0);
+
+ if (!WIFSIGNALED(status) || !WCOREDUMP(status))
+ tst_brk(TFAIL, "Child did not dump core");
+
+ return pid;
+}
+
+static void verify_file_pattern(void)
+{
+ char dump[PATH_MAX + 32];
+ pid_t pid;
+
+ tst_res(TINFO, "Testing file core_pattern");
+
+ set_pattern("%s/core.%%e.%%p.%%s", cwd);
+
+ pid = crash_child();
+
+ snprintf(dump, sizeof(dump), "%s/core.coredump01.%d.%d", cwd, pid, SIGABRT);
+
+ TST_EXP_PASS(access(dump, F_OK), "core.%%e.%%p.%%s expanded to core.coredump01.%d.%d",
+ pid, SIGABRT);
+}
+
+static void verify_pipe_pattern(void)
+{
+ char res[PATH_MAX + 32], exe[PATH_MAX];
+ int pid_seen, sig_seen, elf;
+ long long bytes;
+ pid_t pid;
+
+ tst_res(TINFO, "Testing pipe core_pattern");
+
+ set_pattern("|%s/%s %%e %%p %%s %s/res.%%p", helper_dir, HELPER, cwd);
+
+ pid = crash_child();
+
+ snprintf(res, sizeof(res), "%s/res.%d", cwd, pid);
+
+ /* the kernel spawns the helper asynchronously */
+ if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
+ tst_res(TFAIL, "%s did not report any core dump", HELPER);
+ return;
+ }
+
+ SAFE_FILE_SCANF(res, "exe=%15s pid=%d sig=%d bytes=%lld elf=%d",
+ exe, &pid_seen, &sig_seen, &bytes, &elf);
+
+ TST_EXP_EQ_STR(exe, "coredump01");
+ TST_EXP_EQ_LI(pid_seen, pid);
+ TST_EXP_EQ_LI(sig_seen, SIGABRT);
+ TST_EXP_EXPR(elf && bytes > 0, "%s read %lli bytes of ELF core dump", HELPER, bytes);
+}
+
+static void run(unsigned int n)
+{
+ if (n)
+ verify_pipe_pattern();
+ else
+ verify_file_pattern();
+}
+
+static void setup(void)
+{
+ struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY};
+ ssize_t len;
+
+ SAFE_SETRLIMIT(RLIMIT_CORE, &rl);
+
+ SAFE_PRCTL(PR_GET_DUMPABLE, 1, 0, 0, 0);
+
+ SAFE_GETCWD(cwd, sizeof(cwd));
+
+ len = SAFE_READLINK("/proc/self/exe", helper_dir, sizeof(helper_dir) - 1);
+ helper_dir[len] = '\0';
+ *strrchr(helper_dir, '/') = '\0';
+}
+
+static struct tst_test test = {
+ .test = run,
+ .tcnt = 2,
+ .setup = setup,
+ .needs_root = 1,
+ .needs_tmpdir = 1,
+ .forks_child = 1,
+ .save_restore = (const struct tst_path_val[]) {
+ {PATH_KERN_CORE_PATTERN, NULL, TST_SR_TCONF},
+ {}
+ },
+};
diff --git a/testcases/kernel/coredump/coredump01_helper.c b/testcases/kernel/coredump/coredump01_helper.c
new file mode 100644
index 000000000..a993e2ef7
--- /dev/null
+++ b/testcases/kernel/coredump/coredump01_helper.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Linux Test Project
+ */
+
+/*
+ * Core dump collector for the piped core_pattern tested by coredump01.
+ *
+ * Avoiding the LTP API here is correct, since the kernel spawns the helper
+ * through ``call_usermodehelper()`` without the LTP IPC environment.
+ *
+ * The helper is called as:
+ *
+ * coredump01_helper <exe> <pid> <signal> <result file>
+ *
+ * and stores what it received in the result file, which is published with
+ * :manpage:`rename()` so that the polling test never reads a partial line.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ char buf[4096], tmp[PATH_MAX], magic[4];
+ long long bytes = 0;
+ ssize_t rval, i;
+ int fd, elf;
+
+ if (argc < 5)
+ return 1;
+
+ /*
+ * A core dump embeds the ELF images it has mapped, so the magic is
+ * only meaningful at the very beginning of the stream. Collect it
+ * across reads, since a pipe read can return less than 4 bytes.
+ */
+ while ((rval = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
+ for (i = 0; i < rval && bytes + i < 4; i++)
+ magic[bytes + i] = buf[i];
+
+ bytes += rval;
+ }
+
+ if (rval < 0)
+ return 1;
+
+ if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
+ elf = 1;
+
+ snprintf(tmp, sizeof(tmp), "%s.tmp", argv[4]);
+
+ fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return 1;
+
+ dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
+ argv[1], argv[2], argv[3], bytes, elf);
+
+ close(fd);
+
+ return rename(tmp, argv[4]) ? 1 : 0;
+}
---
base-commit: e62b1a4731f9c458d65c2659d2f8bb58b93e6d6d
change-id: 20260820-coredump-22fc731bde08
Best regards,
--
Andrea Cervesato <andrea.cervesato@suse.com>
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-08-20 18:47 [LTP] [PATCH] " Andrea Cervesato
@ 2026-08-20 19:35 ` linuxtestproject.agent
2026-08-24 7:22 ` Andrea Cervesato via ltp
0 siblings, 1 reply; 13+ messages in thread
From: linuxtestproject.agent @ 2026-08-20 19:35 UTC (permalink / raw)
To: Andrea Cervesato; +Cc: ltp
Hi Andrea,
On Aug 20, 2026, Andrea Cervesato wrote:
> coredump01: New core_pattern specifiers test
> ssize_t rval, i;
> int fd, elf;
>
> if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
> elf = 1;
>
> dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
> argv[1], argv[2], argv[3], bytes, elf);
Could `elf` be initialized to zero? For short or non-ELF input the
condition does not assign it, so `dprintf()` reads an indeterminate value.
A nonzero value can make the test accept a malformed core stream as ELF.
> SAFE_PRCTL(PR_GET_DUMPABLE, 1, 0, 0, 0);
Should this use `PR_SET_DUMPABLE`? `PR_GET_DUMPABLE` only returns the
current state and ignores arg2, so this call does not ensure that
`abort()` can produce a core dump.
> /* the kernel spawns the helper asynchronously */
> if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
> tst_res(TFAIL, "%s did not report any core dump", HELPER);
Could kernels with `CONFIG_STATIC_USERMODEHELPER` be rejected with TCONF
before this check? In particular, an empty
`CONFIG_STATIC_USERMODEHELPER_PATH` intentionally disables the helper, so
this timeout reports TFAIL without testing specifier expansion.
> set_pattern("|%s/%s %%e %%p %%s %s/res.%%p", helper_dir, HELPER, cwd);
>
> len = SAFE_READLINK("/proc/self/exe", helper_dir, sizeof(helper_dir) - 1);
Could the pipe case require the initial mount namespace, or otherwise use
paths visible there? The kernel resolves and runs a `core_pattern` pipe
handler in the initial mount namespace. If LTP runs in another mount
namespace, these helper and result paths may not exist there, producing a
spurious TFAIL.
> /*
> * Core dump collector for the piped core_pattern tested by coredump01.
> *
> * Avoiding the LTP API here is correct, since the kernel spawns the helper
> * through ``call_usermodehelper()`` without the LTP IPC environment.
> */
>
> int main(int argc, char *argv[])
Could this helper follow the LTP helper-binary convention by defining
`TST_NO_DEFAULT_MAIN` and including `tst_test.h`? The missing IPC
environment means it should avoid IPC-backed result calls, but does not
require avoiding the helper API form itself.
Verdict - Needs revision
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [LTP] coredump01: New core_pattern specifiers test
2026-08-20 19:35 ` [LTP] " linuxtestproject.agent
@ 2026-08-24 7:22 ` Andrea Cervesato via ltp
0 siblings, 0 replies; 13+ messages in thread
From: Andrea Cervesato via ltp @ 2026-08-24 7:22 UTC (permalink / raw)
To: linuxtestproject.agent; +Cc: ltp
> > ssize_t rval, i;
> > int fd, elf;
> >
> > if (bytes >= 4 && !memcmp(magic, "\177ELF", 4))
> > elf = 1;
> >
> > dprintf(fd, "exe=%s pid=%s sig=%s bytes=%lld elf=%d\n",
> > argv[1], argv[2], argv[3], bytes, elf);
>
> Could `elf` be initialized to zero? For short or non-ELF input the
> condition does not assign it, so `dprintf()` reads an indeterminate value.
> A nonzero value can make the test accept a malformed core stream as ELF.
This can be fixed.
>
> > SAFE_PRCTL(PR_GET_DUMPABLE, 1, 0, 0, 0);
>
> Should this use `PR_SET_DUMPABLE`? `PR_GET_DUMPABLE` only returns the
> current state and ignores arg2, so this call does not ensure that
> `abort()` can produce a core dump.
>
> > /* the kernel spawns the helper asynchronously */
> > if (TST_RETRY_FN_EXP_BACKOFF(access(res, F_OK), TST_RETVAL_EQ0, HELPER_TIMEOUT)) {
> > tst_res(TFAIL, "%s did not report any core dump", HELPER);
>
> Could kernels with `CONFIG_STATIC_USERMODEHELPER` be rejected with TCONF
> before this check? In particular, an empty
> `CONFIG_STATIC_USERMODEHELPER_PATH` intentionally disables the helper, so
> this timeout reports TFAIL without testing specifier expansion.
This can be added in needs_kconfig.
>
> > set_pattern("|%s/%s %%e %%p %%s %s/res.%%p", helper_dir, HELPER, cwd);
> >
> > len = SAFE_READLINK("/proc/self/exe", helper_dir, sizeof(helper_dir) - 1);
>
> Could the pipe case require the initial mount namespace, or otherwise use
> paths visible there? The kernel resolves and runs a `core_pattern` pipe
> handler in the initial mount namespace. If LTP runs in another mount
> namespace, these helper and result paths may not exist there, producing a
> spurious TFAIL.
>
> > /*
> > * Core dump collector for the piped core_pattern tested by coredump01.
> > *
> > * Avoiding the LTP API here is correct, since the kernel spawns the helper
> > * through ``call_usermodehelper()`` without the LTP IPC environment.
> > */
> >
> > int main(int argc, char *argv[])
>
> Could this helper follow the LTP helper-binary convention by defining
> `TST_NO_DEFAULT_MAIN` and including `tst_test.h`? The missing IPC
> environment means it should avoid IPC-backed result calls, but does not
> require avoiding the helper API form itself.
It doesn't make any sense. We can skip this one.
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-09-08 6:48 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 8:58 [LTP] [PATCH v3] coredump01: New core_pattern specifiers test Andrea Cervesato
2026-08-24 9:49 ` [LTP] " linuxtestproject.agent
2026-08-31 14:52 ` [LTP] [PATCH v3] " Cyril Hrubis
-- strict thread matches above, loose matches on Subject: below --
2026-09-08 6:26 [LTP] [PATCH v8 1/2] " Andrea Cervesato
2026-09-08 6:48 ` [LTP] " linuxtestproject.agent
2026-09-04 11:03 [LTP] [PATCH v7 1/2] " Andrea Cervesato
2026-09-04 12:20 ` [LTP] " linuxtestproject.agent
2026-09-04 12:26 ` Andrea Cervesato via ltp
2026-09-08 6:27 ` Andrea Cervesato via ltp
2026-09-04 7:15 [LTP] [PATCH v6 1/2] " Andrea Cervesato
2026-09-04 7:52 ` [LTP] " linuxtestproject.agent
2026-09-03 7:21 [LTP] [PATCH v5] " Andrea Cervesato
2026-09-03 12:01 ` [LTP] " linuxtestproject.agent
2026-09-02 15:00 [LTP] [PATCH v4] " Andrea Cervesato
2026-09-02 17:44 ` [LTP] " linuxtestproject.agent
2026-09-03 7:22 ` Andrea Cervesato via ltp
2026-08-20 18:47 [LTP] [PATCH] " Andrea Cervesato
2026-08-20 19:35 ` [LTP] " linuxtestproject.agent
2026-08-24 7:22 ` Andrea Cervesato via ltp
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox