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