1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Linux Test Project, 2012
4 * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Test errno codes in process_vm_readv and process_vm_writev syscalls.
11 */
12
13 #include <pwd.h>
14 #include <stdlib.h>
15 #include "tst_test.h"
16 #include "lapi/syscalls.h"
17
18 struct process_vm_params {
19 int len;
20 char *ldummy;
21 char *rdummy;
22 pid_t pid;
23 struct iovec *lvec;
24 unsigned long liovcnt;
25 struct iovec *rvec;
26 unsigned long riovcnt;
27 unsigned long flags;
28 };
29
30 static char *str_read;
31 static void (*test_params)(struct process_vm_params *params);
32
alloc_params(void)33 static struct process_vm_params *alloc_params(void)
34 {
35 struct process_vm_params *sane_params;
36 int len;
37
38 len = getpagesize();
39
40 sane_params = SAFE_MALLOC(sizeof(struct process_vm_params));
41 sane_params->len = len;
42 sane_params->ldummy = SAFE_MALLOC(len);
43 sane_params->rdummy = SAFE_MALLOC(len);
44
45 sane_params->lvec = SAFE_MALLOC(sizeof(struct process_vm_params));
46 sane_params->lvec->iov_base = sane_params->ldummy;
47 sane_params->lvec->iov_len = len;
48 sane_params->liovcnt = 1;
49
50 sane_params->rvec = SAFE_MALLOC(sizeof(struct process_vm_params));
51 sane_params->rvec->iov_base = sane_params->rdummy;
52 sane_params->rvec->iov_len = len;
53 sane_params->riovcnt = 1;
54
55 sane_params->flags = 0;
56 sane_params->pid = getpid();
57
58 return sane_params;
59 }
60
free_params(struct process_vm_params * params)61 static void free_params(struct process_vm_params *params)
62 {
63 if (params) {
64 free(params->ldummy);
65 free(params->rdummy);
66 free(params->lvec);
67 free(params->rvec);
68 free(params);
69 }
70 }
71
test_readv(struct process_vm_params * params)72 static void test_readv(struct process_vm_params *params)
73 {
74 TEST(tst_syscall(__NR_process_vm_readv,
75 params->pid,
76 params->lvec, params->liovcnt,
77 params->rvec, params->riovcnt,
78 params->flags));
79 }
80
test_writev(struct process_vm_params * params)81 static void test_writev(struct process_vm_params *params)
82 {
83 TEST(tst_syscall(__NR_process_vm_writev,
84 params->pid,
85 params->lvec, params->liovcnt,
86 params->rvec, params->riovcnt,
87 params->flags));
88 }
89
check_errno(long expected_errno)90 static void check_errno(long expected_errno)
91 {
92 if (TST_ERR == expected_errno)
93 tst_res(TPASS | TTERRNO, "expected failure");
94 else if (TST_ERR == 0)
95 tst_res(TFAIL, "call succeeded unexpectedly");
96 else
97 tst_res(TFAIL | TTERRNO, "unexpected failure - "
98 "expected = %ld : %s, actual",
99 expected_errno, strerror(expected_errno));
100 }
101
test_sane_params(void)102 static void test_sane_params(void)
103 {
104 struct process_vm_params *sane_params;
105
106 tst_res(TINFO, "Testing sane parameters");
107
108 sane_params = alloc_params();
109 test_params(sane_params);
110 TST_EXP_EQ_LI(TST_RET, sane_params->len);
111 free_params(sane_params);
112 }
113
test_flags(void)114 static void test_flags(void)
115 {
116 struct process_vm_params *params;
117 long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 };
118 int flags_size = ARRAY_SIZE(flags) / sizeof(flags[0]);
119 int i;
120
121 params = alloc_params();
122
123 for (i = 0; i < flags_size; i++) {
124 params->flags = flags[i];
125
126 tst_res(TINFO, "Testing flags=%ld", flags[i]);
127 test_params(params);
128
129 /* atm. only flags == 0 is allowed, everything else
130 * should fail with EINVAL
131 */
132 if (flags[i] != 0) {
133 TST_EXP_EQ_LI(TST_RET, -1);
134 check_errno(EINVAL);
135 } else {
136 TST_EXP_EQ_LI(TST_RET, params->len);
137 }
138 }
139
140 free_params(params);
141 }
142
test_iov_len_overflow(void)143 static void test_iov_len_overflow(void)
144 {
145 struct process_vm_params *params;
146
147 tst_res(TINFO, "Testing iov_len = -1");
148
149 params = alloc_params();
150 params->lvec->iov_len = -1;
151 params->rvec->iov_len = -1;
152 test_params(params);
153 TST_EXP_EQ_LI(TST_RET, -1);
154 check_errno(EINVAL);
155 free_params(params);
156 }
157
test_iov_invalid(void)158 static void test_iov_invalid(void)
159 {
160 struct process_vm_params *sane_params;
161 struct process_vm_params params_copy;
162
163 sane_params = alloc_params();
164
165 tst_res(TINFO, "Testing lvec->iov_base = -1");
166 params_copy = *sane_params;
167 params_copy.lvec->iov_base = (void *)-1;
168 test_params(¶ms_copy);
169 TST_EXP_EQ_LI(TST_RET, -1);
170 check_errno(EFAULT);
171
172 tst_res(TINFO, "Testing rvec->iov_base = -1");
173 params_copy = *sane_params;
174 params_copy.rvec->iov_base = (void *)-1;
175 test_params(¶ms_copy);
176 TST_EXP_EQ_LI(TST_RET, -1);
177 check_errno(EFAULT);
178
179 tst_res(TINFO, "Testing lvec = -1");
180 params_copy = *sane_params;
181 params_copy.lvec = (void *)-1;
182 test_params(¶ms_copy);
183 TST_EXP_EQ_LI(TST_RET, -1);
184 check_errno(EFAULT);
185
186 tst_res(TINFO, "Testing rvec = -1");
187 params_copy = *sane_params;
188 params_copy.rvec = (void *)-1;
189 test_params(¶ms_copy);
190 TST_EXP_EQ_LI(TST_RET, -1);
191 check_errno(EFAULT);
192
193 free_params(sane_params);
194 }
195
test_invalid_pid(void)196 static void test_invalid_pid(void)
197 {
198 pid_t invalid_pid = -1;
199 struct process_vm_params *params;
200 struct process_vm_params params_copy;
201
202 params = alloc_params();
203
204 tst_res(TINFO, "Testing invalid PID");
205 params_copy = *params;
206 params_copy.pid = invalid_pid;
207 test_params(¶ms_copy);
208 TST_EXP_EQ_LI(TST_RET, -1);
209 check_errno(ESRCH);
210
211 tst_res(TINFO, "Testing unused PID");
212 params_copy = *params;
213 invalid_pid = tst_get_unused_pid();
214 params_copy.pid = invalid_pid;
215 test_params(¶ms_copy);
216 TST_EXP_EQ_LI(TST_RET, -1);
217 check_errno(ESRCH);
218
219 free_params(params);
220 }
221
test_invalid_perm(void)222 static void test_invalid_perm(void)
223 {
224 char nobody_uid[] = "nobody";
225 struct passwd *ltpuser;
226 struct process_vm_params *params;
227 pid_t child_pid;
228 pid_t parent_pid;
229
230 tst_res(TINFO, "Testing invalid permissions on given PID");
231
232 parent_pid = getpid();
233 child_pid = SAFE_FORK();
234 if (!child_pid) {
235 ltpuser = SAFE_GETPWNAM(nobody_uid);
236 SAFE_SETUID(ltpuser->pw_uid);
237
238 params = alloc_params();
239 params->pid = parent_pid;
240 test_params(params);
241 TST_EXP_EQ_LI(TST_RET, -1);
242 check_errno(EPERM);
243 free_params(params);
244 return;
245 }
246
247 /* collect result from child before the next test, otherwise
248 * TFAIL/TPASS messages will arrive asynchronously
249 */
250 tst_reap_children();
251 }
252
test_invalid_protection(void)253 static void test_invalid_protection(void)
254 {
255 struct process_vm_params *sane_params;
256 struct process_vm_params params_copy;
257 void *data;
258 int len;
259
260 len = getpagesize();
261 sane_params = alloc_params();
262 data = SAFE_MMAP(NULL, len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
263
264 tst_res(TINFO, "Testing data with invalid protection (lvec)");
265 params_copy = *sane_params;
266 params_copy.lvec->iov_base = data;
267 test_params(¶ms_copy);
268 TST_EXP_EQ_LI(TST_RET, -1);
269 check_errno(EFAULT);
270
271 tst_res(TINFO, "Testing data with invalid protection (rvec)");
272 params_copy = *sane_params;
273 params_copy.rvec->iov_base = data;
274 test_params(¶ms_copy);
275 TST_EXP_EQ_LI(TST_RET, -1);
276 check_errno(EFAULT);
277
278 SAFE_MUNMAP(data, len);
279 free_params(sane_params);
280 }
281
run(void)282 static void run(void)
283 {
284 test_sane_params();
285 test_flags();
286 test_iov_len_overflow();
287 test_iov_invalid();
288 test_invalid_pid();
289 test_invalid_perm();
290 test_invalid_protection();
291 }
292
setup(void)293 static void setup(void)
294 {
295 if (str_read) {
296 tst_res(TINFO, "Selected process_vm_readv");
297 test_params = test_readv;
298 } else {
299 tst_res(TINFO, "Selected process_vm_writev");
300 test_params = test_writev;
301 }
302 }
303
304 static struct tst_test test = {
305 .test_all = run,
306 .setup = setup,
307 .forks_child = 1,
308 .needs_root = 1,
309 .options = (struct tst_option[]) {
310 {"r", &str_read, "Use process_vm_read instead of process_vm_write"},
311 {},
312 },
313 };
314