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_test.h"
13 #include "lapi/syscalls.h"
14 #include "tst_timer.h"
15 #include "tst_safe_clocks.h"
16 
17 #define DELTA_SEC 10
18 #define NSEC_PER_SEC (1000000000L)
19 
20 struct test_case {
21 	clockid_t type;
22 	struct timespec newtime;
23 	int exp_err;
24 	int replace;
25 };
26 
27 struct test_case tc[] = {
28 	{				/* case 01: REALTIME: timespec NULL   */
29 	 .type = CLOCK_REALTIME,
30 	 .exp_err = EFAULT,
31 	 .replace = 1,
32 	 },
33 	{				/* case 02: REALTIME: tv_sec = -1     */
34 	 .type = CLOCK_REALTIME,
35 	 .newtime.tv_sec = -1,
36 	 .exp_err = EINVAL,
37 	 .replace = 1,
38 	 },
39 	{				/* case 03: REALTIME: tv_nsec = -1    */
40 	 .type = CLOCK_REALTIME,
41 	 .newtime.tv_nsec = -1,
42 	 .exp_err = EINVAL,
43 	 .replace = 1,
44 	 },
45 	{				/* case 04: REALTIME: tv_nsec = 1s+1  */
46 	 .type = CLOCK_REALTIME,
47 	 .newtime.tv_nsec = NSEC_PER_SEC + 1,
48 	 .exp_err = EINVAL,
49 	 .replace = 1,
50 	 },
51 	{				/* case 05: MONOTONIC		      */
52 	 .type = CLOCK_MONOTONIC,
53 	 .exp_err = EINVAL,
54 	 },
55 	{				/* case 06: MAXCLOCK		      */
56 	 .type = MAX_CLOCKS,
57 	 .exp_err = EINVAL,
58 	 },
59 	{				/* case 07: MAXCLOCK+1		      */
60 	 .type = MAX_CLOCKS + 1,
61 	 .exp_err = EINVAL,
62 	 },
63 	/* Linux specific */
64 	{				/* case 08: CLOCK_MONOTONIC_COARSE    */
65 	 .type = CLOCK_MONOTONIC_COARSE,
66 	 .exp_err = EINVAL,
67 	 },
68 	{				/* case 09: CLOCK_MONOTONIC_RAW       */
69 	 .type = CLOCK_MONOTONIC_RAW,
70 	 .exp_err = EINVAL,
71 	 },
72 	{				/* case 10: CLOCK_BOOTTIME	      */
73 	 .type = CLOCK_BOOTTIME,
74 	 .exp_err = EINVAL,
75 	 },
76 	{				/* case 11: CLOCK_PROCESS_CPUTIME_ID  */
77 	 .type = CLOCK_PROCESS_CPUTIME_ID,
78 	 .exp_err = EINVAL,
79 	 },
80 	{				/* case 12: CLOCK_THREAD_CPUTIME_ID   */
81 	 .type = CLOCK_THREAD_CPUTIME_ID,
82 	 .exp_err = EINVAL,
83 	 },
84 };
85 
86 /*
87  * Some tests may cause libc to segfault when passing bad arguments.
88  */
sys_clock_settime(clockid_t clk_id,struct timespec * tp)89 static int sys_clock_settime(clockid_t clk_id, struct timespec *tp)
90 {
91 	return tst_syscall(__NR_clock_settime, clk_id, tp);
92 }
93 
verify_clock_settime(unsigned int i)94 static void verify_clock_settime(unsigned int i)
95 {
96 	struct timespec spec, *specptr;
97 
98 	specptr = &spec;
99 
100 	if (tc[i].replace == 0) {
101 
102 		SAFE_CLOCK_GETTIME(CLOCK_REALTIME, specptr);
103 
104 		/* add 1 sec to wall clock */
105 		specptr->tv_sec += 1;
106 
107 	} else {
108 
109 		/* use given time spec */
110 		*specptr = tc[i].newtime;
111 	}
112 
113 	/* bad pointer case */
114 	if (tc[i].exp_err == EFAULT)
115 		specptr = tst_get_bad_addr(NULL);
116 
117 	TEST(sys_clock_settime(tc[i].type, specptr));
118 
119 	if (TST_RET == -1) {
120 
121 		if (tc[i].exp_err == TST_ERR) {
122 			tst_res(TPASS | TTERRNO,
123 				"clock_settime(%s): failed as expected",
124 				tst_clock_name(tc[i].type));
125 			return;
126 		}
127 
128 		tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s "
129 			"expected to fail with %s",
130 			tst_clock_name(tc[i].type),
131 			tst_strerrno(tc[i].exp_err));
132 
133 		return;
134 	}
135 
136 	tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s passed "
137 				 "unexpectedly, expected %s",
138 				 tst_clock_name(tc[i].type),
139 				 tst_strerrno(tc[i].exp_err));
140 }
141 
142 static struct tst_test test = {
143 	.test = verify_clock_settime,
144 	.tcnt = ARRAY_SIZE(tc),
145 	.needs_root = 1,
146 	.restore_wallclock = 1,
147 };
148