blob: 2f34e258ae781da0328988f2a88abaf702986591 [file] [log] [blame]
Jan Stancek5d56dd52012-06-11 16:09:50 +02001/*
2 * Copyright (C) 2012 Linux Test Project, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public
6 * License as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it
13 * is free of the rightful claim of any third person regarding
14 * infringement or the like. Any license provided herein, whether
15 * implied or otherwise, applies only to this software file. Patent
16 * licenses, if any, provided herein do not apply to combinations of
17 * this program with other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25/*
26 * errno tests shared by process_vm_readv, process_vm_writev tests.
27 */
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/syscall.h>
31#include <sys/uio.h>
32#include <sys/wait.h>
33#include <sys/mman.h>
34#include <errno.h>
35#include <signal.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <limits.h>
41#include <pwd.h>
42#include "config.h"
43#include "test.h"
Jan Stancek5d56dd52012-06-11 16:09:50 +020044#include "safe_macros.h"
45#include "process_vm.h"
46
47struct process_vm_params {
48 int len;
49 char *ldummy;
50 char *rdummy;
51 pid_t pid;
52 struct iovec *lvec;
53 unsigned long liovcnt;
54 struct iovec *rvec;
55 unsigned long riovcnt;
56 unsigned long flags;
57};
58
59static int rflag;
60static int wflag;
61
62static option_t options[] = {
63 {"r", &rflag, NULL},
64 {"w", &wflag, NULL},
65 {NULL, NULL, NULL}
66};
67
68static char TCID_readv[] = "process_vm_readv";
69static char TCID_writev[] = "process_vm_writev";
70char *TCID = "cma01";
Wanlong Gao354ebb42012-12-07 10:10:04 +080071int TST_TOTAL = 1;
72static void (*cma_test_params) (struct process_vm_params * params) = NULL;
Jan Stancek5d56dd52012-06-11 16:09:50 +020073
74static void setup(char *argv[]);
75static void cleanup(void);
76static void help(void);
77
78static void cma_test_params_read(struct process_vm_params *params);
79static void cma_test_params_write(struct process_vm_params *params);
80static void cma_test_errnos(void);
81
82int main(int argc, char *argv[])
83{
84 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020085 const char *msg;
Jan Stancek5d56dd52012-06-11 16:09:50 +020086
87 msg = parse_opts(argc, argv, options, &help);
88 if (msg != NULL)
89 tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
90
91 setup(argv);
92 for (lc = 0; TEST_LOOPING(lc); lc++) {
Caspar Zhangd59a6592013-03-07 14:59:12 +080093 tst_count = 0;
Jan Stancek5d56dd52012-06-11 16:09:50 +020094 cma_test_errnos();
95 }
96 cleanup();
97 tst_exit();
98}
99
100static void setup(char *argv[])
101{
102 tst_require_root(NULL);
103
104 if (rflag && wflag)
105 tst_brkm(TBROK, NULL, "Parameters -r -w can not be used"
Wanlong Gao354ebb42012-12-07 10:10:04 +0800106 " at the same time.");
Jan Stancek5d56dd52012-06-11 16:09:50 +0200107 else if (rflag) {
108 TCID = TCID_readv;
109#if defined(__NR_process_vm_readv)
110 cma_test_params = cma_test_params_read;
111#else
112 tst_brkm(TCONF, NULL, "process_vm_readv does not"
Wanlong Gao354ebb42012-12-07 10:10:04 +0800113 " exist on your system.");
Jan Stancek5d56dd52012-06-11 16:09:50 +0200114#endif
115 } else if (wflag) {
116 TCID = TCID_writev;
117#if defined(__NR_process_vm_writev)
118 cma_test_params = cma_test_params_write;
119#else
120 tst_brkm(TCONF, NULL, "process_vm_writev does not"
Wanlong Gao354ebb42012-12-07 10:10:04 +0800121 " exist on your system.");
Jan Stancek5d56dd52012-06-11 16:09:50 +0200122#endif
123 } else
124 tst_brkm(TBROK, NULL, "Parameter missing, required -r or -w.");
125 TEST_PAUSE;
126}
127
128static void cleanup(void)
129{
Jan Stancek5d56dd52012-06-11 16:09:50 +0200130}
131
132static void help(void)
133{
134 printf(" -r Use process_vm_readv\n");
135 printf(" -w Use process_vm_writev\n");
136}
137
138static void cma_test_params_read(struct process_vm_params *params)
139{
140 TEST(test_process_vm_readv(params->pid,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800141 params->lvec, params->liovcnt,
142 params->rvec, params->riovcnt,
143 params->flags));
Jan Stancek5d56dd52012-06-11 16:09:50 +0200144}
145
146static void cma_test_params_write(struct process_vm_params *params)
147{
148 TEST(test_process_vm_writev(params->pid,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800149 params->lvec, params->liovcnt,
150 params->rvec, params->riovcnt,
151 params->flags));
Jan Stancek5d56dd52012-06-11 16:09:50 +0200152}
153
154static int cma_check_ret(long expected_ret, long act_ret)
155{
156 if (expected_ret == act_ret) {
157 tst_resm(TPASS, "expected ret success - "
Wanlong Gao354ebb42012-12-07 10:10:04 +0800158 "returned value = %ld", act_ret);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200159 } else {
160 tst_resm(TFAIL, "unexpected failure - "
Wanlong Gao354ebb42012-12-07 10:10:04 +0800161 "returned value = %ld, expected: %ld",
162 act_ret, expected_ret);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200163 return 1;
164 }
165 return 0;
166}
167
168static int cma_check_errno(long expected_errno)
169{
170 if (TEST_ERRNO == expected_errno)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800171 tst_resm(TPASS | TTERRNO, "expected failure");
Jan Stancek5d56dd52012-06-11 16:09:50 +0200172 else if (TEST_ERRNO == 0) {
173 tst_resm(TFAIL, "call succeeded unexpectedly");
174 return 1;
175 } else {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800176 tst_resm(TFAIL | TTERRNO, "unexpected failure - "
177 "expected = %ld : %s, actual",
178 expected_errno, strerror(expected_errno));
Jan Stancek5d56dd52012-06-11 16:09:50 +0200179 return 2;
180 }
181 return 0;
182}
183
Mike Frysingerc57fba52014-04-09 18:56:30 -0400184static struct process_vm_params *cma_alloc_sane_params(void)
Jan Stancek5d56dd52012-06-11 16:09:50 +0200185{
186 struct process_vm_params *sane_params;
187 int len;
188
189 len = getpagesize();
190 sane_params = SAFE_MALLOC(NULL, sizeof(struct process_vm_params));
191 sane_params->len = len;
192 sane_params->ldummy = SAFE_MALLOC(NULL, len);
193 sane_params->rdummy = SAFE_MALLOC(NULL, len);
194
195 sane_params->lvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
196 sane_params->lvec->iov_base = sane_params->ldummy;
197 sane_params->lvec->iov_len = len;
198 sane_params->liovcnt = 1;
199
200 sane_params->rvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
201 sane_params->rvec->iov_base = sane_params->rdummy;
202 sane_params->rvec->iov_len = len;
203 sane_params->riovcnt = 1;
204
205 sane_params->flags = 0;
206 sane_params->pid = getpid();
207
208 return sane_params;
209}
210
211static void cma_free_params(struct process_vm_params *params)
212{
213 if (params) {
214 free(params->ldummy);
215 free(params->rdummy);
216 free(params->lvec);
217 free(params->rvec);
218 free(params);
219 }
220}
221
222static void cma_test_sane_params(void)
223{
224 struct process_vm_params *sane_params;
225
226 sane_params = cma_alloc_sane_params();
227 tst_resm(TINFO, "test_sane_params");
228 cma_test_params(sane_params);
229 cma_check_ret(sane_params->len, TEST_RETURN);
230 cma_free_params(sane_params);
231}
232
233static void cma_test_flags(void)
234{
235 struct process_vm_params *params;
236 long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 };
Wanlong Gao354ebb42012-12-07 10:10:04 +0800237 int flags_size = sizeof(flags) / sizeof(flags[0]);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200238 int i;
239
240 params = cma_alloc_sane_params();
241 for (i = 0; i < flags_size; i++) {
242 params->flags = flags[i];
243 tst_resm(TINFO, "test_flags, flags=%ld", flags[i]);
244 cma_test_params(params);
245 /* atm. only flags == 0 is allowed, everything else
246 * should fail with EINVAL */
247 if (flags[i] != 0) {
248 cma_check_ret(-1, TEST_RETURN);
249 cma_check_errno(EINVAL);
250 } else {
251 cma_check_ret(params->len, TEST_RETURN);
252 }
253 }
254 cma_free_params(params);
255}
256
257static void cma_test_iov_len_overflow(void)
258{
259 struct process_vm_params *params;
260 ssize_t maxlen = -1;
261 params = cma_alloc_sane_params();
262
263 params->lvec->iov_len = maxlen;
264 params->rvec->iov_len = maxlen;
265 tst_resm(TINFO, "test_iov_len_overflow");
266 cma_test_params(params);
267 cma_check_ret(-1, TEST_RETURN);
268 cma_check_errno(EINVAL);
269 cma_free_params(params);
270}
271
272static void cma_test_iov_invalid(void)
273{
274 struct process_vm_params *sane_params;
275 struct process_vm_params params_copy;
276
277 sane_params = cma_alloc_sane_params();
278 /* make a shallow copy we can 'damage' */
279
280 params_copy = *sane_params;
281 tst_resm(TINFO, "test_iov_invalid - lvec->iov_base");
282 params_copy.lvec->iov_base = (void *)-1;
283 cma_test_params(&params_copy);
284 cma_check_ret(-1, TEST_RETURN);
285 cma_check_errno(EFAULT);
286
287 params_copy = *sane_params;
288 tst_resm(TINFO, "test_iov_invalid - rvec->iov_base");
289 params_copy.rvec->iov_base = (void *)-1;
290 cma_test_params(&params_copy);
291 cma_check_ret(-1, TEST_RETURN);
292 cma_check_errno(EFAULT);
293
294 params_copy = *sane_params;
295 tst_resm(TINFO, "test_iov_invalid - lvec");
296 params_copy.lvec = (void *)-1;
297 cma_test_params(&params_copy);
298 cma_check_ret(-1, TEST_RETURN);
299 cma_check_errno(EFAULT);
300
301 params_copy = *sane_params;
302 tst_resm(TINFO, "test_iov_invalid - rvec");
303 params_copy.rvec = (void *)-1;
304 cma_test_params(&params_copy);
305 cma_check_ret(-1, TEST_RETURN);
306 cma_check_errno(EFAULT);
307
308 cma_free_params(sane_params);
309}
310
311static void cma_test_invalid_pid(void)
312{
Jan Stancek5d56dd52012-06-11 16:09:50 +0200313 pid_t invalid_pid = -1;
314 struct process_vm_params *params;
Jan Stancek5d56dd52012-06-11 16:09:50 +0200315
316 params = cma_alloc_sane_params();
317 tst_resm(TINFO, "test_invalid_pid");
318 params->pid = invalid_pid;
319 cma_test_params(params);
320 cma_check_ret(-1, TEST_RETURN);
321 cma_check_errno(ESRCH);
322 cma_free_params(params);
323
Stanislav Kholmanskikh23b37f32014-06-30 14:48:24 +0400324 invalid_pid = tst_get_unused_pid(cleanup);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200325
326 params = cma_alloc_sane_params();
327 params->pid = invalid_pid;
328 cma_test_params(params);
329 cma_check_ret(-1, TEST_RETURN);
330 cma_check_errno(ESRCH);
331 cma_free_params(params);
332}
333
334static void cma_test_invalid_perm(void)
335{
336 char nobody_uid[] = "nobody";
337 struct passwd *ltpuser;
338 int status;
339 struct process_vm_params *params;
340 pid_t child_pid;
341 pid_t parent_pid;
342 int ret = 0;
343
344 tst_resm(TINFO, "test_invalid_perm");
345 parent_pid = getpid();
346 child_pid = fork();
347 switch (child_pid) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800348 case -1:
349 tst_brkm(TBROK | TERRNO, cleanup, "fork");
350 break;
351 case 0:
352 ltpuser = getpwnam(nobody_uid);
353 if (ltpuser == NULL)
354 tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed");
355 if (setuid(ltpuser->pw_uid) == -1)
356 tst_brkm(TBROK | TERRNO, NULL,
357 "setuid(%u) failed", ltpuser->pw_uid);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200358
Wanlong Gao354ebb42012-12-07 10:10:04 +0800359 params = cma_alloc_sane_params();
360 params->pid = parent_pid;
361 cma_test_params(params);
362 ret |= cma_check_ret(-1, TEST_RETURN);
363 ret |= cma_check_errno(EPERM);
364 cma_free_params(params);
365 exit(ret);
366 default:
367 if (waitpid(child_pid, &status, 0) == -1)
368 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
369 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
370 tst_resm(TFAIL, "child returns %d", status);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200371 }
372}
373
374static void cma_test_invalid_protection(void)
375{
376 struct process_vm_params *sane_params;
377 struct process_vm_params params_copy;
378 void *p;
379
380 sane_params = cma_alloc_sane_params();
381 /* make a shallow copy we can 'damage' */
382
383 p = mmap(NULL, getpagesize(), PROT_NONE,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800384 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
Jan Stancek5d56dd52012-06-11 16:09:50 +0200385 if (p == MAP_FAILED)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800386 tst_brkm(TBROK | TERRNO, cleanup, "mmap");
Jan Stancek5d56dd52012-06-11 16:09:50 +0200387
388 params_copy = *sane_params;
389 params_copy.lvec->iov_base = p;
390 tst_resm(TINFO, "test_invalid_protection lvec");
391 cma_test_params(&params_copy);
392 cma_check_ret(-1, TEST_RETURN);
393 cma_check_errno(EFAULT);
394
395 params_copy = *sane_params;
396 params_copy.rvec->iov_base = p;
397 tst_resm(TINFO, "test_invalid_protection rvec");
398 cma_test_params(&params_copy);
399 cma_check_ret(-1, TEST_RETURN);
400 cma_check_errno(EFAULT);
401
402 if (munmap(p, getpagesize()) < 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800403 tst_brkm(TBROK | TERRNO, cleanup, "munmap");
Jan Stancek5d56dd52012-06-11 16:09:50 +0200404
405 cma_free_params(sane_params);
406}
407
Mike Frysingerc57fba52014-04-09 18:56:30 -0400408static void cma_test_errnos(void)
Jan Stancek5d56dd52012-06-11 16:09:50 +0200409{
410 cma_test_sane_params();
411 cma_test_flags();
412 cma_test_iov_len_overflow();
413 cma_test_iov_invalid();
414 cma_test_invalid_pid();
415 cma_test_invalid_perm();
416 cma_test_invalid_protection();
417}