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/notify_server.h"
16
17 #include "base/logging.h"
18 #include "base/stl_util.h"
19 #include "util/mach/mach_message.h"
20 #include "util/mach/notifyServer.h"
21
22 namespace {
23
24 // The MIG-generated __MIG_check__Request__*() functions are not declared as
25 // accepting const data, but they could have been because they in fact do not
26 // modify the data. These wrapper functions are provided to bridge the const gap
27 // between the code in this file, which is const-correct and treats request
28 // message data as const, and the generated functions.
29
MIGCheckRequestMachNotifyPortDeleted(const __Request__mach_notify_port_deleted_t * in_request)30 kern_return_t MIGCheckRequestMachNotifyPortDeleted(
31 const __Request__mach_notify_port_deleted_t* in_request) {
32 using Request = __Request__mach_notify_port_deleted_t;
33 return __MIG_check__Request__mach_notify_port_deleted_t(
34 const_cast<Request*>(in_request));
35 }
36
MIGCheckRequestMachNotifyPortDestroyed(const __Request__mach_notify_port_destroyed_t * in_request)37 kern_return_t MIGCheckRequestMachNotifyPortDestroyed(
38 const __Request__mach_notify_port_destroyed_t* in_request) {
39 using Request = __Request__mach_notify_port_destroyed_t;
40 return __MIG_check__Request__mach_notify_port_destroyed_t(
41 const_cast<Request*>(in_request));
42 }
43
MIGCheckRequestMachNotifyNoSenders(const __Request__mach_notify_no_senders_t * in_request)44 kern_return_t MIGCheckRequestMachNotifyNoSenders(
45 const __Request__mach_notify_no_senders_t* in_request) {
46 using Request = __Request__mach_notify_no_senders_t;
47 return __MIG_check__Request__mach_notify_no_senders_t(
48 const_cast<Request*>(in_request));
49 }
50
MIGCheckRequestMachNotifySendOnce(const __Request__mach_notify_send_once_t * in_request)51 kern_return_t MIGCheckRequestMachNotifySendOnce(
52 const __Request__mach_notify_send_once_t* in_request) {
53 using Request = __Request__mach_notify_send_once_t;
54 return __MIG_check__Request__mach_notify_send_once_t(
55 const_cast<Request*>(in_request));
56 }
57
MIGCheckRequestMachNotifyDeadName(const __Request__mach_notify_dead_name_t * in_request)58 kern_return_t MIGCheckRequestMachNotifyDeadName(
59 const __Request__mach_notify_dead_name_t* in_request) {
60 using Request = __Request__mach_notify_dead_name_t;
61 return __MIG_check__Request__mach_notify_dead_name_t(
62 const_cast<Request*>(in_request));
63 }
64
65 } // namespace
66
67 namespace crashpad {
68
DoMachNotifyPortDeleted(notify_port_t notify,mach_port_name_t name,const mach_msg_trailer_t * trailer)69 kern_return_t NotifyServer::DefaultInterface::DoMachNotifyPortDeleted(
70 notify_port_t notify,
71 mach_port_name_t name,
72 const mach_msg_trailer_t* trailer) {
73 return MIG_BAD_ID;
74 }
75
DoMachNotifyPortDestroyed(notify_port_t notify,mach_port_t rights,const mach_msg_trailer_t * trailer,bool * destroy_request)76 kern_return_t NotifyServer::DefaultInterface::DoMachNotifyPortDestroyed(
77 notify_port_t notify,
78 mach_port_t rights,
79 const mach_msg_trailer_t* trailer,
80 bool* destroy_request) {
81 *destroy_request = true;
82 return MIG_BAD_ID;
83 }
84
DoMachNotifyNoSenders(notify_port_t notify,mach_port_mscount_t mscount,const mach_msg_trailer_t * trailer)85 kern_return_t NotifyServer::DefaultInterface::DoMachNotifyNoSenders(
86 notify_port_t notify,
87 mach_port_mscount_t mscount,
88 const mach_msg_trailer_t* trailer) {
89 return MIG_BAD_ID;
90 }
91
DoMachNotifySendOnce(notify_port_t notify,const mach_msg_trailer_t * trailer)92 kern_return_t NotifyServer::DefaultInterface::DoMachNotifySendOnce(
93 notify_port_t notify,
94 const mach_msg_trailer_t* trailer) {
95 return MIG_BAD_ID;
96 }
97
DoMachNotifyDeadName(notify_port_t notify,mach_port_name_t name,const mach_msg_trailer_t * trailer)98 kern_return_t NotifyServer::DefaultInterface::DoMachNotifyDeadName(
99 notify_port_t notify,
100 mach_port_name_t name,
101 const mach_msg_trailer_t* trailer) {
102 return MIG_BAD_ID;
103 }
104
NotifyServer(NotifyServer::Interface * interface)105 NotifyServer::NotifyServer(NotifyServer::Interface* interface)
106 : MachMessageServer::Interface(),
107 interface_(interface) {
108 }
109
MachMessageServerFunction(const mach_msg_header_t * in_header,mach_msg_header_t * out_header,bool * destroy_complex_request)110 bool NotifyServer::MachMessageServerFunction(
111 const mach_msg_header_t* in_header,
112 mach_msg_header_t* out_header,
113 bool* destroy_complex_request) {
114 PrepareMIGReplyFromRequest(in_header, out_header);
115
116 const mach_msg_trailer_t* in_trailer =
117 MachMessageTrailerFromHeader(in_header);
118
119 switch (in_header->msgh_id) {
120 case MACH_NOTIFY_PORT_DELETED: {
121 // mach_notify_port_deleted(), do_mach_notify_port_deleted().
122 using Request = __Request__mach_notify_port_deleted_t;
123 const Request* in_request = reinterpret_cast<const Request*>(in_header);
124 kern_return_t kr = MIGCheckRequestMachNotifyPortDeleted(in_request);
125 if (kr != MACH_MSG_SUCCESS) {
126 SetMIGReplyError(out_header, kr);
127 return true;
128 }
129
130 using Reply = __Reply__mach_notify_port_deleted_t;
131 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
132 out_reply->RetCode =
133 interface_->DoMachNotifyPortDeleted(in_header->msgh_local_port,
134 in_request->name,
135 in_trailer);
136 return true;
137 }
138
139 case MACH_NOTIFY_PORT_DESTROYED: {
140 // mach_notify_port_destroyed(), do_mach_notify_port_destroyed().
141 using Request = __Request__mach_notify_port_destroyed_t;
142 const Request* in_request = reinterpret_cast<const Request*>(in_header);
143 kern_return_t kr = MIGCheckRequestMachNotifyPortDestroyed(in_request);
144 if (kr != MACH_MSG_SUCCESS) {
145 SetMIGReplyError(out_header, kr);
146 return true;
147 }
148
149 using Reply = __Reply__mach_notify_port_destroyed_t;
150 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
151 out_reply->RetCode =
152 interface_->DoMachNotifyPortDestroyed(in_header->msgh_local_port,
153 in_request->rights.name,
154 in_trailer,
155 destroy_complex_request);
156 return true;
157 }
158
159 case MACH_NOTIFY_NO_SENDERS: {
160 // mach_notify_no_senders(), do_mach_notify_no_senders().
161 using Request = __Request__mach_notify_no_senders_t;
162 const Request* in_request = reinterpret_cast<const Request*>(in_header);
163 kern_return_t kr = MIGCheckRequestMachNotifyNoSenders(in_request);
164 if (kr != MACH_MSG_SUCCESS) {
165 SetMIGReplyError(out_header, kr);
166 return true;
167 }
168
169 using Reply = __Reply__mach_notify_no_senders_t;
170 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
171 out_reply->RetCode =
172 interface_->DoMachNotifyNoSenders(in_header->msgh_local_port,
173 in_request->mscount,
174 in_trailer);
175 return true;
176 }
177
178 case MACH_NOTIFY_SEND_ONCE: {
179 // mach_notify_send_once(), do_mach_notify_send_once().
180 using Request = __Request__mach_notify_send_once_t;
181 const Request* in_request = reinterpret_cast<const Request*>(in_header);
182 kern_return_t kr = MIGCheckRequestMachNotifySendOnce(in_request);
183 if (kr != MACH_MSG_SUCCESS) {
184 SetMIGReplyError(out_header, kr);
185 return true;
186 }
187
188 using Reply = __Reply__mach_notify_send_once_t;
189 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
190 out_reply->RetCode =
191 interface_->DoMachNotifySendOnce(in_header->msgh_local_port,
192 in_trailer);
193 return true;
194 }
195
196 case MACH_NOTIFY_DEAD_NAME: {
197 // mach_notify_dead_name(), do_mach_notify_dead_name().
198 using Request = __Request__mach_notify_dead_name_t;
199 const Request* in_request = reinterpret_cast<const Request*>(in_header);
200 kern_return_t kr = MIGCheckRequestMachNotifyDeadName(in_request);
201 if (kr != MACH_MSG_SUCCESS) {
202 SetMIGReplyError(out_header, kr);
203 return true;
204 }
205
206 using Reply = __Reply__mach_notify_dead_name_t;
207 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
208 out_reply->RetCode =
209 interface_->DoMachNotifyDeadName(in_header->msgh_local_port,
210 in_request->name,
211 in_trailer);
212 return true;
213 }
214
215 default: {
216 SetMIGReplyError(out_header, MIG_BAD_ID);
217 return false;
218 }
219 }
220 }
221
MachMessageServerRequestIDs()222 std::set<mach_msg_id_t> NotifyServer::MachMessageServerRequestIDs() {
223 static constexpr mach_msg_id_t request_ids[] = {
224 MACH_NOTIFY_PORT_DELETED,
225 MACH_NOTIFY_PORT_DESTROYED,
226 MACH_NOTIFY_NO_SENDERS,
227 MACH_NOTIFY_SEND_ONCE,
228 MACH_NOTIFY_DEAD_NAME,
229 };
230 return std::set<mach_msg_id_t>(&request_ids[0],
231 &request_ids[base::size(request_ids)]);
232 }
233
MachMessageServerRequestSize()234 mach_msg_size_t NotifyServer::MachMessageServerRequestSize() {
235 return sizeof(__RequestUnion__do_notify_subsystem);
236 }
237
MachMessageServerReplySize()238 mach_msg_size_t NotifyServer::MachMessageServerReplySize() {
239 return sizeof(__ReplyUnion__do_notify_subsystem);
240 }
241
242 } // namespace crashpad
243