Skip to content

Commit 27b4a03

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 c0a4d2d commit 27b4a03

3 files changed

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

0 commit comments

Comments
 (0)