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