xref: /openbsd-src/regress/sys/kern/signal/siginfo-fault/siginfo-fault.c (revision 31e18b07b9f98cacc0ab5c092b28d4552a954be5)
1*31e18b07Skettenis /*	$OpenBSD: siginfo-fault.c,v 1.2 2021/09/28 08:56:15 kettenis Exp $	*/
26bcfccdaSmpi /*
36bcfccdaSmpi  * Copyright (c) 2014 Google Inc.
46bcfccdaSmpi  *
56bcfccdaSmpi  * Permission to use, copy, modify, and distribute this software for any
66bcfccdaSmpi  * purpose with or without fee is hereby granted, provided that the above
76bcfccdaSmpi  * copyright notice and this permission notice appear in all copies.
86bcfccdaSmpi  *
96bcfccdaSmpi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106bcfccdaSmpi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116bcfccdaSmpi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126bcfccdaSmpi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136bcfccdaSmpi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146bcfccdaSmpi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156bcfccdaSmpi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166bcfccdaSmpi  */
176bcfccdaSmpi 
186bcfccdaSmpi #include <sys/mman.h>
196bcfccdaSmpi 
206bcfccdaSmpi #include <assert.h>
216bcfccdaSmpi #include <errno.h>
226bcfccdaSmpi #include <fcntl.h>
236bcfccdaSmpi #include <limits.h>
246bcfccdaSmpi #include <setjmp.h>
256bcfccdaSmpi #include <signal.h>
266bcfccdaSmpi #include <stdio.h>
276bcfccdaSmpi #include <stdint.h>
286bcfccdaSmpi #include <stdlib.h>
296bcfccdaSmpi #include <string.h>
306bcfccdaSmpi #include <unistd.h>
316bcfccdaSmpi 
326bcfccdaSmpi /*
33*31e18b07Skettenis  * Some architectures may deliver an imprecise fault address.
346bcfccdaSmpi  */
356bcfccdaSmpi #ifdef __sparc64__
366bcfccdaSmpi #define EXPADDR_MASK	~(3UL)
376bcfccdaSmpi #else
386bcfccdaSmpi #define EXPADDR_MASK	~(0UL)
396bcfccdaSmpi #endif
406bcfccdaSmpi 
416bcfccdaSmpi #define CHECK_EQ(a, b) assert((a) == (b))
426bcfccdaSmpi #define CHECK_NE(a, b) assert((a) != (b))
436bcfccdaSmpi #define CHECK_LE(a, b) assert((a) <= (b))
446bcfccdaSmpi #define FAIL() assert(0)
456bcfccdaSmpi 
466bcfccdaSmpi static jmp_buf env;
476bcfccdaSmpi static volatile int gotsigno;
486bcfccdaSmpi static volatile siginfo_t gotsi;
496bcfccdaSmpi 
506bcfccdaSmpi static void
sigsegv(int signo,siginfo_t * si,void * ctx)516bcfccdaSmpi sigsegv(int signo, siginfo_t *si, void *ctx)
526bcfccdaSmpi {
536bcfccdaSmpi 	gotsigno = signo;
546bcfccdaSmpi 	gotsi = *si;
556bcfccdaSmpi 	siglongjmp(env, 1);
566bcfccdaSmpi }
576bcfccdaSmpi 
586bcfccdaSmpi static const char *
strsigcode(int signum,int sigcode)596bcfccdaSmpi strsigcode(int signum, int sigcode)
606bcfccdaSmpi {
616bcfccdaSmpi 	switch (signum) {
626bcfccdaSmpi 	case SIGSEGV:
636bcfccdaSmpi 		switch (sigcode) {
646bcfccdaSmpi 		case SEGV_MAPERR:
656bcfccdaSmpi 			return "address not mapped to object";
666bcfccdaSmpi 		case SEGV_ACCERR:
676bcfccdaSmpi 			return "invalid permissions";
686bcfccdaSmpi 		}
696bcfccdaSmpi 		break;
706bcfccdaSmpi 	case SIGBUS:
716bcfccdaSmpi 		switch (sigcode) {
726bcfccdaSmpi 		case BUS_ADRALN:
736bcfccdaSmpi 			return "invalid address alignment";
746bcfccdaSmpi 		case BUS_ADRERR:
756bcfccdaSmpi 			return "non-existent physical address";
766bcfccdaSmpi 		case BUS_OBJERR:
776bcfccdaSmpi 			return "object specific hardware error";
786bcfccdaSmpi 		}
796bcfccdaSmpi 		break;
806bcfccdaSmpi 	}
816bcfccdaSmpi 	return "unknown";
826bcfccdaSmpi }
836bcfccdaSmpi 
846bcfccdaSmpi static int
checksig(const char * name,int expsigno,int expcode,volatile char * expaddr)856bcfccdaSmpi checksig(const char *name, int expsigno, int expcode, volatile char *expaddr)
866bcfccdaSmpi {
876bcfccdaSmpi 	int fail = 0;
886bcfccdaSmpi 	char str1[NL_TEXTMAX], str2[NL_TEXTMAX];
896bcfccdaSmpi 
906bcfccdaSmpi 	expaddr = (char *)((uintptr_t)expaddr & EXPADDR_MASK);
916bcfccdaSmpi 
926bcfccdaSmpi 	if (expsigno != gotsigno) {
936bcfccdaSmpi 		strlcpy(str1, strsignal(expsigno), sizeof(str1));
946bcfccdaSmpi 		strlcpy(str2, strsignal(gotsigno), sizeof(str2));
956bcfccdaSmpi 		fprintf(stderr, "%s signo: expect %d (%s), actual %d (%s)\n",
966bcfccdaSmpi 		    name, expsigno, str1, gotsigno, str2);
976bcfccdaSmpi 		++fail;
986bcfccdaSmpi 	}
996bcfccdaSmpi 	if (expsigno != gotsi.si_signo) {
1006bcfccdaSmpi 		strlcpy(str1, strsignal(expsigno), sizeof(str1));
1016bcfccdaSmpi 		strlcpy(str2, strsignal(gotsi.si_signo), sizeof(str2));
1026bcfccdaSmpi 		fprintf(stderr, "%s si_signo: expect %d (%s), actual %d (%s)\n",
1036bcfccdaSmpi 		    name, expsigno, str1, gotsi.si_signo, str2);
1046bcfccdaSmpi 		++fail;
1056bcfccdaSmpi 	}
1066bcfccdaSmpi 	if (expcode != gotsi.si_code) {
1076bcfccdaSmpi 		fprintf(stderr, "%s si_code: expect %d (%s), actual %d (%s)\n",
1086bcfccdaSmpi 		    name, expcode, strsigcode(expsigno, expcode),
1096bcfccdaSmpi 		    gotsi.si_code, strsigcode(gotsigno, gotsi.si_code));
1106bcfccdaSmpi 		++fail;
1116bcfccdaSmpi 	}
112*31e18b07Skettenis 	if (expaddr != (char *)((uintptr_t)gotsi.si_addr & EXPADDR_MASK)) {
1136bcfccdaSmpi 		fprintf(stderr, "%s si_addr: expect %p, actual %p\n",
1146bcfccdaSmpi 		    name, expaddr, gotsi.si_addr);
1156bcfccdaSmpi 		++fail;
1166bcfccdaSmpi 	}
1176bcfccdaSmpi 	return (fail);
1186bcfccdaSmpi }
1196bcfccdaSmpi 
1206bcfccdaSmpi int
main()1216bcfccdaSmpi main()
1226bcfccdaSmpi {
1236bcfccdaSmpi 	int fail = 0;
1246bcfccdaSmpi 	long pagesize = sysconf(_SC_PAGESIZE);
1256bcfccdaSmpi 	CHECK_NE(-1, pagesize);
1266bcfccdaSmpi 
1276bcfccdaSmpi 	const struct sigaction sa = {
1286bcfccdaSmpi 		.sa_sigaction = sigsegv,
1296bcfccdaSmpi 		.sa_flags = SA_SIGINFO,
1306bcfccdaSmpi 	};
1316bcfccdaSmpi 	CHECK_EQ(0, sigaction(SIGSEGV, &sa, NULL));
1326bcfccdaSmpi 	CHECK_EQ(0, sigaction(SIGBUS, &sa, NULL));
1336bcfccdaSmpi 
1346bcfccdaSmpi 	volatile char *p;
1356bcfccdaSmpi 	CHECK_NE(MAP_FAILED, (p = mmap(NULL, pagesize, PROT_NONE,
1366bcfccdaSmpi 	    MAP_PRIVATE|MAP_ANON, -1, 0)));
1376bcfccdaSmpi 
1386bcfccdaSmpi 	CHECK_EQ(0, mprotect((void *)p, pagesize, PROT_READ));
1396bcfccdaSmpi 	if (sigsetjmp(env, 1) == 0) {
1406bcfccdaSmpi 		p[0] = 1;
1416bcfccdaSmpi 		FAIL();
1426bcfccdaSmpi 	}
1436bcfccdaSmpi 	fail += checksig("mprotect read", SIGSEGV, SEGV_ACCERR, p);
1446bcfccdaSmpi 
1456bcfccdaSmpi 	CHECK_EQ(0, mprotect((void *)p, pagesize, PROT_NONE));
1466bcfccdaSmpi 	if (sigsetjmp(env, 1) == 0) {
1476bcfccdaSmpi 		(void)p[1];
1486bcfccdaSmpi 		FAIL();
1496bcfccdaSmpi 	}
1506bcfccdaSmpi 	fail += checksig("mprotect none", SIGSEGV, SEGV_ACCERR, p + 1);
1516bcfccdaSmpi 
1526bcfccdaSmpi 	CHECK_EQ(0, munmap((void *)p, pagesize));
1536bcfccdaSmpi 	if (sigsetjmp(env, 1) == 0) {
1546bcfccdaSmpi 		(void)p[2];
1556bcfccdaSmpi 		FAIL();
1566bcfccdaSmpi 	}
1576bcfccdaSmpi 	fail += checksig("munmap", SIGSEGV, SEGV_MAPERR, p + 2);
1586bcfccdaSmpi 
1596bcfccdaSmpi 	char filename[] = "/tmp/siginfo-fault.XXXXXXXX";
1606bcfccdaSmpi 	int fd;
1616bcfccdaSmpi 	CHECK_LE(0, (fd = mkstemp(filename)));
1626bcfccdaSmpi 	CHECK_EQ(0, unlink(filename));
1636bcfccdaSmpi 	CHECK_EQ(0, ftruncate(fd, 0));  /* just in case */
1646bcfccdaSmpi 	CHECK_NE(MAP_FAILED, (p = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
1656bcfccdaSmpi 	    MAP_SHARED, fd, 0)));
1666bcfccdaSmpi 	CHECK_EQ(0, close(fd));
1676bcfccdaSmpi 
1686bcfccdaSmpi 	if (sigsetjmp(env, 1) == 0) {
1696bcfccdaSmpi 		p[3] = 1;
1706bcfccdaSmpi 		FAIL();
1716bcfccdaSmpi 	}
1726bcfccdaSmpi 	fail += checksig("mmap file", SIGBUS, BUS_OBJERR, p + 3);
1736bcfccdaSmpi 
1746bcfccdaSmpi 	return (fail);
1756bcfccdaSmpi }
176