All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v3 0/3] Separate ptrace tests for CONFIG_PROC_MEM_FORCE_PTRACE
@ 2026-07-21 20:24 Jan Polensky
  2026-07-21 20:24 ` [LTP] [PATCH v3 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only Jan Polensky
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Jan Polensky @ 2026-07-21 20:24 UTC (permalink / raw)
  To: ltp

thp04 is a CVE-2017-1000405 regression test. If direct
/proc/self/mem writes are blocked by CONFIG_PROC_MEM_FORCE_PTRACE=y,
the CVE cannot be triggered and thp04 should report TCONF.

Add separate ptrace tests for the CONFIG_PROC_MEM_FORCE_PTRACE behavior
instead:

- ptrace12 checks that writing to /proc/self/mem is rejected with EIO.
- ptrace13 checks that a parent can write to a traced child's memory via
  /proc/pid/mem.

Both ptrace tests use read-only mappings, so the writes require
FOLL_FORCE and exercise the CONFIG_PROC_MEM_FORCE_PTRACE enforcement.

Validated on s390x with CONFIG_PROC_MEM_FORCE_PTRACE=y:

- ptrace12: TPASS
- ptrace13: TPASS, 100 iterations

Follow-up to the previous thp04 ptrace mode discussion:
https://lore.kernel.org/all/20260709175927.268677-1-japo@linux.ibm.com/

Changes in v3:
- All patches: Fixed RST doc formatting (added blank lines before lists)
- All patches: Removed redundant comments per LTP coding style
- thp04: Removed comments restating pointer arithmetic
- ptrace12: Kept only intent-focused FOLL_FORCE comment
- ptrace13: Removed unused shared_state.result field
- ptrace13: Removed misleading "previous iteration" comment
- ptrace13: Clarified iteration counter in TFAIL message to show which write is being verified
- ptrace13: Kept only intent-focused FOLL_FORCE comment and synchronization pattern comment

Changes in v2:
- thp04: Removed .forks_child flag (not needed without actual fork)
- thp04: Changed MAP_SHARED to MAP_PRIVATE for child state mapping
- thp04: Added missing #include <string.h> for memset()
- thp04: Renamed struct child_state → struct thp_state (no longer uses fork)
- thp04: Renamed child → state, child_setup() → thp_setup(), child_cleanup() → thp_cleanup()
- ptrace12: Removed deprecated [Description] line from doc block
- ptrace12: Replaced bare write() with TEST() macro, using TST_RET/TST_ERR
- ptrace12: Adjusted setup comment to clarify page initialization sequence
- ptrace13: Removed deprecated [Description] line from doc block
- ptrace13: Added missing #include <string.h> for memset()
- Both ptrace tests: Added to runtest/syscalls

v2: https://lore.kernel.org/all/20260716095004.92793-1-japo@linux.ibm.com/
v1: https://lore.kernel.org/all/20260714150631.250972-1-japo@linux.ibm.com/

Jan Polensky (3):
  thp04: Simplify to focus on CVE-2017-1000405 race test only
  ptrace: add test for /proc/self/mem write rejection
  ptrace: add test for /proc/pid/mem writes under ptrace

 runtest/syscalls                            |   2 +
 testcases/kernel/mem/thp/thp04.c            | 163 +++++++++++-----
 testcases/kernel/syscalls/ptrace/.gitignore |   2 +
 testcases/kernel/syscalls/ptrace/ptrace12.c |  92 +++++++++
 testcases/kernel/syscalls/ptrace/ptrace13.c | 204 ++++++++++++++++++++
 5 files changed, 411 insertions(+), 52 deletions(-)
 create mode 100644 testcases/kernel/syscalls/ptrace/ptrace12.c
 create mode 100644 testcases/kernel/syscalls/ptrace/ptrace13.c


base-commit: d139524b04d360c4dabaee61a6066a9a52b0e454
prerequisite-patch-id: bded72bcb9b40d815798ce62381eec472c28aace
prerequisite-patch-id: 16fc00d302aefbf6fb17e972a4390341bfbb0e50
prerequisite-patch-id: 6e77ef09b2259daae915f4a4895bf0879b7b7211
prerequisite-patch-id: 1d13f676c1c1b9b37e97b1e18ae75611a3516f96
prerequisite-patch-id: 11b8f2b102029b41838899f2a78132b50cac12a0
prerequisite-patch-id: 811e85d9a4158f72559de5f551ad93f109362c96
--
2.55.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [LTP] [PATCH v3 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only
  2026-07-21 20:24 [LTP] [PATCH v3 0/3] Separate ptrace tests for CONFIG_PROC_MEM_FORCE_PTRACE Jan Polensky
@ 2026-07-21 20:24 ` Jan Polensky
  2026-07-21 21:21   ` [LTP] " linuxtestproject.agent
  2026-07-21 20:24 ` [LTP] [PATCH v3 2/3] ptrace: add test for /proc/self/mem write rejection Jan Polensky
  2026-07-21 20:24 ` [LTP] [PATCH v3 3/3] ptrace: add test for /proc/pid/mem writes under ptrace Jan Polensky
  2 siblings, 1 reply; 6+ messages in thread
From: Jan Polensky @ 2026-07-21 20:24 UTC (permalink / raw)
  To: ltp

Remove ptrace mode support from thp04.c to keep the test focused on
its original purpose: testing the CVE-2017-1000405 race condition.

The ptrace-based /proc/pid/mem write functionality is now covered by
dedicated tests in testcases/kernel/syscalls/ptrace/:
- ptrace12: Tests that CONFIG_PROC_MEM_FORCE_PTRACE blocks self-writes
- ptrace13: Tests that ptrace allows parent-to-child memory writes

This separation follows the principle of one test per feature and makes
the test suite more maintainable.

Signed-off-by: Jan Polensky <japo@linux.ibm.com>
---
 testcases/kernel/mem/thp/thp04.c | 163 +++++++++++++++++++++----------
 1 file changed, 111 insertions(+), 52 deletions(-)

diff --git a/testcases/kernel/mem/thp/thp04.c b/testcases/kernel/mem/thp/thp04.c
index 16d766c349b7..c5c07b5b58d1 100644
--- a/testcases/kernel/mem/thp/thp04.c
+++ b/testcases/kernel/mem/thp/thp04.c
@@ -3,7 +3,7 @@
  * Copyright (c) 2019 SUSE LLC <mdoucha@suse.cz>
  */
 
-/*
+/*\
  * CVE-2017-1000405
  *
  * Check for the Huge Dirty Cow vulnerability which allows a userspace process
@@ -21,27 +21,40 @@
  * On old kernel such as 4.9, it has fixed the Dirty Cow bug but a similar check
  * in huge_memory.c was forgotten.  As a result, remote memory writes to ro regions
  * of memory backed by transparent huge pages cause an infinite loop in the kernel.
- * While in this state the process is stil SIGKILLable, but little else works.
+ * While in this state the process is still SIGKILLable, but little else works.
  * It is also a regression test about kernel
  * commit 8310d48b125d("huge_memory.c: respect FOLL_FORCE/FOLL_COW for thp").
+ *
+ * This test uses direct writes to /proc/self/mem with fuzzy-sync to trigger
+ * the race condition. If direct writes are not available (e.g., when
+ * CONFIG_PROC_MEM_FORCE_PTRACE=y is set), the test reports TCONF.
+ * For ptrace-based /proc/pid/mem testing, see testcases/kernel/syscalls/ptrace/.
  */
 
-#include "tst_test.h"
+#include <string.h>
+
 #include "lapi/mmap.h"
 #include "tst_fuzzy_sync.h"
+#include "tst_test.h"
 
-static char *write_thp, *read_thp;
-static int *write_ptr, *read_ptr;
-static size_t thp_size;
-static int writefd = -1, readfd = -1;
-static struct tst_fzsync_pair fzsync_pair;
+struct thp_state {
+	char *write_thp;
+	char *read_thp;
+	int *write_ptr;
+	int *read_ptr;
+	size_t thp_size;
+	int writefd;
+	int readfd;
+	struct tst_fzsync_pair fzsync_pair;
+};
 
-static void *alloc_zero_page(void *baseaddr)
+static struct thp_state *state;
+
+static void *alloc_zero_page(void *baseaddr, size_t thp_size)
 {
 	int i;
 	void *ret;
 
-	/* Find aligned chunk of address space. MAP_HUGETLB doesn't work. */
 	for (i = 0; i < 16; i++, baseaddr += thp_size) {
 		ret = mmap(baseaddr, thp_size, PROT_READ,
 			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -67,47 +80,68 @@ static void *alloc_zero_page(void *baseaddr)
 	}
 
 	tst_brk(TBROK, "Cannot map huge zero page near the specified address");
-	return NULL;	/* Silence compiler warning */
+	return NULL;
 }
 
-static void setup(void)
+static void thp_cleanup(void)
+{
+	if (!state)
+		return;
+
+	tst_fzsync_pair_cleanup(&state->fzsync_pair);
+
+	if (state->readfd >= 0)
+		SAFE_CLOSE(state->readfd);
+
+	if (state->writefd >= 0)
+		SAFE_CLOSE(state->writefd);
+
+	if (state->read_thp)
+		SAFE_MUNMAP(state->read_thp, state->thp_size);
+
+	if (state->write_thp)
+		SAFE_MUNMAP(state->write_thp, state->thp_size);
+}
+
+static void thp_setup(void)
 {
 	size_t i;
 
-	thp_size = tst_get_hugepage_size();
+	state->thp_size = tst_get_hugepage_size();
 
-	if (!thp_size)
+	if (!state->thp_size)
 		tst_brk(TCONF, "Kernel does not support huge pages");
 
-	write_thp = alloc_zero_page((void *)thp_size);
+	state->write_thp = alloc_zero_page((void *)state->thp_size,
+		state->thp_size);
 
-	for (i = 0; i < thp_size; i++) {
-		if (write_thp[i])
+	for (i = 0; i < state->thp_size; i++) {
+		if (state->write_thp[i])
 			tst_brk(TCONF, "Huge zero page is pre-polluted");
 	}
 
-	/* leave a hole between read and write THP to prevent merge */
-	read_thp = alloc_zero_page(write_thp + 2 * thp_size);
-	write_ptr = (int *)(write_thp + thp_size - sizeof(int));
-	read_ptr = (int *)(read_thp + thp_size - sizeof(int));
-	writefd = SAFE_OPEN("/proc/self/mem", O_RDWR);
-	readfd = SAFE_OPEN("/proc/self/mem", O_RDWR);
+	state->read_thp = alloc_zero_page(state->write_thp + 2 * state->thp_size,
+		state->thp_size);
+	state->write_ptr = (int *)(state->write_thp + state->thp_size - sizeof(int));
+	state->read_ptr = (int *)(state->read_thp + state->thp_size - sizeof(int));
 
-	fzsync_pair.exec_loops = 100000;
-	tst_fzsync_pair_init(&fzsync_pair);
+	state->writefd = SAFE_OPEN("/proc/self/mem", O_RDWR);
+	state->readfd = SAFE_OPEN("/proc/self/mem", O_RDWR);
+	state->fzsync_pair.exec_loops = 100000;
+	tst_fzsync_pair_init(&state->fzsync_pair);
 }
 
 static void *thread_run(void *arg)
 {
 	int c;
 
-	while (tst_fzsync_run_b(&fzsync_pair)) {
-		tst_fzsync_start_race_b(&fzsync_pair);
-		madvise(write_thp, thp_size, MADV_DONTNEED);
-		memcpy(&c, write_ptr, sizeof(c));
-		SAFE_LSEEK(readfd, (off_t)write_ptr, SEEK_SET);
-		SAFE_READ(1, readfd, &c, sizeof(int));
-		tst_fzsync_end_race_b(&fzsync_pair);
+	while (tst_fzsync_run_b(&state->fzsync_pair)) {
+		tst_fzsync_start_race_b(&state->fzsync_pair);
+		madvise(state->write_thp, state->thp_size, MADV_DONTNEED);
+		memcpy(&c, state->write_ptr, sizeof(c));
+		SAFE_LSEEK(state->readfd, (off_t)state->write_ptr, SEEK_SET);
+		SAFE_READ(1, state->readfd, &c, sizeof(int));
+		tst_fzsync_end_race_b(&state->fzsync_pair);
 		/* Wait for dirty page handling before next madvise() */
 		usleep(10);
 	}
@@ -119,20 +153,20 @@ static void run(void)
 {
 	int c = 0xdeadbeef;
 
-	tst_fzsync_pair_reset(&fzsync_pair, thread_run);
+	tst_fzsync_pair_reset(&state->fzsync_pair, thread_run);
 
-	while (tst_fzsync_run_a(&fzsync_pair)) {
+	while (tst_fzsync_run_a(&state->fzsync_pair)) {
 		/* Write into the main huge page */
-		tst_fzsync_start_race_a(&fzsync_pair);
-		SAFE_LSEEK(writefd, (off_t)write_ptr, SEEK_SET);
-		madvise(write_thp, thp_size, MADV_DONTNEED);
-		SAFE_WRITE(SAFE_WRITE_ALL, writefd, &c, sizeof(int));
-		tst_fzsync_end_race_a(&fzsync_pair);
+		tst_fzsync_start_race_a(&state->fzsync_pair);
+		SAFE_LSEEK(state->writefd, (off_t)state->write_ptr, SEEK_SET);
+		madvise(state->write_thp, state->thp_size, MADV_DONTNEED);
+		SAFE_WRITE(SAFE_WRITE_ALL, state->writefd, &c, sizeof(int));
+		tst_fzsync_end_race_a(&state->fzsync_pair);
 
 		/* Check the other huge zero page for pollution */
-		madvise(read_thp, thp_size, MADV_DONTNEED);
+		madvise(state->read_thp, state->thp_size, MADV_DONTNEED);
 
-		if (*read_ptr != 0) {
+		if (*state->read_ptr != 0) {
 			tst_res(TFAIL, "Huge zero page was polluted");
 			return;
 		}
@@ -141,20 +175,45 @@ static void run(void)
 	tst_res(TPASS, "Huge zero page is still clean");
 }
 
+static void setup(void)
+{
+	int test_val = 0;
+
+	state = SAFE_MMAP(NULL, sizeof(*state), PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	memset(state, 0, sizeof(*state));
+	state->writefd = -1;
+	state->readfd = -1;
+
+	thp_setup();
+
+	/* Verify that direct writes to /proc/self/mem work */
+	TEST(lseek(state->writefd, (off_t)state->write_ptr, SEEK_SET));
+	if (TST_RET == -1)
+		tst_brk(TBROK | TTERRNO, "lseek on /proc/self/mem failed");
+
+	TEST(write(state->writefd, &test_val, sizeof(test_val)));
+
+	if (TST_RET == -1 && TST_ERR == EIO) {
+		tst_brk(TCONF,
+			"Direct writes to /proc/self/mem disabled "
+			"(CONFIG_PROC_MEM_FORCE_PTRACE=y). "
+			"See testcases/kernel/syscalls/ptrace/ptrace12 and ptrace13 for ptrace coverage.");
+	}
+
+	if (TST_RET == -1)
+		tst_brk(TBROK | TTERRNO, "test write to /proc/self/mem failed");
+
+	if (TST_RET != sizeof(test_val))
+		tst_brk(TBROK, "short write to /proc/self/mem: %ld bytes", TST_RET);
+}
+
 static void cleanup(void)
 {
-	tst_fzsync_pair_cleanup(&fzsync_pair);
+	thp_cleanup();
 
-	if (readfd >= 0)
-		SAFE_CLOSE(readfd);
-
-	if (writefd >= 0)
-		SAFE_CLOSE(writefd);
-
-	if (read_thp)
-		SAFE_MUNMAP(read_thp, thp_size);
-	if (write_thp)
-		SAFE_MUNMAP(write_thp, thp_size);
+	if (state)
+		SAFE_MUNMAP(state, sizeof(*state));
 }
 
 static struct tst_test test = {
-- 
2.55.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [LTP] [PATCH v3 2/3] ptrace: add test for /proc/self/mem write rejection
  2026-07-21 20:24 [LTP] [PATCH v3 0/3] Separate ptrace tests for CONFIG_PROC_MEM_FORCE_PTRACE Jan Polensky
  2026-07-21 20:24 ` [LTP] [PATCH v3 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only Jan Polensky
@ 2026-07-21 20:24 ` Jan Polensky
  2026-07-21 20:24 ` [LTP] [PATCH v3 3/3] ptrace: add test for /proc/pid/mem writes under ptrace Jan Polensky
  2 siblings, 0 replies; 6+ messages in thread
From: Jan Polensky @ 2026-07-21 20:24 UTC (permalink / raw)
  To: ltp

Add ptrace12 to verify that direct writes to /proc/self/mem are
correctly rejected when CONFIG_PROC_MEM_FORCE_PTRACE=y is active.

The test allocates a read-only memory page and attempts to write to it
via /proc/self/mem. With CONFIG_PROC_MEM_FORCE_PTRACE=y, this write
should fail with EIO because:
- FOLL_FORCE flag is needed to write to read-only pages
- CONFIG_PROC_MEM_FORCE_PTRACE blocks FOLL_FORCE unless actively ptracing
- A process cannot ptrace itself

Test validates kernel commit 41e8149c8892 ("proc: add config & param to
block forcing mem writes").

Signed-off-by: Jan Polensky <japo@linux.ibm.com>
---
 runtest/syscalls                            |  1 +
 testcases/kernel/syscalls/ptrace/.gitignore |  1 +
 testcases/kernel/syscalls/ptrace/ptrace12.c | 92 +++++++++++++++++++++
 3 files changed, 94 insertions(+)
 create mode 100644 testcases/kernel/syscalls/ptrace/ptrace12.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 2be7012a6cd4..9df4684cca41 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1176,6 +1176,7 @@ ptrace09 ptrace09
 ptrace10 ptrace10
 ptrace11 ptrace11
 
+ptrace12 ptrace12
 pwrite01 pwrite01
 pwrite02 pwrite02
 pwrite03 pwrite03
diff --git a/testcases/kernel/syscalls/ptrace/.gitignore b/testcases/kernel/syscalls/ptrace/.gitignore
index 1ee6117e9d5b..8631219312d5 100644
--- a/testcases/kernel/syscalls/ptrace/.gitignore
+++ b/testcases/kernel/syscalls/ptrace/.gitignore
@@ -9,3 +9,4 @@
 /ptrace09
 /ptrace10
 /ptrace11
+/ptrace12
diff --git a/testcases/kernel/syscalls/ptrace/ptrace12.c b/testcases/kernel/syscalls/ptrace/ptrace12.c
new file mode 100644
index 000000000000..8bf1707b9923
--- /dev/null
+++ b/testcases/kernel/syscalls/ptrace/ptrace12.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 SUSE LLC <japo@suse.cz>
+ */
+
+/*\
+ * Verify that direct writes to /proc/self/mem are correctly rejected
+ * when CONFIG_PROC_MEM_FORCE_PTRACE=y is active.
+ *
+ * When CONFIG_PROC_MEM_FORCE_PTRACE=y is set, the kernel requires
+ * PTRACE_MODE_ATTACH for /proc/pid/mem writes. This means a process
+ * cannot write to its own memory via /proc/self/mem - such writes
+ * should fail with EIO.
+ *
+ * Test behavior:
+ *
+ * - If write succeeds: TCONF (feature not active)
+ * - If write fails with EIO: TPASS (feature working correctly)
+ * - If write fails with other error: TFAIL (unexpected behavior)
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "tst_test.h"
+
+static int *test_ptr;
+static int memfd = -1;
+
+static void setup(void)
+{
+	test_ptr = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE,
+			     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	*test_ptr = 0;
+
+	/* Force /proc/self/mem to require FOLL_FORCE by targeting a read-only page */
+	SAFE_MPROTECT((void *)test_ptr, sizeof(int), PROT_READ);
+
+	memfd = SAFE_OPEN("/proc/self/mem", O_RDWR);
+}
+
+static void run(void)
+{
+	int test_val = 0xdeadbeef;
+
+	SAFE_LSEEK(memfd, (off_t)test_ptr, SEEK_SET);
+	TEST(write(memfd, &test_val, sizeof(test_val)));
+
+	if (TST_RET == sizeof(test_val)) {
+		tst_res(TCONF,
+			"Direct writes to /proc/self/mem succeeded - "
+			"CONFIG_PROC_MEM_FORCE_PTRACE not active or overridden");
+		return;
+	}
+
+	if (TST_RET == -1 && TST_ERR == EIO) {
+		tst_res(TPASS,
+			"Write to /proc/self/mem correctly rejected with EIO");
+		return;
+	}
+
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TERRNO,
+			"Write to /proc/self/mem failed with unexpected error");
+		return;
+	}
+
+	tst_res(TFAIL,
+		"Short write to /proc/self/mem: %zd bytes (expected %zu or -1)",
+		TST_RET, sizeof(test_val));
+}
+
+static void cleanup(void)
+{
+	if (memfd >= 0)
+		SAFE_CLOSE(memfd);
+
+	if (test_ptr)
+		SAFE_MUNMAP(test_ptr, sizeof(int));
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "41e8149c8892"},
+		{}
+	}
+};
-- 
2.55.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [LTP] [PATCH v3 3/3] ptrace: add test for /proc/pid/mem writes under ptrace
  2026-07-21 20:24 [LTP] [PATCH v3 0/3] Separate ptrace tests for CONFIG_PROC_MEM_FORCE_PTRACE Jan Polensky
  2026-07-21 20:24 ` [LTP] [PATCH v3 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only Jan Polensky
  2026-07-21 20:24 ` [LTP] [PATCH v3 2/3] ptrace: add test for /proc/self/mem write rejection Jan Polensky
