1 /******************************************************************************/ 2 /* Copyright (c) Kerlabs 2008. */ 3 /* Copyright (c) International Business Machines Corp., 2008 */ 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 * setresuid04.c 23 * 24 * DESCRIPTION 25 * Check if setresuid behaves correctly with file permissions. 26 * The test creates a file as ROOT with permissions 0644, does a setresuid 27 * and then tries to open the file with RDWR permissions. 28 * The same test is done in a fork to check if new UIDs are correctly 29 * passed to the son. 30 * 31 * USAGE: <for command-line> 32 * setresuid04 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 33 * where, -c n : Run n copies concurrently. 34 * -e : Turn on errno logging. 35 * -i n : Execute test n times. 36 * -I x : Execute test for x seconds. 37 * -P x : Pause for x seconds between iterations. 38 * -t : Turn on syscall timing. 39 * 40 * HISTORY 41 * 07/2001 Created by Renaud Lottiaux 42 * 43 * RESTRICTIONS 44 * Must be run as root. 45 */ 46 #define _GNU_SOURCE 1 47 #include <errno.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <sys/wait.h> 51 #include <fcntl.h> 52 #include <unistd.h> 53 #include "test.h" 54 #include "safe_macros.h" 55 #include <pwd.h> 56 #include "compat_16.h" 57 58 TCID_DEFINE(setresuid04); 59 int TST_TOTAL = 1; 60 char nobody_uid[] = "nobody"; 61 char testfile[256] = ""; 62 struct passwd *ltpuser; 63 64 int fd = -1; 65 66 void setup(void); 67 void cleanup(void); 68 void do_master_child(); 69 70 int main(int ac, char **av) 71 { 72 pid_t pid; 73 74 tst_parse_opts(ac, av, NULL, NULL); 75 setup(); 76 77 pid = FORK_OR_VFORK(); 78 if (pid < 0) 79 tst_brkm(TBROK, cleanup, "Fork failed"); 80 81 if (pid == 0) 82 do_master_child(); 83 84 tst_record_childstatus(cleanup, pid); 85 86 cleanup(); 87 tst_exit(); 88 } 89 90 /* 91 * do_master_child() 92 */ 93 void do_master_child(void) 94 { 95 int lc; 96 int pid; 97 int status; 98 99 for (lc = 0; TEST_LOOPING(lc); lc++) { 100 int tst_fd; 101 102 /* Reset tst_count in case we are looping */ 103 tst_count = 0; 104 105 if (SETRESUID(NULL, 0, ltpuser->pw_uid, 0) == -1) { 106 perror("setresuid failed"); 107 exit(TFAIL); 108 } 109 110 /* Test 1: Check the process with new uid cannot open the file 111 * with RDWR permissions. 112 */ 113 TEST(tst_fd = open(testfile, O_RDWR)); 114 115 if (TEST_RETURN != -1) { 116 printf("open succeeded unexpectedly\n"); 117 close(tst_fd); 118 exit(TFAIL); 119 } 120 121 if (TEST_ERRNO == EACCES) { 122 printf("open failed with EACCES as expected\n"); 123 } else { 124 perror("open failed unexpectedly"); 125 exit(TFAIL); 126 } 127 128 /* Test 2: Check a son process cannot open the file 129 * with RDWR permissions. 130 */ 131 pid = FORK_OR_VFORK(); 132 if (pid < 0) 133 tst_brkm(TBROK, NULL, "Fork failed"); 134 135 if (pid == 0) { 136 int tst_fd2; 137 138 /* Test to open the file in son process */ 139 TEST(tst_fd2 = open(testfile, O_RDWR)); 140 141 if (TEST_RETURN != -1) { 142 printf("call succeeded unexpectedly\n"); 143 close(tst_fd2); 144 exit(TFAIL); 145 } 146 147 if (TEST_ERRNO == EACCES) { 148 printf("open failed with EACCES as expected\n"); 149 exit(TPASS); 150 } else { 151 printf("open failed unexpectedly\n"); 152 exit(TFAIL); 153 } 154 } else { 155 /* Wait for son completion */ 156 if (waitpid(pid, &status, 0) == -1) { 157 perror("waitpid failed"); 158 exit(TFAIL); 159 } 160 161 if (!WIFEXITED(status)) 162 exit(TFAIL); 163 164 if (WEXITSTATUS(status) != TPASS) 165 exit(WEXITSTATUS(status)); 166 } 167 168 /* Test 3: Fallback to initial uid and check we can again open 169 * the file with RDWR permissions. 170 */ 171 tst_count++; 172 if (SETRESUID(NULL, 0, 0, 0) == -1) { 173 perror("setresuid failed"); 174 exit(TFAIL); 175 } 176 177 TEST(tst_fd = open(testfile, O_RDWR)); 178 179 if (TEST_RETURN == -1) { 180 perror("open failed unexpectedly"); 181 exit(TFAIL); 182 } else { 183 printf("open call succeeded\n"); 184 close(tst_fd); 185 } 186 } 187 exit(TPASS); 188 } 189 190 /* 191 * setup() - performs all ONE TIME setup for this test 192 */ 193 void setup(void) 194 { 195 tst_require_root(); 196 197 ltpuser = getpwnam(nobody_uid); 198 199 UID16_CHECK(ltpuser->pw_uid, "setresuid", cleanup) 200 201 tst_tmpdir(); 202 203 sprintf(testfile, "setresuid04file%d.tst", getpid()); 204 205 /* Create test file */ 206 fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644); 207 208 tst_sig(FORK, DEF_HANDLER, cleanup); 209 210 TEST_PAUSE; 211 } 212 213 /* 214 * cleanup() - performs all the ONE TIME cleanup for this test at completion 215 * or premature exit 216 */ 217 void cleanup(void) 218 { 219 close(fd); 220 221 tst_rmdir(); 222 223 } 224