* [LTP] [PATCH v15 1/2] futex_wake05: Add EFAULT error coverage test
2026-06-16 18:30 [LTP] [PATCH v15 0/2] futex: Add EFAULT coverage for wake and cmp_requeue Michael Menasherov via ltp
@ 2026-06-16 18:30 ` Michael Menasherov via ltp
2026-06-16 19:47 ` [LTP] " linuxtestproject.agent
` (2 more replies)
2026-06-16 18:30 ` [LTP] [PATCH v15 2/2] futex_cmp_requeue03: " Michael Menasherov via ltp
1 sibling, 3 replies; 7+ messages in thread
From: Michael Menasherov via ltp @ 2026-06-16 18:30 UTC (permalink / raw)
To: ltp
futex(FUTEX_WAKE) has no existing test for EFAULT. Add coverage for
unmapped, PROT_NONE, and kernel-space uaddr, each exercising a
different code path in the kernel's address validation.
Signed-off-by: Michael Menasherov <mmenashe@redhat.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/futex/.gitignore | 1 +
.../kernel/syscalls/futex/futex_wake05.c | 101 ++++++++++++++++++
3 files changed, 103 insertions(+)
create mode 100644 testcases/kernel/syscalls/futex/futex_wake05.c
diff --git a/runtest/syscalls b/runtest/syscalls
index a021c79da..67509826f 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1878,6 +1878,7 @@ futex_wake01 futex_wake01
futex_wake02 futex_wake02
futex_wake03 futex_wake03
futex_wake04 futex_wake04
+futex_wake05 futex_wake05
futex_wait_bitset01 futex_wait_bitset01
memfd_create01 memfd_create01
diff --git a/testcases/kernel/syscalls/futex/.gitignore b/testcases/kernel/syscalls/futex/.gitignore
index 74ac9a926..c11546e07 100644
--- a/testcases/kernel/syscalls/futex/.gitignore
+++ b/testcases/kernel/syscalls/futex/.gitignore
@@ -15,3 +15,4 @@
/futex_waitv03
/futex_wait06
/futex_wait07
+/futex_wake05
diff --git a/testcases/kernel/syscalls/futex/futex_wake05.c b/testcases/kernel/syscalls/futex/futex_wake05.c
new file mode 100644
index 000000000..162bc4e04
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_wake05.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ * Copyright (C) 2026 Michael Menasherov <mmenashe@redhat.com>
+ */
+
+/*\
+ * Check that futex(FUTEX_WAKE) returns EFAULT when uaddr points to
+ * unmapped, PROT_NONE, or kernel-space memory.
+ *
+ * For the unmapped and PROT_NONE cases, opflags=0 (no FUTEX_PRIVATE_FLAG)
+ * ensures futex_wake() takes the shared-futex path in get_futex_key()
+ * which must resolve the physical page. For PROT_NONE memory this page
+ * lookup fails with EFAULT, even though futex_wake() never reads *uaddr.
+ *
+ * The three cases exercise different code paths: a kernel-space address
+ * is rejected by the kernel's user-space address check before physical
+ * page resolution; unmapped memory fails at find_vma() (no VMA exists);
+ * PROT_NONE memory fails at get_user_pages_fast() (VMA exists but page
+ * is inaccessible).
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "futextest.h"
+
+static futex_t *unmapped_addr;
+static futex_t *prot_none_addr;
+static futex_t *kernel_addr = (futex_t *)-1L;
+
+static struct futex_test_variants variants[] = {
+#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
+ { .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
+#endif
+
+#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
+ { .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
+#endif
+};
+
+static struct testcase {
+ const char *desc;
+ futex_t **addr;
+ int exp_errno;
+} testcases[] = {
+ {
+ .desc = "uaddr unmapped",
+ .addr = &unmapped_addr,
+ .exp_errno = EFAULT,
+ },
+ {
+ .desc = "uaddr PROT_NONE",
+ .addr = &prot_none_addr,
+ .exp_errno = EFAULT,
+ },
+ {
+ .desc = "uaddr kernel address",
+ .addr = &kernel_addr,
+ .exp_errno = EFAULT,
+ },
+};
+
+static void run(unsigned int n)
+{
+ struct futex_test_variants *tv = &variants[tst_variant];
+ struct testcase *tc = &testcases[n];
+
+ TST_EXP_FAIL(futex_wake(tv->fntype, *tc->addr, 1, 0),
+ tc->exp_errno, "%s", tc->desc);
+}
+
+static void setup(void)
+{
+ struct futex_test_variants *tv = &variants[tst_variant];
+ size_t pagesize = getpagesize();
+
+ tst_res(TINFO, "Testing variant: %s", tv->desc);
+ futex_supported_by_kernel(tv->fntype);
+
+ unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ SAFE_MUNMAP((void *)unmapped_addr, pagesize);
+
+ prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+ if (prot_none_addr)
+ SAFE_MUNMAP((void *)prot_none_addr, getpagesize());
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test = run,
+ .tcnt = ARRAY_SIZE(testcases),
+ .test_variants = ARRAY_SIZE(variants),
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread* [LTP] [PATCH v15 2/2] futex_cmp_requeue03: Add EFAULT error coverage test
2026-06-16 18:30 [LTP] [PATCH v15 0/2] futex: Add EFAULT coverage for wake and cmp_requeue Michael Menasherov via ltp
2026-06-16 18:30 ` [LTP] [PATCH v15 1/2] futex_wake05: Add EFAULT error coverage test Michael Menasherov via ltp
@ 2026-06-16 18:30 ` Michael Menasherov via ltp
2026-06-17 12:34 ` Andrea Cervesato via ltp
1 sibling, 1 reply; 7+ messages in thread
From: Michael Menasherov via ltp @ 2026-06-16 18:30 UTC (permalink / raw)
To: ltp
futex(FUTEX_CMP_REQUEUE) has no existing test for EFAULT. Add coverage
for the cases where uaddr or uaddr2 points to unmapped or inaccessible
(PROT_NONE) memory.
Signed-off-by: Michael Menasherov <mmenashe@redhat.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/futex/.gitignore | 1 +
.../syscalls/futex/futex_cmp_requeue03.c | 102 ++++++++++++++++++
3 files changed, 104 insertions(+)
create mode 100644 testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
diff --git a/runtest/syscalls b/runtest/syscalls
index 67509826f..0cb4e3dba 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1864,6 +1864,7 @@ perf_event_open02 perf_event_open02
futex_cmp_requeue01 futex_cmp_requeue01
futex_cmp_requeue02 futex_cmp_requeue02
+futex_cmp_requeue03 futex_cmp_requeue03
futex_wait01 futex_wait01
futex_wait02 futex_wait02
futex_wait03 futex_wait03
diff --git a/testcases/kernel/syscalls/futex/.gitignore b/testcases/kernel/syscalls/futex/.gitignore
index c11546e07..231b6bd25 100644
--- a/testcases/kernel/syscalls/futex/.gitignore
+++ b/testcases/kernel/syscalls/futex/.gitignore
@@ -16,3 +16,4 @@
/futex_wait06
/futex_wait07
/futex_wake05
+/futex_cmp_requeue03
diff --git a/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
new file mode 100644
index 000000000..6063ddd86
--- /dev/null
+++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue03.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Red Hat, Inc.
+ * Copyright (C) 2026 Michael Menasherov <mmenashe@redhat.com>
+ */
+
+/*\
+ * Check that futex(FUTEX_CMP_REQUEUE) returns EFAULT when uaddr or
+ * uaddr2 points to unmapped memory, or when uaddr points to memory
+ * without read permission (PROT_NONE).
+ *
+ * The test uses opflags=0 (no FUTEX_PRIVATE_FLAG) so get_futex_key()
+ * takes the shared-futex path and resolves the physical page; this
+ * lookup fails with EFAULT for unmapped and PROT_NONE addresses.
+ * get_futex_key() is called for both uaddr and uaddr2 before the
+ * *uaddr == val check; futex_var and val are both FUTEX_INITIALIZER.
+ */
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "futextest.h"
+
+static futex_t futex_var = FUTEX_INITIALIZER;
+static futex_t *futex_ptr = &futex_var;
+static futex_t *unmapped_addr;
+static futex_t *prot_none_addr;
+
+static struct futex_test_variants variants[] = {
+#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
+ { .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
+#endif
+
+#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
+ { .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
+#endif
+};
+
+static struct testcase {
+ const char *desc;
+ futex_t **uaddr;
+ futex_t **uaddr2;
+ int exp_errno;
+} testcases[] = {
+ {
+ .desc = "uaddr unmapped",
+ .uaddr = &unmapped_addr,
+ .uaddr2 = &futex_ptr,
+ .exp_errno = EFAULT,
+ },
+ {
+ .desc = "uaddr2 unmapped",
+ .uaddr = &futex_ptr,
+ .uaddr2 = &unmapped_addr,
+ .exp_errno = EFAULT,
+ },
+ {
+ .desc = "uaddr PROT_NONE",
+ .uaddr = &prot_none_addr,
+ .uaddr2 = &futex_ptr,
+ .exp_errno = EFAULT,
+ },
+};
+
+static void run(unsigned int n)
+{
+ struct futex_test_variants *tv = &variants[tst_variant];
+ struct testcase *tc = &testcases[n];
+
+ TST_EXP_FAIL(futex_cmp_requeue(tv->fntype, *tc->uaddr, futex_var,
+ *tc->uaddr2, 1, 1, 0), tc->exp_errno, "%s", tc->desc);
+}
+
+static void setup(void)
+{
+ struct futex_test_variants *tv = &variants[tst_variant];
+ size_t pagesize = getpagesize();
+
+ tst_res(TINFO, "Testing variant: %s", tv->desc);
+ futex_supported_by_kernel(tv->fntype);
+
+ unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ SAFE_MUNMAP((void *)unmapped_addr, pagesize);
+
+ prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+}
+
+static void cleanup(void)
+{
+ if (prot_none_addr)
+ SAFE_MUNMAP((void *)prot_none_addr, getpagesize());
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test = run,
+ .tcnt = ARRAY_SIZE(testcases),
+ .test_variants = ARRAY_SIZE(variants),
+};
--
2.54.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 7+ messages in thread