1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved.
5 * AUTHOR : Saji Kumar.V.R <saji.kumar@wipro.com>
6 */
7
8 /*\
9 * [Description]
10 *
11 * Tests for adjtimex() error conditions:
12 *
13 * - EPERM with SET_MODE as nobody
14 * - EFAULT with SET_MODE and invalid timex pointer
15 * - EINVAL with ADJ_TICK greater than max tick
16 * - EINVAL with ADJ_TICK smaller than min tick
17 *
18 * On kernels older than 2.6.26:
19 *
20 * - EINVAL with AJD_OFFSET smaller than min offset
21 * - EINVAL with AJD_OFFSET greater than max offset
22 */
23
24 #include <errno.h>
25 #include <sys/timex.h>
26 #include <unistd.h>
27 #include <pwd.h>
28 #include "tst_test.h"
29 #include "lapi/syscalls.h"
30
31 #define SET_MODE (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
32 ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
33
34 static int hz; /* HZ from sysconf */
35
36 static struct timex *tim_save, *buf;
37 static struct passwd *ltpuser;
38
libc_adjtimex(struct timex * value)39 static int libc_adjtimex(struct timex *value)
40 {
41 return adjtimex(value);
42 }
43
sys_adjtimex(struct timex * value)44 static int sys_adjtimex(struct timex *value)
45 {
46 return tst_syscall(__NR_adjtimex, value);
47 }
48
49 static struct test_case {
50 unsigned int modes;
51 long lowlimit;
52 long highlimit;
53 long delta;
54 int exp_err;
55 } tc[] = {
56 {.modes = SET_MODE, .exp_err = EPERM},
57 {.modes = SET_MODE, .exp_err = EFAULT},
58 {.modes = ADJ_TICK, .lowlimit = 900000, .delta = 1, .exp_err = EINVAL},
59 {.modes = ADJ_TICK, .highlimit = 1100000, .delta = 1, .exp_err = EINVAL},
60 {.modes = ADJ_OFFSET, .highlimit = 512000L, .delta = 1, .exp_err = EINVAL},
61 {.modes = ADJ_OFFSET, .lowlimit = -512000L, .delta = -1, .exp_err = EINVAL},
62 };
63
64 static struct test_variants
65 {
66 int (*adjtimex)(struct timex *value);
67 char *desc;
68 } variants[] = {
69 { .adjtimex = libc_adjtimex, .desc = "libc adjtimex()"},
70
71 #if (__NR_adjtimex != __LTP__NR_INVALID_SYSCALL)
72 { .adjtimex = sys_adjtimex, .desc = "__NR_adjtimex syscall"},
73 #endif
74 };
75
verify_adjtimex(unsigned int i)76 static void verify_adjtimex(unsigned int i)
77 {
78 struct timex *bufp;
79 struct test_variants *tv = &variants[tst_variant];
80
81 *buf = *tim_save;
82 buf->modes = tc[i].modes;
83 bufp = buf;
84
85 if (tc[i].exp_err == EPERM)
86 SAFE_SETEUID(ltpuser->pw_uid);
87
88 if (tc[i].exp_err == EINVAL) {
89 if (tc[i].modes == ADJ_TICK) {
90 if (tc[i].lowlimit)
91 buf->tick = tc[i].lowlimit - tc[i].delta;
92
93 if (tc[i].highlimit)
94 buf->tick = tc[i].highlimit + tc[i].delta;
95 }
96 if (tc[i].modes == ADJ_OFFSET && (tst_kvercmp(2, 6, 25) > 0)) {
97 if (tc[i].lowlimit || tc[i].highlimit) {
98 tst_res(TCONF, "Newer kernels normalize offset value outside range");
99 return;
100 }
101 }
102 }
103
104 if (tc[i].exp_err == EFAULT) {
105 if (tv->adjtimex != libc_adjtimex) {
106 bufp = (struct timex *) -1;
107 } else {
108 tst_res(TCONF, "EFAULT is skipped for libc variant");
109 return;
110 }
111 }
112
113 TST_EXP_FAIL2(tv->adjtimex(bufp), tc[i].exp_err, "adjtimex() error");
114
115 if (tc[i].exp_err == EPERM)
116 SAFE_SETEUID(0);
117 }
118
setup(void)119 static void setup(void)
120 {
121 struct test_variants *tv = &variants[tst_variant];
122 size_t i;
123
124 tst_res(TINFO, "Testing variant: %s", tv->desc);
125
126 tim_save->modes = 0;
127
128 ltpuser = SAFE_GETPWNAM("nobody");
129 SAFE_SETEUID(ltpuser->pw_uid);
130
131 /* set the HZ from sysconf */
132 hz = SAFE_SYSCONF(_SC_CLK_TCK);
133
134 for (i = 0; i < ARRAY_SIZE(tc); i++) {
135 if (tc[i].modes == ADJ_TICK) {
136 tc[i].highlimit /= hz;
137 tc[i].lowlimit /= hz;
138 }
139 }
140
141 if ((adjtimex(tim_save)) == -1) {
142 tst_brk(TBROK | TERRNO,
143 "adjtimex(): failed to save current params");
144 }
145 }
146
cleanup(void)147 static void cleanup(void)
148 {
149
150 tim_save->modes = SET_MODE;
151
152 /* Restore saved parameters */
153 if ((adjtimex(tim_save)) == -1)
154 tst_res(TWARN, "Failed to restore saved parameters");
155 }
156
157 static struct tst_test test = {
158 .test = verify_adjtimex,
159 .setup = setup,
160 .cleanup = cleanup,
161 .tcnt = ARRAY_SIZE(tc),
162 .test_variants = ARRAY_SIZE(variants),
163 .needs_root = 1,
164 .bufs = (struct tst_buffers []) {
165 {&buf, .size = sizeof(*buf)},
166 {&tim_save, .size = sizeof(*tim_save)},
167 {},
168 }
169 };
170