mknod08.c revision fdce7d5e2a219d201a2b0e3bab6b61b01ec1d716
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 * Test Name: mknod08 22 * 23 * Test Description: 24 * Verify that mknod(2) succeeds when used to create a filesystem 25 * node on a directory without set group-ID bit set. The node created 26 * should not have set group-ID bit set and its gid should be equal to that 27 * of its parent directory. 28 * 29 * Expected Result: 30 * mknod() should return value 0 on success and node created should not 31 * have set group-ID bit set. 32 * 33 * Algorithm: 34 * Setup: 35 * Setup signal handling. 36 * Create temporary directory. 37 * Pause for SIGUSR1 if option specified. 38 * 39 * Test: 40 * Loop if the proper options are given. 41 * Execute system call 42 * Check return code, if system call failed (return=-1) 43 * Log the errno and Issue a FAIL message. 44 * Otherwise, 45 * Verify the Functionality of system call 46 * if successful, 47 * Issue Functionality-Pass message. 48 * Otherwise, 49 * Issue Functionality-Fail message. 50 * Cleanup: 51 * Print errno log and/or timing stats if options given 52 * Delete the temporary directory created. 53 * 54 * Usage: <for command-line> 55 * mknod08 [-c n] [-e] [-f] [-i n] [-I x] [-P x] [-t] 56 * where, -c n : Run n copies concurrently. 57 * -e : Turn on errno logging. 58 * -f : Turn off functionality Testing. 59 * -i n : Execute test n times. 60 * -I x : Execute test for x seconds. 61 * -P x : Pause for x seconds between iterations. 62 * -t : Turn on syscall timing. 63 * 64 * HISTORY 65 * 07/2001 Ported by Wayne Boyer 66 * 67 * RESTRICTIONS: 68 * This test should be run by 'super-user' (root) only. 69 * 70 */ 71 72#include <stdio.h> 73#include <stdlib.h> 74#include <unistd.h> 75#include <errno.h> 76#include <string.h> 77#include <signal.h> 78#include <pwd.h> 79#include <sys/types.h> 80#include <sys/stat.h> 81 82#include "test.h" 83#include "usctest.h" 84 85#define LTPUSER "nobody" 86#define MODE_RWX S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO 87#define DIR_TEMP "testdir_1" 88#define TNODE "tnode_%d" 89 90struct stat buf; /* struct. to hold stat(2) o/p contents */ 91struct passwd *user1; /* struct. to hold getpwnam(3) o/p contents */ 92 93char *TCID = "mknod08"; 94int TST_TOTAL = 1; 95char node_name[PATH_MAX]; /* buffer to hold node name created */ 96 97gid_t group1_gid, group2_gid, mygid; /* user and process group id's */ 98uid_t save_myuid, user1_uid; /* user and process user id's */ 99pid_t mypid; /* process id */ 100 101void setup(); /* setup function for the test */ 102void cleanup(); /* cleanup function for the test */ 103 104int main(int ac, char **av) 105{ 106 int lc; 107 int fflag; /* functionality flag variable */ 108 char *msg; 109 110 msg = parse_opts(ac, av, NULL, NULL); 111 if (msg != NULL) { 112 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 113 114 } 115 116 setup(); 117 118 for (lc = 0; TEST_LOOPING(lc); lc++) { 119 120 tst_count = 0; 121 122 /* 123 * Call mknod() to creat a node on a directory without 124 * set group-ID (sgid) bit set. 125 */ 126 TEST(mknod(node_name, MODE_RWX, 0)); 127 128 /* Check return code from mknod(2) */ 129 if (TEST_RETURN == -1) { 130 tst_resm(TFAIL, 131 "mknod(%s, %#o, 0) failed, errno=%d : %s", 132 node_name, MODE_RWX, TEST_ERRNO, 133 strerror(TEST_ERRNO)); 134 continue; 135 } 136 /* 137 * Perform functional verification if test executed 138 * without (-f) option. 139 */ 140 if (STD_FUNCTIONAL_TEST) { 141 /* Set the functionality flag */ 142 fflag = 1; 143 144 /* Check for node's creation */ 145 if (stat(node_name, &buf) < 0) { 146 tst_resm(TFAIL, 147 "stat() of %s failed, errno:%d", 148 node_name, TEST_ERRNO); 149 /* unset flag as functionality fails */ 150 fflag = 0; 151 } 152 153 /* Verify mode permissions of node */ 154 if (buf.st_mode & S_ISGID) { 155 tst_resm(TFAIL, "%s: Incorrect modes, setgid " 156 "bit set", node_name); 157 /* unset flag as functionality fails */ 158 fflag = 0; 159 } 160 161 /* Verify group ID */ 162 if (buf.st_gid != mygid) { 163 tst_resm(TFAIL, "%s: Incorrect group", 164 node_name); 165 /* unset flag as functionality fails */ 166 fflag = 0; 167 } 168 if (fflag) { 169 tst_resm(TPASS, "Functionality of mknod(%s, " 170 "%#o, 0) successful", 171 node_name, MODE_RWX); 172 } 173 } else { 174 tst_resm(TPASS, "call succeeded"); 175 } 176 177 /* Remove the node for the next go `round */ 178 if (unlink(node_name) == -1) { 179 tst_resm(TWARN, 180 "unlink(%s) failed, errno:%d %s", 181 node_name, errno, strerror(errno)); 182 } 183 } 184 185 /* Change the directory back to temporary directory */ 186 chdir(".."); 187 188 /* 189 * Invoke cleanup() to delete the test directories created 190 * in the setup() and exit main(). 191 */ 192 cleanup(); 193 194 tst_exit(); 195} 196 197/* 198 * setup(void) - performs all ONE TIME setup for this test. 199 * Exit the test program on receipt of unexpected signals. 200 * Create a temporary directory used to hold test directories created 201 * and change the directory to it. 202 * Verify that pid of process executing the test is root. 203 * Create a test directory on temporary directory and set the ownership 204 * of test directory to nobody user. 205 * Set the effective uid/gid of the process to that of nobody user. 206 */ 207void setup() 208{ 209 210 /* Capture unexpected signals */ 211 tst_sig(NOFORK, DEF_HANDLER, cleanup); 212 213 /* Check that the test process id is super/root */ 214 if (geteuid() != 0) { 215 tst_brkm(TBROK, NULL, "Must be super/root for this test!"); 216 tst_exit(); 217 } 218 219 TEST_PAUSE; 220 221 /* Make a temp dir and cd to it */ 222 tst_tmpdir(); 223 224 /* fix permissions on the tmpdir */ 225 if (chmod(".", 0711) != 0) { 226 tst_brkm(TBROK, cleanup, "chmod() failed"); 227 } 228 229 /* Save the real user id of the test process */ 230 save_myuid = getuid(); 231 232 /* Save the process id of the test process */ 233 mypid = getpid(); 234 235 /* Get the node name to be created in the test */ 236 sprintf(node_name, TNODE, mypid); 237 238 /* Get the uid/gid of guest user - nobody */ 239 if ((user1 = getpwnam(LTPUSER)) == NULL) { 240 tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER); 241 } 242 user1_uid = user1->pw_uid; 243 group1_gid = user1->pw_gid; 244 245 /* Get effective group id of the test process */ 246 group2_gid = getegid(); 247 248 /* 249 * Create a test directory under temporary directory with the 250 * specified mode permissions, with uid/gid set to that of guest 251 * user and the test process. 252 */ 253 if (mkdir(DIR_TEMP, MODE_RWX) < 0) { 254 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP); 255 } 256 if (chown(DIR_TEMP, user1_uid, group2_gid) < 0) { 257 tst_brkm(TBROK, cleanup, "chown(2) of %s failed", DIR_TEMP); 258 } 259 260 /* 261 * Verify that test directory created with expected permission modes 262 * and ownerships. 263 */ 264 if (stat(DIR_TEMP, &buf) < 0) { 265 tst_brkm(TBROK, cleanup, "stat(2) of %s failed", DIR_TEMP); 266 } 267 268 /* Verify modes of test directory */ 269 if (buf.st_mode & S_ISGID) { 270 tst_brkm(TBROK, cleanup, 271 "%s: Incorrect modes, setgid bit set", DIR_TEMP); 272 } 273 274 /* Verify group ID */ 275 if (buf.st_gid != group2_gid) { 276 tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); 277 } 278 279 /* 280 * Set the effective group id and user id of the test process 281 * to that of guest user. 282 */ 283 if (setgid(group1_gid) < 0) { 284 tst_brkm(TBROK, cleanup, 285 "Unable to set process gid to that of ltp user"); 286 } 287 if (setreuid(-1, user1_uid) < 0) { 288 tst_brkm(TBROK, cleanup, 289 "Unable to set process uid to that of ltp user"); 290 } 291 292 /* Save the real group ID of the current process */ 293 mygid = getgid(); 294 295 /* Change directory to DIR_TEMP */ 296 if (chdir(DIR_TEMP) < 0) { 297 tst_brkm(TBROK, cleanup, 298 "Unable to change to %s directory", DIR_TEMP); 299 } 300} 301 302/* 303 * cleanup() - Performs all ONE TIME cleanup for this test at 304 * completion or premature exit. 305 * Print test timing stats and errno log if test executed with options. 306 * Restore the real/effective user id of the process changed during 307 * setup(). 308 * Remove temporary directory and sub-directories/files under it 309 * created during setup(). 310 * Exit the test program with normal exit code. 311 */ 312void cleanup() 313{ 314 /* 315 * print timing stats if that option was specified. 316 * print errno log if that option was specified. 317 */ 318 TEST_CLEANUP; 319 320 /* 321 * Restore the effective uid of the process changed in the 322 * setup(). 323 */ 324 if (setreuid(-1, save_myuid) < 0) { 325 tst_brkm(TBROK, NULL, 326 "resetting process real/effective uid failed"); 327 } 328 329 tst_rmdir(); 330 331} 332