Skip to content

Commit c0a4d2d

Browse files
committed
futex_wake05: Add EFAULT error coverage test
futex(FUTEX_WAKE) has no existing test for EFAULT. Add coverage for the cases where uaddr points to unmapped or PROT_NONE memory. Signed-off-by: Michael Menasherov <mmenashe@redhat.com>
1 parent 30bdc78 commit c0a4d2d

3 files changed

Lines changed: 91 additions & 0 deletions

File tree

runtest/syscalls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,7 @@ futex_wake01 futex_wake01
18771877
futex_wake02 futex_wake02
18781878
futex_wake03 futex_wake03
18791879
futex_wake04 futex_wake04
1880+
futex_wake05 futex_wake05
18801881
futex_wait_bitset01 futex_wait_bitset01
18811882

18821883
memfd_create01 memfd_create01

testcases/kernel/syscalls/futex/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
/futex_waitv03
1616
/futex_wait06
1717
/futex_wait07
18+
/futex_wake05
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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_WAKE) returns EFAULT when uaddr points to
9+
* unmapped or PROT_NONE memory.
10+
*
11+
* The test uses opflags=0 (no FUTEX_PRIVATE_FLAG), so futex_wake() takes
12+
* the shared-futex path in get_futex_key() which must resolve the physical
13+
* page. For PROT_NONE memory this page lookup fails with EFAULT, even though
14+
* futex_wake() never reads *uaddr.
15+
*/
16+
17+
#include <errno.h>
18+
#include <sys/mman.h>
19+
20+
#include "futextest.h"
21+
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 **addr;
38+
int exp_errno;
39+
} testcases[] = {
40+
{
41+
.desc = "uaddr unmapped",
42+
.addr = &unmapped_addr,
43+
.exp_errno = EFAULT,
44+
},
45+
{
46+
.desc = "uaddr PROT_NONE",
47+
.addr = &prot_none_addr,
48+
.exp_errno = EFAULT,
49+
},
50+
};
51+
52+
static void run(unsigned int n)
53+
{
54+
struct futex_test_variants *tv = &variants[tst_variant];
55+
struct testcase *tc = &testcases[n];
56+
57+
TST_EXP_FAIL(futex_wake(tv->fntype, *tc->addr, 1, 0),
58+
tc->exp_errno, "%s", tc->desc);
59+
}
60+
61+
static void setup(void)
62+
{
63+
struct futex_test_variants *tv = &variants[tst_variant];
64+
size_t pagesize = getpagesize();
65+
66+
tst_res(TINFO, "Testing variant: %s", tv->desc);
67+
futex_supported_by_kernel(tv->fntype);
68+
69+
unmapped_addr = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE,
70+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
71+
SAFE_MUNMAP((void *)unmapped_addr, pagesize);
72+
73+
prot_none_addr = SAFE_MMAP(NULL, pagesize, PROT_NONE,
74+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
75+
}
76+
77+
static void cleanup(void)
78+
{
79+
if (prot_none_addr)
80+
SAFE_MUNMAP((void *)prot_none_addr, getpagesize());
81+
}
82+
83+
static struct tst_test test = {
84+
.setup = setup,
85+
.cleanup = cleanup,
86+
.test = run,
87+
.tcnt = ARRAY_SIZE(testcases),
88+
.test_variants = ARRAY_SIZE(variants),
89+
};

0 commit comments

Comments
 (0)