@ 2026-07-21 20:24 ` Jan Polensky
  2 siblings, 0 replies; 6+ messages in thread
From: Jan Polensky @ 2026-07-21 20:24 UTC (permalink / raw)
  To: ltp

Add ptrace13 to verify that a tracer can write to tracee memory via
/proc/pid/mem when CONFIG_PROC_MEM_FORCE_PTRACE=y is active.

The test uses PTRACE_SEIZE to attach to a child process and writes to
its read-only memory pages via /proc/pid/mem. This validates that:
- FOLL_FORCE is allowed when actively ptracing
- Parent can modify child's read-only memory
- Write-stop-continue cycle works correctly (100 iterations)

Test validates kernel commit 41e8149c8892 ("proc: add config & param to
block forcing mem writes").

Signed-off-by: Jan Polensky <japo@linux.ibm.com>
---
 runtest/syscalls                            |   1 +
 testcases/kernel/syscalls/ptrace/.gitignore |   1 +
 testcases/kernel/syscalls/ptrace/ptrace13.c | 204 ++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 testcases/kernel/syscalls/ptrace/ptrace13.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 9df4684cca41..476c69d4c5f0 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1177,6 +1177,7 @@ ptrace10 ptrace10
 ptrace11 ptrace11
 
 ptrace12 ptrace12
+ptrace13 ptrace13
 pwrite01 pwrite01
 pwrite02 pwrite02
 pwrite03 pwrite03
diff --git a/testcases/kernel/syscalls/ptrace/.gitignore b/testcases/kernel/syscalls/ptrace/.gitignore
index 8631219312d5..72f9cef98e22 100644
--- a/testcases/kernel/syscalls/ptrace/.gitignore
+++ b/testcases/kernel/syscalls/ptrace/.gitignore
@@ -10,3 +10,4 @@
 /ptrace10
 /ptrace11
 /ptrace12
+/ptrace13
diff --git a/testcases/kernel/syscalls/ptrace/ptrace13.c b/testcases/kernel/syscalls/ptrace/ptrace13.c
new file mode 100644
index 000000000000..a052fab81cb6
--- /dev/null
+++ b/testcases/kernel/syscalls/ptrace/ptrace13.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2025 SUSE LLC <japo@suse.cz>
+ */
+
+/*\
+ * Verify that a parent process can write to a traced child's memory
+ * via /proc/pid/mem when the child is in a stopped state.
+ *
+ * This test validates the ptrace-based memory write mechanism that
+ * becomes mandatory when CONFIG_PROC_MEM_FORCE_PTRACE=y is active.
+ *
+ * Test flow:
+ *
+ * 1. Parent forks a child process
+ * 2. Child signals readiness via checkpoint
+ * 3. Parent attaches with PTRACE_SEIZE
+ * 4. Child self-stops with raise(SIGSTOP)
+ * 5. Parent writes to child's memory via /proc/pid/mem
+ * 6. Parent continues child with PTRACE_CONT
+ * 7. Child verifies the write took effect
+ * 8. Repeat for multiple iterations
+ *
+ * The test uses checkpoint synchronization to prevent race conditions
+ * during ptrace attachment.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "tst_test.h"
+#include "tst_checkpoint.h"
+
+#define TEST_ITERATIONS 100
+
+struct shared_state {
+	int *test_ptr;
+	int expected_val;
+};
+
+static struct shared_state *shared;
+static pid_t tracee_pid;
+
+static void tracee_main(void)
+{
+	int i;
+
+	shared->test_ptr = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE,
+				     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	*shared->test_ptr = 0;
+
+	/* Force parent write through /proc/pid/mem to require FOLL_FORCE */
+	SAFE_MPROTECT((void *)shared->test_ptr, sizeof(int), PROT_READ);
+
+	TST_CHECKPOINT_WAKE(0);
+	TST_CHECKPOINT_WAIT(1);
+	raise(SIGSTOP);
+
+	for (i = 0; i < TEST_ITERATIONS; i++) {
+		if (*shared->test_ptr != shared->expected_val) {
+			tst_res(TFAIL,
+				"Iteration %d: expected 0x%x (written in iteration %d), got 0x%x",
+				i, shared->expected_val, i > 0 ? i-1 : 0, *shared->test_ptr);
+			exit(1);
+		}
+
+		raise(SIGSTOP);
+	}
+
+	while (1)
+		pause();
+}
+
+static void setup(void)
+{
+	/* Allocate shared memory for parent-child communication */
+	shared = SAFE_MMAP(NULL, sizeof(*shared), PROT_READ | PROT_WRITE,
+			   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	memset(shared, 0, sizeof(*shared));
+}
+
+static void run(void)
+{
+	char path[64];
+	int memfd;
+	int status;
+	int i;
+
+	tracee_pid = SAFE_FORK();
+	if (!tracee_pid) {
+		tracee_main();
+		exit(0);
+	}
+
+	TST_CHECKPOINT_WAIT(0);
+	SAFE_PTRACE(PTRACE_SEIZE, tracee_pid, NULL, NULL);
+	TST_CHECKPOINT_WAKE(1);
+	SAFE_WAITPID(tracee_pid, &status, 0);
+
+	if (WIFEXITED(status)) {
+		tst_brk(TBROK,
+			"Tracee exited unexpectedly before first SIGSTOP: %s",
+			tst_strstatus(status));
+	}
+
+	if (WIFSIGNALED(status)) {
+		tst_brk(TBROK,
+			"Tracee was killed before first SIGSTOP: %s",
+			tst_strstatus(status));
+	}
+
+	if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
+		tst_brk(TBROK,
+			"Tracee did not self-stop with SIGSTOP: %s",
+			tst_strstatus(status));
+	}
+
+	snprintf(path, sizeof(path), "/proc/%d/mem", tracee_pid);
+	memfd = SAFE_OPEN(path, O_RDWR);
+
+	/*
+	 * Write-stop-continue cycle: tracee is already stopped from initial raise(SIGSTOP).
+	 * Pattern: write → continue → tracee verifies → tracee stops → repeat
+	 */
+	for (i = 0; i < TEST_ITERATIONS; i++) {
+		int write_val = 0xdead0000 | i;
+
+		shared->expected_val = write_val;
+		SAFE_LSEEK(memfd, (off_t)shared->test_ptr, SEEK_SET);
+		SAFE_WRITE(SAFE_WRITE_ALL, memfd, &write_val, sizeof(write_val));
+		SAFE_PTRACE(PTRACE_CONT, tracee_pid, NULL, NULL);
+		SAFE_WAITPID(tracee_pid, &status, 0);
+
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status) == 0) {
+				tst_brk(TBROK,
+					"Tracee exited unexpectedly at iteration %d: %s",
+					i, tst_strstatus(status));
+			}
+			/* Tracee reported failure and exited */
+			SAFE_CLOSE(memfd);
+			tracee_pid = 0;
+			return;
+		}
+
+		if (WIFSIGNALED(status)) {
+			tst_brk(TBROK,
+				"Tracee was killed at iteration %d: %s",
+				i, tst_strstatus(status));
+		}
+
+		if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
+			tst_brk(TBROK,
+				"Tracee did not stop correctly at iteration %d: %s",
+				i, tst_strstatus(status));
+		}
+	}
+
+	SAFE_CLOSE(memfd);
+
+	/* Test passed - all writes were successful and tracee verified them */
+	tst_res(TPASS,
+		"Successfully wrote to tracee memory via /proc/pid/mem "
+		"for %d iterations", TEST_ITERATIONS);
+
+	/* Detach and terminate tracee */
+	SAFE_PTRACE(PTRACE_DETACH, tracee_pid, NULL, NULL);
+	SAFE_KILL(tracee_pid, SIGKILL);
+	SAFE_WAITPID(tracee_pid, &status, 0);
+	tracee_pid = 0;
+}
+
+static void cleanup(void)
+{
+	if (tracee_pid > 0) {
+		/* Kill tracee if still alive (e.g., test aborted) */
+		if (kill(tracee_pid, 0) == 0) {
+			SAFE_KILL(tracee_pid, SIGKILL);
+			tst_reap_children();
+		}
+		tracee_pid = 0;
+	}
+
+	if (shared)
+		SAFE_MUNMAP(shared, sizeof(*shared));
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "41e8149c8892"},
+		{}
+	}
+};
-- 
2.55.0


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [LTP] thp04: Simplify to focus on CVE-2017-1000405 race test only
  2026-07-21 20:24 ` [LTP] [PATCH v3 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only Jan Polensky
@ 2026-07-21 21:21   ` linuxtestproject.agent
  2026-07-22  7:31     ` Andrea Cervesato via ltp
  0 siblings, 1 reply; 6+ messages in thread
From: linuxtestproject.agent @ 2026-07-21 21:21 UTC (permalink / raw)
  To: Jan Polensky; +Cc: ltp

Hi Jan,

On Tue, 21 Jul 2026, Jan Polensky wrote:
> thp04: Simplify to focus on CVE-2017-1000405 race test only

--- [PATCH 1/3] ---

> Remove ptrace mode support from thp04.c to keep the test focused on
> its original purpose: testing the CVE-2017-1000405 race condition.

The pre-patch thp04.c has no ptrace calls or "ptrace mode" branch at
all -- it is already just the plain fuzzy-sync race test using
/proc/self/mem. There does not seem to be anything to remove here.

What the diff actually does is move the static globals (write_thp,
read_thp, write_ptr, read_ptr, thp_size, writefd, readfd, fzsync_pair)
into a heap-allocated `struct thp_state *state`, and add a new probe in
setup() that performs a real write() to /proc/self/mem and reports
TCONF if it fails with EIO (i.e. when CONFIG_PROC_MEM_FORCE_PTRACE or
CONFIG_PROC_MEM_NO_FORCE blocks unforced self-writes). Could the commit
message be updated to describe this actual change and its motivation?

> The ptrace-based /proc/pid/mem write functionality is now covered by
> dedicated tests in testcases/kernel/syscalls/ptrace/:
> - ptrace12: Tests that CONFIG_PROC_MEM_FORCE_PTRACE blocks self-writes
> - ptrace13: Tests that ptrace allows parent-to-child memory writes

Neither ptrace12 nor ptrace13 exists yet at this point in the series --
they are added by patches 2/3 and 3/3. The same names are also baked
into the new TCONF message added to thp04.c's setup(). Someone
bisecting to this commit alone would see references to tests that
don't exist. Would moving this patch after the two ptrace patches (or
dropping the concrete test names) avoid the forward reference?

