xref: /xnu-10063.121.3/tests/proc_core_name_24152432.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions #include <darwintest.h>
2*2c2f96dcSApple OSS Distributions #include <errno.h>
3*2c2f96dcSApple OSS Distributions #include <fcntl.h>
4*2c2f96dcSApple OSS Distributions #include <sys/types.h>
5*2c2f96dcSApple OSS Distributions #include <sys/event.h>
6*2c2f96dcSApple OSS Distributions #include <sys/time.h>
7*2c2f96dcSApple OSS Distributions #include <sys/sysctl.h>
8*2c2f96dcSApple OSS Distributions #include <sys/resource.h>
9*2c2f96dcSApple OSS Distributions #include <signal.h>
10*2c2f96dcSApple OSS Distributions #include <stdlib.h>
11*2c2f96dcSApple OSS Distributions #include <string.h>
12*2c2f96dcSApple OSS Distributions #include <stdio.h>
13*2c2f96dcSApple OSS Distributions #include <TargetConditionals.h>
14*2c2f96dcSApple OSS Distributions #include <unistd.h>
15*2c2f96dcSApple OSS Distributions #include <dirent.h>
16*2c2f96dcSApple OSS Distributions 
17*2c2f96dcSApple OSS Distributions #define BUFFLEN  2048
18*2c2f96dcSApple OSS Distributions #define EVILLEN  19
19*2c2f96dcSApple OSS Distributions #define TIMEOUT  420 /* Timeout in seconds to wait for coredumps to appear */
20*2c2f96dcSApple OSS Distributions 
21*2c2f96dcSApple OSS Distributions static const char corefile_ctl[]     = "kern.corefile";
22*2c2f96dcSApple OSS Distributions static const char coredump_ctl[]     = "kern.coredump";
23*2c2f96dcSApple OSS Distributions /* The directory where coredumps will be */
24*2c2f96dcSApple OSS Distributions static const char dump_dir[]         = "/cores";
25*2c2f96dcSApple OSS Distributions /* The default coredump location if the kern.coredump ctl is invalid */
26*2c2f96dcSApple OSS Distributions static const char default_dump_fmt[] = "/cores/core.%d";
27*2c2f96dcSApple OSS Distributions /* The coredump location when we set kern.coredump ctl to something valid */
28*2c2f96dcSApple OSS Distributions static const char valid_dump_fmt[]   = "/cores/test-core.%d";
29*2c2f96dcSApple OSS Distributions static const char ls_path[]          = "/bin/ls";
30*2c2f96dcSApple OSS Distributions 
31*2c2f96dcSApple OSS Distributions /* /cores/core.%(null), then BORK immediately after. */
32*2c2f96dcSApple OSS Distributions static char evil[] = "/cores/core.%\0BORK";
33*2c2f96dcSApple OSS Distributions /* A valid coredump location to test. */
34*2c2f96dcSApple OSS Distributions static char valid_dump_loc[]   = "/cores/test-core.%P";
35*2c2f96dcSApple OSS Distributions 
36*2c2f96dcSApple OSS Distributions static const struct rlimit lim_infty = {
37*2c2f96dcSApple OSS Distributions 	RLIM_INFINITY,
38*2c2f96dcSApple OSS Distributions 	RLIM_INFINITY
39*2c2f96dcSApple OSS Distributions };
40*2c2f96dcSApple OSS Distributions 
41*2c2f96dcSApple OSS Distributions static volatile int stop_looking = 0;
42*2c2f96dcSApple OSS Distributions 
43*2c2f96dcSApple OSS Distributions static const struct timespec timeout = {
44*2c2f96dcSApple OSS Distributions 	TIMEOUT,
45*2c2f96dcSApple OSS Distributions 	0
46*2c2f96dcSApple OSS Distributions };
47*2c2f96dcSApple OSS Distributions 
48*2c2f96dcSApple OSS Distributions #if TARGET_OS_OSX
49*2c2f96dcSApple OSS Distributions static int fork_and_wait_for_segfault(void);
50*2c2f96dcSApple OSS Distributions 
51*2c2f96dcSApple OSS Distributions static void
sigalrm_handler(int sig)52*2c2f96dcSApple OSS Distributions sigalrm_handler(int sig)
53*2c2f96dcSApple OSS Distributions {
54*2c2f96dcSApple OSS Distributions 	(void)sig;
55*2c2f96dcSApple OSS Distributions 	stop_looking = 1;
56*2c2f96dcSApple OSS Distributions 	return;
57*2c2f96dcSApple OSS Distributions }
58*2c2f96dcSApple OSS Distributions 
59*2c2f96dcSApple OSS Distributions static void
list_coredump_files()60*2c2f96dcSApple OSS Distributions list_coredump_files()
61*2c2f96dcSApple OSS Distributions {
62*2c2f96dcSApple OSS Distributions 	int ret;
63*2c2f96dcSApple OSS Distributions 	char buf[BUFFLEN] = { 0 };
64*2c2f96dcSApple OSS Distributions 
65*2c2f96dcSApple OSS Distributions 	T_LOG("Contents of %s:", dump_dir);
66*2c2f96dcSApple OSS Distributions 	snprintf(buf, BUFFLEN, "%s %s", ls_path, dump_dir);
67*2c2f96dcSApple OSS Distributions 	ret = system(buf);
68*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "Listing contents of cores directory");
69*2c2f96dcSApple OSS Distributions 	return;
70*2c2f96dcSApple OSS Distributions }
71*2c2f96dcSApple OSS Distributions 
72*2c2f96dcSApple OSS Distributions static int
fork_and_wait_for_segfault()73*2c2f96dcSApple OSS Distributions fork_and_wait_for_segfault()
74*2c2f96dcSApple OSS Distributions {
75*2c2f96dcSApple OSS Distributions 	int pid, ret;
76*2c2f96dcSApple OSS Distributions 	pid = fork();
77*2c2f96dcSApple OSS Distributions 	if (pid == 0) {
78*2c2f96dcSApple OSS Distributions 		unsigned int *ptr = (unsigned int *)0x30; /* Cause a segfault so that we get a coredump */
79*2c2f96dcSApple OSS Distributions 		*ptr = 0xdeadd00d;
80*2c2f96dcSApple OSS Distributions 		T_FAIL("Expected segmentation fault on write to invalid memory address 0x30");
81*2c2f96dcSApple OSS Distributions 	}
82*2c2f96dcSApple OSS Distributions 	T_ASSERT_TRUE(pid != -1, "Checking fork success in parent");
83*2c2f96dcSApple OSS Distributions 
84*2c2f96dcSApple OSS Distributions 	ret = wait(NULL);
85*2c2f96dcSApple OSS Distributions 	T_ASSERT_TRUE(ret != -1, "Waited for child to segfault and dump core");
86*2c2f96dcSApple OSS Distributions 	return pid;
87*2c2f96dcSApple OSS Distributions }
88*2c2f96dcSApple OSS Distributions 
89*2c2f96dcSApple OSS Distributions static int
setup_coredump_kevent(struct kevent * kev,int dir)90*2c2f96dcSApple OSS Distributions setup_coredump_kevent(struct kevent *kev, int dir)
91*2c2f96dcSApple OSS Distributions {
92*2c2f96dcSApple OSS Distributions 	int ret;
93*2c2f96dcSApple OSS Distributions 	int kqfd;
94*2c2f96dcSApple OSS Distributions 
95*2c2f96dcSApple OSS Distributions 	EV_SET(kev, dir, EVFILT_VNODE, EV_ADD, NOTE_WRITE, 0, NULL);
96*2c2f96dcSApple OSS Distributions 	kqfd = kqueue();
97*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(kqfd, "kqueue: get kqueue for coredump monitoring");
98*2c2f96dcSApple OSS Distributions 
99*2c2f96dcSApple OSS Distributions 	ret = kevent(kqfd, kev, 1, NULL, 0, NULL);
100*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "kevent: setup directory monitoring for coredump");
101*2c2f96dcSApple OSS Distributions 	return kqfd;
102*2c2f96dcSApple OSS Distributions }
103*2c2f96dcSApple OSS Distributions 
104*2c2f96dcSApple OSS Distributions static void
look_for_coredump(const char * format,int pid,int kqfd,struct kevent * kev)105*2c2f96dcSApple OSS Distributions look_for_coredump(const char *format, int pid, int kqfd, struct kevent *kev)
106*2c2f96dcSApple OSS Distributions {
107*2c2f96dcSApple OSS Distributions 	int ret = 0;
108*2c2f96dcSApple OSS Distributions 	int i = 0;
109*2c2f96dcSApple OSS Distributions 	char buf[BUFFLEN];
110*2c2f96dcSApple OSS Distributions 	memset(buf, 0, BUFFLEN);
111*2c2f96dcSApple OSS Distributions 	/*
112*2c2f96dcSApple OSS Distributions 	 * Something else might touch this directory. If we get notified and don't see
113*2c2f96dcSApple OSS Distributions 	 * anything, try a few more times before failing.
114*2c2f96dcSApple OSS Distributions 	 */
115*2c2f96dcSApple OSS Distributions 	alarm(TIMEOUT);
116*2c2f96dcSApple OSS Distributions 	while (!stop_looking) {
117*2c2f96dcSApple OSS Distributions 		/* Wait for kevent to tell us the coredump folder was modified */
118*2c2f96dcSApple OSS Distributions 		ret = kevent(kqfd, NULL, 0, kev, 1, &timeout);
119*2c2f96dcSApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(ret, "kevent: Waiting for coredump to appear");
120*2c2f96dcSApple OSS Distributions 
121*2c2f96dcSApple OSS Distributions 		snprintf(buf, BUFFLEN, format, pid);
122*2c2f96dcSApple OSS Distributions 		ret = remove(buf);
123*2c2f96dcSApple OSS Distributions 
124*2c2f96dcSApple OSS Distributions 		if (ret != -1) {
125*2c2f96dcSApple OSS Distributions 			break;
126*2c2f96dcSApple OSS Distributions 		}
127*2c2f96dcSApple OSS Distributions 
128*2c2f96dcSApple OSS Distributions 		T_LOG("Couldn't find coredump file (try #%d).", i + 1);
129*2c2f96dcSApple OSS Distributions 		i++;
130*2c2f96dcSApple OSS Distributions 	}
131*2c2f96dcSApple OSS Distributions 	alarm(0);
132*2c2f96dcSApple OSS Distributions 
133*2c2f96dcSApple OSS Distributions 	if (ret == -1) {
134*2c2f96dcSApple OSS Distributions 		/* Couldn't find the coredump -- list contents of /cores */
135*2c2f96dcSApple OSS Distributions 		list_coredump_files();
136*2c2f96dcSApple OSS Distributions 	}
137*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "Removing coredump file (should be at %s)", buf);
138*2c2f96dcSApple OSS Distributions }
139*2c2f96dcSApple OSS Distributions 
140*2c2f96dcSApple OSS Distributions static void
sysctl_enable_coredumps(void)141*2c2f96dcSApple OSS Distributions sysctl_enable_coredumps(void)
142*2c2f96dcSApple OSS Distributions {
143*2c2f96dcSApple OSS Distributions 	int ret;
144*2c2f96dcSApple OSS Distributions 	int enable_core_dump = 1;
145*2c2f96dcSApple OSS Distributions 	size_t oldlen = BUFFLEN;
146*2c2f96dcSApple OSS Distributions 	char buf[BUFFLEN];
147*2c2f96dcSApple OSS Distributions 	memset(buf, 0, BUFFLEN);
148*2c2f96dcSApple OSS Distributions 
149*2c2f96dcSApple OSS Distributions 	ret = sysctlbyname(coredump_ctl, buf, &oldlen, &enable_core_dump, sizeof(int));
150*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "sysctl: enable core dumps");
151*2c2f96dcSApple OSS Distributions 
152*2c2f96dcSApple OSS Distributions 	ret = setrlimit(RLIMIT_CORE, &lim_infty);
153*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "setrlimit: remove limit on maximum coredump size");
154*2c2f96dcSApple OSS Distributions }
155*2c2f96dcSApple OSS Distributions #endif
156*2c2f96dcSApple OSS Distributions 
157*2c2f96dcSApple OSS Distributions T_DECL(
158*2c2f96dcSApple OSS Distributions 	proc_core_name_24152432,
159*2c2f96dcSApple OSS Distributions 	"Tests behavior of core dump when kern.corefile ends in %, e.g., /cores/core.%",
160*2c2f96dcSApple OSS Distributions 	T_META_ASROOT(true),
161*2c2f96dcSApple OSS Distributions 	T_META_IGNORECRASHES("proc_core_name_24152432.*"))
162*2c2f96dcSApple OSS Distributions {
163*2c2f96dcSApple OSS Distributions #if TARGET_OS_OSX
164*2c2f96dcSApple OSS Distributions 	DIR *dirp;
165*2c2f96dcSApple OSS Distributions 	int ret, pid, dir;
166*2c2f96dcSApple OSS Distributions 	char buf[BUFFLEN];
167*2c2f96dcSApple OSS Distributions 	memset(buf, 0, BUFFLEN);
168*2c2f96dcSApple OSS Distributions 	size_t oldlen = BUFFLEN;
169*2c2f96dcSApple OSS Distributions 	struct kevent kev;
170*2c2f96dcSApple OSS Distributions 	sig_t sig;
171*2c2f96dcSApple OSS Distributions 	int kqfd;
172*2c2f96dcSApple OSS Distributions 
173*2c2f96dcSApple OSS Distributions 	sig = signal(SIGALRM, sigalrm_handler);
174*2c2f96dcSApple OSS Distributions 	T_WITH_ERRNO; T_EXPECT_NE(sig, SIG_ERR, "signal: set sigalrm handler");
175*2c2f96dcSApple OSS Distributions 
176*2c2f96dcSApple OSS Distributions 	dirp = opendir(dump_dir);
177*2c2f96dcSApple OSS Distributions 	T_ASSERT_NOTNULL(dirp, "opendir: opening coredump directory");
178*2c2f96dcSApple OSS Distributions 	dir = dirfd(dirp);
179*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(dir, "dirfd: getting file descriptor for coredump directory");
180*2c2f96dcSApple OSS Distributions 	kqfd = setup_coredump_kevent(&kev, dir);
181*2c2f96dcSApple OSS Distributions 
182*2c2f96dcSApple OSS Distributions 	sysctl_enable_coredumps();
183*2c2f96dcSApple OSS Distributions 
184*2c2f96dcSApple OSS Distributions 	ret = sysctlbyname(corefile_ctl, buf, &oldlen, evil, EVILLEN);
185*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "sysctl: set bad core dump location, old value was %s", buf);
186*2c2f96dcSApple OSS Distributions 	memset(buf, 0, BUFFLEN);
187*2c2f96dcSApple OSS Distributions 	oldlen = BUFFLEN;
188*2c2f96dcSApple OSS Distributions 
189*2c2f96dcSApple OSS Distributions 	pid = fork_and_wait_for_segfault();
190*2c2f96dcSApple OSS Distributions 	look_for_coredump(default_dump_fmt, pid, kqfd, &kev);
191*2c2f96dcSApple OSS Distributions 
192*2c2f96dcSApple OSS Distributions 	ret = sysctlbyname(corefile_ctl, buf, &oldlen, valid_dump_loc, strlen(valid_dump_loc));
193*2c2f96dcSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "sysctl: set valid core dump location, old value was %s", buf);
194*2c2f96dcSApple OSS Distributions 	memset(buf, 0, BUFFLEN);
195*2c2f96dcSApple OSS Distributions 
196*2c2f96dcSApple OSS Distributions 	pid = fork_and_wait_for_segfault();
197*2c2f96dcSApple OSS Distributions 	look_for_coredump(valid_dump_fmt, pid, kqfd, &kev);
198*2c2f96dcSApple OSS Distributions 
199*2c2f96dcSApple OSS Distributions 	closedir(dirp);
200*2c2f96dcSApple OSS Distributions 	close(kqfd);
201*2c2f96dcSApple OSS Distributions #else
202*2c2f96dcSApple OSS Distributions 	T_LOG("proc_core_name appears in OS X only, skipping test.");
203*2c2f96dcSApple OSS Distributions #endif
204*2c2f96dcSApple OSS Distributions 	T_PASS("proc_core_name_24152432 PASSED");
205*2c2f96dcSApple OSS Distributions }
206