xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/adjtimex/adjtimex02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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