> +	TEST(lseek(state->writefd, (off_t)state->write_ptr, SEEK_SET));
> +	if (TST_RET == -1)
> +		tst_brk(TBROK | TTERRNO, "lseek on /proc/self/mem failed");

lseek() isn't the subject under test here -- only the write() probe
right after it is meant to observe the FOLL_FORCE policy. Since
SAFE_LSEEK() exists and this duplicates its abort-on-error behavior by
hand, could this use SAFE_LSEEK() instead?

--- [PATCH 3/3] ---

> Add ptrace13 to verify that a tracer can write to tracee memory via
> /proc/pid/mem when CONFIG_PROC_MEM_FORCE_PTRACE=y is active.

Unlike ptrace12's self-write probe (which reports TCONF whenever the
write unexpectedly succeeds), this test has no runtime or
.needs_kconfigs gate on CONFIG_PROC_MEM_FORCE_PTRACE. If the running
kernel enforces CONFIG_PROC_MEM_NO_FORCE (or is booted with
"proc_mem.force_override=never"), proc_mem_foll_force() in
fs/proc/base.c always returns false, so the write to the read-only
page in the run() loop fails with -EIO:

> 		SAFE_LSEEK(memfd, (off_t)shared->test_ptr, SEEK_SET);
> 		SAFE_WRITE(SAFE_WRITE_ALL, memfd, &write_val, sizeof(write_val));

