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 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 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 125 static void cleanup(void) 126 { 127 } 128 129 static void help(void) 130 { 131 printf(" -r Use process_vm_readv\n"); 132 printf(" -w Use process_vm_writev\n"); 133 } 134 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 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 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 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 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 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 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 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 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 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 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 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 if (setuid(ltpuser->pw_uid) == -1) 353 tst_brkm(TBROK | TERRNO, NULL, 354 "setuid(%u) failed", ltpuser->pw_uid); 355 356 params = cma_alloc_sane_params(); 357 params->pid = parent_pid; 358 cma_test_params(params); 359 ret |= cma_check_ret(-1, TEST_RETURN); 360 ret |= cma_check_errno(EPERM); 361 cma_free_params(params); 362 exit(ret); 363 default: 364 if (waitpid(child_pid, &status, 0) == -1) 365 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 366 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 367 tst_resm(TFAIL, "child returns %d", status); 368 } 369 } 370 371 static void cma_test_invalid_protection(void) 372 { 373 struct process_vm_params *sane_params; 374 struct process_vm_params params_copy; 375 void *p; 376 377 sane_params = cma_alloc_sane_params(); 378 /* make a shallow copy we can 'damage' */ 379 380 p = mmap(NULL, getpagesize(), PROT_NONE, 381 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 382 if (p == MAP_FAILED) 383 tst_brkm(TBROK | TERRNO, cleanup, "mmap"); 384 385 params_copy = *sane_params; 386 params_copy.lvec->iov_base = p; 387 tst_resm(TINFO, "test_invalid_protection lvec"); 388 cma_test_params(¶ms_copy); 389 cma_check_ret(-1, TEST_RETURN); 390 cma_check_errno(EFAULT); 391 392 params_copy = *sane_params; 393 params_copy.rvec->iov_base = p; 394 tst_resm(TINFO, "test_invalid_protection rvec"); 395 cma_test_params(¶ms_copy); 396 cma_check_ret(-1, TEST_RETURN); 397 cma_check_errno(EFAULT); 398 399 if (munmap(p, getpagesize()) < 0) 400 tst_brkm(TBROK | TERRNO, cleanup, "munmap"); 401 402 cma_free_params(sane_params); 403 } 404 405 static void cma_test_errnos(void) 406 { 407 cma_test_sane_params(); 408 cma_test_flags(); 409 cma_test_iov_len_overflow(); 410 cma_test_iov_invalid(); 411 cma_test_invalid_pid(); 412 cma_test_invalid_perm(); 413 cma_test_invalid_protection(); 414 } 415