• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "time64_variants.h"
23 #include "tst_timer.h"
24 #include "tst_safe_clocks.h"
25 
26 static void *bad_addr;
27 
28 struct test_case {
29 	clockid_t clktype;
30 	int exp_err;
31 	int allow_inval;
32 };
33 
34 static struct test_case tc[] = {
35 	{
36 	 .clktype = MAX_CLOCKS,
37 	 .exp_err = EINVAL,
38 	 },
39 	{
40 	 .clktype = MAX_CLOCKS + 1,
41 	 .exp_err = EINVAL,
42 	 },
43 	/*
44 	 * Different POSIX clocks have different (*clock_get)() handlers.
45 	 * It justifies testing EFAULT for all.
46 	 */
47 	{
48 	 .clktype = CLOCK_REALTIME,
49 	 .exp_err = EFAULT,
50 	 },
51 	{
52 	 .clktype = CLOCK_MONOTONIC,
53 	 .exp_err = EFAULT,
54 	 },
55 	{
56 	 .clktype = CLOCK_PROCESS_CPUTIME_ID,
57 	 .exp_err = EFAULT,
58 	 },
59 	{
60 	 .clktype = CLOCK_THREAD_CPUTIME_ID,
61 	 .exp_err = EFAULT,
62 	 },
63 	{
64 	 .clktype = CLOCK_REALTIME_COARSE,
65 	 .exp_err = EFAULT,
66 	 .allow_inval = 1,
67 	 },
68 	{
69 	 .clktype = CLOCK_MONOTONIC_COARSE,
70 	 .exp_err = EFAULT,
71 	 .allow_inval = 1,
72 	 },
73 	{
74 	 .clktype = CLOCK_MONOTONIC_RAW,
75 	 .exp_err = EFAULT,
76 	 .allow_inval = 1,
77 	 },
78 	{
79 	 .clktype = CLOCK_BOOTTIME,
80 	 .exp_err = EFAULT,
81 	 .allow_inval = 1,
82 	 },
83 };
84 
85 static struct tst_ts spec;
86 
87 /*
88  * bad pointer w/ libc causes SIGSEGV signal, call syscall directly
89  */
90 static struct time64_variants variants[] = {
91 #if (__NR_clock_gettime != __LTP__NR_INVALID_SYSCALL)
92 	{ .clock_gettime = sys_clock_gettime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
93 #endif
94 
95 #if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL)
96 	{ .clock_gettime = sys_clock_gettime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
97 #endif
98 };
99 
setup(void)100 static void setup(void)
101 {
102 	tst_res(TINFO, "Testing variant: %d: %s", tst_variant, variants[tst_variant].desc);
103 
104 	bad_addr = tst_get_bad_addr(NULL);
105 }
106 
verify_clock_gettime(unsigned int i)107 static void verify_clock_gettime(unsigned int i)
108 {
109 	struct time64_variants *tv = &variants[tst_variant];
110 	void *ts;
111 
112 	/* bad pointer cases */
113 	if (tc[i].exp_err == EFAULT) {
114 		ts = bad_addr;
115 	} else {
116 		spec.type = tv->ts_type;
117 		ts = tst_ts_get(&spec);
118 	}
119 
120 	TEST(tv->clock_gettime(tc[i].clktype, ts));
121 
122 	if (TST_RET != -1) {
123 		tst_res(TFAIL, "clock_gettime(2): clock %s passed unexpectedly",
124 			tst_clock_name(tc[i].clktype));
125 		return;
126 	}
127 
128 	if ((tc[i].exp_err == TST_ERR) ||
129 	    (tc[i].allow_inval && TST_ERR == EINVAL)) {
130 		tst_res(TPASS | TTERRNO, "clock_gettime(2): clock %s failed as expected",
131 			tst_clock_name(tc[i].clktype));
132 	} else {
133 		tst_res(TFAIL | TTERRNO, "clock_gettime(2): clock %s failed unexpectedly",
134 			tst_clock_name(tc[i].clktype));
135 	}
136 }
137 
138 static struct tst_test test = {
139 	.test = verify_clock_gettime,
140 	.tcnt = ARRAY_SIZE(tc),
141 	.test_variants = ARRAY_SIZE(variants),
142 	.setup = setup,
143 	.needs_root = 1,
144 };
145