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