1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "client/simulate_crash.h"
16 
17 #include <mach/mach.h>
18 #include <string.h>
19 #include <sys/types.h>
20 
21 #include "base/macros.h"
22 #include "base/stl_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "build/build_config.h"
25 #include "gtest/gtest.h"
26 #include "test/mac/mach_errors.h"
27 #include "test/mac/mach_multiprocess.h"
28 #include "util/mach/exc_server_variants.h"
29 #include "util/mach/exception_behaviors.h"
30 #include "util/mach/exception_ports.h"
31 #include "util/mach/mach_extensions.h"
32 #include "util/mach/mach_message.h"
33 #include "util/mach/mach_message_server.h"
34 #include "util/mach/symbolic_constants_mach.h"
35 #include "util/misc/implicit_cast.h"
36 
37 namespace crashpad {
38 namespace test {
39 namespace {
40 
41 class TestSimulateCrashMac final : public MachMultiprocess,
42                                    public UniversalMachExcServer::Interface {
43  public:
44   // Defines which targets the child should set an EXC_CRASH exception handler
45   // for.
46   enum ExceptionPortsTarget {
47     // The child should clear its EXC_CRASH handler for both its task and thread
48     // targets. SimulateCrash() will attempt to deliver the exception to the
49     // host target, which will fail if not running as root. In any case, the
50     // parent should not expect to receive any exception message from the child.
51     kExceptionPortsTargetNone = 0,
52 
53     // The child will set an EXC_CRASH handler for its task target, and clear it
54     // for its thread target. The parent runs an exception server to receive
55     // the child’s simulated crash message.
56     kExceptionPortsTargetTask,
57 
58     // The child will set an EXC_CRASH handler for its thread target, and clear
59     // it for its task target. The parent runs an exception server to receive
60     // the child’s simulated crash message.
61     kExceptionPortsTargetThread,
62 
63     // The child sets an EXC_CRASH handler for both its task and thread targets.
64     // The parent runs an exception server to receive the message expected to be
65     // delivered to the thread target, but returns an error code. The child will
66     // then fall back to trying the server registered for the task target,
67     // sending a second message to the parent. The server in the parent will
68     // handle this one successfully.
69     kExceptionPortsTargetBoth,
70   };
71 
TestSimulateCrashMac(ExceptionPortsTarget target,exception_behavior_t behavior,thread_state_flavor_t flavor)72   TestSimulateCrashMac(ExceptionPortsTarget target,
73                        exception_behavior_t behavior,
74                        thread_state_flavor_t flavor)
75       : MachMultiprocess(),
76         UniversalMachExcServer::Interface(),
77         target_(target),
78         behavior_(behavior),
79         flavor_(flavor),
80         succeed_(true) {
81   }
82 
~TestSimulateCrashMac()83   ~TestSimulateCrashMac() {}
84 
85   // UniversalMachExcServer::Interface:
CatchMachException(exception_behavior_t behavior,exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const mach_exception_data_type_t * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer,bool * destroy_complex_request)86   kern_return_t CatchMachException(exception_behavior_t behavior,
87                                    exception_handler_t exception_port,
88                                    thread_t thread,
89                                    task_t task,
90                                    exception_type_t exception,
91                                    const mach_exception_data_type_t* code,
92                                    mach_msg_type_number_t code_count,
93                                    thread_state_flavor_t* flavor,
94                                    ConstThreadState old_state,
95                                    mach_msg_type_number_t old_state_count,
96                                    thread_state_t new_state,
97                                    mach_msg_type_number_t* new_state_count,
98                                    const mach_msg_trailer_t* trailer,
99                                    bool* destroy_complex_request) override {
100     *destroy_complex_request = true;
101 
102     // Check the entire exception message, because most or all of it was
103     // generated by SimulateCrash() instead of the kernel.
104 
105     EXPECT_EQ(behavior, behavior_);
106     EXPECT_EQ(exception_port, LocalPort());
107     if (ExceptionBehaviorHasIdentity(behavior)) {
108       EXPECT_NE(thread, THREAD_NULL);
109       EXPECT_EQ(task, ChildTask());
110     } else {
111       EXPECT_EQ(thread, THREAD_NULL);
112       EXPECT_EQ(task, TASK_NULL);
113     }
114     EXPECT_EQ(exception, kMachExceptionSimulated);
115     EXPECT_EQ(code_count, 2u);
116     if (code_count >= 1) {
117       EXPECT_EQ(code[0], 0);
118     }
119     if (code_count >= 2) {
120       EXPECT_EQ(code[1], 0);
121     }
122     if (!ExceptionBehaviorHasState(behavior)) {
123       EXPECT_EQ(*flavor, THREAD_STATE_NONE);
124     } else {
125       EXPECT_EQ(*flavor, flavor_);
126       switch (*flavor) {
127 #if defined(ARCH_CPU_X86_FAMILY)
128         case x86_THREAD_STATE: {
129           EXPECT_EQ(old_state_count, x86_THREAD_STATE_COUNT);
130           const x86_thread_state* state =
131               reinterpret_cast<const x86_thread_state*>(old_state);
132           switch (state->tsh.flavor) {
133             case x86_THREAD_STATE32:
134               EXPECT_EQ(implicit_cast<uint32_t>(state->tsh.count),
135                         implicit_cast<uint32_t>(x86_THREAD_STATE32_COUNT));
136               break;
137             case x86_THREAD_STATE64:
138               EXPECT_EQ(implicit_cast<uint32_t>(state->tsh.count),
139                         implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT));
140               break;
141             default:
142               ADD_FAILURE() << "unexpected tsh.flavor " << state->tsh.flavor;
143               break;
144           }
145           break;
146         }
147         case x86_FLOAT_STATE: {
148           EXPECT_EQ(old_state_count, x86_FLOAT_STATE_COUNT);
149           const x86_float_state* state =
150               reinterpret_cast<const x86_float_state*>(old_state);
151           switch (state->fsh.flavor) {
152             case x86_FLOAT_STATE32:
153               EXPECT_EQ(implicit_cast<uint32_t>(state->fsh.count),
154                         implicit_cast<uint32_t>(x86_FLOAT_STATE32_COUNT));
155               break;
156             case x86_FLOAT_STATE64:
157               EXPECT_EQ(implicit_cast<uint32_t>(state->fsh.count),
158                         implicit_cast<uint32_t>(x86_FLOAT_STATE64_COUNT));
159               break;
160             default:
161               ADD_FAILURE() << "unexpected fsh.flavor " << state->fsh.flavor;
162               break;
163           }
164           break;
165         }
166         case x86_DEBUG_STATE: {
167           EXPECT_EQ(old_state_count, x86_DEBUG_STATE_COUNT);
168           const x86_debug_state* state =
169               reinterpret_cast<const x86_debug_state*>(old_state);
170           switch (state->dsh.flavor) {
171             case x86_DEBUG_STATE32:
172               EXPECT_EQ(implicit_cast<uint32_t>(state->dsh.count),
173                         implicit_cast<uint32_t>(x86_DEBUG_STATE32_COUNT));
174               break;
175             case x86_DEBUG_STATE64:
176               EXPECT_EQ(implicit_cast<uint32_t>(state->dsh.count),
177                         implicit_cast<uint32_t>(x86_DEBUG_STATE64_COUNT));
178               break;
179             default:
180               ADD_FAILURE() << "unexpected dsh.flavor " << state->dsh.flavor;
181               break;
182           }
183           break;
184         }
185         case x86_THREAD_STATE32:
186           EXPECT_EQ(old_state_count, x86_THREAD_STATE32_COUNT);
187           break;
188         case x86_FLOAT_STATE32:
189           EXPECT_EQ(old_state_count, x86_FLOAT_STATE32_COUNT);
190           break;
191         case x86_DEBUG_STATE32:
192           EXPECT_EQ(old_state_count, x86_DEBUG_STATE32_COUNT);
193           break;
194         case x86_THREAD_STATE64:
195           EXPECT_EQ(old_state_count, x86_THREAD_STATE64_COUNT);
196           break;
197         case x86_FLOAT_STATE64:
198           EXPECT_EQ(old_state_count, x86_FLOAT_STATE64_COUNT);
199           break;
200         case x86_DEBUG_STATE64:
201           EXPECT_EQ(old_state_count, x86_DEBUG_STATE64_COUNT);
202           break;
203 #elif defined(ARCH_CPU_ARM64)
204         case ARM_UNIFIED_THREAD_STATE: {
205           EXPECT_EQ(old_state_count, ARM_UNIFIED_THREAD_STATE_COUNT);
206           const arm_unified_thread_state* state =
207               reinterpret_cast<const arm_unified_thread_state*>(old_state);
208           EXPECT_EQ(state->ash.flavor,
209                     implicit_cast<uint32_t>(ARM_THREAD_STATE64));
210           if (state->ash.flavor == ARM_THREAD_STATE64) {
211             EXPECT_EQ(state->ash.count,
212                       implicit_cast<uint32_t>(ARM_THREAD_STATE64_COUNT));
213           }
214           break;
215         }
216         case ARM_THREAD_STATE64:
217           EXPECT_EQ(old_state_count, ARM_THREAD_STATE64_COUNT);
218           break;
219         case ARM_NEON_STATE64:
220           EXPECT_EQ(old_state_count, ARM_NEON_STATE64_COUNT);
221           break;
222         case ARM_DEBUG_STATE64:
223           EXPECT_EQ(old_state_count, ARM_DEBUG_STATE64_COUNT);
224           break;
225 #else
226 #error Port to your CPU architecture
227 #endif
228         default:
229           ADD_FAILURE() << "unexpected flavor " << *flavor;
230           break;
231       }
232 
233       // Attempt to set a garbage thread state, which would cause the child to
234       // crash inside SimulateCrash() if it actually succeeded. This tests that
235       // SimulateCrash() ignores new_state instead of attempting to set the
236       // state as the kernel would do. This operates in conjunction with the
237       // |true| argument to ExcServerSuccessfulReturnValue() below.
238       *new_state_count = old_state_count;
239       size_t new_state_size = sizeof(natural_t) * old_state_count;
240       memset(new_state, 0xa5, new_state_size);
241     }
242 
243     if (!succeed_) {
244       // The client has registered EXC_CRASH handlers for both its thread and
245       // task targets, and sent a simulated exception message to its
246       // thread-level EXC_CRASH handler. To test that it will fall back to
247       // trying the task-level EXC_CRASH handler, return a failure code, which
248       // should cause SimulateCrash() to try the next target.
249       EXPECT_EQ(target_, kExceptionPortsTargetBoth);
250       return KERN_ABORTED;
251     }
252 
253     ExcServerCopyState(
254         behavior, old_state, old_state_count, new_state, new_state_count);
255 
256     return ExcServerSuccessfulReturnValue(exception, behavior, true);
257   }
258 
259  private:
260   // MachMultiprocess:
261 
MachMultiprocessParent()262   void MachMultiprocessParent() override {
263     if (target_ == kExceptionPortsTargetNone) {
264       // The child does not have any EXC_CRASH handlers registered for its
265       // thread or task targets, so no exception message is expected to be
266       // generated. Don’t run the server at all.
267       return;
268     }
269 
270     UniversalMachExcServer universal_mach_exc_server(this);
271 
272     mach_msg_return_t mr;
273     if (target_ == kExceptionPortsTargetBoth) {
274       // The client has registered EXC_CRASH handlers for both its thread and
275       // task targets. Run a server that will return a failure code when the
276       // exception message is sent to the thread target, which will cause the
277       // client to fall back to the task target and send another message.
278       succeed_ = false;
279       mr = MachMessageServer::Run(&universal_mach_exc_server,
280                                   LocalPort(),
281                                   MACH_MSG_OPTION_NONE,
282                                   MachMessageServer::kOneShot,
283                                   MachMessageServer::kReceiveLargeError,
284                                   kMachMessageTimeoutWaitIndefinitely);
285       EXPECT_EQ(mr, MACH_MSG_SUCCESS)
286           << MachErrorMessage(mr, "MachMessageServer::Run");
287     }
288 
289     succeed_ = true;
290     mr = MachMessageServer::Run(&universal_mach_exc_server,
291                                 LocalPort(),
292                                 MACH_MSG_OPTION_NONE,
293                                 MachMessageServer::kOneShot,
294                                 MachMessageServer::kReceiveLargeError,
295                                 kMachMessageTimeoutWaitIndefinitely);
296     EXPECT_EQ(mr, MACH_MSG_SUCCESS)
297         << MachErrorMessage(mr, "MachMessageServer::Run");
298   }
299 
MachMultiprocessChild()300   void MachMultiprocessChild() override {
301     bool task_valid = target_ == kExceptionPortsTargetTask ||
302                       target_ == kExceptionPortsTargetBoth;
303     ExceptionPorts task_exception_ports(ExceptionPorts::kTargetTypeTask,
304                                         TASK_NULL);
305     ASSERT_TRUE(task_exception_ports.SetExceptionPort(
306         EXC_MASK_CRASH,
307         task_valid ? RemotePort() : MACH_PORT_NULL,
308         behavior_,
309         flavor_));
310 
311     bool thread_valid = target_ == kExceptionPortsTargetThread ||
312                         target_ == kExceptionPortsTargetBoth;
313     ExceptionPorts thread_exception_ports(ExceptionPorts::kTargetTypeThread,
314                                           THREAD_NULL);
315     ASSERT_TRUE(thread_exception_ports.SetExceptionPort(
316         EXC_MASK_CRASH,
317         thread_valid ? RemotePort() : MACH_PORT_NULL,
318         behavior_,
319         flavor_));
320 
321     CRASHPAD_SIMULATE_CRASH();
322   }
323 
324   ExceptionPortsTarget target_;
325   exception_behavior_t behavior_;
326   thread_state_flavor_t flavor_;
327   bool succeed_;
328 
329   DISALLOW_COPY_AND_ASSIGN(TestSimulateCrashMac);
330 };
331 
TEST(SimulateCrash,SimulateCrash)332 TEST(SimulateCrash, SimulateCrash) {
333   static constexpr TestSimulateCrashMac::ExceptionPortsTarget kTargets[] = {
334       TestSimulateCrashMac::kExceptionPortsTargetNone,
335       TestSimulateCrashMac::kExceptionPortsTargetTask,
336       TestSimulateCrashMac::kExceptionPortsTargetThread,
337       TestSimulateCrashMac::kExceptionPortsTargetBoth,
338   };
339 
340   static constexpr exception_behavior_t kBehaviors[] = {
341       EXCEPTION_DEFAULT,
342       EXCEPTION_STATE,
343       EXCEPTION_STATE_IDENTITY,
344       EXCEPTION_DEFAULT | kMachExceptionCodes,
345       EXCEPTION_STATE | kMachExceptionCodes,
346       EXCEPTION_STATE_IDENTITY | kMachExceptionCodes,
347   };
348 
349   static constexpr thread_state_flavor_t kFlavors[] = {
350 #if defined(ARCH_CPU_X86_FAMILY)
351     x86_THREAD_STATE,
352     x86_FLOAT_STATE,
353     x86_DEBUG_STATE,
354 #if defined(ARCH_CPU_X86)
355     x86_THREAD_STATE32,
356     x86_FLOAT_STATE32,
357     x86_DEBUG_STATE32,
358 #elif defined(ARCH_CPU_X86_64)
359     x86_THREAD_STATE64,
360     x86_FLOAT_STATE64,
361     x86_DEBUG_STATE64,
362 #endif
363 #elif defined(ARCH_CPU_ARM64)
364     ARM_UNIFIED_THREAD_STATE,
365     ARM_THREAD_STATE64,
366     ARM_NEON_STATE64,
367     ARM_DEBUG_STATE64,
368 #else
369 #error Port to your CPU architecture
370 #endif
371   };
372 
373   for (size_t target_index = 0; target_index < base::size(kTargets);
374        ++target_index) {
375     TestSimulateCrashMac::ExceptionPortsTarget target = kTargets[target_index];
376     SCOPED_TRACE(base::StringPrintf(
377         "target_index %zu, target %d", target_index, target));
378 
379     for (size_t behavior_index = 0; behavior_index < base::size(kBehaviors);
380          ++behavior_index) {
381       exception_behavior_t behavior = kBehaviors[behavior_index];
382       SCOPED_TRACE(base::StringPrintf(
383           "behavior_index %zu, behavior %s",
384           behavior_index,
385           ExceptionBehaviorToString(behavior, kUseFullName | kUnknownIsNumeric)
386               .c_str()));
387 
388       if (!ExceptionBehaviorHasState(behavior)) {
389         TestSimulateCrashMac test_simulate_crash_mac(
390             target, behavior, THREAD_STATE_NONE);
391         test_simulate_crash_mac.Run();
392       } else {
393         for (size_t flavor_index = 0; flavor_index < base::size(kFlavors);
394              ++flavor_index) {
395           thread_state_flavor_t flavor = kFlavors[flavor_index];
396           SCOPED_TRACE(base::StringPrintf(
397               "flavor_index %zu, flavor %s",
398               flavor_index,
399               ThreadStateFlavorToString(
400                   flavor, kUseFullName | kUnknownIsNumeric).c_str()));
401 
402           TestSimulateCrashMac test_simulate_crash_mac(
403               target, behavior, flavor);
404           test_simulate_crash_mac.Run();
405         }
406       }
407     }
408   }
409 }
410 
411 }  // namespace
412 }  // namespace test
413 }  // namespace crashpad
414