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