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 "util/mach/exc_server_variants.h"
16 
17 #include <AvailabilityMacros.h>
18 #include <string.h>
19 
20 #include <algorithm>
21 #include <vector>
22 
23 #include "base/logging.h"
24 #include "base/stl_util.h"
25 #include "util/mac/mac_util.h"
26 #include "util/mach/composite_mach_message_server.h"
27 #include "util/mach/exc.h"
28 #include "util/mach/excServer.h"
29 #include "util/mach/exception_behaviors.h"
30 #include "util/mach/mach_exc.h"
31 #include "util/mach/mach_excServer.h"
32 #include "util/mach/mach_message.h"
33 
34 namespace crashpad {
35 
36 namespace {
37 
38 // Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
39 // the exc subsystem.
40 struct ExcTraits {
41   using ExceptionCode = exception_data_type_t;
42 
43   using RequestUnion = __RequestUnion__exc_subsystem;
44   using ReplyUnion = __ReplyUnion__exc_subsystem;
45 
46   using ExceptionRaiseRequest = __Request__exception_raise_t;
47   using ExceptionRaiseStateRequest = __Request__exception_raise_state_t;
48   using ExceptionRaiseStateIdentityRequest =
49       __Request__exception_raise_state_identity_t;
50 
51   using ExceptionRaiseReply = __Reply__exception_raise_t;
52   using ExceptionRaiseStateReply = __Reply__exception_raise_state_t;
53   using ExceptionRaiseStateIdentityReply =
54       __Reply__exception_raise_state_identity_t;
55 
56   // The MIG-generated __MIG_check__Request__*() functions are not declared as
57   // accepting const data, but they could have been because they in fact do not
58   // modify the data.
59 
MIGCheckRequestExceptionRaisecrashpad::__anon7ba16b890111::ExcTraits60   static kern_return_t MIGCheckRequestExceptionRaise(
61       const ExceptionRaiseRequest* in_request) {
62     return __MIG_check__Request__exception_raise_t(
63         const_cast<ExceptionRaiseRequest*>(in_request));
64   }
65 
MIGCheckRequestExceptionRaiseStatecrashpad::__anon7ba16b890111::ExcTraits66   static kern_return_t MIGCheckRequestExceptionRaiseState(
67       const ExceptionRaiseStateRequest* in_request,
68       const ExceptionRaiseStateRequest** in_request_1) {
69     return __MIG_check__Request__exception_raise_state_t(
70         const_cast<ExceptionRaiseStateRequest*>(in_request),
71         const_cast<ExceptionRaiseStateRequest**>(in_request_1));
72   }
73 
MIGCheckRequestExceptionRaiseStateIdentitycrashpad::__anon7ba16b890111::ExcTraits74   static kern_return_t MIGCheckRequestExceptionRaiseStateIdentity(
75       const ExceptionRaiseStateIdentityRequest* in_request,
76       const ExceptionRaiseStateIdentityRequest** in_request_1) {
77     return __MIG_check__Request__exception_raise_state_identity_t(
78         const_cast<ExceptionRaiseStateIdentityRequest*>(in_request),
79         const_cast<ExceptionRaiseStateIdentityRequest**>(in_request_1));
80   }
81 
82   // There are no predefined constants for these.
83   static const mach_msg_id_t kMachMessageIDExceptionRaise = 2401;
84   static const mach_msg_id_t kMachMessageIDExceptionRaiseState = 2402;
85   static const mach_msg_id_t kMachMessageIDExceptionRaiseStateIdentity = 2403;
86 
87   static const exception_behavior_t kExceptionBehavior = 0;
88 };
89 
90 // Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
91 // the mach_exc subsystem.
92 struct MachExcTraits {
93   using ExceptionCode = mach_exception_data_type_t;
94 
95   using RequestUnion = __RequestUnion__mach_exc_subsystem;
96   using ReplyUnion = __ReplyUnion__mach_exc_subsystem;
97 
98   using ExceptionRaiseRequest = __Request__mach_exception_raise_t;
99   using ExceptionRaiseStateRequest = __Request__mach_exception_raise_state_t;
100   using ExceptionRaiseStateIdentityRequest =
101       __Request__mach_exception_raise_state_identity_t;
102 
103   using ExceptionRaiseReply = __Reply__mach_exception_raise_t;
104   using ExceptionRaiseStateReply = __Reply__mach_exception_raise_state_t;
105   using ExceptionRaiseStateIdentityReply =
106       __Reply__mach_exception_raise_state_identity_t;
107 
108   // The MIG-generated __MIG_check__Request__*() functions are not declared as
109   // accepting const data, but they could have been because they in fact do not
110   // modify the data.
111 
MIGCheckRequestExceptionRaisecrashpad::__anon7ba16b890111::MachExcTraits112   static kern_return_t MIGCheckRequestExceptionRaise(
113       const ExceptionRaiseRequest* in_request) {
114     return __MIG_check__Request__mach_exception_raise_t(
115         const_cast<ExceptionRaiseRequest*>(in_request));
116   }
117 
MIGCheckRequestExceptionRaiseStatecrashpad::__anon7ba16b890111::MachExcTraits118   static kern_return_t MIGCheckRequestExceptionRaiseState(
119       const ExceptionRaiseStateRequest* in_request,
120       const ExceptionRaiseStateRequest** in_request_1) {
121     return __MIG_check__Request__mach_exception_raise_state_t(
122         const_cast<ExceptionRaiseStateRequest*>(in_request),
123         const_cast<ExceptionRaiseStateRequest**>(in_request_1));
124   }
125 
MIGCheckRequestExceptionRaiseStateIdentitycrashpad::__anon7ba16b890111::MachExcTraits126   static kern_return_t MIGCheckRequestExceptionRaiseStateIdentity(
127       const ExceptionRaiseStateIdentityRequest* in_request,
128       const ExceptionRaiseStateIdentityRequest** in_request_1) {
129     return __MIG_check__Request__mach_exception_raise_state_identity_t(
130         const_cast<ExceptionRaiseStateIdentityRequest*>(in_request),
131         const_cast<ExceptionRaiseStateIdentityRequest**>(in_request_1));
132   }
133 
134   // There are no predefined constants for these.
135   static const mach_msg_id_t kMachMessageIDExceptionRaise = 2405;
136   static const mach_msg_id_t kMachMessageIDExceptionRaiseState = 2406;
137   static const mach_msg_id_t kMachMessageIDExceptionRaiseStateIdentity = 2407;
138 
139   static const exception_behavior_t kExceptionBehavior = MACH_EXCEPTION_CODES;
140 };
141 
142 //! \brief A server interface for the `exc` or `mach_exc` Mach subsystems.
143 template <typename Traits>
144 class ExcServer : public MachMessageServer::Interface {
145  public:
146   //! \brief An interface that the different request messages that are a part of
147   //!     the `exc` or `mach_exc` Mach subsystems can be dispatched to.
148   class Interface {
149    public:
150     //! \brief Handles exceptions raised by `exception_raise()` or
151     //!     `mach_exception_raise()`.
152     //!
153     //! This behaves equivalently to a `catch_exception_raise()` function used
154     //! with `exc_server()`, or a `catch_mach_exception_raise()` function used
155     //! with `mach_exc_server()`.
156     //!
157     //! \param[in] trailer The trailer received with the request message.
158     //! \param[out] destroy_request `true` if the request message is to be
159     //!     destroyed even when this method returns success. See
160     //!     MachMessageServer::Interface.
161     virtual kern_return_t CatchExceptionRaise(
162         exception_handler_t exception_port,
163         thread_t thread,
164         task_t task,
165         exception_type_t exception,
166         const typename Traits::ExceptionCode* code,
167         mach_msg_type_number_t code_count,
168         const mach_msg_trailer_t* trailer,
169         bool* destroy_request) = 0;
170 
171     //! \brief Handles exceptions raised by `exception_raise_state()` or
172     //!     `mach_exception_raise_state()`.
173     //!
174     //! This behaves equivalently to a `catch_exception_raise_state()` function
175     //! used with `exc_server()`, or a `catch_mach_exception_raise_state()`
176     //! function used with `mach_exc_server()`.
177     //!
178     //! There is no \a destroy_request parameter because, unlike
179     //! CatchExceptionRaise() and CatchExceptionRaiseStateIdentity(), the
180     //! request message is not complex (it does not carry the \a thread or \a
181     //! task port rights) and thus there is nothing to destroy.
182     //!
183     //! \param[in] trailer The trailer received with the request message.
184     virtual kern_return_t CatchExceptionRaiseState(
185         exception_handler_t exception_port,
186         exception_type_t exception,
187         const typename Traits::ExceptionCode* code,
188         mach_msg_type_number_t code_count,
189         thread_state_flavor_t* flavor,
190         ConstThreadState old_state,
191         mach_msg_type_number_t old_state_count,
192         thread_state_t new_state,
193         mach_msg_type_number_t* new_state_count,
194         const mach_msg_trailer_t* trailer) = 0;
195 
196     //! \brief Handles exceptions raised by `exception_raise_state_identity()`
197     //!     or `mach_exception_raise_state_identity()`.
198     //!
199     //! This behaves equivalently to a `catch_exception_raise_state_identity()`
200     //! function used with `exc_server()`, or a
201     //! `catch_mach_exception_raise_state_identity()` function used with
202     //! `mach_exc_server()`.
203     //!
204     //! \param[in] trailer The trailer received with the request message.
205     //! \param[out] destroy_request `true` if the request message is to be
206     //!     destroyed even when this method returns success. See
207     //!     MachMessageServer::Interface.
208     virtual kern_return_t CatchExceptionRaiseStateIdentity(
209         exception_handler_t exception_port,
210         thread_t thread,
211         task_t task,
212         exception_type_t exception,
213         const typename Traits::ExceptionCode* code,
214         mach_msg_type_number_t code_count,
215         thread_state_flavor_t* flavor,
216         ConstThreadState old_state,
217         mach_msg_type_number_t old_state_count,
218         thread_state_t new_state,
219         mach_msg_type_number_t* new_state_count,
220         const mach_msg_trailer_t* trailer,
221         bool* destroy_request) = 0;
222 
223    protected:
~Interface()224     ~Interface() {}
225   };
226 
227   //! \brief Constructs an object of this class.
228   //!
229   //! \param[in] interface The interface to dispatch requests to. Weak.
ExcServer(Interface * interface)230   explicit ExcServer(Interface* interface)
231       : MachMessageServer::Interface(), interface_(interface) {}
232 
233   // MachMessageServer::Interface:
234 
235   bool MachMessageServerFunction(const mach_msg_header_t* in_header,
236                                  mach_msg_header_t* out_header,
237                                  bool* destroy_complex_request) override;
238 
MachMessageServerRequestIDs()239   std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
240     constexpr mach_msg_id_t request_ids[] = {
241         Traits::kMachMessageIDExceptionRaise,
242         Traits::kMachMessageIDExceptionRaiseState,
243         Traits::kMachMessageIDExceptionRaiseStateIdentity,
244     };
245     return std::set<mach_msg_id_t>(&request_ids[0],
246                                    &request_ids[base::size(request_ids)]);
247   }
248 
MachMessageServerRequestSize()249   mach_msg_size_t MachMessageServerRequestSize() override {
250     return sizeof(typename Traits::RequestUnion);
251   }
252 
MachMessageServerReplySize()253   mach_msg_size_t MachMessageServerReplySize() override {
254     return sizeof(typename Traits::ReplyUnion);
255   }
256 
257  private:
258   Interface* interface_;  // weak
259 
260   DISALLOW_COPY_AND_ASSIGN(ExcServer);
261 };
262 
263 template <typename Traits>
MachMessageServerFunction(const mach_msg_header_t * in_header,mach_msg_header_t * out_header,bool * destroy_complex_request)264 bool ExcServer<Traits>::MachMessageServerFunction(
265     const mach_msg_header_t* in_header,
266     mach_msg_header_t* out_header,
267     bool* destroy_complex_request) {
268   PrepareMIGReplyFromRequest(in_header, out_header);
269 
270   const mach_msg_trailer_t* in_trailer =
271       MachMessageTrailerFromHeader(in_header);
272 
273   switch (in_header->msgh_id) {
274     case Traits::kMachMessageIDExceptionRaise: {
275       // exception_raise(), catch_exception_raise(), mach_exception_raise(),
276       // catch_mach_exception_raise().
277       using Request = typename Traits::ExceptionRaiseRequest;
278       const Request* in_request = reinterpret_cast<const Request*>(in_header);
279       kern_return_t kr = Traits::MIGCheckRequestExceptionRaise(in_request);
280       if (kr != MACH_MSG_SUCCESS) {
281         SetMIGReplyError(out_header, kr);
282         return true;
283       }
284 
285       using Reply = typename Traits::ExceptionRaiseReply;
286       Reply* out_reply = reinterpret_cast<Reply*>(out_header);
287       out_reply->RetCode =
288           interface_->CatchExceptionRaise(in_header->msgh_local_port,
289                                           in_request->thread.name,
290                                           in_request->task.name,
291                                           in_request->exception,
292                                           in_request->code,
293                                           in_request->codeCnt,
294                                           in_trailer,
295                                           destroy_complex_request);
296       if (out_reply->RetCode != KERN_SUCCESS) {
297         return true;
298       }
299 
300       out_header->msgh_size = sizeof(*out_reply);
301       return true;
302     }
303 
304     case Traits::kMachMessageIDExceptionRaiseState: {
305       // exception_raise_state(), catch_exception_raise_state(),
306       // mach_exception_raise_state(), catch_mach_exception_raise_state().
307       using Request = typename Traits::ExceptionRaiseStateRequest;
308       const Request* in_request = reinterpret_cast<const Request*>(in_header);
309 
310       // in_request_1 is used for the portion of the request after the codes,
311       // which in theory can be variable-length. The check function will set it.
312       const Request* in_request_1;
313       kern_return_t kr =
314           Traits::MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
315       if (kr != MACH_MSG_SUCCESS) {
316         SetMIGReplyError(out_header, kr);
317         return true;
318       }
319 
320       using Reply = typename Traits::ExceptionRaiseStateReply;
321       Reply* out_reply = reinterpret_cast<Reply*>(out_header);
322       out_reply->flavor = in_request_1->flavor;
323       out_reply->new_stateCnt = base::size(out_reply->new_state);
324       out_reply->RetCode =
325           interface_->CatchExceptionRaiseState(in_header->msgh_local_port,
326                                                in_request->exception,
327                                                in_request->code,
328                                                in_request->codeCnt,
329                                                &out_reply->flavor,
330                                                in_request_1->old_state,
331                                                in_request_1->old_stateCnt,
332                                                out_reply->new_state,
333                                                &out_reply->new_stateCnt,
334                                                in_trailer);
335       if (out_reply->RetCode != KERN_SUCCESS) {
336         return true;
337       }
338 
339       out_header->msgh_size =
340           sizeof(*out_reply) - sizeof(out_reply->new_state) +
341           sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
342       return true;
343     }
344 
345     case Traits::kMachMessageIDExceptionRaiseStateIdentity: {
346       // exception_raise_state_identity(),
347       // catch_exception_raise_state_identity(),
348       // mach_exception_raise_state_identity(),
349       // catch_mach_exception_raise_state_identity().
350       using Request = typename Traits::ExceptionRaiseStateIdentityRequest;
351       const Request* in_request = reinterpret_cast<const Request*>(in_header);
352 
353       // in_request_1 is used for the portion of the request after the codes,
354       // which in theory can be variable-length. The check function will set it.
355       const Request* in_request_1;
356       kern_return_t kr = Traits::MIGCheckRequestExceptionRaiseStateIdentity(
357           in_request, &in_request_1);
358       if (kr != MACH_MSG_SUCCESS) {
359         SetMIGReplyError(out_header, kr);
360         return true;
361       }
362 
363       using Reply = typename Traits::ExceptionRaiseStateIdentityReply;
364       Reply* out_reply = reinterpret_cast<Reply*>(out_header);
365       out_reply->flavor = in_request_1->flavor;
366       out_reply->new_stateCnt = base::size(out_reply->new_state);
367       out_reply->RetCode = interface_->CatchExceptionRaiseStateIdentity(
368           in_header->msgh_local_port,
369           in_request->thread.name,
370           in_request->task.name,
371           in_request->exception,
372           in_request->code,
373           in_request->codeCnt,
374           &out_reply->flavor,
375           in_request_1->old_state,
376           in_request_1->old_stateCnt,
377           out_reply->new_state,
378           &out_reply->new_stateCnt,
379           in_trailer,
380           destroy_complex_request);
381       if (out_reply->RetCode != KERN_SUCCESS) {
382         return true;
383       }
384 
385       out_header->msgh_size =
386           sizeof(*out_reply) - sizeof(out_reply->new_state) +
387           sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
388       return true;
389     }
390 
391     default: {
392       SetMIGReplyError(out_header, MIG_BAD_ID);
393       return false;
394     }
395   }
396 }
397 
398 //! \brief A server interface for the `exc` or `mach_exc` Mach subsystems,
399 //!     simplified to have only a single interface method needing
400 //!     implementation.
401 template <typename Traits>
402 class SimplifiedExcServer final : public ExcServer<Traits>,
403                                   public ExcServer<Traits>::Interface {
404  public:
405   //! \brief An interface that the different request messages that are a part of
406   //!     the `exc` or `mach_exc` Mach subsystems can be dispatched to.
407   class Interface {
408    public:
409     //! \brief Handles exceptions raised by `exception_raise()`,
410     //!     `exception_raise_state()`, and `exception_raise_state_identity()`;
411     //!     or `mach_exception_raise()`, `mach_exception_raise_state()`, and
412     //!     `mach_exception_raise_state_identity()`.
413     //!
414     //! For convenience in implementation, these different “behaviors” of
415     //! exception messages are all mapped to a single interface method. The
416     //! exception’s original “behavior” is specified in the \a behavior
417     //! parameter. Only parameters that were supplied in the request message
418     //! are populated, other parameters are set to reasonable default values.
419     //!
420     //! The meanings of most parameters are identical to that of
421     //! ExcServer<>::Interface::CatchExceptionRaiseStateIdentity().
422     //!
423     //! \param[in] behavior `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
424     //!     `EXCEPTION_STATE_IDENTITY`, identifying which exception request
425     //!     message was processed and thus which other parameters are valid.
426     //!     When used with the `mach_exc` subsystem, `MACH_EXCEPTION_CODES` will
427     //!     be ORed in to this parameter.
428     virtual kern_return_t CatchException(
429         exception_behavior_t behavior,
430         exception_handler_t exception_port,
431         thread_t thread,
432         task_t task,
433         exception_type_t exception,
434         const typename Traits::ExceptionCode* code,
435         mach_msg_type_number_t code_count,
436         thread_state_flavor_t* flavor,
437         ConstThreadState old_state,
438         mach_msg_type_number_t old_state_count,
439         thread_state_t new_state,
440         mach_msg_type_number_t* new_state_count,
441         const mach_msg_trailer_t* trailer,
442         bool* destroy_complex_request) = 0;
443 
444    protected:
~Interface()445     ~Interface() {}
446   };
447 
448   //! \brief Constructs an object of this class.
449   //!
450   //! \param[in] interface The interface to dispatch requests to. Weak.
SimplifiedExcServer(Interface * interface)451   explicit SimplifiedExcServer(Interface* interface)
452       : ExcServer<Traits>(this),
453         ExcServer<Traits>::Interface(),
454         interface_(interface) {}
455 
456   // ExcServer::Interface:
457 
CatchExceptionRaise(exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const typename Traits::ExceptionCode * code,mach_msg_type_number_t code_count,const mach_msg_trailer_t * trailer,bool * destroy_request)458   kern_return_t CatchExceptionRaise(exception_handler_t exception_port,
459                                     thread_t thread,
460                                     task_t task,
461                                     exception_type_t exception,
462                                     const typename Traits::ExceptionCode* code,
463                                     mach_msg_type_number_t code_count,
464                                     const mach_msg_trailer_t* trailer,
465                                     bool* destroy_request) override {
466     thread_state_flavor_t flavor = THREAD_STATE_NONE;
467     mach_msg_type_number_t new_state_count = 0;
468     return interface_->CatchException(
469         Traits::kExceptionBehavior | EXCEPTION_DEFAULT,
470         exception_port,
471         thread,
472         task,
473         exception,
474         code_count ? code : nullptr,
475         code_count,
476         &flavor,
477         nullptr,
478         0,
479         nullptr,
480         &new_state_count,
481         trailer,
482         destroy_request);
483   }
484 
CatchExceptionRaiseState(exception_handler_t exception_port,exception_type_t exception,const typename Traits::ExceptionCode * 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)485   kern_return_t CatchExceptionRaiseState(
486       exception_handler_t exception_port,
487       exception_type_t exception,
488       const typename Traits::ExceptionCode* code,
489       mach_msg_type_number_t code_count,
490       thread_state_flavor_t* flavor,
491       ConstThreadState old_state,
492       mach_msg_type_number_t old_state_count,
493       thread_state_t new_state,
494       mach_msg_type_number_t* new_state_count,
495       const mach_msg_trailer_t* trailer) override {
496     bool destroy_complex_request = false;
497     return interface_->CatchException(
498         Traits::kExceptionBehavior | EXCEPTION_STATE,
499         exception_port,
500         THREAD_NULL,
501         TASK_NULL,
502         exception,
503         code_count ? code : nullptr,
504         code_count,
505         flavor,
506         old_state_count ? old_state : nullptr,
507         old_state_count,
508         new_state_count ? new_state : nullptr,
509         new_state_count,
510         trailer,
511         &destroy_complex_request);
512   }
513 
CatchExceptionRaiseStateIdentity(exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const typename Traits::ExceptionCode * 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_request)514   kern_return_t CatchExceptionRaiseStateIdentity(
515       exception_handler_t exception_port,
516       thread_t thread,
517       task_t task,
518       exception_type_t exception,
519       const typename Traits::ExceptionCode* code,
520       mach_msg_type_number_t code_count,
521       thread_state_flavor_t* flavor,
522       ConstThreadState old_state,
523       mach_msg_type_number_t old_state_count,
524       thread_state_t new_state,
525       mach_msg_type_number_t* new_state_count,
526       const mach_msg_trailer_t* trailer,
527       bool* destroy_request) override {
528     return interface_->CatchException(
529         Traits::kExceptionBehavior | EXCEPTION_STATE_IDENTITY,
530         exception_port,
531         thread,
532         task,
533         exception,
534         code_count ? code : nullptr,
535         code_count,
536         flavor,
537         old_state_count ? old_state : nullptr,
538         old_state_count,
539         new_state_count ? new_state : nullptr,
540         new_state_count,
541         trailer,
542         destroy_request);
543   }
544 
545  private:
546   Interface* interface_;  // weak
547 
548   DISALLOW_COPY_AND_ASSIGN(SimplifiedExcServer);
549 };
550 
551 }  // namespace
552 
553 namespace internal {
554 
555 class UniversalMachExcServerImpl final
556     : public CompositeMachMessageServer,
557       public SimplifiedExcServer<ExcTraits>::Interface,
558       public SimplifiedExcServer<MachExcTraits>::Interface {
559  public:
UniversalMachExcServerImpl(UniversalMachExcServer::Interface * interface)560   explicit UniversalMachExcServerImpl(
561       UniversalMachExcServer::Interface* interface)
562       : CompositeMachMessageServer(),
563         SimplifiedExcServer<ExcTraits>::Interface(),
564         SimplifiedExcServer<MachExcTraits>::Interface(),
565         exc_server_(this),
566         mach_exc_server_(this),
567         interface_(interface) {
568     AddHandler(&exc_server_);
569     AddHandler(&mach_exc_server_);
570   }
571 
~UniversalMachExcServerImpl()572   ~UniversalMachExcServerImpl() {}
573 
574   // SimplifiedExcServer<ExcTraits>::Interface:
CatchException(exception_behavior_t behavior,exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const 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)575   kern_return_t CatchException(exception_behavior_t behavior,
576                                exception_handler_t exception_port,
577                                thread_t thread,
578                                task_t task,
579                                exception_type_t exception,
580                                const exception_data_type_t* code,
581                                mach_msg_type_number_t code_count,
582                                thread_state_flavor_t* flavor,
583                                ConstThreadState old_state,
584                                mach_msg_type_number_t old_state_count,
585                                thread_state_t new_state,
586                                mach_msg_type_number_t* new_state_count,
587                                const mach_msg_trailer_t* trailer,
588                                bool* destroy_complex_request) {
589     std::vector<mach_exception_data_type_t> mach_codes;
590     mach_codes.reserve(code_count);
591     for (size_t index = 0; index < code_count; ++index) {
592       mach_codes.push_back(code[index]);
593     }
594 
595     return interface_->CatchMachException(behavior,
596                                           exception_port,
597                                           thread,
598                                           task,
599                                           exception,
600                                           code_count ? &mach_codes[0] : nullptr,
601                                           code_count,
602                                           flavor,
603                                           old_state_count ? old_state : nullptr,
604                                           old_state_count,
605                                           new_state_count ? new_state : nullptr,
606                                           new_state_count,
607                                           trailer,
608                                           destroy_complex_request);
609   }
610 
611   // SimplifiedExcServer<MachExcTraits>::Interface:
CatchException(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)612   kern_return_t CatchException(exception_behavior_t behavior,
613                                exception_handler_t exception_port,
614                                thread_t thread,
615                                task_t task,
616                                exception_type_t exception,
617                                const mach_exception_data_type_t* code,
618                                mach_msg_type_number_t code_count,
619                                thread_state_flavor_t* flavor,
620                                ConstThreadState old_state,
621                                mach_msg_type_number_t old_state_count,
622                                thread_state_t new_state,
623                                mach_msg_type_number_t* new_state_count,
624                                const mach_msg_trailer_t* trailer,
625                                bool* destroy_complex_request) {
626     return interface_->CatchMachException(behavior,
627                                           exception_port,
628                                           thread,
629                                           task,
630                                           exception,
631                                           code_count ? code : nullptr,
632                                           code_count,
633                                           flavor,
634                                           old_state_count ? old_state : nullptr,
635                                           old_state_count,
636                                           new_state_count ? new_state : nullptr,
637                                           new_state_count,
638                                           trailer,
639                                           destroy_complex_request);
640   }
641 
642  private:
643   SimplifiedExcServer<ExcTraits> exc_server_;
644   SimplifiedExcServer<MachExcTraits> mach_exc_server_;
645   UniversalMachExcServer::Interface* interface_;  // weak
646 
647   DISALLOW_COPY_AND_ASSIGN(UniversalMachExcServerImpl);
648 };
649 
650 }  // namespace internal
651 
UniversalMachExcServer(UniversalMachExcServer::Interface * interface)652 UniversalMachExcServer::UniversalMachExcServer(
653     UniversalMachExcServer::Interface* interface)
654     : MachMessageServer::Interface(),
655       impl_(new internal::UniversalMachExcServerImpl(interface)) {
656 }
657 
~UniversalMachExcServer()658 UniversalMachExcServer::~UniversalMachExcServer() {
659 }
660 
MachMessageServerFunction(const mach_msg_header_t * in_header,mach_msg_header_t * out_header,bool * destroy_complex_request)661 bool UniversalMachExcServer::MachMessageServerFunction(
662     const mach_msg_header_t* in_header,
663     mach_msg_header_t* out_header,
664     bool* destroy_complex_request) {
665   return impl_->MachMessageServerFunction(
666       in_header, out_header, destroy_complex_request);
667 }
668 
MachMessageServerRequestIDs()669 std::set<mach_msg_id_t> UniversalMachExcServer::MachMessageServerRequestIDs() {
670   return impl_->MachMessageServerRequestIDs();
671 }
672 
MachMessageServerRequestSize()673 mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() {
674   return impl_->MachMessageServerRequestSize();
675 }
676 
MachMessageServerReplySize()677 mach_msg_size_t UniversalMachExcServer::MachMessageServerReplySize() {
678   return impl_->MachMessageServerReplySize();
679 }
680 
ExcServerSuccessfulReturnValue(exception_type_t exception,exception_behavior_t behavior,bool set_thread_state)681 kern_return_t ExcServerSuccessfulReturnValue(exception_type_t exception,
682                                              exception_behavior_t behavior,
683                                              bool set_thread_state) {
684   if (exception == EXC_CRASH
685 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
686       && MacOSXMinorVersion() >= 11
687 #endif
688      ) {
689     return KERN_SUCCESS;
690   }
691 
692   if (!set_thread_state && ExceptionBehaviorHasState(behavior)) {
693     return MACH_RCV_PORT_DIED;
694   }
695 
696   return KERN_SUCCESS;
697 }
698 
ExcServerCopyState(exception_behavior_t behavior,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)699 void ExcServerCopyState(exception_behavior_t behavior,
700                         ConstThreadState old_state,
701                         mach_msg_type_number_t old_state_count,
702                         thread_state_t new_state,
703                         mach_msg_type_number_t* new_state_count) {
704   if (ExceptionBehaviorHasState(behavior)) {
705     *new_state_count = std::min(old_state_count, *new_state_count);
706     memcpy(new_state, old_state, *new_state_count * sizeof(old_state[0]));
707   }
708 }
709 
710 }  // namespace crashpad
711