Skip to content

Commit aadbca5

Browse files
committed
futex_cmp_requeue03: Add EFAULT error coverage test
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>
1 parent 1bbef99 commit aadbca5

3 files changed

Lines changed: 100 additions & 0 deletions

File tree

runtest/syscalls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,7 @@ perf_event_open02 perf_event_open02
18631863

18641864
futex_cmp_requeue01 futex_cmp_requeue01
18651865
futex_cmp_requeue02 futex_cmp_requeue02
1866+
futex_cmp_requeue03 futex_cmp_requeue03
18661867
futex_wait01 futex_wait01
18671868
futex_wait02 futex_wait02
18681869
futex_wait03 futex_wait03

testcases/kernel/syscalls/futex/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
/futex_wait06
1717
/futex_wait07
1818
/futex_wake05
19+
/futex_cmp_requeue03
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (C) 2026 Red Hat, Inc. Michael Menasherov <mmenashe@redhat.com>
4+
*/
5+
6+
/*\
7+
* Check that futex(FUTEX_CMP_REQUEUE) returns EFAULT when uaddr or
8+
* uaddr2 points to unmapped memory, or when uaddr points to memory
9+
* without read permission (PROT_NONE).
10+
*
11+
* uaddr2 is only reached after *uaddr == val passes; both are
12+
* FUTEX_INITIALIZER so the comparison succeeds.
13+
*/
14+
15+
#include <errno.h>
16+
#include <sys/mman.h>
17+
18+
#include "futextest.h"
19+
20+
static futex_t futex_var = FUTEX_INITIALIZER;
21+
static futex_t *futex_ptr = &futex_var;
22+
static futex_t *unmapped_addr;
23+
static futex_t *prot_none_addr;
24+
25+
static struct futex_test_variants variants[] = {
26+
#if (__NR_futex != __LTP__NR_INVALID_SYSCALL)
27+
{ .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec"},
28+
#endif
29+
30+
#if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL)
31+
{ .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec"},
32+
#endif
33+
};
34+
35+
static struct testcase {
36+
const char *desc;
37+
futex_t **uaddr;
38+
futex_t **uaddr2;
39+
int exp_errno;
40+
} testcases[] = {
41+
{
42+
.desc = "uaddr unmapped",
43+
.uaddr = &unmapped_addr,
44+
.uaddr2 = &futex_ptr,
45+
.exp_errno = EFAULT,
46+
},
47+
{
48+
.desc = "uaddr2 unmapped",
49+
.uaddr = &futex_ptr,
50+
.uaddr2 = &unmapped_addr,
51+
.exp_errno = EFAULT,
52+
},
53+
{
54+
.desc = "uaddr PROT_NONE",
55+
.uaddr = &prot_none_addr,
56+
.uaddr2 = &futex_ptr,
57+
.exp_errno = EFAULT,
58+
},
59+
};
60+
61+
static void run(unsigned int n)
62+
{
63+
struct futex_test_variants *tv = &variants[tst_variant];
64+
struct testcase *tc = &testcases[n];
65+
66+
TST_EXP_FAIL(futex_cmp_requeue(tv->fntype, *tc->uaddr, futex_var,
67+
*tc->uaddr2, 1, 1, 0), tc->exp_errno, "%s", tc->desc);
68+
}
69+
70+
static void setup(void)
71+
{
72+
struct futex_test_variants *tv = &variants[tst_variant];
73+
size_t pagesize = getpagesize();
74+
75+
tst_res(TINFO, "Testing variant: %s", tv->desc);
76+
futex_supported_by_kernel(tv->fntype);
77+
78+
unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
79+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
80+
SAFE_MUNMAP((void *)unmapped_addr, pagesize);
81+
82+
prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
83+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
84+
}
85+
86+
static void cleanup(void)
87+
{
88+
if (prot_none_addr)
89+
SAFE_MUNMAP((void *)prot_none_addr, getpagesize());
90+
}
91+
92+
static struct tst_test test = {
93+
.setup = setup,
94+
.cleanup = cleanup,
95+
.test = run,
96+
.tcnt = ARRAY_SIZE(testcases),
97+
.test_variants = ARRAY_SIZE(variants),
98+
};

0 commit comments

Comments
 (0)