Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: handler/mac/exception_handler_server.cc

Issue 789693005: Add the crashpad_handler executable (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « handler/mac/exception_handler_server.h ('k') | handler/mac/main.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "handler/mac/exception_handler_server.h"
16
17 #include "base/logging.h"
18 #include "base/mac/mach_logging.h"
19 #include "base/strings/stringprintf.h"
20 #include "util/mach/composite_mach_message_server.h"
21 #include "util/mach/exc_server_variants.h"
22 #include "util/mach/exception_behaviors.h"
23 #include "util/mach/mach_extensions.h"
24 #include "util/mach/mach_message.h"
25 #include "util/mach/mach_message_server.h"
26 #include "util/mach/notify_server.h"
27
28 namespace crashpad {
29
30 namespace {
31
32 class ExceptionHandlerServerRun
33 : public UniversalMachExcServer::Interface,
34 public NotifyServer::Interface {
35 public:
36 explicit ExceptionHandlerServerRun(mach_port_t exception_port)
37 : UniversalMachExcServer::Interface(),
38 NotifyServer::Interface(),
39 mach_exc_server_(this),
40 notify_server_(this),
41 composite_mach_message_server_(),
42 exception_port_(exception_port),
43 notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)),
44 running_(true) {
45 CHECK_NE(notify_port_, kMachPortNull);
46
47 composite_mach_message_server_.AddHandler(&mach_exc_server_);
48 composite_mach_message_server_.AddHandler(&notify_server_);
49 }
50
51 ~ExceptionHandlerServerRun() {
52 }
53
54 void Run() {
55 DCHECK(running_);
56
57 // Request that a no-senders notification for exception_port_ be sent to
58 // notify_port_.
59 mach_port_t previous;
60 kern_return_t kr =
61 mach_port_request_notification(mach_task_self(),
62 exception_port_,
63 MACH_NOTIFY_NO_SENDERS,
64 0,
65 notify_port_,
66 MACH_MSG_TYPE_MAKE_SEND_ONCE,
67 &previous);
68 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_request_notification";
69
70 if (previous != MACH_PORT_NULL) {
71 kr = mach_port_deallocate(mach_task_self(), previous);
72 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_deallocate";
73 }
74
75 // A single CompositeMachMessageServer will dispatch both exception messages
76 // and the no-senders notification. Put both receive rights into a port set.
77 //
78 // A single receive right can’t be used because the notification request
79 // requires a send-once right, which would prevent the no-senders condition
80 // from ever existing. Using distinct receive rights also allows the handler
81 // methods to ensure that the messages they process were sent by a holder of
82 // the proper send right.
83 base::mac::ScopedMachPortSet server_port_set(
84 NewMachPort(MACH_PORT_RIGHT_PORT_SET));
85
86 kr = mach_port_insert_member(
87 mach_task_self(), exception_port_, server_port_set);
88 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_member";
89
90 kr = mach_port_insert_member(
91 mach_task_self(), notify_port_, server_port_set);
92 MACH_CHECK(kr == KERN_SUCCESS, kr) << "mach_port_insert_member";
93
94 // Run the server in kOneShot mode so that running_ can be reevaluated after
95 // each message. Receipt of a valid no-senders notification causes it to be
96 // set to false.
97 while (running_) {
98 // This will result in a call to CatchMachException() or
99 // DoMachNotifyNoSenders() as appropriate.
100 mach_msg_return_t mr =
101 MachMessageServer::Run(&composite_mach_message_server_,
102 server_port_set,
103 MACH_MSG_OPTION_NONE,
104 MachMessageServer::kOneShot,
105 MachMessageServer::kReceiveLargeIgnore,
106 kMachMessageTimeoutWaitIndefinitely);
107 MACH_CHECK(mr == MACH_MSG_SUCCESS, mr) << "MachMessageServer::Run";
108 }
109 }
110
111 // UniversalMachExcServer::Interface:
112
113 kern_return_t CatchMachException(exception_behavior_t behavior,
114 exception_handler_t exception_port,
115 thread_t thread,
116 task_t task,
117 exception_type_t exception,
118 const mach_exception_data_type_t* code,
119 mach_msg_type_number_t code_count,
120 thread_state_flavor_t* flavor,
121 const natural_t* old_state,
122 mach_msg_type_number_t old_state_count,
123 thread_state_t new_state,
124 mach_msg_type_number_t* new_state_count,
125 const mach_msg_trailer_t* trailer,
126 bool* destroy_complex_request) override {
127 *destroy_complex_request = true;
128
129 if (exception_port != exception_port_) {
130 LOG(WARNING) << "exception port mismatch";
131 return MIG_BAD_ID;
132 }
133
134 // The expected behavior is EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
135 // but it’s possible to deal with any exception behavior as long as it
136 // carries identity information (valid thread and task ports).
137 if (!ExceptionBehaviorHasIdentity(behavior)) {
138 LOG(WARNING) << base::StringPrintf(
139 "unexpected exception behavior 0x%x, rejecting", behavior);
140 return KERN_FAILURE;
141 } else if (behavior != (EXCEPTION_STATE_IDENTITY | kMachExceptionCodes)) {
142 LOG(WARNING) << base::StringPrintf(
143 "unexpected exception behavior 0x%x, proceeding", behavior);
144 }
145
146 // TODO(mark): Implement.
147
148 return ExcServerSuccessfulReturnValue(behavior, false);
149 }
150
151 // NotifyServer::Interface:
152
153 kern_return_t DoMachNotifyPortDeleted(
154 notify_port_t notify,
155 mach_port_name_t name,
156 const mach_msg_trailer_t* trailer) override {
157 return UnimplementedNotifyRoutine(notify);
158 }
159
160 kern_return_t DoMachNotifyPortDestroyed(notify_port_t notify,
161 mach_port_t rights,
162 const mach_msg_trailer_t* trailer,
163 bool* destroy_request) override {
164 *destroy_request = true;
165 return UnimplementedNotifyRoutine(notify);
166 }
167
168 kern_return_t DoMachNotifyNoSenders(
169 notify_port_t notify,
170 mach_port_mscount_t mscount,
171 const mach_msg_trailer_t* trailer) override {
172 if (notify != notify_port_) {
173 // The message was received as part of a port set. This check ensures that
174 // only the authorized sender of the no-senders notification is able to
175 // stop the exception server. Otherwise, a malicious client would be able
176 // to craft and send a no-senders notification via its exception port, and
177 // cause the handler to stop processing exceptions and exit.
178 LOG(WARNING) << "notify port mismatch";
179 return MIG_BAD_ID;
180 }
181
182 running_ = false;
183
184 return KERN_SUCCESS;
185 }
186
187 kern_return_t DoMachNotifySendOnce(
188 notify_port_t notify,
189 const mach_msg_trailer_t* trailer) override {
190 return UnimplementedNotifyRoutine(notify);
191 }
192
193 kern_return_t DoMachNotifyDeadName(
194 notify_port_t notify,
195 mach_port_name_t name,
196 const mach_msg_trailer_t* trailer) override {
197 return UnimplementedNotifyRoutine(notify);
198 }
199
200 private:
201 kern_return_t UnimplementedNotifyRoutine(notify_port_t notify) {
202 // Most of the routines in the notify subsystem are not expected to be
203 // called.
204 if (notify != notify_port_) {
205 LOG(WARNING) << "notify port mismatch";
206 return MIG_BAD_ID;
207 }
208
209 NOTREACHED();
210 return KERN_FAILURE;
211 }
212
213 UniversalMachExcServer mach_exc_server_;
214 NotifyServer notify_server_;
215 CompositeMachMessageServer composite_mach_message_server_;
216 mach_port_t exception_port_; // weak
217 base::mac::ScopedMachReceiveRight notify_port_;
218 bool running_;
219
220 DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServerRun);
221 };
222
223 } // namespace
224
225 ExceptionHandlerServer::ExceptionHandlerServer()
226 : receive_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)) {
227 CHECK_NE(receive_port_, kMachPortNull);
228 }
229
230 ExceptionHandlerServer::~ExceptionHandlerServer() {
231 }
232
233 void ExceptionHandlerServer::Run() {
234 ExceptionHandlerServerRun run(receive_port_);
235 run.Run();
236 }
237
238 } // namespace crashpad
OLDNEW
« no previous file with comments | « handler/mac/exception_handler_server.h ('k') | handler/mac/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698