1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Linaro Limited. All rights reserved.
4 * Author: Rafael David Tinoco <[email protected]>
5 */
6
7 /*
8 * Basic tests for errors of clock_settime(2) on different clock types.
9 */
10
11 #include "config.h"
12 #include "time64_variants.h"
13 #include "tst_timer.h"
14 #include "tst_safe_clocks.h"
15
16 #define DELTA_SEC 10
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 time64_variants variants[] = {
95 #if (__NR_clock_settime != __LTP__NR_INVALID_SYSCALL)
96 { .clock_gettime = sys_clock_gettime, .clock_settime = sys_clock_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
97 #endif
98
99 #if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL)
100 { .clock_gettime = sys_clock_gettime64, .clock_settime = sys_clock_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
101 #endif
102 };
103
setup(void)104 static void setup(void)
105 {
106 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
107
108 bad_addr = tst_get_bad_addr(NULL);
109 }
110
verify_clock_settime(unsigned int i)111 static void verify_clock_settime(unsigned int i)
112 {
113 struct time64_variants *tv = &variants[tst_variant];
114 void *ts;
115
116 spec.type = tv->ts_type;
117
118 if (tc[i].replace == 0) {
119 TEST(tv->clock_gettime(CLOCK_REALTIME, tst_ts_get(&spec)));
120 if (TST_RET == -1) {
121 tst_res(TFAIL | TTERRNO, "clock_gettime(2) failed for clock %s",
122 tst_clock_name(CLOCK_REALTIME));
123 return;
124 }
125
126 /* add 1 sec to wall clock */
127 spec = tst_ts_add_us(spec, 1000000);
128 } else {
129 /* use given time spec */
130 tst_ts_set_sec(&spec, tc[i].tv_sec);
131 tst_ts_set_nsec(&spec, tc[i].tv_nsec);
132 }
133
134 /* bad pointer case */
135 if (tc[i].exp_err == EFAULT)
136 ts = bad_addr;
137 else
138 ts = tst_ts_get(&spec);
139
140 TEST(tv->clock_settime(tc[i].type, ts));
141
142 if (TST_RET != -1) {
143 tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s passed unexpectedly, expected %s",
144 tst_clock_name(tc[i].type),
145 tst_strerrno(tc[i].exp_err));
146 return;
147 }
148
149 if (tc[i].exp_err == TST_ERR) {
150 tst_res(TPASS | TTERRNO, "clock_settime(%s): failed as expected",
151 tst_clock_name(tc[i].type));
152 return;
153 }
154
155 tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s " "expected to fail with %s",
156 tst_clock_name(tc[i].type), tst_strerrno(tc[i].exp_err));
157 }
158
159 static struct tst_test test = {
160 .test = verify_clock_settime,
161 .test_variants = ARRAY_SIZE(variants),
162 .setup = setup,
163 .tcnt = ARRAY_SIZE(tc),
164 .needs_root = 1,
165 .restore_wallclock = 1,
166 };
167