1 /* 2 * Copyright (C) Bull S.A. 2005. $ 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * You should have received a copy of the GNU General Public License along 13 * with this program; if not, write the Free Software Foundation, Inc., 14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 * 16 */ 17 /************************************************************************** 18 * 19 * TEST IDENTIFIER : mlockall03 20 * 21 * EXECUTED BY : root / superuser 22 * 23 * TEST TITLE : Test for checking basic error conditions for 24 * mlockall(2) 25 * 26 * TEST CASE TOTAL : 3 27 * 28 * AUTHOR : Jacky Malcles 29 * 30 * SIGNALS 31 * Uses SIGUSR1 to pause before test if option set. 32 * (See the parse_opts(3) man page). 33 * 34 * DESCRIPTION 35 *$ 36 * Verify that mlockall(2) returns -1 and sets errno to 37 * 38 * 1) ENOMEM - If the caller had a non-zero RLIMIT_MEMLOCK 39 * and tried to lock more memory than the limit permitted. 40 * 2) EPERM - If the caller was not privileged 41 * and its RLIMIT_MEMLOCK soft resource limit was 0. 42 * 3) EINVAL - Unknown flags were specified. 43 * 44 * Setup: 45 * Setup signal handling. 46 * Pause for SIGUSR1 if option specified. 47 * 48 * Test: 49 * Loop if the proper options are given. 50 * Do necessary setup for each test. 51 * Execute system call 52 * Check return code, if system call failed and errno == expected errno 53 * Issue sys call passed with expected return value and errno. 54 * Otherwise, 55 * Issue sys call failed to produce expected error. 56 * Do cleanup for each test. 57 * 58 * Cleanup: 59 * Print errno log and/or timing stats if options given 60 * 61 * USAGE: <for command-line> 62 * mlockall03 [-c n] [-e] [-i n] [-I x] [-p x] [-t] 63 * where, 64 * -c n : Run n copies concurrently 65 * -e : Turn on errno logging. 66 * -h : Show this help screen 67 * -i n : Execute test n times. 68 * -I x : Execute test for x seconds. 69 * -p : Pause for SIGUSR1 before starting 70 * -P x : Pause for x seconds between iterations. 71 * -t : Turn on syscall timing. 72 * 73 * RESTRICTIONS 74 * Test must run as root. 75 *****************************************************************************/ 76 #include <errno.h> 77 #include <unistd.h> 78 #include <pwd.h> 79 #include <ctype.h> 80 #include <sys/mman.h> 81 #include "test.h" 82 #include <sys/resource.h> 83 #include <sys/utsname.h> 84 85 void setup(); 86 int setup_test(int); 87 int compare(char s1[], char s2[]); 88 void cleanup_test(int); 89 void cleanup(); 90 91 char *TCID = "mlockall03"; 92 int TST_TOTAL = 3; 93 94 #if !defined(UCLINUX) 95 96 char *ref_release = "2.6.8\0"; 97 98 struct test_case_t { 99 int flag; /* flag value */ 100 int error; /* error description */ 101 char *edesc; /* Expected error no */ 102 } TC[] = { 103 { 104 MCL_CURRENT, ENOMEM, 105 "tried to lock more memory than the limit permitted"}, { 106 MCL_CURRENT, EPERM, "Not a superuser and RLIMIT_MEMLOCK was 0"}, { 107 ~(MCL_CURRENT | MCL_FUTURE), EINVAL, "Unknown flag"} 108 }; 109 110 int main(int ac, char **av) 111 { 112 int lc, i; 113 struct utsname *buf; 114 115 tst_parse_opts(ac, av, NULL, NULL); 116 117 /* allocate some space for buf */ 118 if ((buf = malloc((size_t)sizeof(struct utsname))) == NULL) { 119 tst_brkm(TFAIL, NULL, "malloc failed for buf"); 120 } 121 122 if (uname(buf) < 0) { 123 tst_resm(TFAIL, "uname failed getting release number"); 124 } 125 126 if ((compare(ref_release, buf->release)) <= 0) { 127 tst_brkm(TCONF, 128 NULL, 129 "In Linux 2.6.8 and earlier this test will not run."); 130 } 131 132 setup(); 133 134 /* check looping state */ 135 for (lc = 0; TEST_LOOPING(lc); lc++) { 136 137 tst_count = 0; 138 139 for (i = 0; i < TST_TOTAL; i++) { 140 141 if (setup_test(i)) { 142 tst_resm(TFAIL, "mlockall() Failed while setup " 143 "for checking error %s", TC[i].edesc); 144 continue; 145 } 146 147 TEST(mlockall(TC[i].flag)); 148 149 /* check return code */ 150 if (TEST_RETURN == -1) { 151 if (TEST_ERRNO != TC[i].error) 152 tst_brkm(TFAIL, cleanup, 153 "mlockall() Failed with wrong " 154 "errno, expected errno=%s, " 155 "got errno=%d : %s", 156 TC[i].edesc, TEST_ERRNO, 157 strerror(TEST_ERRNO)); 158 else 159 tst_resm(TPASS, 160 "expected failure - errno " 161 "= %d : %s", 162 TEST_ERRNO, 163 strerror(TEST_ERRNO)); 164 } else { 165 tst_brkm(TFAIL, cleanup, 166 "mlockall() Failed, expected " 167 "return value=-1, got %ld", 168 TEST_RETURN); 169 } 170 cleanup_test(i); 171 } 172 } 173 174 /* cleanup and exit */ 175 cleanup(); 176 177 tst_exit(); 178 } 179 180 /* 181 * setup() - performs all ONE TIME setup for this test. 182 */ 183 void setup(void) 184 { 185 186 tst_require_root(); 187 188 tst_sig(FORK, DEF_HANDLER, cleanup); 189 190 TEST_PAUSE; 191 192 return; 193 } 194 195 int compare(char s1[], char s2[]) 196 { 197 int i = 0; 198 while (s1[i] == s2[i] && s1[i]) 199 i++; 200 201 if (i < 4) 202 return s2[i] - s1[i]; 203 if ((i == 4) && (isalnum(s2[i + 1]))) { 204 return 1; 205 } else { 206 /* it is not an alphanumeric character */ 207 return s2[i] - s1[i]; 208 } 209 return 0; 210 } 211 212 int setup_test(int i) 213 { 214 struct rlimit rl; 215 char nobody_uid[] = "nobody"; 216 struct passwd *ltpuser; 217 218 switch (i) { 219 case 0: 220 ltpuser = getpwnam(nobody_uid); 221 if (seteuid(ltpuser->pw_uid) == -1) { 222 tst_brkm(TBROK, cleanup, "seteuid() failed to " 223 "change euid to %d errno = %d : %s", 224 ltpuser->pw_uid, TEST_ERRNO, 225 strerror(TEST_ERRNO)); 226 return 1; 227 } 228 229 rl.rlim_max = 10; 230 rl.rlim_cur = 7; 231 232 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { 233 tst_resm(TWARN, "setrlimit failed to set the " 234 "resource for RLIMIT_MEMLOCK to check " 235 "for mlockall() error %s\n", TC[i].edesc); 236 return 1; 237 } 238 return 0; 239 case 1: 240 rl.rlim_max = 0; 241 rl.rlim_cur = 0; 242 243 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { 244 tst_resm(TWARN, "setrlimit failed to set the " 245 "resource for RLIMIT_MEMLOCK to check " 246 "for mlockall() error %s\n", TC[i].edesc); 247 return 1; 248 } 249 250 ltpuser = getpwnam(nobody_uid); 251 if (seteuid(ltpuser->pw_uid) == -1) { 252 tst_brkm(TBROK, cleanup, "seteuid() failed to " 253 "change euid to %d errno = %d : %s", 254 ltpuser->pw_uid, TEST_ERRNO, 255 strerror(TEST_ERRNO)); 256 return 1; 257 } 258 259 return 0; 260 } 261 return 0; 262 } 263 264 void cleanup_test(int i) 265 { 266 struct rlimit rl; 267 268 switch (i) { 269 case 0: 270 if (seteuid(0) == -1) { 271 tst_brkm(TBROK, cleanup, "seteuid() failed to " 272 "change euid to %d errno = %d : %s", 273 0, TEST_ERRNO, strerror(TEST_ERRNO)); 274 } 275 276 rl.rlim_max = -1; 277 rl.rlim_cur = -1; 278 279 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { 280 tst_brkm(TFAIL, cleanup, 281 "setrlimit failed to reset the " 282 "resource for RLIMIT_MEMLOCK while " 283 "checking for mlockall() error %s\n", 284 TC[i].edesc); 285 } 286 287 return; 288 289 case 1: 290 if (seteuid(0) == -1) { 291 tst_brkm(TBROK, cleanup, "seteuid() failed to " 292 "change euid to %d errno = %d : %s", 293 0, TEST_ERRNO, strerror(TEST_ERRNO)); 294 } 295 return; 296 297 } 298 } 299 300 #else 301 302 int main(void) 303 { 304 tst_resm(TINFO, "test is not available on uClinux"); 305 tst_exit(); 306 } 307 308 #endif /* if !defined(UCLINUX) */ 309 310 /* 311 * cleanup() - performs all ONE TIME cleanup for this test at 312 * completion or premature exit. 313 */ 314 void cleanup(void) 315 { 316 return; 317 } 318