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  * Bad argument tests for clock_gettime(2) on multiple clocks:
8  *
9  *  1) MAX_CLOCKS
10  *  2) MAX_CLOCKS + 1
11  *  3) CLOCK_REALTIME
12  *  4) CLOCK_MONOTONIC
13  *  5) CLOCK_PROCESS_CPUTIME_ID
14  *  6) CLOCK_THREAD_CPUTIME_ID
15  *  7) CLOCK_REALTIME_COARSE
16  *  8) CLOCK_MONOTONIC_COARSE
17  *  9) CLOCK_MONOTONIC_RAW
18  * 10) CLOCK_BOOTTIME
19  */
20 
21 #include "config.h"
22 #include "tst_test.h"
23 #include "lapi/syscalls.h"
24 #include "tst_timer.h"
25 #include "tst_safe_clocks.h"
26 
27 struct test_case {
28 	clockid_t clktype;
29 	int exp_err;
30 	int allow_inval;
31 };
32 
33 struct test_case tc[] = {
34 	{
35 	 .clktype = MAX_CLOCKS,
36 	 .exp_err = EINVAL,
37 	 },
38 	{
39 	 .clktype = MAX_CLOCKS + 1,
40 	 .exp_err = EINVAL,
41 	 },
42 	/*
43 	 * Different POSIX clocks have different (*clock_get)() handlers.
44 	 * It justifies testing EFAULT for all.
45 	 */
46 	{
47 	 .clktype = CLOCK_REALTIME,
48 	 .exp_err = EFAULT,
49 	 },
50 	{
51 	 .clktype = CLOCK_MONOTONIC,
52 	 .exp_err = EFAULT,
53 	 },
54 	{
55 	 .clktype = CLOCK_PROCESS_CPUTIME_ID,
56 	 .exp_err = EFAULT,
57 	 },
58 	{
59 	 .clktype = CLOCK_THREAD_CPUTIME_ID,
60 	 .exp_err = EFAULT,
61 	 },
62 	{
63 	 .clktype = CLOCK_REALTIME_COARSE,
64 	 .exp_err = EFAULT,
65 	 .allow_inval = 1,
66 	 },
67 	{
68 	 .clktype = CLOCK_MONOTONIC_COARSE,
69 	 .exp_err = EFAULT,
70 	 .allow_inval = 1,
71 	 },
72 	{
73 	 .clktype = CLOCK_MONOTONIC_RAW,
74 	 .exp_err = EFAULT,
75 	 .allow_inval = 1,
76 	 },
77 	{
78 	 .clktype = CLOCK_BOOTTIME,
79 	 .exp_err = EFAULT,
80 	 .allow_inval = 1,
81 	 },
82 };
83 
84 /*
85  * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
86  */
sys_clock_gettime(clockid_t clk_id,struct timespec * tp)87 static int sys_clock_gettime(clockid_t clk_id, struct timespec *tp)
88 {
89 	return tst_syscall(__NR_clock_gettime, clk_id, tp);
90 }
91 
verify_clock_gettime(unsigned int i)92 static void verify_clock_gettime(unsigned int i)
93 {
94 	struct timespec spec, *specptr;
95 
96 	specptr = &spec;
97 
98 	/* bad pointer cases */
99 	if (tc[i].exp_err == EFAULT)
100 		specptr = tst_get_bad_addr(NULL);
101 
102 	TEST(sys_clock_gettime(tc[i].clktype, specptr));
103 
104 	if (TST_RET == -1) {
105 
106 		if ((tc[i].exp_err == TST_ERR) ||
107 			(tc[i].allow_inval && TST_ERR == EINVAL)) {
108 
109 			tst_res(TPASS | TTERRNO, "clock_gettime(2): "
110 					"clock %s failed as expected",
111 					tst_clock_name(tc[i].clktype));
112 
113 		} else {
114 
115 			tst_res(TFAIL | TTERRNO, "clock_gettime(2): "
116 					"clock %s failed unexpectedly",
117 					tst_clock_name(tc[i].clktype));
118 		}
119 
120 	} else {
121 
122 		tst_res(TFAIL, "clock_gettime(2): clock %s passed"
123 				" unexcpectedly",
124 				tst_clock_name(tc[i].clktype));
125 	}
126 }
127 
128 static struct tst_test test = {
129 	.test = verify_clock_gettime,
130 	.tcnt = ARRAY_SIZE(tc),
131 	.needs_root = 1,
132 };
133