1 /*
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"
44 #include "safe_macros.h"
45 #include "process_vm.h"
46
47 struct 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
59 static int rflag;
60 static int wflag;
61
62 static option_t options[] = {
63 {"r", &rflag, NULL},
64 {"w", &wflag, NULL},
65 {NULL, NULL, NULL}
66 };
67
68 static char TCID_readv[] = "process_vm_readv";
69 static char TCID_writev[] = "process_vm_writev";
70 char *TCID = "cma01";
71 int TST_TOTAL = 1;
72 static void (*cma_test_params) (struct process_vm_params * params) = NULL;
73
74 static void setup(char *argv[]);
75 static void cleanup(void);
76 static void help(void);
77
78 static void cma_test_params_read(struct process_vm_params *params);
79 static void cma_test_params_write(struct process_vm_params *params);
80 static void cma_test_errnos(void);
81
main(int argc,char * argv[])82 int main(int argc, char *argv[])
83 {
84 int lc;
85
86 tst_parse_opts(argc, argv, options, &help);
87
88 setup(argv);
89 for (lc = 0; TEST_LOOPING(lc); lc++) {
90 tst_count = 0;
91 cma_test_errnos();
92 }
93 cleanup();
94 tst_exit();
95 }
96
setup(char * argv[])97 static void setup(char *argv[])
98 {
99 tst_require_root();
100
101 if (rflag && wflag)
102 tst_brkm(TBROK, NULL, "Parameters -r -w can not be used"
103 " at the same time.");
104 else if (rflag) {
105 TCID = TCID_readv;
106 #if defined(__NR_process_vm_readv)
107 cma_test_params = cma_test_params_read;
108 #else
109 tst_brkm(TCONF, NULL, "process_vm_readv does not"
110 " exist on your system.");
111 #endif
112 } else if (wflag) {
113 TCID = TCID_writev;
114 #if defined(__NR_process_vm_writev)
115 cma_test_params = cma_test_params_write;
116 #else
117 tst_brkm(TCONF, NULL, "process_vm_writev does not"
118 " exist on your system.");
119 #endif
120 } else
121 tst_brkm(TBROK, NULL, "Parameter missing, required -r or -w.");
122 TEST_PAUSE;
123 }
124
cleanup(void)125 static void cleanup(void)
126 {
127 }
128
help(void)129 static void help(void)
130 {
131 printf(" -r Use process_vm_readv\n");
132 printf(" -w Use process_vm_writev\n");
133 }
134
cma_test_params_read(struct process_vm_params * params)135 static void cma_test_params_read(struct process_vm_params *params)
136 {
137 TEST(test_process_vm_readv(params->pid,
138 params->lvec, params->liovcnt,
139 params->rvec, params->riovcnt,
140 params->flags));
141 }
142
cma_test_params_write(struct process_vm_params * params)143 static void cma_test_params_write(struct process_vm_params *params)
144 {
145 TEST(test_process_vm_writev(params->pid,
146 params->lvec, params->liovcnt,
147 params->rvec, params->riovcnt,
148 params->flags));
149 }
150
cma_check_ret(long expected_ret,long act_ret)151 static int cma_check_ret(long expected_ret, long act_ret)
152 {
153 if (expected_ret == act_ret) {
154 tst_resm(TPASS, "expected ret success - "
155 "returned value = %ld", act_ret);
156 } else {
157 tst_resm(TFAIL, "unexpected failure - "
158 "returned value = %ld, expected: %ld",
159 act_ret, expected_ret);
160 return 1;
161 }
162 return 0;
163 }
164
cma_check_errno(long expected_errno)165 static int cma_check_errno(long expected_errno)
166 {
167 if (TEST_ERRNO == expected_errno)
168 tst_resm(TPASS | TTERRNO, "expected failure");
169 else if (TEST_ERRNO == 0) {
170 tst_resm(TFAIL, "call succeeded unexpectedly");
171 return 1;
172 } else {
173 tst_resm(TFAIL | TTERRNO, "unexpected failure - "
174 "expected = %ld : %s, actual",
175 expected_errno, strerror(expected_errno));
176 return 2;
177 }
178 return 0;
179 }
180
cma_alloc_sane_params(void)181 static struct process_vm_params *cma_alloc_sane_params(void)
182 {
183 struct process_vm_params *sane_params;
184 int len;
185
186 len = getpagesize();
187 sane_params = SAFE_MALLOC(NULL, sizeof(struct process_vm_params));
188 sane_params->len = len;
189 sane_params->ldummy = SAFE_MALLOC(NULL, len);
190 sane_params->rdummy = SAFE_MALLOC(NULL, len);
191
192 sane_params->lvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
193 sane_params->lvec->iov_base = sane_params->ldummy;
194 sane_params->lvec->iov_len = len;
195 sane_params->liovcnt = 1;
196
197 sane_params->rvec = SAFE_MALLOC(NULL, sizeof(struct iovec));
198 sane_params->rvec->iov_base = sane_params->rdummy;
199 sane_params->rvec->iov_len = len;
200 sane_params->riovcnt = 1;
201
202 sane_params->flags = 0;
203 sane_params->pid = getpid();
204
205 return sane_params;
206 }
207
cma_free_params(struct process_vm_params * params)208 static void cma_free_params(struct process_vm_params *params)
209 {
210 if (params) {
211 free(params->ldummy);
212 free(params->rdummy);
213 free(params->lvec);
214 free(params->rvec);
215 free(params);
216 }
217 }
218
cma_test_sane_params(void)219 static void cma_test_sane_params(void)
220 {
221 struct process_vm_params *sane_params;
222
223 sane_params = cma_alloc_sane_params();
224 tst_resm(TINFO, "test_sane_params");
225 cma_test_params(sane_params);
226 cma_check_ret(sane_params->len, TEST_RETURN);
227 cma_free_params(sane_params);
228 }
229
cma_test_flags(void)230 static void cma_test_flags(void)
231 {
232 struct process_vm_params *params;
233 long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 };
234 int flags_size = sizeof(flags) / sizeof(flags[0]);
235 int i;
236
237 params = cma_alloc_sane_params();
238 for (i = 0; i < flags_size; i++) {
239 params->flags = flags[i];
240 tst_resm(TINFO, "test_flags, flags=%ld", flags[i]);
241 cma_test_params(params);
242 /* atm. only flags == 0 is allowed, everything else
243 * should fail with EINVAL */
244 if (flags[i] != 0) {
245 cma_check_ret(-1, TEST_RETURN);
246 cma_check_errno(EINVAL);
247 } else {
248 cma_check_ret(params->len, TEST_RETURN);
249 }
250 }
251 cma_free_params(params);
252 }
253
cma_test_iov_len_overflow(void)254 static void cma_test_iov_len_overflow(void)
255 {
256 struct process_vm_params *params;
257 ssize_t maxlen = -1;
258 params = cma_alloc_sane_params();
259
260 params->lvec->iov_len = maxlen;
261 params->rvec->iov_len = maxlen;
262 tst_resm(TINFO, "test_iov_len_overflow");
263 cma_test_params(params);
264 cma_check_ret(-1, TEST_RETURN);
265 cma_check_errno(EINVAL);
266 cma_free_params(params);
267 }
268
cma_test_iov_invalid(void)269 static void cma_test_iov_invalid(void)
270 {
271 struct process_vm_params *sane_params;
272 struct process_vm_params params_copy;
273
274 sane_params = cma_alloc_sane_params();
275 /* make a shallow copy we can 'damage' */
276
277 params_copy = *sane_params;
278 tst_resm(TINFO, "test_iov_invalid - lvec->iov_base");
279 params_copy.lvec->iov_base = (void *)-1;
280 cma_test_params(¶ms_copy);
281 cma_check_ret(-1, TEST_RETURN);
282 cma_check_errno(EFAULT);
283
284 params_copy = *sane_params;
285 tst_resm(TINFO, "test_iov_invalid - rvec->iov_base");
286 params_copy.rvec->iov_base = (void *)-1;
287 cma_test_params(¶ms_copy);
288 cma_check_ret(-1, TEST_RETURN);
289 cma_check_errno(EFAULT);
290
291 params_copy = *sane_params;
292 tst_resm(TINFO, "test_iov_invalid - lvec");
293 params_copy.lvec = (void *)-1;
294 cma_test_params(¶ms_copy);
295 cma_check_ret(-1, TEST_RETURN);
296 cma_check_errno(EFAULT);
297
298 params_copy = *sane_params;
299 tst_resm(TINFO, "test_iov_invalid - rvec");
300 params_copy.rvec = (void *)-1;
301 cma_test_params(¶ms_copy);
302 cma_check_ret(-1, TEST_RETURN);
303 cma_check_errno(EFAULT);
304
305 cma_free_params(sane_params);
306 }
307
cma_test_invalid_pid(void)308 static void cma_test_invalid_pid(void)
309 {
310 pid_t invalid_pid = -1;
311 struct process_vm_params *params;
312
313 params = cma_alloc_sane_params();
314 tst_resm(TINFO, "test_invalid_pid");
315 params->pid = invalid_pid;
316 cma_test_params(params);
317 cma_check_ret(-1, TEST_RETURN);
318 cma_check_errno(ESRCH);
319 cma_free_params(params);
320
321 invalid_pid = tst_get_unused_pid(cleanup);
322
323 params = cma_alloc_sane_params();
324 params->pid = invalid_pid;
325 cma_test_params(params);
326 cma_check_ret(-1, TEST_RETURN);
327 cma_check_errno(ESRCH);
328 cma_free_params(params);
329 }
330
cma_test_invalid_perm(void)331 static void cma_test_invalid_perm(void)
332 {
333 char nobody_uid[] = "nobody";
334 struct passwd *ltpuser;
335 int status;
336 struct process_vm_params *params;
337 pid_t child_pid;
338 pid_t parent_pid;
339 int ret = 0;
340
341 tst_resm(TINFO, "test_invalid_perm");
342 parent_pid = getpid();
343 child_pid = fork();
344 switch (child_pid) {
345 case -1:
346 tst_brkm(TBROK | TERRNO, cleanup, "fork");
347 break;
348 case 0:
349 ltpuser = getpwnam(nobody_uid);
350 if (ltpuser == NULL)
351 tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed");
352 SAFE_SETUID(NULL, ltpuser->pw_uid);
353
354 params = cma_alloc_sane_params();
355 params->pid = parent_pid;
356 cma_test_params(params);
357 ret |= cma_check_ret(-1, TEST_RETURN);
358 ret |= cma_check_errno(EPERM);
359 cma_free_params(params);
360 exit(ret);
361 default:
362 SAFE_WAITPID(cleanup, child_pid, &status, 0);
363 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
364 tst_resm(TFAIL, "child returns %d", status);
365 }
366 }
367
cma_test_invalid_protection(void)368 static void cma_test_invalid_protection(void)
369 {
370 struct process_vm_params *sane_params;
371 struct process_vm_params params_copy;
372 void *p;
373
374 sane_params = cma_alloc_sane_params();
375 /* make a shallow copy we can 'damage' */
376
377 p = mmap(NULL, getpagesize(), PROT_NONE,
378 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
379 if (p == MAP_FAILED)
380 tst_brkm(TBROK | TERRNO, cleanup, "mmap");
381
382 params_copy = *sane_params;
383 params_copy.lvec->iov_base = p;
384 tst_resm(TINFO, "test_invalid_protection lvec");
385 cma_test_params(¶ms_copy);
386 cma_check_ret(-1, TEST_RETURN);
387 cma_check_errno(EFAULT);
388
389 params_copy = *sane_params;
390 params_copy.rvec->iov_base = p;
391 tst_resm(TINFO, "test_invalid_protection rvec");
392 cma_test_params(¶ms_copy);
393 cma_check_ret(-1, TEST_RETURN);
394 cma_check_errno(EFAULT);
395
396 SAFE_MUNMAP(cleanup, p, getpagesize());
397
398 cma_free_params(sane_params);
399 }
400
cma_test_errnos(void)401 static void cma_test_errnos(void)
402 {
403 cma_test_sane_params();
404 cma_test_flags();
405 cma_test_iov_len_overflow();
406 cma_test_iov_invalid();
407 cma_test_invalid_pid();
408 cma_test_invalid_perm();
409 cma_test_invalid_protection();
410 }
411