1 /* 2 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * You should have received a copy of the GNU General Public License along 13 * with this program; if not, write the Free Software Foundation, Inc., 14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 * 16 */ 17 /********************************************************** 18 * 19 * TEST IDENTIFIER : adjtimex02 20 * 21 * EXECUTED BY : root / superuser 22 * 23 * TEST TITLE : Tests for error conditions 24 * 25 * TEST CASE TOTAL : 6 26 * 27 * AUTHOR : Saji Kumar.V.R <saji.kumar (at) wipro.com> 28 * 29 * SIGNALS 30 * Uses SIGUSR1 to pause before test if option set. 31 * (See the parse_opts(3) man page). 32 * 33 * DESCRIPTION 34 * Verify that 35 * 1) adjtimex(2) fails with errno set to EFAULT if buf does 36 * not point to writable memory 37 * 2) adjtimex(2) fails with errno set to EINVAL if an attempt 38 * is made to set buf.tick to a value < 900000/HZ 39 * 3) adjtimex(2) fails with errno set to EINVAL if an attempt 40 * is made to set buf.tick to a value > 1100000/HZ 41 * 4) adjtimex(2) fails with errno set to EINVAL if an attempt 42 * is made to set buf.offset to a value > 512000L 43 * (This test case will be executed only if the kernel version 44 * is 2.6.25 or below) 45 * 5) adjtimex(2) fails with errno set to EINVAL if an attempt 46 * is made to set buf.offset to a value < 512000L 47 * (This test case will be executed only if the kernel version 48 * is 2.6.25 or below) 49 * 6) adjtimex(2) fails with errno set to EPERM if buf.mode is 50 * non-zero and the user is not super-user. 51 * 52 * Setup: 53 * Setup signal handling. 54 * Pause for SIGUSR1 if option specified. 55 * Save current parameters in tim_save 56 * 57 * Test: 58 * Loop if the proper options are given. 59 * Call test case specific setup if needed 60 * call adjtimex with saved timex structure 61 * Check return value is between 0 & 5 62 * Test passed 63 * Otherwise 64 * Test failed 65 * Call test case specific cleanup if needed 66 * 67 * Cleanup: 68 * Print errno log and/or timing stats if options given 69 * 70 * USAGE: <for command-line> 71 * adjtimex02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] [-h] [-f] [-p] 72 * where, -c n : Run n copies concurrently. 73 * -e : Turn on errno logging. 74 * -h : Show help screen 75 * -f : Turn off functional testing 76 * -i n : Execute test n times. 77 * -I x : Execute test for x seconds. 78 * -p : Pause for SIGUSR1 before starting 79 * -P x : Pause for x seconds between iterations. 80 * -t : Turn on syscall timing. 81 * 82 ****************************************************************/ 83 84 #if defined UCLINUX && !__THROW 85 /* workaround for libc bug causing failure in sys/timex.h */ 86 #define __THROW 87 #endif 88 89 #include <errno.h> 90 #include <sys/timex.h> 91 #include <unistd.h> 92 #include <pwd.h> 93 #include "test.h" 94 95 #define SET_MODE ( ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \ 96 ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK ) 97 98 static void setup(void); 99 static int setup2(void); 100 static int setup3(void); 101 static int setup4(void); 102 static int setup5(void); 103 static int setup6(void); 104 static void cleanup(void); 105 static void cleanup6(void); 106 107 char *TCID = "adjtimex02"; 108 109 static int hz; /* HZ from sysconf */ 110 111 static struct timex tim_save; 112 static struct timex buff; 113 114 static char nobody_uid[] = "nobody"; 115 struct passwd *ltpuser; 116 117 struct test_cases_t { 118 struct timex *buffp; 119 int (*setup) (); 120 void (*cleanup) (); 121 int exp_errno; 122 } test_cases[] = { 123 #ifndef UCLINUX 124 /* Skip since uClinux does not implement memory protection */ 125 { 126 (struct timex *)-1, NULL, NULL, EFAULT}, 127 #endif 128 { 129 &buff, setup2, NULL, EINVAL}, { 130 &buff, setup3, NULL, EINVAL}, { 131 &buff, setup4, NULL, EINVAL}, { 132 &buff, setup5, NULL, EINVAL}, { 133 &buff, setup6, cleanup6, EPERM} 134 }; 135 136 int TST_TOTAL = sizeof(test_cases) / sizeof(test_cases[0]); 137 138 int main(int ac, char **av) 139 { 140 141 int lc, i; 142 143 tst_parse_opts(ac, av, NULL, NULL); 144 145 setup(); 146 147 for (lc = 0; TEST_LOOPING(lc); lc++) { 148 149 tst_count = 0; 150 151 for (i = 0; i < TST_TOTAL; ++i) { 152 /* 153 * since Linux 2.6.26, if buf.offset value is outside 154 * the acceptable range, it is simply normalized instead 155 * of letting the syscall fail. so just skip this test 156 * case. 157 */ 158 if ((i == 3 || i == 4) && tst_kvercmp(2, 6, 25) > 0) { 159 tst_resm(TCONF, "this kernel normalizes buf." 160 "offset value if it is outside" 161 " the acceptable range."); 162 continue; 163 } 164 165 buff = tim_save; 166 buff.modes = SET_MODE; 167 if ((test_cases[i].setup) && (test_cases[i].setup())) { 168 tst_resm(TWARN, "setup() failed, skipping" 169 " this test case"); 170 continue; 171 } 172 173 /* Call adjtimex(2) */ 174 TEST(adjtimex(test_cases[i].buffp)); 175 176 if ((TEST_RETURN == -1) && (TEST_ERRNO == 177 test_cases[i].exp_errno)) { 178 tst_resm(TPASS | TTERRNO, 179 "Test Passed, adjtimex() returned -1"); 180 } else { 181 tst_resm(TFAIL | TTERRNO, 182 "Test Failed, adjtimex() returned %ld", 183 TEST_RETURN); 184 } 185 if (test_cases[i].cleanup) { 186 test_cases[i].cleanup(); 187 } 188 } 189 } 190 191 /* cleanup and exit */ 192 cleanup(); 193 194 tst_exit(); 195 196 } 197 198 /* setup() - performs all ONE TIME setup for this test */ 199 void setup(void) 200 { 201 tst_require_root(); 202 203 tim_save.modes = 0; 204 205 tst_sig(NOFORK, DEF_HANDLER, cleanup); 206 207 /* set the HZ from sysconf */ 208 hz = sysconf(_SC_CLK_TCK); 209 if (hz == -1) { 210 tst_brkm(TBROK, NULL, "Failed to read the HZ from sysconf\n"); 211 } 212 213 TEST_PAUSE; 214 215 /* Save current parameters in tim_save */ 216 if ((adjtimex(&tim_save)) == -1) { 217 tst_brkm(TBROK, NULL, "Failed to save current parameters"); 218 } 219 } 220 221 /* 222 *cleanup() - performs all ONE TIME cleanup for this test at 223 * completion or premature exit. 224 */ 225 void cleanup(void) 226 { 227 228 tim_save.modes = SET_MODE; 229 /* Restore saved parameters */ 230 if ((adjtimex(&tim_save)) == -1) { 231 tst_resm(TWARN, "Failed to restore saved parameters"); 232 } 233 } 234 235 int setup2(void) 236 { 237 buff.tick = 900000 / hz - 1; 238 return 0; 239 } 240 241 int setup3(void) 242 { 243 buff.tick = 1100000 / hz + 1; 244 return 0; 245 } 246 247 int setup4(void) 248 { 249 buff.offset = 512000L + 1; 250 return 0; 251 } 252 253 int setup5(void) 254 { 255 buff.offset = (-1) * (512000L) - 1; 256 return 0; 257 } 258 259 int setup6(void) 260 { 261 /* Switch to nobody user for correct error code collection */ 262 if ((ltpuser = getpwnam(nobody_uid)) == NULL) { 263 tst_brkm(TBROK, NULL, "\"nobody\" user not present"); 264 } 265 if (seteuid(ltpuser->pw_uid) == -1) { 266 tst_resm(TWARN | TERRNO, "seteuid(%d) failed", ltpuser->pw_uid); 267 return 1; 268 } 269 return 0; 270 } 271 272 void cleanup6(void) 273 { 274 /* Set effective user id back to root */ 275 if (seteuid(0) == -1) { 276 tst_brkm(TBROK | TERRNO, cleanup, "seteuid failed to set the" 277 " effective uid to root"); 278 } 279 } 280