1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Author: Rajeev Tiwari: rajeevti (at) in.ibm.com 4 * Copyright (c) 2004 Gernot Payer <gpayer (at) suse.de> 5 * Copyright (c) 2013 Cyril Hrubis <chrubis (at) suse.cz> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 15 * the GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22 /* 23 * test1: 24 * Invoke mincore() when the start address is not multiple of page size. 25 * EINVAL 26 * test2: 27 * Invoke mincore() when the vector points to an invalid address. EFAULT 28 * test3: 29 * Invoke mincore() when the starting address + length contained unmapped 30 * memory. ENOMEM 31 * test4: 32 * Invoke mincore() when length is greater than (TASK_SIZE - addr). ENOMEM 33 * In Linux 2.6.11 and earlier, the error EINVAL was returned for this 34 * condition. 35 */ 36 37 #include <fcntl.h> 38 #include <errno.h> 39 #include <sys/mman.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 #include <sys/resource.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include "test.h" 46 #include "safe_macros.h" 47 48 static int pagesize; 49 static rlim_t STACK_LIMIT = 10485760; 50 51 static void cleanup(void); 52 static void setup(void); 53 54 char *TCID = "mincore01"; 55 56 static char *global_pointer; 57 static unsigned char *global_vec; 58 static int global_len; 59 60 struct test_case_t; 61 static void setup1(struct test_case_t *tc); 62 static void setup2(struct test_case_t *tc); 63 static void setup3(struct test_case_t *tc); 64 static void setup4(struct test_case_t *tc); 65 66 static struct test_case_t { 67 char *addr; 68 size_t len; 69 unsigned char *vector; 70 int exp_errno; 71 void (*setupfunc) (struct test_case_t *tc); 72 } TC[] = { 73 {NULL, 0, NULL, EINVAL, setup1}, 74 {NULL, 0, NULL, EFAULT, setup2}, 75 {NULL, 0, NULL, ENOMEM, setup3}, 76 {NULL, 0, NULL, ENOMEM, setup4} 77 }; 78 79 static void mincore_verify(struct test_case_t *tc); 80 81 int TST_TOTAL = ARRAY_SIZE(TC); 82 83 int main(int ac, char **av) 84 { 85 int i, lc; 86 87 tst_parse_opts(ac, av, NULL, NULL); 88 89 setup(); 90 91 for (lc = 0; TEST_LOOPING(lc); lc++) { 92 tst_count = 0; 93 94 for (i = 0; i < TST_TOTAL; i++) 95 mincore_verify(&TC[i]); 96 } 97 98 cleanup(); 99 tst_exit(); 100 } 101 102 static void setup1(struct test_case_t *tc) 103 { 104 tc->addr = global_pointer + 1; 105 tc->len = global_len; 106 tc->vector = global_vec; 107 } 108 109 void setup2(struct test_case_t *tc) 110 { 111 unsigned char *t; 112 struct rlimit limit; 113 114 t = SAFE_MMAP(cleanup, NULL, global_len, PROT_READ | PROT_WRITE, 115 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 116 117 SAFE_MUNMAP(cleanup, t, global_len); 118 119 /* set stack limit so that the unmaped pointer is invalid for architectures like s390 */ 120 limit.rlim_cur = STACK_LIMIT; 121 limit.rlim_max = STACK_LIMIT; 122 123 if (setrlimit(RLIMIT_STACK, &limit) != 0) 124 tst_brkm(TBROK | TERRNO, cleanup, "setrlimit failed"); 125 126 tc->addr = global_pointer; 127 tc->len = global_len; 128 tc->vector = t; 129 } 130 131 static void setup3(struct test_case_t *tc) 132 { 133 tc->addr = global_pointer; 134 tc->len = global_len * 2; 135 SAFE_MUNMAP(cleanup, global_pointer + global_len, global_len); 136 tc->vector = global_vec; 137 } 138 139 static void setup4(struct test_case_t *tc) 140 { 141 struct rlimit as_lim; 142 143 SAFE_GETRLIMIT(cleanup, RLIMIT_AS, &as_lim); 144 145 tc->addr = global_pointer; 146 tc->len = as_lim.rlim_cur - (rlim_t)global_pointer + pagesize; 147 tc->vector = global_vec; 148 149 /* 150 * In linux 2.6.11 and earlier, EINVAL was returned for this condition. 151 */ 152 if (tst_kvercmp(2, 6, 11) <= 0) 153 tc->exp_errno = EINVAL; 154 } 155 156 static void setup(void) 157 { 158 char *buf; 159 int fd; 160 161 pagesize = getpagesize(); 162 163 tst_sig(NOFORK, DEF_HANDLER, cleanup); 164 165 tst_tmpdir(); 166 167 TEST_PAUSE; 168 169 /* global_pointer will point to a mmapped area of global_len bytes */ 170 global_len = pagesize * 2; 171 172 buf = SAFE_MALLOC(cleanup, global_len); 173 memset(buf, 42, global_len); 174 175 fd = SAFE_OPEN(cleanup, "mincore01", O_CREAT | O_RDWR, 176 S_IRUSR | S_IWUSR); 177 178 SAFE_WRITE(cleanup, 1, fd, buf, global_len); 179 180 free(buf); 181 182 global_pointer = SAFE_MMAP(cleanup, NULL, global_len * 2, 183 PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 184 185 global_vec = SAFE_MALLOC(cleanup, 186 (global_len + pagesize - 1) / pagesize); 187 188 SAFE_CLOSE(cleanup, fd); 189 } 190 191 static void mincore_verify(struct test_case_t *tc) 192 { 193 if (tc->setupfunc) 194 tc->setupfunc(tc); 195 196 TEST(mincore(tc->addr, tc->len, tc->vector)); 197 198 if (TEST_RETURN != -1) { 199 tst_resm(TFAIL, "succeeded unexpectedly"); 200 return; 201 } 202 203 if (TEST_ERRNO == tc->exp_errno) { 204 tst_resm(TPASS | TTERRNO, "failed as expected"); 205 } else { 206 tst_resm(TFAIL | TTERRNO, 207 "mincore failed unexpectedly; expected: " 208 "%d - %s", tc->exp_errno, 209 strerror(tc->exp_errno)); 210 } 211 } 212 213 static void cleanup(void) 214 { 215 free(global_vec); 216 217 if (munmap(global_pointer, global_len) == -1) 218 tst_resm(TWARN | TERRNO, "munmap failed"); 219 220 tst_rmdir(); 221 } 222