Delete the change_owner binary, as it is an insecure suid root binary; rewrite tests...
[ltp-debian.git] / testcases / kernel / syscalls / chmod / chmod06.c
blob139b9b91bf83ac7d8e9d8972ab6de8ed0e57a14e
1 /*
3 * Copyright (c) International Business Machines Corp., 2001
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Test Name: chmod06
23 * Test Description:
24 * Verify that,
25 * 1) chmod(2) returns -1 and sets errno to EPERM if the effective user id
26 * of process does not match the owner of the file and the process is
27 * not super user.
28 * 2) chmod(2) returns -1 and sets errno to EACCES if search permission is
29 * denied on a component of the path prefix.
30 * 3) chmod(2) returns -1 and sets errno to EFAULT if pathname points
31 * outside user's accessible address space.
32 * 4) chmod(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
33 * component is too long.
34 * 5) chmod(2) returns -1 and sets errno to ENOTDIR if the directory
35 * component in pathname is not a directory.
36 * 6) chmod(2) returns -1 and sets errno to ENOENT if the specified file
37 * does not exists.
39 * Expected Result:
40 * chmod() should fail with return value -1 and set expected errno.
42 * Algorithm:
43 * Setup:
44 * Setup signal handling.
45 * Create temporary directory.
46 * Pause for SIGUSR1 if option specified.
48 * Test:
49 * Loop if the proper options are given.
50 * Execute system call
51 * Check return code, if system call failed (return=-1)
52 * if errno set == expected errno
53 * Issue sys call fails with expected return value and errno.
54 * Otherwise,
55 * Issue sys call fails with unexpected errno.
56 * Otherwise,
57 * Issue sys call returns unexpected value.
59 * Cleanup:
60 * Print errno log and/or timing stats if options given
61 * Delete the temporary directory(s)/file(s) created.
63 * Usage: <for command-line>
64 * chmod06 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t]
65 * where, -c n : Run n copies concurrently.
66 * -e : Turn on errno logging.
67 * -f : Turn off functionality Testing.
68 * -i n : Execute test n times.
69 * -I x : Execute test for x seconds.
70 * -P x : Pause for x seconds between iterations.
71 * -t : Turn on syscall timing.
73 * HISTORY
74 * 07/2001 Ported by Wayne Boyer
76 * RESTRICTIONS:
79 #ifndef _GNU_SOURCE
80 # define _GNU_SOURCE
81 #endif
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <unistd.h>
86 #include <fcntl.h>
87 #include <errno.h>
88 #include <string.h>
89 #include <signal.h>
90 #include <grp.h>
91 #include <pwd.h>
92 #include <sys/types.h>
93 #include <sys/stat.h>
94 #include <sys/mman.h>
96 #include "test.h"
97 #include "usctest.h"
99 #define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
100 #define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
101 #define DIR_TEMP "testdir_1"
102 #define TEST_FILE1 "tfile_1"
103 #define TEST_FILE2 "testdir_1/tfile_2"
104 #define TEST_FILE3 "t_file/tfile_3"
106 int no_setup(); /* dummy setup function */
107 int setup1(); /* setup function to test chmod for EPERM */
108 int setup2(); /* setup function to test chmod for EACCES */
109 int setup3(); /* setup function to test chmod for ENOTDIR */
110 int longpath_setup(); /* setup function to test chmod for ENAMETOOLONG */
112 char *get_high_address(); /* Function from ltp-Lib */
114 char *test_home; /* variable to hold TESTHOME env. */
115 char Longpathname[PATH_MAX+2];
116 char High_address_node[64];
118 struct test_case_t { /* test case struct. to hold ref. test cond's*/
119 char *pathname;
120 char *desc;
121 int mode;
122 int exp_errno;
123 int (*setupfunc)();
124 } Test_cases[] = {
125 { TEST_FILE1, "Process is not owner/root", FILE_MODE, EPERM, setup1 },
126 { TEST_FILE2, "No Search permissions to process", FILE_MODE, EACCES, setup2 },
127 { High_address_node, "Address beyond address space", FILE_MODE, EFAULT, no_setup },
128 { (char *)-1, "Negative address", FILE_MODE, EFAULT, no_setup },
129 { Longpathname, "Pathname too long", FILE_MODE, ENAMETOOLONG, longpath_setup },
130 { "", "Pathname is empty", FILE_MODE, ENOENT, no_setup },
131 { TEST_FILE3, "Path contains regular file", FILE_MODE, ENOTDIR, setup3 },
132 { NULL, NULL, 0, 0, no_setup }
135 char *TCID="chmod06"; /* Test program identifier. */
136 int TST_TOTAL = 7; /* Total number of test cases. */
137 extern int Tst_count; /* Test Case counter for tst_* routines */
138 int exp_enos[]={EPERM, EACCES, EFAULT, ENAMETOOLONG, ENOENT, ENOTDIR, 0};
140 char * bad_addr = 0;
142 void setup(); /* Main setup function for the tests */
143 void cleanup(); /* cleanup function for the test */
146 main(int ac, char **av)
148 int lc; /* loop counter */
149 char *msg; /* message returned from parse_opts */
150 char *file_name; /* ptr. for file name whose mode is modified*/
151 char *test_desc; /* test specific error message */
152 int ind; /* counter to test different test conditions */
153 int mode; /* creation mode for the node created */
154 char nobody_uid[] = "nobody";
155 struct passwd *ltpuser;
157 /* Parse standard options given to run the test. */
158 msg = parse_opts(ac, av, (option_t *) NULL, NULL);
159 if (msg != (char *) NULL) {
160 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
161 tst_exit();
165 * Invoke setup function to call individual test setup functions
166 * to simulate test conditions.
168 setup();
170 /* set the expected errnos... */
171 TEST_EXP_ENOS(exp_enos);
174 /* Check looping state if -c option given */
175 for (lc = 0; TEST_LOOPING(lc); lc++) {
176 /* Reset Tst_count in case we are looping. */
177 Tst_count=0;
179 for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
180 file_name = Test_cases[ind].pathname;
181 mode = Test_cases[ind].mode;
182 test_desc = Test_cases[ind].desc;
184 if (file_name == High_address_node) {
185 file_name = (char *)get_high_address();
187 if (ind < 2) {
188 /* Switch to nobody user for correct error code collection */
189 ltpuser = getpwnam(nobody_uid);
190 if (seteuid(ltpuser->pw_uid) == -1) {
191 tst_resm(TINFO, "seteuid failed to "
192 "to set the effective uid to %d",
193 ltpuser->pw_uid);
194 perror("seteuid");
197 if (ind >= 2) {
198 seteuid(0);
202 * Call chmod(2) to test different test conditions.
203 * verify that it fails with -1 return value and
204 * sets appropriate errno.
206 TEST(chmod(file_name, mode));
208 /* Check return code from chmod(2) */
209 if (TEST_RETURN != -1) {
210 tst_resm(TFAIL, "chmod() returned %d, "
211 "expected -1, errno:%d", TEST_RETURN,
212 Test_cases[ind].exp_errno);
213 continue;
216 TEST_ERROR_LOG(TEST_ERRNO);
217 if (TEST_ERRNO == Test_cases[ind].exp_errno) {
218 tst_resm(TPASS, "chmod() fails, %s, errno:%d",
219 test_desc, TEST_ERRNO);
220 } else {
221 tst_resm(TFAIL, "chmod() fails, %s, errno:%d, "
222 "expected errno:%d", test_desc,
223 TEST_ERRNO, Test_cases[ind].exp_errno);
225 } /* End of TEST CASE LOOPING. */
227 } /* End for TEST_LOOPING */
230 * Invoke cleanup() to delete the test directory/file(s) created
231 * in the setup().
233 cleanup();
235 return 0;
236 /*NOTREACHED*/
237 } /* End main */
240 * void
241 * setup(void) - performs all ONE TIME setup for this test.
242 * Exit the test program on receipt of unexpected signals.
243 * Create a temporary directory and change directory to it.
244 * Invoke individual test setup functions according to the order
245 * set in struct. definition.
247 void
248 setup()
250 int ind; /* counter for setup functions */
252 /* Capture unexpected signals */
253 tst_sig(FORK, DEF_HANDLER, cleanup);
255 test_home = get_current_dir_name();
257 /* Switch to nobody user for correct error code collection */
258 if (geteuid() != 0) {
259 tst_brkm(TBROK, tst_exit, "Test must be run as root");
263 /* Pause if that option was specified */
264 TEST_PAUSE;
266 /* Make a temp dir and cd to it */
267 tst_tmpdir();
269 bad_addr = mmap(0, 1, PROT_NONE,
270 MAP_PRIVATE_EXCEPT_UCLINUX|MAP_ANONYMOUS, 0, 0);
271 if (bad_addr == MAP_FAILED) {
272 tst_brkm(TBROK, cleanup, "mmap failed");
274 Test_cases[3].pathname = bad_addr;
276 /* call individual setup functions */
277 for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
278 Test_cases[ind].setupfunc();
280 } /* End setup() */
283 * int
284 * no_setup() - Some test conditions for mknod(2) do not any setup.
285 * Hence, this function just returns 0.
286 * This function simply returns 0.
289 no_setup()
291 return 0;
295 * int
296 * setup1() - setup function for a test condition for which chmod(2)
297 * returns -1 and sets errno to EPERM.
299 * Create a testfile under temporary directory and invoke setuid to root
300 * program to change the ownership of testfile to that of "ltpuser2" user.
304 setup1()
306 int fd;
309 /* open/creat a test file and close it */
310 if ((fd = open(TEST_FILE1, O_RDWR|O_CREAT, 0666)) == -1) {
311 tst_brkm(TBROK, cleanup,
312 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
313 TEST_FILE1, errno, strerror(errno));
316 if(fchown(fd, 0, 0)<0)
317 tst_brkm(TBROK, cleanup,
318 "Fail to modify %s ownership(s): %s", TEST_FILE1, strerror(errno));
320 if (close(fd) == -1) {
321 tst_brkm(TBROK, cleanup,
322 "close(%s) Failed, errno=%d : %s",
323 TEST_FILE1, errno, strerror(errno));
326 return 0;
330 * int
331 * setup2() - setup function for a test condition for which mknod(2)
332 * returns -1 and sets errno to EACCES.
333 * Create a test directory under temporary directory and create a test file
334 * under this directory with mode "0666" permissions.
335 * Modify the mode permissions on test directory such that process will not
336 * have search permissions on test directory.
338 * The function returns 0.
341 setup2()
343 int fd; /* file handle for testfile */
345 /* Creat a test directory and a file under it */
346 if (mkdir(DIR_TEMP, MODE_RWX) < 0) {
347 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP);
350 if ((fd = open(TEST_FILE2, O_RDWR|O_CREAT, 0666)) == -1) {
351 tst_brkm(TBROK, cleanup,
352 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
353 TEST_FILE2, errno, strerror(errno));
356 /* Close the testfile created above */
357 if (close(fd) == -1) {
358 tst_brkm(TBROK, cleanup,
359 "close(%s) Failed, errno=%d : %s",
360 TEST_FILE2, errno, strerror(errno));
363 /* Modify mode permissions on test directory */
364 if (chmod(DIR_TEMP, FILE_MODE) < 0) {
365 tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", DIR_TEMP);
367 return 0;
371 * int
372 * setup3() - setup function for a test condition for which chmod(2)
373 * returns -1 and sets errno to ENOTDIR.
375 * Create a test file under temporary directory so that test tries to
376 * change mode of a testfile "tfile_3" under "t_file" which happens to be
377 * another regular file.
380 setup3()
382 int fd;
384 /* Creat a test file under temporary directory and close it */
385 if ((fd = open("t_file", O_RDWR|O_CREAT, MODE_RWX)) == -1) {
386 tst_brkm(TBROK, cleanup,
387 "open(2) on t_file failed, errno=%d : %s",
388 errno, strerror(errno));
390 if (close(fd) == -1) {
391 tst_brkm(TBROK, cleanup,
392 "close(t_file) Failed, errno=%d : %s",
393 errno, strerror(errno));
395 return 0;
399 * int
400 * longpath_setup() - setup to create a node with a name length exceeding
401 * the MAX. length of PATH_MAX.
402 * This function returns 0.
405 longpath_setup()
407 int ind; /* counter variable */
409 for (ind = 0; ind <= (PATH_MAX + 1); ind++) {
410 Longpathname[ind] = 'a';
412 return 0;
416 * void
417 * cleanup() - Performs all ONE TIME cleanup for this test at
418 * completion or premature exit.
419 * Print test timing stats and errno log if test executed with options.
420 * Remove temporary directory and sub-directories/files under it
421 * created during setup().
422 * Exit the test program with normal exit code.
424 void
425 cleanup()
428 * print timing stats if that option was specified.
429 * print errno log if that option was specified.
431 TEST_CLEANUP;
433 /* Restore mode permissions on test directory created in setup2() */
434 if (chmod(DIR_TEMP, MODE_RWX) < 0) {
435 tst_brkm(TBROK, NULL, "chmod(2) of %s failed", DIR_TEMP);
438 /* Remove files and temporary directory created */
439 tst_rmdir();
441 /* exit with return code appropriate for results */
442 tst_exit();
443 } /* End cleanup() */