• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd
4  *          Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
5  *		       Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
6  *		       Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
7  * Copyright (c) 2016 Linux Test Project
8  */
9 /*
10  *   test status of errors on man page
11  *   EINTR        v (function was interrupted by a signal)
12  *   EINVAL       v (invalid tv_nsec, etc.)
13  *   ENOTSUP      v (sleep not supported against the specified clock_id)
14  *   EFAULT       v (Invalid request pointer)
15  *   EFAULT       V (Invalid remain pointer when interrupted by a signal)
16  */
17 
18 #include <limits.h>
19 
20 #include "time64_variants.h"
21 #include "tst_safe_clocks.h"
22 #include "tst_sig_proc.h"
23 #include "tst_timer.h"
24 
sighandler(int sig LTP_ATTRIBUTE_UNUSED)25 static void sighandler(int sig LTP_ATTRIBUTE_UNUSED)
26 {
27 }
28 
29 enum test_type {
30 	NORMAL = 1,
31 	SEND_SIGINT = 2,
32 	BAD_TS_ADDR_REQ = 4,
33 	BAD_TS_ADDR_REM = 8,
34 };
35 
36 #define TYPE_NAME(x) .ttype = x, .desc = #x
37 
38 static void *bad_addr;
39 
40 struct test_case {
41 	clockid_t clk_id;	   /* clock_* clock type parameter */
42 	int ttype;		   /* test type (enum) */
43 	const char *desc;	   /* test description (name) */
44 	int flags;		   /* clock_nanosleep flags parameter */
45 	long tv_sec;
46 	long tv_nsec;
47 	int exp_ret;
48 	int exp_err;
49 };
50 
51 static struct test_case tcase[] = {
52 	{
53 		TYPE_NAME(NORMAL),
54 		.clk_id = CLOCK_REALTIME,
55 		.flags = 0,
56 		.tv_sec = 0,
57 		.tv_nsec = -1,
58 		.exp_ret = -1,
59 		.exp_err = EINVAL,
60 	},
61 	{
62 		TYPE_NAME(NORMAL),
63 		.clk_id = CLOCK_REALTIME,
64 		.flags = 0,
65 		.tv_sec = 0,
66 		.tv_nsec = 1000000000,
67 		.exp_ret = -1,
68 		.exp_err = EINVAL,
69 	},
70 	{
71 		TYPE_NAME(NORMAL),
72 		.clk_id = CLOCK_THREAD_CPUTIME_ID,
73 		.flags = 0,
74 		.tv_sec = 0,
75 		.tv_nsec = 500000000,
76 		.exp_ret = -1,
77 		.exp_err = ENOTSUP,
78 	},
79 	{
80 		TYPE_NAME(SEND_SIGINT),
81 		.clk_id = CLOCK_REALTIME,
82 		.flags = 0,
83 		.tv_sec = 10,
84 		.tv_nsec = 0,
85 		.exp_ret = -1,
86 		.exp_err = EINTR,
87 	},
88 	{
89 		TYPE_NAME(BAD_TS_ADDR_REQ),
90 		.clk_id = CLOCK_REALTIME,
91 		.flags = 0,
92 		.exp_ret = -1,
93 		.exp_err = EFAULT,
94 	},
95 	{
96 		TYPE_NAME(BAD_TS_ADDR_REM),
97 		.clk_id = CLOCK_REALTIME,
98 		.flags = 0,
99 		.tv_sec = 10,
100 		.tv_nsec = 0,
101 		.exp_ret = -1,
102 		.exp_err = EFAULT,
103 	},
104 };
105 
106 static struct tst_ts *rq;
107 static struct tst_ts *rm;
108 
109 static struct time64_variants variants[] = {
110 	{ .clock_nanosleep = libc_clock_nanosleep, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"},
111 
112 #if (__NR_clock_nanosleep != __LTP__NR_INVALID_SYSCALL)
113 	{ .clock_nanosleep = sys_clock_nanosleep, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
114 #endif
115 
116 #if (__NR_clock_nanosleep_time64 != __LTP__NR_INVALID_SYSCALL)
117 	{ .clock_nanosleep = sys_clock_nanosleep64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
118 #endif
119 };
120 
setup(void)121 void setup(void)
122 {
123 	rq->type = variants[tst_variant].ts_type;
124 	tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
125 	SAFE_SIGNAL(SIGINT, sighandler);
126 	bad_addr = tst_get_bad_addr(NULL);
127 }
128 
do_test(unsigned int i)129 static void do_test(unsigned int i)
130 {
131 	struct time64_variants *tv = &variants[tst_variant];
132 	struct test_case *tc = &tcase[i];
133 	pid_t pid = 0;
134 	void *request, *remain;
135 
136 	memset(rm, 0, sizeof(*rm));
137 	rm->type = rq->type;
138 
139 	tst_res(TINFO, "case %s", tc->desc);
140 
141 	if (tc->ttype & (BAD_TS_ADDR_REQ | BAD_TS_ADDR_REM) &&
142 	    tv->clock_nanosleep == libc_clock_nanosleep) {
143 		tst_res(TCONF,
144 			"The libc wrapper may dereference req or rem");
145 		return;
146 	}
147 
148 	if (tc->ttype & (SEND_SIGINT | BAD_TS_ADDR_REM))
149 		pid = create_sig_proc(SIGINT, 40, 500000);
150 
151 	tst_ts_set_sec(rq, tc->tv_sec);
152 	tst_ts_set_nsec(rq, tc->tv_nsec);
153 
154 	if (tc->ttype == BAD_TS_ADDR_REQ)
155 		request = bad_addr;
156 	else
157 		request = tst_ts_get(rq);
158 
159 	if (tc->ttype == BAD_TS_ADDR_REM)
160 		remain = bad_addr;
161 	else
162 		remain = tst_ts_get(rm);
163 
164 	TEST(tv->clock_nanosleep(tc->clk_id, tc->flags, request, remain));
165 
166 	if (tv->clock_nanosleep == libc_clock_nanosleep) {
167 		/*
168 		 * The return value and error number are differently set for
169 		 * libc syscall as compared to kernel syscall.
170 		 */
171 		if (TST_RET) {
172 			TST_ERR = TST_RET;
173 			TST_RET = -1;
174 		}
175 
176 		/*
177 		 * nsleep isn't implemented by kernelf or
178 		 * CLOCK_THREAD_CPUTIME_ID and it returns ENOTSUP, but libc
179 		 * changes that error value to EINVAL.
180 		 */
181 		if (tc->clk_id == CLOCK_THREAD_CPUTIME_ID)
182 			tc->exp_err = EINVAL;
183 	}
184 
185 	if (pid) {
186 		SAFE_KILL(pid, SIGTERM);
187 		SAFE_WAIT(NULL);
188 	}
189 
190 	if (tc->ttype == SEND_SIGINT) {
191 		long long expect_ms = tst_ts_to_ms(*rq);
192 		long long remain_ms = tst_ts_to_ms(*rm);
193 
194 		if (tst_ts_valid(rm)) {
195 			tst_res(TFAIL | TTERRNO,
196 				"The clock_nanosleep() haven't updated"
197 				" timespec or it's not valid");
198 			return;
199 		}
200 
201 		if (remain_ms > expect_ms) {
202 			tst_res(TFAIL | TTERRNO,
203 				"remaining time > requested time (%lld > %lld)",
204 				remain_ms, expect_ms);
205 			return;
206 		}
207 
208 		tst_res(TPASS, "Timespec updated correctly");
209 	}
210 
211 	if ((TST_RET != tc->exp_ret) || (TST_ERR != tc->exp_err)) {
212 		tst_res(TFAIL | TTERRNO, "returned %ld, expected %d,"
213 			" expected errno: %s (%d)", TST_RET,
214 			tc->exp_ret, tst_strerrno(tc->exp_err), tc->exp_err);
215 		return;
216 	}
217 
218 	tst_res(TPASS | TTERRNO, "clock_nanosleep() failed with");
219 }
220 
221 static struct tst_test test = {
222 	.tcnt = ARRAY_SIZE(tcase),
223 	.test = do_test,
224 	.test_variants = ARRAY_SIZE(variants),
225 	.setup = setup,
226 	.forks_child = 1,
227 	.bufs = (struct tst_buffers []) {
228 		{&rq, .size = sizeof(*rq)},
229 		{&rm, .size = sizeof(*rm)},
230 		{},
231 	}
232 };
233