t_siginfo.c revision 272343
1/* $NetBSD: t_siginfo.c,v 1.23 2014/02/09 21:26:07 jmmv Exp $ */
2
3/*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <atf-c.h>
30#include <atf-c/config.h>
31
32#include <sys/inttypes.h>
33#include <sys/resource.h>
34#include <sys/sysctl.h>
35#include <sys/time.h>
36#include <sys/ucontext.h>
37#include <sys/wait.h>
38
39#include <assert.h>
40#include <signal.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#include <setjmp.h>
46#include <float.h>
47
48#ifdef HAVE_FENV
49#include <fenv.h>
50#elif defined(_FLOAT_IEEE754)
51#include <ieeefp.h>
52#endif
53
54#include "isqemu.h"
55
56/* for sigbus */
57volatile char *addr;
58
59/* for sigchild */
60pid_t child;
61int code;
62int status;
63
64/* for sigfpe */
65sig_atomic_t fltdiv_signalled = 0;
66sig_atomic_t intdiv_signalled = 0;
67
68static void
69sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
70{
71	unsigned int i;
72
73	printf("%d %p %p\n", signo, info, ctx);
74	if (info != NULL) {
75		printf("si_signo=%d\n", info->si_signo);
76		printf("si_errno=%d\n", info->si_errno);
77		printf("si_code=%d\n", info->si_code);
78		printf("si_value.sival_int=%d\n", info->si_value.sival_int);
79	}
80	if (ctx != NULL) {
81		printf("uc_flags 0x%x\n", ctx->uc_flags);
82		printf("uc_link %p\n", ctx->uc_link);
83		for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
84			printf("uc_sigmask[%d] 0x%x\n", i,
85			    ctx->uc_sigmask.__bits[i]);
86		printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
87		    (unsigned long)ctx->uc_stack.ss_size,
88		    ctx->uc_stack.ss_flags);
89		for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
90			printf("uc_mcontext.greg[%d] 0x%lx\n", i,
91			    (long)ctx->uc_mcontext.__gregs[i]);
92	}
93}
94
95static void
96sigalrm_action(int signo, siginfo_t *info, void *ptr)
97{
98
99	sig_debug(signo, info, (ucontext_t *)ptr);
100
101	ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
102	ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
103	ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
104
105	atf_tc_pass();
106	/* NOTREACHED */
107}
108
109ATF_TC(sigalarm);
110
111ATF_TC_HEAD(sigalarm, tc)
112{
113
114	atf_tc_set_md_var(tc, "descr",
115	    "Checks that signal trampoline correctly calls SIGALRM handler");
116}
117
118ATF_TC_BODY(sigalarm, tc)
119{
120	struct sigaction sa;
121	sa.sa_flags = SA_SIGINFO;
122	sa.sa_sigaction = sigalrm_action;
123	sigemptyset(&sa.sa_mask);
124	sigaction(SIGALRM, &sa, NULL);
125	for (;;) {
126		alarm(1);
127		sleep(1);
128	}
129	atf_tc_fail("SIGALRM handler wasn't called");
130}
131
132static void
133sigchild_action(int signo, siginfo_t *info, void *ptr)
134{
135	if (info != NULL) {
136		printf("info=%p\n", info);
137		printf("ptr=%p\n", ptr);
138		printf("si_signo=%d\n", info->si_signo);
139		printf("si_errno=%d\n", info->si_errno);
140		printf("si_code=%d\n", info->si_code);
141		printf("si_uid=%d\n", info->si_uid);
142		printf("si_pid=%d\n", info->si_pid);
143		printf("si_status=%d\n", info->si_status);
144		printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
145		printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
146	}
147	ATF_REQUIRE_EQ(info->si_code, code);
148	ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
149	ATF_REQUIRE_EQ(info->si_uid, getuid());
150	ATF_REQUIRE_EQ(info->si_pid, child);
151	if (WIFEXITED(info->si_status))
152		ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
153	else if (WIFSTOPPED(info->si_status))
154		ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
155	else if (WIFSIGNALED(info->si_status))
156		ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
157}
158
159static void
160setchildhandler(void (*action)(int, siginfo_t *, void *))
161{
162	struct sigaction sa;
163	sa.sa_flags = SA_SIGINFO;
164	sa.sa_sigaction = action;
165	sigemptyset(&sa.sa_mask);
166	sigaction(SIGCHLD, &sa, NULL);
167}
168
169static void
170sigchild_setup(void)
171{
172	sigset_t set;
173	struct rlimit rlim;
174
175	(void)getrlimit(RLIMIT_CORE, &rlim);
176	rlim.rlim_cur = rlim.rlim_max;
177	(void)setrlimit(RLIMIT_CORE, &rlim);
178
179	setchildhandler(sigchild_action);
180	sigemptyset(&set);
181	sigaddset(&set, SIGCHLD);
182	sigprocmask(SIG_BLOCK, &set, NULL);
183}
184
185ATF_TC(sigchild_normal);
186ATF_TC_HEAD(sigchild_normal, tc)
187{
188
189	atf_tc_set_md_var(tc, "descr",
190	    "Checks that signal trampoline correctly calls SIGCHLD handler "
191	    "when child exits normally");
192}
193
194ATF_TC_BODY(sigchild_normal, tc)
195{
196	sigset_t set;
197
198	sigchild_setup();
199
200	status = 25;
201	code = CLD_EXITED;
202
203	switch ((child = fork())) {
204	case 0:
205		sleep(1);
206		exit(status);
207	case -1:
208		atf_tc_fail("fork failed");
209	default:
210		sigemptyset(&set);
211		sigsuspend(&set);
212	}
213}
214
215ATF_TC(sigchild_dump);
216ATF_TC_HEAD(sigchild_dump, tc)
217{
218
219	atf_tc_set_md_var(tc, "descr",
220	    "Checks that signal trampoline correctly calls SIGCHLD handler "
221	    "when child segfaults");
222}
223
224ATF_TC_BODY(sigchild_dump, tc)
225{
226	sigset_t set;
227
228	sigchild_setup();
229
230	status = SIGSEGV;
231	code = CLD_DUMPED;
232
233	switch ((child = fork())) {
234	case 0:
235		sleep(1);
236		*(volatile long *)0 = 0;
237		atf_tc_fail("Child did not segfault");
238		/* NOTREACHED */
239	case -1:
240		atf_tc_fail("fork failed");
241	default:
242		sigemptyset(&set);
243		sigsuspend(&set);
244	}
245}
246
247ATF_TC(sigchild_kill);
248ATF_TC_HEAD(sigchild_kill, tc)
249{
250
251	atf_tc_set_md_var(tc, "descr",
252	    "Checks that signal trampoline correctly calls SIGCHLD handler "
253	    "when child is killed");
254}
255
256ATF_TC_BODY(sigchild_kill, tc)
257{
258	sigset_t set;
259
260	sigchild_setup();
261
262	status = SIGPIPE;
263	code = CLD_KILLED;
264
265	switch ((child = fork())) {
266	case 0:
267		sigemptyset(&set);
268		sigsuspend(&set);
269		break;
270	case -1:
271		atf_tc_fail("fork failed");
272	default:
273		kill(child, SIGPIPE);
274		sigemptyset(&set);
275		sigsuspend(&set);
276	}
277}
278
279static sigjmp_buf sigfpe_flt_env;
280static void
281sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
282{
283
284	sig_debug(signo, info, (ucontext_t *)ptr);
285
286	if (fltdiv_signalled++ != 0)
287		atf_tc_fail("FPE handler called more than once");
288
289	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
290	ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
291	ATF_REQUIRE_EQ(info->si_errno, 0);
292
293	siglongjmp(sigfpe_flt_env, 1);
294}
295
296ATF_TC(sigfpe_flt);
297ATF_TC_HEAD(sigfpe_flt, tc)
298{
299
300	atf_tc_set_md_var(tc, "descr",
301	    "Checks that signal trampoline correctly calls SIGFPE handler "
302	    "for floating div-by-zero");
303}
304
305ATF_TC_BODY(sigfpe_flt, tc)
306{
307	struct sigaction sa;
308	double d = strtod("0", NULL);
309
310	if (isQEMU())
311		atf_tc_skip("Test does not run correctly under QEMU");
312#if defined(__powerpc__)
313	atf_tc_skip("Test not valid on powerpc");
314#endif
315	if (sigsetjmp(sigfpe_flt_env, 0) == 0) {
316		sa.sa_flags = SA_SIGINFO;
317		sa.sa_sigaction = sigfpe_flt_action;
318		sigemptyset(&sa.sa_mask);
319		sigaction(SIGFPE, &sa, NULL);
320#ifdef HAVE_FENV
321		feenableexcept(FE_ALL_EXCEPT);
322#elif defined(_FLOAT_IEEE754)
323		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
324#endif
325		printf("%g\n", 1 / d);
326	}
327	if (fltdiv_signalled == 0)
328		atf_tc_fail("FPE signal handler was not invoked");
329}
330
331static sigjmp_buf sigfpe_int_env;
332static void
333sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
334{
335
336	sig_debug(signo, info, (ucontext_t *)ptr);
337
338	if (intdiv_signalled++ != 0)
339		atf_tc_fail("INTDIV handler called more than once");
340
341	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
342	ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
343	atf_tc_expect_pass();
344	ATF_REQUIRE_EQ(info->si_errno, 0);
345
346	siglongjmp(sigfpe_int_env, 1);
347}
348
349ATF_TC(sigfpe_int);
350ATF_TC_HEAD(sigfpe_int, tc)
351{
352
353	atf_tc_set_md_var(tc, "descr",
354	    "Checks that signal trampoline correctly calls SIGFPE handler "
355	    "for integer div-by-zero (PR port-i386/43655)");
356}
357
358ATF_TC_BODY(sigfpe_int, tc)
359{
360	struct sigaction sa;
361	long l = strtol("0", NULL, 10);
362
363#if defined(__powerpc__)
364	atf_tc_skip("Test not valid on powerpc");
365#endif
366	if (sigsetjmp(sigfpe_int_env, 0) == 0) {
367		sa.sa_flags = SA_SIGINFO;
368		sa.sa_sigaction = sigfpe_int_action;
369		sigemptyset(&sa.sa_mask);
370		sigaction(SIGFPE, &sa, NULL);
371#ifdef HAVE_FENV
372		feenableexcept(FE_ALL_EXCEPT);
373#elif defined(_FLOAT_IEEE754)
374		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
375#endif
376		printf("%ld\n", 1 / l);
377	}
378	if (intdiv_signalled == 0)
379		atf_tc_fail("FPE signal handler was not invoked");
380}
381
382static void
383sigsegv_action(int signo, siginfo_t *info, void *ptr)
384{
385
386	sig_debug(signo, info, (ucontext_t *)ptr);
387
388	ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
389	ATF_REQUIRE_EQ(info->si_errno, 0);
390	ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
391	ATF_REQUIRE_EQ(info->si_addr, (void *)0);
392
393	atf_tc_pass();
394	/* NOTREACHED */
395}
396
397ATF_TC(sigsegv);
398ATF_TC_HEAD(sigsegv, tc)
399{
400
401	atf_tc_set_md_var(tc, "descr",
402	    "Checks that signal trampoline correctly calls SIGSEGV handler");
403}
404
405ATF_TC_BODY(sigsegv, tc)
406{
407	struct sigaction sa;
408
409	sa.sa_flags = SA_SIGINFO;
410	sa.sa_sigaction = sigsegv_action;
411	sigemptyset(&sa.sa_mask);
412	sigaction(SIGSEGV, &sa, NULL);
413
414	*(volatile long *)0 = 0;
415	atf_tc_fail("Test did not fault as expected");
416}
417
418static void
419sigbus_action(int signo, siginfo_t *info, void *ptr)
420{
421
422	printf("si_addr = %p\n", info->si_addr);
423	sig_debug(signo, info, (ucontext_t *)ptr);
424
425	ATF_REQUIRE_EQ(info->si_signo, SIGBUS);
426	ATF_REQUIRE_EQ(info->si_errno, 0);
427	ATF_REQUIRE_EQ(info->si_code, BUS_ADRALN);
428
429#if defined(__i386__) || defined(__x86_64__)
430	atf_tc_expect_fail("x86 architecture does not correctly "
431	    "report the address where the unaligned access occured");
432#endif
433	ATF_REQUIRE_EQ(info->si_addr, (volatile void *)addr);
434
435	atf_tc_pass();
436	/* NOTREACHED */
437}
438
439ATF_TC(sigbus_adraln);
440ATF_TC_HEAD(sigbus_adraln, tc)
441{
442
443	atf_tc_set_md_var(tc, "descr",
444	    "Checks that signal trampoline correctly calls SIGBUS handler "
445	    "for invalid address alignment");
446}
447
448ATF_TC_BODY(sigbus_adraln, tc)
449{
450	struct sigaction sa;
451
452#if defined(__alpha__)
453	int rv, val;
454	size_t len = sizeof(val);
455	rv = sysctlbyname("machdep.unaligned_sigbus", &val, &len, NULL, 0);
456	ATF_REQUIRE(rv == 0);
457	if (val == 0)
458		atf_tc_skip("SIGBUS signal not enabled for unaligned accesses");
459#endif
460
461	sa.sa_flags = SA_SIGINFO;
462	sa.sa_sigaction = sigbus_action;
463	sigemptyset(&sa.sa_mask);
464	sigaction(SIGBUS, &sa, NULL);
465
466	/* Enable alignment checks for x86. 0x40000 is PSL_AC. */
467#if defined(__i386__)
468	__asm__("pushf; orl $0x40000, (%esp); popf");
469#elif defined(__amd64__)
470	__asm__("pushf; orl $0x40000, (%rsp); popf");
471#endif
472
473	addr = calloc(2, sizeof(int));
474	ATF_REQUIRE(addr != NULL);
475
476	if (isQEMU())
477		atf_tc_expect_fail("QEMU fails to trap unaligned accesses");
478
479	/* Force an unaligned access */
480	addr++;
481	printf("now trying to access unaligned address %p\n", addr);
482	ATF_REQUIRE_EQ(*(volatile int *)addr, 0);
483
484	atf_tc_fail("Test did not fault as expected");
485}
486
487ATF_TP_ADD_TCS(tp)
488{
489
490	ATF_TP_ADD_TC(tp, sigalarm);
491	ATF_TP_ADD_TC(tp, sigchild_normal);
492	ATF_TP_ADD_TC(tp, sigchild_dump);
493	ATF_TP_ADD_TC(tp, sigchild_kill);
494	ATF_TP_ADD_TC(tp, sigfpe_flt);
495	ATF_TP_ADD_TC(tp, sigfpe_int);
496	ATF_TP_ADD_TC(tp, sigsegv);
497	ATF_TP_ADD_TC(tp, sigbus_adraln);
498
499	return atf_no_error();
500}
501