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 "safe_macros.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; 108 109 tst_parse_opts(ac, av, NULL, NULL); 110 111 setup(); 112 113 for (lc = 0; TEST_LOOPING(lc); lc++) { 114 115 tst_count = 0; 116 117 /* 118 * Call mknod() to creat a node on a directory without 119 * set group-ID (sgid) bit set. 120 */ 121 TEST(mknod(node_name, MODE_RWX, 0)); 122 123 /* Check return code from mknod(2) */ 124 if (TEST_RETURN == -1) { 125 tst_resm(TFAIL, 126 "mknod(%s, %#o, 0) failed, errno=%d : %s", 127 node_name, MODE_RWX, TEST_ERRNO, 128 strerror(TEST_ERRNO)); 129 continue; 130 } 131 /* Set the functionality flag */ 132 fflag = 1; 133 134 /* Check for node's creation */ 135 if (stat(node_name, &buf) < 0) { 136 tst_resm(TFAIL, 137 "stat() of %s failed, errno:%d", 138 node_name, TEST_ERRNO); 139 /* unset flag as functionality fails */ 140 fflag = 0; 141 } 142 143 /* Verify mode permissions of node */ 144 if (buf.st_mode & S_ISGID) { 145 tst_resm(TFAIL, "%s: Incorrect modes, setgid " 146 "bit set", node_name); 147 /* unset flag as functionality fails */ 148 fflag = 0; 149 } 150 151 /* Verify group ID */ 152 if (buf.st_gid != mygid) { 153 tst_resm(TFAIL, "%s: Incorrect group", 154 node_name); 155 /* unset flag as functionality fails */ 156 fflag = 0; 157 } 158 if (fflag) { 159 tst_resm(TPASS, "Functionality of mknod(%s, " 160 "%#o, 0) successful", 161 node_name, MODE_RWX); 162 } 163 164 /* Remove the node for the next go `round */ 165 if (unlink(node_name) == -1) { 166 tst_resm(TWARN, 167 "unlink(%s) failed, errno:%d %s", 168 node_name, errno, strerror(errno)); 169 } 170 } 171 172 /* Change the directory back to temporary directory */ 173 chdir(".."); 174 175 /* 176 * Invoke cleanup() to delete the test directories created 177 * in the setup() and exit main(). 178 */ 179 cleanup(); 180 181 tst_exit(); 182} 183 184/* 185 * setup(void) - performs all ONE TIME setup for this test. 186 * Exit the test program on receipt of unexpected signals. 187 * Create a temporary directory used to hold test directories created 188 * and change the directory to it. 189 * Verify that pid of process executing the test is root. 190 * Create a test directory on temporary directory and set the ownership 191 * of test directory to nobody user. 192 * Set the effective uid/gid of the process to that of nobody user. 193 */ 194void setup(void) 195{ 196 tst_require_root(); 197 198 /* Capture unexpected signals */ 199 tst_sig(NOFORK, DEF_HANDLER, cleanup); 200 201 TEST_PAUSE; 202 203 /* Make a temp dir and cd to it */ 204 tst_tmpdir(); 205 206 /* fix permissions on the tmpdir */ 207 if (chmod(".", 0711) != 0) { 208 tst_brkm(TBROK, cleanup, "chmod() failed"); 209 } 210 211 /* Save the real user id of the test process */ 212 save_myuid = getuid(); 213 214 /* Save the process id of the test process */ 215 mypid = getpid(); 216 217 /* Get the node name to be created in the test */ 218 sprintf(node_name, TNODE, mypid); 219 220 /* Get the uid/gid of guest user - nobody */ 221 if ((user1 = getpwnam(LTPUSER)) == NULL) { 222 tst_brkm(TBROK, cleanup, "%s not in /etc/passwd", LTPUSER); 223 } 224 user1_uid = user1->pw_uid; 225 group1_gid = user1->pw_gid; 226 227 /* Get effective group id of the test process */ 228 group2_gid = getegid(); 229 230 /* 231 * Create a test directory under temporary directory with the 232 * specified mode permissions, with uid/gid set to that of guest 233 * user and the test process. 234 */ 235 SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX); 236 SAFE_CHOWN(cleanup, DIR_TEMP, user1_uid, group2_gid); 237 238 /* 239 * Verify that test directory created with expected permission modes 240 * and ownerships. 241 */ 242 SAFE_STAT(cleanup, DIR_TEMP, &buf); 243 244 /* Verify modes of test directory */ 245 if (buf.st_mode & S_ISGID) { 246 tst_brkm(TBROK, cleanup, 247 "%s: Incorrect modes, setgid bit set", DIR_TEMP); 248 } 249 250 /* Verify group ID */ 251 if (buf.st_gid != group2_gid) { 252 tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); 253 } 254 255 /* 256 * Set the effective group id and user id of the test process 257 * to that of guest user. 258 */ 259 SAFE_SETGID(cleanup, group1_gid); 260 if (setreuid(-1, user1_uid) < 0) { 261 tst_brkm(TBROK, cleanup, 262 "Unable to set process uid to that of ltp user"); 263 } 264 265 /* Save the real group ID of the current process */ 266 mygid = getgid(); 267 268 /* Change directory to DIR_TEMP */ 269 SAFE_CHDIR(cleanup, DIR_TEMP); 270} 271 272/* 273 * cleanup() - Performs all ONE TIME cleanup for this test at 274 * completion or premature exit. 275 * Print test timing stats and errno log if test executed with options. 276 * Restore the real/effective user id of the process changed during 277 * setup(). 278 * Remove temporary directory and sub-directories/files under it 279 * created during setup(). 280 * Exit the test program with normal exit code. 281 */ 282void cleanup(void) 283{ 284 285 /* 286 * Restore the effective uid of the process changed in the 287 * setup(). 288 */ 289 if (setreuid(-1, save_myuid) < 0) { 290 tst_brkm(TBROK, NULL, 291 "resetting process real/effective uid failed"); 292 } 293 294 tst_rmdir(); 295 296} 297