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