Home | History | Annotate | Download | only in cma
      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(&params_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(&params_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(&params_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(&params_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 		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 
    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(&params_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(&params_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 
    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