Skip to content

Commit 1bbef99

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 1cca745 commit 1bbef99

3 files changed

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

0 commit comments

Comments
 (0)