1 // Copyright (c) 2011, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // crash_generator.cc: Implement google_breakpad::CrashGenerator.
31 // See crash_generator.h for details.
32
33 #include "common/linux/tests/crash_generator.h"
34
35 #include <pthread.h>
36 #include <sched.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <sys/mman.h>
40 #include <sys/resource.h>
41 #include <sys/syscall.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44
45 #include <string>
46
47 #if defined(__ANDROID__)
48 #include "common/android/testing/pthread_fixes.h"
49 #endif
50 #include "common/linux/eintr_wrapper.h"
51 #include "common/tests/auto_tempdir.h"
52 #include "common/tests/file_utils.h"
53 #include "common/using_std_string.h"
54
55 namespace {
56
57 struct ThreadData {
58 pthread_t thread;
59 pthread_barrier_t* barrier;
60 pid_t* thread_id_ptr;
61 };
62
63 const char* const kProcFilesToCopy[] = {
64 "auxv", "cmdline", "environ", "maps", "status"
65 };
66 const size_t kNumProcFilesToCopy =
67 sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]);
68
gettid()69 int gettid() {
70 // Glibc does not provide a wrapper for this.
71 return syscall(__NR_gettid);
72 }
73
tkill(pid_t tid,int sig)74 int tkill(pid_t tid, int sig) {
75 // Glibc does not provide a wrapper for this.
76 return syscall(__NR_tkill, tid, sig);
77 }
78
79 // Core file size limit set to 1 MB, which is big enough for test purposes.
80 const rlim_t kCoreSizeLimit = 1024 * 1024;
81
thread_function(void * data)82 void *thread_function(void *data) {
83 ThreadData* thread_data = reinterpret_cast<ThreadData*>(data);
84 volatile pid_t thread_id = gettid();
85 *(thread_data->thread_id_ptr) = thread_id;
86 int result = pthread_barrier_wait(thread_data->barrier);
87 if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) {
88 perror("Failed to wait for sync barrier");
89 exit(1);
90 }
91 while (true) {
92 sched_yield();
93 }
94 }
95
96 } // namespace
97
98 namespace google_breakpad {
99
CrashGenerator()100 CrashGenerator::CrashGenerator()
101 : shared_memory_(NULL),
102 shared_memory_size_(0) {
103 }
104
~CrashGenerator()105 CrashGenerator::~CrashGenerator() {
106 UnmapSharedMemory();
107 }
108
HasDefaultCorePattern() const109 bool CrashGenerator::HasDefaultCorePattern() const {
110 char buffer[8];
111 ssize_t buffer_size = sizeof(buffer);
112 return ReadFile("/proc/sys/kernel/core_pattern", buffer, &buffer_size) &&
113 buffer_size == 5 && memcmp(buffer, "core", 4) == 0;
114 }
115
GetCoreFilePath() const116 string CrashGenerator::GetCoreFilePath() const {
117 return temp_dir_.path() + "/core";
118 }
119
GetDirectoryOfProcFilesCopy() const120 string CrashGenerator::GetDirectoryOfProcFilesCopy() const {
121 return temp_dir_.path() + "/proc";
122 }
123
GetThreadId(unsigned index) const124 pid_t CrashGenerator::GetThreadId(unsigned index) const {
125 return reinterpret_cast<pid_t*>(shared_memory_)[index];
126 }
127
GetThreadIdPointer(unsigned index)128 pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) {
129 return reinterpret_cast<pid_t*>(shared_memory_) + index;
130 }
131
MapSharedMemory(size_t memory_size)132 bool CrashGenerator::MapSharedMemory(size_t memory_size) {
133 if (!UnmapSharedMemory())
134 return false;
135
136 void* mapped_memory = mmap(0, memory_size, PROT_READ | PROT_WRITE,
137 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
138 if (mapped_memory == MAP_FAILED) {
139 perror("CrashGenerator: Failed to map shared memory");
140 return false;
141 }
142
143 memset(mapped_memory, 0, memory_size);
144 shared_memory_ = mapped_memory;
145 shared_memory_size_ = memory_size;
146 return true;
147 }
148
UnmapSharedMemory()149 bool CrashGenerator::UnmapSharedMemory() {
150 if (!shared_memory_)
151 return true;
152
153 if (munmap(shared_memory_, shared_memory_size_) == 0) {
154 shared_memory_ = NULL;
155 shared_memory_size_ = 0;
156 return true;
157 }
158
159 perror("CrashGenerator: Failed to unmap shared memory");
160 return false;
161 }
162
SetCoreFileSizeLimit(rlim_t limit) const163 bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const {
164 struct rlimit limits = { limit, limit };
165 if (setrlimit(RLIMIT_CORE, &limits) == -1) {
166 perror("CrashGenerator: Failed to set core file size limit");
167 return false;
168 }
169 return true;
170 }
171
CreateChildCrash(unsigned num_threads,unsigned crash_thread,int crash_signal,pid_t * child_pid)172 bool CrashGenerator::CreateChildCrash(
173 unsigned num_threads, unsigned crash_thread, int crash_signal,
174 pid_t* child_pid) {
175 if (num_threads == 0 || crash_thread >= num_threads) {
176 fprintf(stderr, "CrashGenerator: Invalid thread counts; num_threads=%u"
177 " crash_thread=%u\n", num_threads, crash_thread);
178 return false;
179 }
180
181 if (!MapSharedMemory(num_threads * sizeof(pid_t))) {
182 perror("CrashGenerator: Unable to map shared memory");
183 return false;
184 }
185
186 pid_t pid = fork();
187 if (pid == 0) {
188 // Custom signal handlers, which may have been installed by a test launcher,
189 // are undesirable in this child.
190 if (signal(crash_signal, SIG_DFL) == SIG_ERR) {
191 perror("CrashGenerator: signal");
192 exit(1);
193 }
194 if (chdir(temp_dir_.path().c_str()) == -1) {
195 perror("CrashGenerator: Failed to change directory");
196 exit(1);
197 }
198 if (SetCoreFileSizeLimit(kCoreSizeLimit)) {
199 CreateThreadsInChildProcess(num_threads);
200 string proc_dir = GetDirectoryOfProcFilesCopy();
201 if (mkdir(proc_dir.c_str(), 0755) == -1) {
202 perror("CrashGenerator: Failed to create proc directory");
203 exit(1);
204 }
205 if (!CopyProcFiles(getpid(), proc_dir.c_str())) {
206 fprintf(stderr, "CrashGenerator: Failed to copy proc files\n");
207 exit(1);
208 }
209 // On Android the signal sometimes doesn't seem to get sent even though
210 // tkill returns '0'. Retry a couple of times if the signal doesn't get
211 // through on the first go:
212 // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=579
213 #if defined(__ANDROID__)
214 const int kRetries = 60;
215 const unsigned int kSleepTimeInSeconds = 1;
216 #else
217 const int kRetries = 1;
218 const unsigned int kSleepTimeInSeconds = 600;
219 #endif
220 for (int i = 0; i < kRetries; i++) {
221 if (tkill(*GetThreadIdPointer(crash_thread), crash_signal) == -1) {
222 perror("CrashGenerator: Failed to kill thread by signal");
223 } else {
224 // At this point, we've queued the signal for delivery, but there's no
225 // guarantee when it'll be delivered. We don't want the main thread to
226 // race and exit before the thread we signaled is processed. So sleep
227 // long enough that we won't flake even under fairly high load.
228 // TODO: See if we can't be a bit more deterministic. There doesn't
229 // seem to be an API to check on signal delivery status, so we can't
230 // really poll and wait for the kernel to declare the signal has been
231 // delivered. If it has, and things worked, we'd be killed, so the
232 // sleep length doesn't really matter.
233 sleep(kSleepTimeInSeconds);
234 }
235 }
236 } else {
237 perror("CrashGenerator: Failed to set core limit");
238 }
239 exit(1);
240 } else if (pid == -1) {
241 perror("CrashGenerator: Failed to create child process");
242 return false;
243 }
244
245 int status;
246 if (HANDLE_EINTR(waitpid(pid, &status, 0)) == -1) {
247 perror("CrashGenerator: Failed to wait for child process");
248 return false;
249 }
250 if (!WIFSIGNALED(status) || WTERMSIG(status) != crash_signal) {
251 fprintf(stderr, "CrashGenerator: Child process not killed by the expected signal\n"
252 " exit status=0x%x pid=%u signaled=%s sig=%d expected=%d\n",
253 status, pid, WIFSIGNALED(status) ? "true" : "false",
254 WTERMSIG(status), crash_signal);
255 return false;
256 }
257
258 if (child_pid)
259 *child_pid = pid;
260 return true;
261 }
262
CopyProcFiles(pid_t pid,const char * path) const263 bool CrashGenerator::CopyProcFiles(pid_t pid, const char* path) const {
264 char from_path[PATH_MAX], to_path[PATH_MAX];
265 for (size_t i = 0; i < kNumProcFilesToCopy; ++i) {
266 int num_chars = snprintf(from_path, PATH_MAX, "/proc/%d/%s",
267 pid, kProcFilesToCopy[i]);
268 if (num_chars < 0 || num_chars >= PATH_MAX)
269 return false;
270
271 num_chars = snprintf(to_path, PATH_MAX, "%s/%s",
272 path, kProcFilesToCopy[i]);
273 if (num_chars < 0 || num_chars >= PATH_MAX)
274 return false;
275
276 if (!CopyFile(from_path, to_path))
277 return false;
278 }
279 return true;
280 }
281
CreateThreadsInChildProcess(unsigned num_threads)282 void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) {
283 *GetThreadIdPointer(0) = getpid();
284
285 if (num_threads <= 1)
286 return;
287
288 // This method does not clean up any pthread resource, as the process
289 // is expected to be killed anyway.
290 ThreadData* thread_data = new ThreadData[num_threads];
291
292 // Create detached threads so that we do not worry about pthread_join()
293 // later being called or not.
294 pthread_attr_t thread_attributes;
295 if (pthread_attr_init(&thread_attributes) != 0 ||
296 pthread_attr_setdetachstate(&thread_attributes,
297 PTHREAD_CREATE_DETACHED) != 0) {
298 fprintf(stderr, "CrashGenerator: Failed to initialize thread attribute\n");
299 exit(1);
300 }
301
302 pthread_barrier_t thread_barrier;
303 if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) {
304 fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n");
305 exit(1);
306 }
307
308 for (unsigned i = 1; i < num_threads; ++i) {
309 thread_data[i].barrier = &thread_barrier;
310 thread_data[i].thread_id_ptr = GetThreadIdPointer(i);
311 if (pthread_create(&thread_data[i].thread, &thread_attributes,
312 thread_function, &thread_data[i]) != 0) {
313 fprintf(stderr, "CrashGenerator: Failed to create thread %d\n", i);
314 exit(1);
315 }
316 }
317
318 int result = pthread_barrier_wait(&thread_barrier);
319 if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) {
320 fprintf(stderr, "CrashGenerator: Failed to wait for thread barrier\n");
321 exit(1);
322 }
323
324 pthread_barrier_destroy(&thread_barrier);
325 pthread_attr_destroy(&thread_attributes);
326 delete[] thread_data;
327 }
328
329 } // namespace google_breakpad
330