• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
main(int ac,char ** av)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 		SAFE_MKDIR(cleanup, tstdir1, PERMS);
136 		if (stat(tstdir1, &buf1) == -1) {
137 			perror("stat");
138 			tst_brkm(TBROK, cleanup, "failed to stat directory %s "
139 				 "in rmdir()", tstdir1);
140 
141 		}
142 		/* set the sticky bit */
143 		if (chmod(tstdir1, buf1.st_mode | S_ISVTX) != 0) {
144 			perror("chmod");
145 			tst_brkm(TBROK, cleanup,
146 				 "failed to set the S_ISVTX bit");
147 
148 		}
149 		/* create a sub directory under tstdir1 */
150 		SAFE_MKDIR(cleanup, tstdir2, PERMS);
151 
152 		if ((pid = FORK_OR_VFORK()) == -1) {
153 			tst_brkm(TBROK, cleanup, "fork() failed");
154 		}
155 
156 		if (pid == 0) {	/* first child */
157 #ifdef UCLINUX
158 			if (self_exec(av[0], "ns", 1, tstdir2) < 0) {
159 				tst_brkm(TBROK, cleanup, "self_exec failed");
160 			}
161 #else
162 			dochild1();
163 #endif
164 		}
165 		/* Parent */
166 
167 //test2:       $
168 		/* create the a directory with 0700 permits */
169 		SAFE_MKDIR(cleanup, tstdir3, 0700);
170 		/* create the a directory with 0700 permits */
171 		SAFE_MKDIR(cleanup, tstdir4, 0777);
172 
173 		if ((pid = FORK_OR_VFORK()) == -1) {
174 			tst_brkm(TBROK, cleanup, "fork() failed");
175 		}
176 
177 		if (pid == 0) {	/* child */
178 #ifdef UCLINUX
179 			if (self_exec(av[0], "ns", 2, tstdir4) < 0) {
180 				tst_brkm(TBROK, cleanup, "self_exec failed");
181 			}
182 #else
183 			dochild2();
184 #endif
185 		} else {	/* parent */
186 			/* wait for the child to finish */
187 			wait(&status);
188 			wait(&status2);
189 			/* make sure the child returned a good exit status */
190 			e_code = status >> 8;
191 			if (e_code != 0) {
192 				tst_resm(TFAIL, "Failures reported above");
193 			} else {
194 				/* No error in the 1st one, check the 2nd */
195 				e_code = status2 >> 8;
196 				if (e_code != 0) {
197 					tst_resm(TFAIL,
198 						 "Failures reported above");
199 				}
200 			}
201 		}
202 
203 		/* clean up things in case we are looping */
204 
205 		(void)rmdir(tstdir2);
206 		(void)rmdir(tstdir1);
207 		(void)rmdir(tstdir4);
208 		(void)rmdir(tstdir3);
209 
210 	}
211 
212 	/*
213 	 * cleanup and exit
214 	 */
215 	cleanup();
216 	tst_exit();
217 
218 }
219 
220 /*
221  * dochild1()
222  */
dochild1(void)223 void dochild1(void)
224 {
225 	int retval = 0;
226 
227 	/* set to nobody */
228 	if (seteuid(nobody_uid) == -1) {
229 		retval = 1;
230 		tst_brkm(TBROK, cleanup, "setreuid failed to "
231 			 "set effective uid to %d", nobody_uid);
232 	}
233 
234 	/* rmdir tstdir2 */
235 	TEST(rmdir(tstdir2));
236 
237 	if (TEST_ERRNO) {
238 	}
239 
240 	if (TEST_RETURN != -1) {
241 		retval = 1;
242 		tst_resm(TFAIL, "call succeeded unexpectedly");
243 	} else if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) {
244 		retval = 1;
245 		tst_resm(TFAIL, "Expected EPERM or EACCES, got %d", TEST_ERRNO);
246 	} else {
247 		tst_resm(TPASS, "rmdir() produced EPERM or EACCES");
248 	}
249 
250 	if (seteuid(0) == -1) {
251 		retval = 1;
252 		tst_brkm(TBROK, cleanup, "seteuid(0) failed");
253 	}
254 	exit(retval);
255 	/* END of child 1 (test1) */
256 }
257 
258 /*
259  * dochild1()
260  */
dochild2(void)261 void dochild2(void)
262 {
263 	int retval = 0;
264 
265 	/* set to nobody */
266 	if (seteuid(nobody_uid) == -1) {
267 		retval = 1;
268 		tst_brkm(TBROK, cleanup, "setreuid failed to "
269 			 "set effective uid to %d", nobody_uid);
270 	}
271 
272 	/* rmdir tstdir4 */
273 	TEST(rmdir(tstdir4));
274 
275 	if (TEST_ERRNO) {
276 	}
277 
278 	if (TEST_RETURN != -1) {
279 		retval = 1;
280 		tst_resm(TFAIL, "call succeeded unexpectedly");
281 	} else if (TEST_ERRNO != EACCES) {
282 		retval = 1;
283 		tst_resm(TFAIL, "Expected EACCES got %d", TEST_ERRNO);
284 	} else {
285 		tst_resm(TPASS, "rmdir() produced EACCES");
286 	}
287 
288 	if (seteuid(0) == -1) {
289 		retval = 1;
290 		tst_brkm(TBROK, cleanup, "seteuid(0) failed");
291 	}
292 	exit(retval);
293 }
294 
295 /*
296  * setup() - performs all ONE TIME setup for this test.
297  */
setup(void)298 void setup(void)
299 {
300 	struct passwd *pw;
301 
302 	tst_require_root();
303 
304 	pw = SAFE_GETPWNAM(NULL, "nobody");
305 	nobody_uid = pw->pw_uid;
306 
307 	tst_sig(FORK, DEF_HANDLER, cleanup);
308 
309 	TEST_PAUSE;
310 
311 	/* Create a temporary directory and make it current. */
312 	tst_tmpdir();
313 
314 	umask(0);
315 
316 	sprintf(tstdir1, "./tstdir1_%d", getpid());
317 	sprintf(tstdir2, "%s/tstdir2_%d", tstdir1, getpid());
318 	sprintf(tstdir3, "./tstdir3_%d", getpid());
319 	sprintf(tstdir4, "%s/tstdir3_%d", tstdir3, getpid());
320 }
321 
322 /*
323  * cleanup() - performs all ONE TIME cleanup for this test at
324  *              completion or premature exit.
325  */
cleanup(void)326 void cleanup(void)
327 {
328 
329 	/*
330 	 * Remove the temporary directory.
331 	 */
332 	tst_rmdir();
333 
334 	/*
335 	 * Exit with return code appropriate for results.
336 	 */
337 
338 }
339