1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * rmdir03 23 * 24 * DESCRIPTION 25 * check rmdir() fails with EPERM or EACCES 26 * 27 * ALGORITHM 28 * Setup: 29 * Setup signal handling. 30 * Pause for SIGUSR1 if option specified. 31 * Create temporary directory. 32 * 33 * Test: 34 * Loop if the proper options are given. 35 * 1. create a directory tstdir1 and set the sticky bit, then 36 * create directory tstdir2 under tstdir1. Fork a 37 * child , set to be user nobody. Pass tstdir2 to rmdir(2). 38 * Verify the return value is not 0 and the errno is EPERM 39 * or EACCES. 40 * 2. Fork a child, set to be user nobody. Create a directory 41 * tstdir1 and only give write permission to nobody. 42 * Create directory tstdir2 under tstdir1. Fork the second 43 * child , set to be user nobody. Pass tstdir2 to rmdir(2). 44 * Verify the return value is not 0 and the errno is EACCES. 45 * 46 * Cleanup: 47 * Print errno log and/or timing stats if options given 48 * Delete the temporary directory created. 49 * 50 * USAGE 51 * rmdir03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 52 * where, -c n : Run n copies concurrently. 53 * -e : Turn on errno logging. 54 * -i n : Execute test n times. 55 * -I x : Execute test for x seconds. 56 * -P x : Pause for x seconds between iterations. 57 * -t : Turn on syscall timing. 58 * 59 * HISTORY 60 * 07/2001 Ported by Wayne Boyer 61 * 62 * RESTRICTIONS 63 * Test must be run as root. 64 * 65 */ 66 #include <errno.h> 67 #include <string.h> 68 #include <sys/stat.h> 69 #include <sys/types.h> 70 #include <sys/wait.h> 71 #include <fcntl.h> 72 #include <pwd.h> 73 #include <unistd.h> 74 75 #include "test.h" 76 #include "safe_macros.h" 77 78 void dochild1(); 79 void dochild2(); 80 void setup(); 81 void cleanup(); 82 83 #define PERMS 0777 84 85 static uid_t nobody_uid; 86 87 char *TCID = "rmdir03"; 88 int TST_TOTAL = 1; 89 90 char tstdir1[255]; 91 char tstdir2[255]; 92 char tstdir3[255]; 93 char tstdir4[255]; 94 95 int main(int ac, char **av) 96 { 97 int lc; 98 pid_t pid; 99 struct stat buf1; 100 int e_code, status, status2; 101 102 /* 103 * parse standard options 104 */ 105 tst_parse_opts(ac, av, NULL, NULL); 106 #ifdef UCLINUX 107 maybe_run_child(&dochild1, "ns", 1, tstdir2); 108 maybe_run_child(&dochild2, "ns", 2, tstdir4); 109 #endif 110 111 /* 112 * perform global setup for test 113 */ 114 setup(); 115 116 /* 117 * check looping state if -i option given 118 */ 119 for (lc = 0; TEST_LOOPING(lc); lc++) { 120 121 tst_count = 0; 122 123 //test1: $ 124 /* 125 * attempt to rmdir a file whose parent directory has 126 * the sticky bit set without the root right 127 * or effective uid 128 */ 129 130 if (stat(tstdir1, &buf1) != -1) { 131 tst_brkm(TBROK, cleanup, 132 "tmp directory %s found!", tstdir1); 133 } 134 /* create a directory */ 135 if (mkdir(tstdir1, PERMS) == -1) { 136 tst_brkm(TBROK, cleanup, 137 "Couldnot create directory %s", tstdir1); 138 } 139 if (stat(tstdir1, &buf1) == -1) { 140 perror("stat"); 141 tst_brkm(TBROK, cleanup, "failed to stat directory %s " 142 "in rmdir()", tstdir1); 143 144 } 145 /* set the sticky bit */ 146 if (chmod(tstdir1, buf1.st_mode | S_ISVTX) != 0) { 147 perror("chmod"); 148 tst_brkm(TBROK, cleanup, 149 "failed to set the S_ISVTX bit"); 150 151 } 152 /* create a sub directory under tstdir1 */ 153 if (mkdir(tstdir2, PERMS) == -1) { 154 tst_brkm(TBROK, cleanup, 155 "Could not create directory %s", tstdir2); 156 } 157 158 if ((pid = FORK_OR_VFORK()) == -1) { 159 tst_brkm(TBROK, cleanup, "fork() failed"); 160 } 161 162 if (pid == 0) { /* first child */ 163 #ifdef UCLINUX 164 if (self_exec(av[0], "ns", 1, tstdir2) < 0) { 165 tst_brkm(TBROK, cleanup, "self_exec failed"); 166 } 167 #else 168 dochild1(); 169 #endif 170 } 171 /* Parent */ 172 173 //test2: $ 174 /* create the a directory with 0700 permits */ 175 if (mkdir(tstdir3, 0700) == -1) { 176 tst_brkm(TBROK, cleanup, "mkdir(%s, %#o) Failed", 177 tstdir3, PERMS); 178 } 179 /* create the a directory with 0700 permits */ 180 if (mkdir(tstdir4, 0777) == -1) { 181 tst_brkm(TBROK, cleanup, "mkdir(%s, %#o) Failed", 182 tstdir4, PERMS); 183 } 184 185 if ((pid = FORK_OR_VFORK()) == -1) { 186 tst_brkm(TBROK, cleanup, "fork() failed"); 187 } 188 189 if (pid == 0) { /* child */ 190 #ifdef UCLINUX 191 if (self_exec(av[0], "ns", 2, tstdir4) < 0) { 192 tst_brkm(TBROK, cleanup, "self_exec failed"); 193 } 194 #else 195 dochild2(); 196 #endif 197 } else { /* parent */ 198 /* wait for the child to finish */ 199 wait(&status); 200 wait(&status2); 201 /* make sure the child returned a good exit status */ 202 e_code = status >> 8; 203 if (e_code != 0) { 204 tst_resm(TFAIL, "Failures reported above"); 205 } else { 206 /* No error in the 1st one, check the 2nd */ 207 e_code = status2 >> 8; 208 if (e_code != 0) { 209 tst_resm(TFAIL, 210 "Failures reported above"); 211 } 212 } 213 } 214 215 /* clean up things in case we are looping */ 216 217 (void)rmdir(tstdir2); 218 (void)rmdir(tstdir1); 219 (void)rmdir(tstdir4); 220 (void)rmdir(tstdir3); 221 222 } 223 224 /* 225 * cleanup and exit 226 */ 227 cleanup(); 228 tst_exit(); 229 230 } 231 232 /* 233 * dochild1() 234 */ 235 void dochild1(void) 236 { 237 int retval = 0; 238 239 /* set to nobody */ 240 if (seteuid(nobody_uid) == -1) { 241 retval = 1; 242 tst_brkm(TBROK, cleanup, "setreuid failed to " 243 "set effective uid to %d", nobody_uid); 244 } 245 246 /* rmdir tstdir2 */ 247 TEST(rmdir(tstdir2)); 248 249 if (TEST_ERRNO) { 250 } 251 252 if (TEST_RETURN != -1) { 253 retval = 1; 254 tst_resm(TFAIL, "call succeeded unexpectedly"); 255 } else if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) { 256 retval = 1; 257 tst_resm(TFAIL, "Expected EPERM or EACCES, got %d", TEST_ERRNO); 258 } else { 259 tst_resm(TPASS, "rmdir() produced EPERM or EACCES"); 260 } 261 262 if (seteuid(0) == -1) { 263 retval = 1; 264 tst_brkm(TBROK, cleanup, "seteuid(0) failed"); 265 } 266 exit(retval); 267 /* END of child 1 (test1) */ 268 } 269 270 /* 271 * dochild1() 272 */ 273 void dochild2(void) 274 { 275 int retval = 0; 276 277 /* set to nobody */ 278 if (seteuid(nobody_uid) == -1) { 279 retval = 1; 280 tst_brkm(TBROK, cleanup, "setreuid failed to " 281 "set effective uid to %d", nobody_uid); 282 } 283 284 /* rmdir tstdir4 */ 285 TEST(rmdir(tstdir4)); 286 287 if (TEST_ERRNO) { 288 } 289 290 if (TEST_RETURN != -1) { 291 retval = 1; 292 tst_resm(TFAIL, "call succeeded unexpectedly"); 293 } else if (TEST_ERRNO != EACCES) { 294 retval = 1; 295 tst_resm(TFAIL, "Expected EACCES got %d", TEST_ERRNO); 296 } else { 297 tst_resm(TPASS, "rmdir() produced EACCES"); 298 } 299 300 if (seteuid(0) == -1) { 301 retval = 1; 302 tst_brkm(TBROK, cleanup, "seteuid(0) failed"); 303 } 304 exit(retval); 305 } 306 307 /* 308 * setup() - performs all ONE TIME setup for this test. 309 */ 310 void setup(void) 311 { 312 struct passwd *pw; 313 314 tst_require_root(); 315 316 pw = SAFE_GETPWNAM(NULL, "nobody"); 317 nobody_uid = pw->pw_uid; 318 319 tst_sig(FORK, DEF_HANDLER, cleanup); 320 321 TEST_PAUSE; 322 323 /* Create a temporary directory and make it current. */ 324 tst_tmpdir(); 325 326 umask(0); 327 328 sprintf(tstdir1, "./tstdir1_%d", getpid()); 329 sprintf(tstdir2, "%s/tstdir2_%d", tstdir1, getpid()); 330 sprintf(tstdir3, "./tstdir3_%d", getpid()); 331 sprintf(tstdir4, "%s/tstdir3_%d", tstdir3, getpid()); 332 } 333 334 /* 335 * cleanup() - performs all ONE TIME cleanup for this test at 336 * completion or premature exit. 337 */ 338 void cleanup(void) 339 { 340 341 /* 342 * Remove the temporary directory. 343 */ 344 tst_rmdir(); 345 346 /* 347 * Exit with return code appropriate for results. 348 */ 349 350 } 351