1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2021 SUSE LLC Andrea Cervesato <[email protected]>
4 */
5
6 /*\
7 * [Description]
8 *
9 * This test verifies EINVAL for futex_waitv syscall.
10 */
11
12 #include <time.h>
13 #include <stdlib.h>
14 #include "tst_test.h"
15 #include "lapi/futex.h"
16 #include "futex2test.h"
17 #include "tst_safe_clocks.h"
18
19 static uint32_t *futex;
20 static struct futex_waitv *waitv;
21
setup(void)22 static void setup(void)
23 {
24 futex = SAFE_MALLOC(sizeof(uint32_t));
25 *futex = FUTEX_INITIALIZER;
26 }
27
init_timeout(struct timespec * to)28 static void init_timeout(struct timespec *to)
29 {
30 SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, to);
31 to->tv_sec++;
32 }
33
init_waitv(void)34 static void init_waitv(void)
35 {
36 waitv->uaddr = (uintptr_t)futex;
37 waitv->flags = FUTEX_32 | FUTEX_PRIVATE_FLAG;
38 waitv->val = 0;
39 }
40
test_invalid_flags(void)41 static void test_invalid_flags(void)
42 {
43 struct timespec to;
44
45 init_waitv();
46 init_timeout(&to);
47
48 /* Testing a waiter without FUTEX_32 flag */
49 waitv->flags = FUTEX_PRIVATE_FLAG;
50
51 TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EINVAL,
52 "futex_waitv with invalid flags");
53 }
54
test_unaligned_address(void)55 static void test_unaligned_address(void)
56 {
57 struct timespec to;
58
59 init_waitv();
60 init_timeout(&to);
61
62 waitv->uaddr = 1;
63
64 TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EINVAL,
65 "futex_waitv with unligned address");
66 }
67
test_null_address(void)68 static void test_null_address(void)
69 {
70 struct timespec to;
71
72 init_waitv();
73 init_timeout(&to);
74
75 waitv->uaddr = 0x00000000;
76
77 TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EFAULT,
78 "futex_waitv address is NULL");
79 }
80
test_null_waiters(void)81 static void test_null_waiters(void)
82 {
83 struct timespec to;
84
85 init_timeout(&to);
86
87 TST_EXP_FAIL(futex_waitv(NULL, 1, 0, &to, CLOCK_MONOTONIC), EINVAL,
88 "futex_waitv waiters are NULL");
89 }
90
test_invalid_clockid(void)91 static void test_invalid_clockid(void)
92 {
93 struct timespec to;
94
95 init_waitv();
96 init_timeout(&to);
97
98 TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_TAI), EINVAL,
99 "futex_waitv invalid clockid");
100 }
101
test_invalid_nr_futexes(void)102 static void test_invalid_nr_futexes(void)
103 {
104 struct timespec to;
105
106 init_waitv();
107 init_timeout(&to);
108
109 /* Valid nr_futexes is [1, 128] */
110 TST_EXP_FAIL(futex_waitv(waitv, 129, 0, &to, CLOCK_MONOTONIC), EINVAL,
111 "futex_waitv invalid nr_futexes");
112 TST_EXP_FAIL(futex_waitv(waitv, 0, 0, &to, CLOCK_MONOTONIC), EINVAL,
113 "futex_waitv invalid nr_futexes");
114 }
115
test_mismatch_between_uaddr_and_val(void)116 static void test_mismatch_between_uaddr_and_val(void)
117 {
118 struct timespec to;
119
120 waitv->uaddr = (uintptr_t)futex;
121 waitv->flags = FUTEX_32 | FUTEX_PRIVATE_FLAG;
122 waitv->val = 1;
123
124 init_timeout(&to);
125
126 TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EAGAIN,
127 "futex_waitv mismatch between value of uaddr and val");
128 }
129
test_timeout(void)130 static void test_timeout(void)
131 {
132 struct timespec to;
133
134 waitv->uaddr = (uintptr_t)futex;
135 waitv->flags = FUTEX_32 | FUTEX_PRIVATE_FLAG;
136 waitv->val = 0;
137
138 SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &to);
139 to = tst_timespec_add_us(to, 10000);
140
141 TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_REALTIME), ETIMEDOUT,
142 "futex_waitv timeout");
143 }
144
cleanup(void)145 static void cleanup(void)
146 {
147 free(futex);
148 }
149
run(void)150 static void run(void)
151 {
152 test_invalid_flags();
153 test_unaligned_address();
154 test_null_address();
155 test_null_waiters();
156 test_invalid_clockid();
157 test_invalid_nr_futexes();
158 test_mismatch_between_uaddr_and_val();
159 test_timeout();
160 }
161
162 static struct tst_test test = {
163 .test_all = run,
164 .setup = setup,
165 .cleanup = cleanup,
166 .min_kver = "5.16",
167 .bufs =
168 (struct tst_buffers[]){
169 { &waitv, .size = sizeof(struct futex_waitv) },
170 {},
171 },
172 };
173