chmod06.c revision 4bb656a129f7507823e9e6d6b98b1a02fd80ef89
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20/* 21 * Test Name: chmod06 22 * 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. 38 * 39 * Expected Result: 40 * chmod() should fail with return value -1 and set expected errno. 41 * 42 * Algorithm: 43 * Setup: 44 * Setup signal handling. 45 * Create temporary directory. 46 * Pause for SIGUSR1 if option specified. 47 * 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. 58 * 59 * Cleanup: 60 * Print errno log and/or timing stats if options given 61 * Delete the temporary directory(s)/file(s) created. 62 * 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. 72 * 73 * HISTORY 74 * 07/2001 Ported by Wayne Boyer 75 * 76 * RESTRICTIONS: 77 */ 78 79#ifndef _GNU_SOURCE 80# define _GNU_SOURCE 81#endif 82 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> 95 96#include "test.h" 97#include "usctest.h" 98 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" 105 106int no_setup(); /* dummy setup function */ 107int setup1(); /* setup function to test chmod for EPERM */ 108int setup2(); /* setup function to test chmod for EACCES */ 109int setup3(); /* setup function to test chmod for ENOTDIR */ 110int longpath_setup(); /* setup function to test chmod for ENAMETOOLONG */ 111 112char *get_high_address(); /* Function from ltp-Lib */ 113 114char *test_home; /* variable to hold TESTHOME env. */ 115char Longpathname[PATH_MAX+2]; 116char High_address_node[64]; 117 118struct 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 } 133}; 134 135char *TCID="chmod06"; /* Test program identifier. */ 136int TST_TOTAL = 7; /* Total number of test cases. */ 137extern int Tst_count; /* Test Case counter for tst_* routines */ 138int exp_enos[]={EPERM, EACCES, EFAULT, ENAMETOOLONG, ENOENT, ENOTDIR, 0}; 139 140char * bad_addr = 0; 141 142void setup(); /* Main setup function for the tests */ 143void cleanup(); /* cleanup function for the test */ 144 145int 146main(int ac, char **av) 147{ 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; 156 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(); 162 } 163 164 /* 165 * Invoke setup function to call individual test setup functions 166 * to simulate test conditions. 167 */ 168 setup(); 169 170 /* set the expected errnos... */ 171 TEST_EXP_ENOS(exp_enos); 172 173 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; 178 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; 183 184 if (file_name == High_address_node) { 185 file_name = (char *)get_high_address(); 186 } 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"); 195 } 196 } 197 if (ind >= 2) { 198 seteuid(0); 199 } 200 201 /* 202 * Call chmod(2) to test different test conditions. 203 * verify that it fails with -1 return value and 204 * sets appropriate errno. 205 */ 206 TEST(chmod(file_name, mode)); 207 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; 214 } 215 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); 224 } 225 } /* End of TEST CASE LOOPING. */ 226 227 } /* End for TEST_LOOPING */ 228 229 /* 230 * Invoke cleanup() to delete the test directory/file(s) created 231 * in the setup(). 232 */ 233 cleanup(); 234 235 return 0; 236 /*NOTREACHED*/ 237} /* End main */ 238 239/* 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. 246 */ 247void 248setup() 249{ 250 int ind; /* counter for setup functions */ 251 252 /* Capture unexpected signals */ 253 tst_sig(FORK, DEF_HANDLER, cleanup); 254 255 test_home = get_current_dir_name(); 256 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"); 260 } 261 262 263 /* Pause if that option was specified */ 264 TEST_PAUSE; 265 266 /* Make a temp dir and cd to it */ 267 tst_tmpdir(); 268 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"); 273 } 274 Test_cases[3].pathname = bad_addr; 275 276 /* call individual setup functions */ 277 for (ind = 0; Test_cases[ind].desc != NULL; ind++) { 278 Test_cases[ind].setupfunc(); 279 } 280} /* End setup() */ 281 282/* 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. 287 */ 288int 289no_setup() 290{ 291 return 0; 292} 293 294/* 295 * int 296 * setup1() - setup function for a test condition for which chmod(2) 297 * returns -1 and sets errno to EPERM. 298 * 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. 301 * 302 */ 303int 304setup1() 305{ 306 int fd; 307 char Path_name[PATH_MAX]; /* Buffer to hold command string */ 308 char Cmd_buffer[BUFSIZ]; /* Buffer to hold command string */ 309 310 311 /* open/creat a test file and close it */ 312 if ((fd = open(TEST_FILE1, O_RDWR|O_CREAT, 0666)) == -1) { 313 tst_brkm(TBROK, cleanup, 314 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s", 315 TEST_FILE1, errno, strerror(errno)); 316 } 317 if (close(fd) == -1) { 318 tst_brkm(TBROK, cleanup, 319 "close(%s) Failed, errno=%d : %s", 320 TEST_FILE1, errno, strerror(errno)); 321 } 322 323 /* Get the current working directory of the process */ 324 if (getcwd(Path_name, sizeof(Path_name)) == NULL) { 325 tst_brkm(TBROK, cleanup, 326 "getcwd(3) fails to get working directory of process"); 327 } 328 329 /* Get the path of test file created under temporary directory */ 330 strcat(Path_name, "/"TEST_FILE1); 331 332 /* Get the command name to be executed as setuid to root */ 333 strcpy((char *)Cmd_buffer, (const char *)test_home); 334 strcat((char *)Cmd_buffer, "/change_owner "); 335 strcat((char *)Cmd_buffer, TCID); 336 strcat((char *)Cmd_buffer, " "); 337 strcat((char *)Cmd_buffer, Path_name); 338 339 /* Change the ownership of testfile */ 340 if (system((const char *)Cmd_buffer) != 0) { 341 tst_brkm(TBROK, cleanup, 342 "Fail to modify %s ownership(s)!", TEST_FILE1); 343 } 344 return 0; 345} 346 347/* 348 * int 349 * setup2() - setup function for a test condition for which mknod(2) 350 * returns -1 and sets errno to EACCES. 351 * Create a test directory under temporary directory and create a test file 352 * under this directory with mode "0666" permissions. 353 * Modify the mode permissions on test directory such that process will not 354 * have search permissions on test directory. 355 * 356 * The function returns 0. 357 */ 358int 359setup2() 360{ 361 int fd; /* file handle for testfile */ 362 363 /* Creat a test directory and a file under it */ 364 if (mkdir(DIR_TEMP, MODE_RWX) < 0) { 365 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP); 366 } 367 368 if ((fd = open(TEST_FILE2, O_RDWR|O_CREAT, 0666)) == -1) { 369 tst_brkm(TBROK, cleanup, 370 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s", 371 TEST_FILE2, errno, strerror(errno)); 372 } 373 374 /* Close the testfile created above */ 375 if (close(fd) == -1) { 376 tst_brkm(TBROK, cleanup, 377 "close(%s) Failed, errno=%d : %s", 378 TEST_FILE2, errno, strerror(errno)); 379 } 380 381 /* Modify mode permissions on test directory */ 382 if (chmod(DIR_TEMP, FILE_MODE) < 0) { 383 tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", DIR_TEMP); 384 } 385 return 0; 386} 387 388/* 389 * int 390 * setup3() - setup function for a test condition for which chmod(2) 391 * returns -1 and sets errno to ENOTDIR. 392 * 393 * Create a test file under temporary directory so that test tries to 394 * change mode of a testfile "tfile_3" under "t_file" which happens to be 395 * another regular file. 396 */ 397int 398setup3() 399{ 400 int fd; 401 402 /* Creat a test file under temporary directory and close it */ 403 if ((fd = open("t_file", O_RDWR|O_CREAT, MODE_RWX)) == -1) { 404 tst_brkm(TBROK, cleanup, 405 "open(2) on t_file failed, errno=%d : %s", 406 errno, strerror(errno)); 407 } 408 if (close(fd) == -1) { 409 tst_brkm(TBROK, cleanup, 410 "close(t_file) Failed, errno=%d : %s", 411 errno, strerror(errno)); 412 } 413 return 0; 414} 415 416/* 417 * int 418 * longpath_setup() - setup to create a node with a name length exceeding 419 * the MAX. length of PATH_MAX. 420 * This function returns 0. 421 */ 422int 423longpath_setup() 424{ 425 int ind; /* counter variable */ 426 427 for (ind = 0; ind <= (PATH_MAX + 1); ind++) { 428 Longpathname[ind] = 'a'; 429 } 430 return 0; 431} 432 433/* 434 * void 435 * cleanup() - Performs all ONE TIME cleanup for this test at 436 * completion or premature exit. 437 * Print test timing stats and errno log if test executed with options. 438 * Remove temporary directory and sub-directories/files under it 439 * created during setup(). 440 * Exit the test program with normal exit code. 441 */ 442void 443cleanup() 444{ 445 /* 446 * print timing stats if that option was specified. 447 * print errno log if that option was specified. 448 */ 449 TEST_CLEANUP; 450 451 /* Restore mode permissions on test directory created in setup2() */ 452 if (chmod(DIR_TEMP, MODE_RWX) < 0) { 453 tst_resm(TBROK, "chmod(2) of %s failed", DIR_TEMP); 454 } 455 456 /* Remove files and temporary directory created */ 457 tst_rmdir(); 458 459 /* exit with return code appropriate for results */ 460 tst_exit(); 461} /* End cleanup() */ 462