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 #include "safe_macros.h" 95 96 #define SET_MODE ( ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \ 97 ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK ) 98 99 static void setup(void); 100 static int setup2(void); 101 static int setup3(void); 102 static int setup4(void); 103 static int setup5(void); 104 static int setup6(void); 105 static void cleanup(void); 106 static void cleanup6(void); 107 108 char *TCID = "adjtimex02"; 109 110 static int hz; /* HZ from sysconf */ 111 112 static struct timex tim_save; 113 static struct timex buff; 114 115 static char nobody_uid[] = "nobody"; 116 struct passwd *ltpuser; 117 118 struct test_cases_t { 119 struct timex *buffp; 120 int (*setup) (); 121 void (*cleanup) (); 122 int exp_errno; 123 } test_cases[] = { 124 #ifndef UCLINUX 125 /* Skip since uClinux does not implement memory protection */ 126 { 127 (struct timex *)-1, NULL, NULL, EFAULT}, 128 #endif 129 { 130 &buff, setup2, NULL, EINVAL}, { 131 &buff, setup3, NULL, EINVAL}, { 132 &buff, setup4, NULL, EINVAL}, { 133 &buff, setup5, NULL, EINVAL}, { 134 &buff, setup6, cleanup6, EPERM} 135 }; 136 137 int TST_TOTAL = sizeof(test_cases) / sizeof(test_cases[0]); 138 139 int main(int ac, char **av) 140 { 141 142 int lc, i; 143 144 tst_parse_opts(ac, av, NULL, NULL); 145 146 setup(); 147 148 for (lc = 0; TEST_LOOPING(lc); lc++) { 149 150 tst_count = 0; 151 152 for (i = 0; i < TST_TOTAL; ++i) { 153 /* 154 * since Linux 2.6.26, if buf.offset value is outside 155 * the acceptable range, it is simply normalized instead 156 * of letting the syscall fail. so just skip this test 157 * case. 158 */ 159 if ((i == 3 || i == 4) && tst_kvercmp(2, 6, 25) > 0) { 160 tst_resm(TCONF, "this kernel normalizes buf." 161 "offset value if it is outside" 162 " the acceptable range."); 163 continue; 164 } 165 166 buff = tim_save; 167 buff.modes = SET_MODE; 168 if ((test_cases[i].setup) && (test_cases[i].setup())) { 169 tst_resm(TWARN, "setup() failed, skipping" 170 " this test case"); 171 continue; 172 } 173 174 /* Call adjtimex(2) */ 175 TEST(adjtimex(test_cases[i].buffp)); 176 177 if ((TEST_RETURN == -1) && (TEST_ERRNO == 178 test_cases[i].exp_errno)) { 179 tst_resm(TPASS | TTERRNO, 180 "Test Passed, adjtimex() returned -1"); 181 } else { 182 tst_resm(TFAIL | TTERRNO, 183 "Test Failed, adjtimex() returned %ld", 184 TEST_RETURN); 185 } 186 if (test_cases[i].cleanup) { 187 test_cases[i].cleanup(); 188 } 189 } 190 } 191 192 /* cleanup and exit */ 193 cleanup(); 194 195 tst_exit(); 196 197 } 198 199 /* setup() - performs all ONE TIME setup for this test */ 200 void setup(void) 201 { 202 tst_require_root(); 203 204 tim_save.modes = 0; 205 206 tst_sig(NOFORK, DEF_HANDLER, cleanup); 207 208 /* set the HZ from sysconf */ 209 hz = SAFE_SYSCONF(NULL, _SC_CLK_TCK); 210 211 TEST_PAUSE; 212 213 /* Save current parameters in tim_save */ 214 if ((adjtimex(&tim_save)) == -1) { 215 tst_brkm(TBROK, NULL, "Failed to save current parameters"); 216 } 217 } 218 219 /* 220 *cleanup() - performs all ONE TIME cleanup for this test at 221 * completion or premature exit. 222 */ 223 void cleanup(void) 224 { 225 226 tim_save.modes = SET_MODE; 227 /* Restore saved parameters */ 228 if ((adjtimex(&tim_save)) == -1) { 229 tst_resm(TWARN, "Failed to restore saved parameters"); 230 } 231 } 232 233 int setup2(void) 234 { 235 buff.tick = 900000 / hz - 1; 236 return 0; 237 } 238 239 int setup3(void) 240 { 241 buff.tick = 1100000 / hz + 1; 242 return 0; 243 } 244 245 int setup4(void) 246 { 247 buff.offset = 512000L + 1; 248 return 0; 249 } 250 251 int setup5(void) 252 { 253 buff.offset = (-1) * (512000L) - 1; 254 return 0; 255 } 256 257 int setup6(void) 258 { 259 /* Switch to nobody user for correct error code collection */ 260 if ((ltpuser = getpwnam(nobody_uid)) == NULL) { 261 tst_brkm(TBROK, NULL, "\"nobody\" user not present"); 262 } 263 if (seteuid(ltpuser->pw_uid) == -1) { 264 tst_resm(TWARN | TERRNO, "seteuid(%d) failed", ltpuser->pw_uid); 265 return 1; 266 } 267 return 0; 268 } 269 270 void cleanup6(void) 271 { 272 /* Set effective user id back to root */ 273 SAFE_SETEUID(cleanup, 0); 274 } 275