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