• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019 Linaro Limited. All rights reserved.
4  * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
5  */
6 
7 /*
8  * Basic tests for errors of clock_settime(2) on different clock types.
9  */
10 
11 #include "config.h"
12 #include "tst_timer.h"
13 #include "tst_safe_clocks.h"
14 
15 #define DELTA_SEC 10
16 #define NSEC_PER_SEC (1000000000L)
17 
18 static void *bad_addr;
19 
20 struct test_case {
21 	clockid_t type;
22 	int exp_err;
23 	int replace;
24 	long tv_sec;
25 	long tv_nsec;
26 };
27 
28 struct test_case tc[] = {
29 	{				/* case 01: REALTIME: timespec NULL   */
30 	 .type = CLOCK_REALTIME,
31 	 .exp_err = EFAULT,
32 	 .replace = 1,
33 	 .tv_sec = 0,
34 	 .tv_nsec = 0,
35 	 },
36 	{				/* case 02: REALTIME: tv_sec = -1     */
37 	 .type = CLOCK_REALTIME,
38 	 .exp_err = EINVAL,
39 	 .replace = 1,
40 	 .tv_sec = -1,
41 	 .tv_nsec = 0,
42 	 },
43 	{				/* case 03: REALTIME: tv_nsec = -1    */
44 	 .type = CLOCK_REALTIME,
45 	 .exp_err = EINVAL,
46 	 .replace = 1,
47 	 .tv_sec = 0,
48 	 .tv_nsec = -1,
49 	 },
50 	{				/* case 04: REALTIME: tv_nsec = 1s+1  */
51 	 .type = CLOCK_REALTIME,
52 	 .exp_err = EINVAL,
53 	 .replace = 1,
54 	 .tv_sec = 0,
55 	 .tv_nsec = NSEC_PER_SEC + 1,
56 	 },
57 	{				/* case 05: MONOTONIC		      */
58 	 .type = CLOCK_MONOTONIC,
59 	 .exp_err = EINVAL,
60 	 },
61 	{				/* case 06: MAXCLOCK		      */
62 	 .type = MAX_CLOCKS,
63 	 .exp_err = EINVAL,
64 	 },
65 	{				/* case 07: MAXCLOCK+1		      */
66 	 .type = MAX_CLOCKS + 1,
67 	 .exp_err = EINVAL,
68 	 },
69 	/* Linux specific */
70 	{				/* case 08: CLOCK_MONOTONIC_COARSE    */
71 	 .type = CLOCK_MONOTONIC_COARSE,
72 	 .exp_err = EINVAL,
73 	 },
74 	{				/* case 09: CLOCK_MONOTONIC_RAW       */
75 	 .type = CLOCK_MONOTONIC_RAW,
76 	 .exp_err = EINVAL,
77 	 },
78 	{				/* case 10: CLOCK_BOOTTIME	      */
79 	 .type = CLOCK_BOOTTIME,
80 	 .exp_err = EINVAL,
81 	 },
82 	{				/* case 11: CLOCK_PROCESS_CPUTIME_ID  */
83 	 .type = CLOCK_PROCESS_CPUTIME_ID,
84 	 .exp_err = EINVAL,
85 	 },
86 	{				/* case 12: CLOCK_THREAD_CPUTIME_ID   */
87 	 .type = CLOCK_THREAD_CPUTIME_ID,
88 	 .exp_err = EINVAL,
89 	 },
90 };
91 
92 static struct tst_ts spec;
93 
94 static struct test_variants {
95 	int (*gettime)(clockid_t clk_id, void *ts);
96 	int (*settime)(clockid_t clk_id, void *ts);
97 	enum tst_ts_type type;
98 	char *desc;
99 } variants[] = {
100 #if (__NR_clock_settime != __LTP__NR_INVALID_SYSCALL)
101 	{ .gettime = sys_clock_gettime, .settime = sys_clock_settime, .type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
102 #endif
103 
104 #if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL)
105 	{ .gettime = sys_clock_gettime64, .settime = sys_clock_settime64, .type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
106 #endif
107 };
108 
setup(void)109 static void setup(void)
110 {
111 	tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
112 
113 	bad_addr = tst_get_bad_addr(NULL);
114 }
115 
verify_clock_settime(unsigned int i)116 static void verify_clock_settime(unsigned int i)
117 {
118 	struct test_variants *tv = &variants[tst_variant];
119 	void *ts;
120 
121 	spec.type = tv->type;
122 
123 	if (tc[i].replace == 0) {
124 		TEST(tv->gettime(CLOCK_REALTIME, tst_ts_get(&spec)));
125 		if (TST_RET == -1) {
126 			tst_res(TFAIL | TTERRNO, "clock_gettime(2) failed for clock %s",
127 				tst_clock_name(CLOCK_REALTIME));
128 			return;
129 		}
130 
131 		/* add 1 sec to wall clock */
132 		spec = tst_ts_add_us(spec, 1000000);
133 	} else {
134 		/* use given time spec */
135 		tst_ts_set_sec(&spec, tc[i].tv_sec);
136 		tst_ts_set_nsec(&spec, tc[i].tv_nsec);
137 	}
138 
139 	/* bad pointer case */
140 	if (tc[i].exp_err == EFAULT)
141 		ts = bad_addr;
142 	else
143 		ts = tst_ts_get(&spec);
144 
145 	TEST(tv->settime(tc[i].type, ts));
146 
147 	if (TST_RET != -1) {
148 		tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s passed unexpectedly, expected %s",
149 			tst_clock_name(tc[i].type),
150 			tst_strerrno(tc[i].exp_err));
151 		return;
152 	}
153 
154 	if (tc[i].exp_err == TST_ERR) {
155 		tst_res(TPASS | TTERRNO, "clock_settime(%s): failed as expected",
156 			tst_clock_name(tc[i].type));
157 		return;
158 	}
159 
160 	tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s " "expected to fail with %s",
161 		tst_clock_name(tc[i].type), tst_strerrno(tc[i].exp_err));
162 }
163 
164 static struct tst_test test = {
165 	.test = verify_clock_settime,
166 	.test_variants = ARRAY_SIZE(variants),
167 	.setup = setup,
168 	.tcnt = ARRAY_SIZE(tc),
169 	.needs_root = 1,
170 	.restore_wallclock = 1,
171 };
172