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 "safe_macros.h" 83 #include <sys/resource.h> 84 #include <sys/utsname.h> 85 86 void setup(); 87 int setup_test(int); 88 int compare(char s1[], char s2[]); 89 void cleanup_test(int); 90 void cleanup(); 91 92 char *TCID = "mlockall03"; 93 int TST_TOTAL = 3; 94 95 #if !defined(UCLINUX) 96 97 char *ref_release = "2.6.8\0"; 98 99 struct test_case_t { 100 int flag; /* flag value */ 101 int error; /* error description */ 102 char *edesc; /* Expected error no */ 103 } TC[] = { 104 { 105 MCL_CURRENT, ENOMEM, 106 "tried to lock more memory than the limit permitted"}, { 107 MCL_CURRENT, EPERM, "Not a superuser and RLIMIT_MEMLOCK was 0"}, { 108 ~(MCL_CURRENT | MCL_FUTURE), EINVAL, "Unknown flag"} 109 }; 110 111 int main(int ac, char **av) 112 { 113 int lc, i; 114 struct utsname *buf; 115 116 tst_parse_opts(ac, av, NULL, NULL); 117 118 /* allocate some space for buf */ 119 if ((buf = malloc((size_t)sizeof(struct utsname))) == NULL) { 120 tst_brkm(TFAIL, NULL, "malloc failed for buf"); 121 } 122 123 if (uname(buf) < 0) { 124 tst_resm(TFAIL, "uname failed getting release number"); 125 } 126 127 if ((compare(ref_release, buf->release)) <= 0) { 128 tst_brkm(TCONF, 129 NULL, 130 "In Linux 2.6.8 and earlier this test will not run."); 131 } 132 133 setup(); 134 135 /* check looping state */ 136 for (lc = 0; TEST_LOOPING(lc); lc++) { 137 138 tst_count = 0; 139 140 for (i = 0; i < TST_TOTAL; i++) { 141 142 if (setup_test(i)) { 143 tst_resm(TFAIL, "mlockall() Failed while setup " 144 "for checking error %s", TC[i].edesc); 145 continue; 146 } 147 148 TEST(mlockall(TC[i].flag)); 149 150 /* check return code */ 151 if (TEST_RETURN == -1) { 152 if (TEST_ERRNO != TC[i].error) 153 tst_brkm(TFAIL, cleanup, 154 "mlockall() Failed with wrong " 155 "errno, expected errno=%s, " 156 "got errno=%d : %s", 157 TC[i].edesc, TEST_ERRNO, 158 strerror(TEST_ERRNO)); 159 else 160 tst_resm(TPASS, 161 "expected failure - errno " 162 "= %d : %s", 163 TEST_ERRNO, 164 strerror(TEST_ERRNO)); 165 } else { 166 tst_brkm(TFAIL, cleanup, 167 "mlockall() Failed, expected " 168 "return value=-1, got %ld", 169 TEST_RETURN); 170 } 171 cleanup_test(i); 172 } 173 } 174 175 /* cleanup and exit */ 176 cleanup(); 177 178 tst_exit(); 179 } 180 181 /* 182 * setup() - performs all ONE TIME setup for this test. 183 */ 184 void setup(void) 185 { 186 187 tst_require_root(); 188 189 tst_sig(FORK, DEF_HANDLER, cleanup); 190 191 TEST_PAUSE; 192 193 return; 194 } 195 196 int compare(char s1[], char s2[]) 197 { 198 int i = 0; 199 while (s1[i] == s2[i] && s1[i]) 200 i++; 201 202 if (i < 4) 203 return s2[i] - s1[i]; 204 if ((i == 4) && (isalnum(s2[i + 1]))) { 205 return 1; 206 } else { 207 /* it is not an alphanumeric character */ 208 return s2[i] - s1[i]; 209 } 210 return 0; 211 } 212 213 int setup_test(int i) 214 { 215 struct rlimit rl; 216 char nobody_uid[] = "nobody"; 217 struct passwd *ltpuser; 218 219 switch (i) { 220 case 0: 221 ltpuser = getpwnam(nobody_uid); 222 if (seteuid(ltpuser->pw_uid) == -1) { 223 tst_brkm(TBROK, cleanup, "seteuid() failed to " 224 "change euid to %d errno = %d : %s", 225 ltpuser->pw_uid, TEST_ERRNO, 226 strerror(TEST_ERRNO)); 227 return 1; 228 } 229 230 rl.rlim_max = 10; 231 rl.rlim_cur = 7; 232 233 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { 234 tst_resm(TWARN, "setrlimit failed to set the " 235 "resource for RLIMIT_MEMLOCK to check " 236 "for mlockall() error %s\n", TC[i].edesc); 237 return 1; 238 } 239 return 0; 240 case 1: 241 rl.rlim_max = 0; 242 rl.rlim_cur = 0; 243 244 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { 245 tst_resm(TWARN, "setrlimit failed to set the " 246 "resource for RLIMIT_MEMLOCK to check " 247 "for mlockall() error %s\n", TC[i].edesc); 248 return 1; 249 } 250 251 ltpuser = getpwnam(nobody_uid); 252 if (seteuid(ltpuser->pw_uid) == -1) { 253 tst_brkm(TBROK, cleanup, "seteuid() failed to " 254 "change euid to %d errno = %d : %s", 255 ltpuser->pw_uid, TEST_ERRNO, 256 strerror(TEST_ERRNO)); 257 return 1; 258 } 259 260 return 0; 261 } 262 return 0; 263 } 264 265 void cleanup_test(int i) 266 { 267 struct rlimit rl; 268 269 switch (i) { 270 case 0: 271 SAFE_SETEUID(cleanup, 0); 272 273 rl.rlim_max = -1; 274 rl.rlim_cur = -1; 275 276 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { 277 tst_brkm(TFAIL, cleanup, 278 "setrlimit failed to reset the " 279 "resource for RLIMIT_MEMLOCK while " 280 "checking for mlockall() error %s\n", 281 TC[i].edesc); 282 } 283 284 return; 285 286 case 1: 287 SAFE_SETEUID(cleanup, 0); 288 return; 289 290 } 291 } 292 293 #else 294 295 int main(void) 296 { 297 tst_resm(TINFO, "test is not available on uClinux"); 298 tst_exit(); 299 } 300 301 #endif /* if !defined(UCLINUX) */ 302 303 /* 304 * cleanup() - performs all ONE TIME cleanup for this test at 305 * completion or premature exit. 306 */ 307 void cleanup(void) 308 { 309 return; 310 } 311