From: Jan Polensky <japo@linux.ibm.com>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v2 1/3] thp04: Simplify to focus on CVE-2017-1000405 race test only
Date: Thu, 16 Jul 2026 11:50:01 +0200 [thread overview]
Message-ID: <20260716095004.92793-2-japo@linux.ibm.com> (raw)
In-Reply-To: <20260716095004.92793-1-japo@linux.ibm.com>
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 | 166 +++++++++++++++++++++----------
1 file changed, 114 insertions(+), 52 deletions(-)
diff --git a/testcases/kernel/mem/thp/thp04.c b/testcases/kernel/mem/thp/thp04.c
index 16d766c349b7..c8d71289e005 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,70 @@ 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);
+ /* write_ptr points to last int in write_thp page */
+ state->write_ptr = (int *)(state->write_thp + state->thp_size - sizeof(int));
+ /* read_ptr points to last int in read_thp page */
+ 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 +155,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 +177,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 = {
@@ -162,6 +223,7 @@ static struct tst_test test = {
.setup = setup,
.cleanup = cleanup,
.runtime = 150,
+
.tags = (const struct tst_tag[]) {
{"linux-git", "a8f97366452e"},
{"linux-git", "8310d48b125d"},
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next prev parent reply other threads:[~2026-07-16 9:51 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 9:50 [LTP] [PATCH v2 0/3] Separate ptrace tests for CONFIG_PROC_MEM_FORCE_PTRACE Jan Polensky
2026-07-16 9:50 ` Jan Polensky [this message]
2026-07-16 13:17 ` [LTP] thp04: Simplify to focus on CVE-2017-1000405 race test only linuxtestproject.agent
2026-07-16 9:50 ` [LTP] [PATCH v2 2/3] ptrace: add test for /proc/self/mem write rejection Jan Polensky
2026-07-16 9:50 ` [LTP] [PATCH v2 3/3] ptrace: add test for /proc/pid/mem writes under ptrace Jan Polensky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260716095004.92793-2-japo@linux.ibm.com \
--to=japo@linux.ibm.com \
--cc=ltp@lists.linux.it \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.