SAFE_WRITE() aborts with TBROK on that -EIO instead of the test
reporting TCONF for a kernel that isn't configured with the "ptrace"
policy. Could this test gate on
`.needs_kconfigs = {"CONFIG_PROC_MEM_FORCE_PTRACE=y", NULL}`, or add a
runtime probe similar to the one used in ptrace12/thp04, so it reports
TCONF instead of TBROK on such kernels?

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] 6+ messages in thread

* Re: [LTP] thp04: Simplify to focus on CVE-2017-1000405 race test only
  2026-07-21 21:21   ` [LTP] " linuxtestproject.agent
@ 2026-07-22  7:31     ` Andrea Cervesato via ltp
  0 siblings, 0 replies; 6+ messages in thread
From: Andrea Cervesato via ltp @ 2026-07-22  7:31 UTC (permalink / raw)
  To: linuxtestproject.agent; +Cc: ltp

Hi Jan,

> Hi Jan,
> 
> On Tue, 21 Jul 2026, Jan Polensky wrote:
> > thp04: Simplify to focus on CVE-2017-1000405 race test only
> 
> --- [PATCH 1/3] ---
> 
> > Remove ptrace mode support from thp04.c to keep the test focused on
> > its original purpose: testing the CVE-2017-1000405 race condition.
> 
> The pre-patch thp04.c has no ptrace calls or "ptrace mode" branch at
> all -- it is already just the plain fuzzy-sync race test using
> /proc/self/mem. There does not seem to be anything to remove here.
> 
> What the diff actually does is move the static globals (write_thp,
> read_thp, write_ptr, read_ptr, thp_size, writefd, readfd, fzsync_pair)
> into a heap-allocated `struct thp_state *state`, and add a new probe in
> setup() that performs a real write() to /proc/self/mem and reports
> TCONF if it fails with EIO (i.e. when CONFIG_PROC_MEM_FORCE_PTRACE or
> CONFIG_PROC_MEM_NO_FORCE blocks unforced self-writes). Could the commit
> message be updated to describe this actual change and its motivation?

LLMs tends to be a bit verbose in here, so please keep commit message
straight to the point. The rest of the review is correct.

--
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] 6+ messages in thread

end of thread, other threads:[~2026-07-22  7:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 20:24 [LTP] [PATCH v3 0/3] Separate ptrace tests for CONFIG_PROC_MEM_FORCE_PTRACE Jan Polensky
2026-07-21 20:24 ` [LTP] [PATCH v3 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only Jan Polensky
2026-07-21 21:21   ` [LTP] " linuxtestproject.agent
2026-07-22  7:31     ` Andrea Cervesato via ltp
2026-07-21 20:24 ` [LTP] [PATCH v3 2/3] ptrace: add test for /proc/self/mem write rejection Jan Polensky
2026-07-21 20:24 ` [LTP] [PATCH v3 3/3] ptrace: add test for /proc/pid/mem writes under ptrace Jan Polensky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.