• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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