Home | History | Annotate | Download | only in rmdir
      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