]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // mach++ - C++ bindings for useful Mach primitives | |
27 | // | |
28 | #ifndef _H_MACHPP | |
29 | #define _H_MACHPP | |
30 | ||
31 | #include <security_utilities/utilities.h> | |
32 | #include <security_utilities/errors.h> | |
33 | #include <security_utilities/threading.h> | |
34 | #include <security_utilities/globalizer.h> | |
fa7225c8 | 35 | #include <security_utilities/debugging_internal.h> |
b1ab9ed8 A |
36 | #include <mach/mach.h> |
37 | #include <servers/bootstrap.h> | |
38 | #include <set> | |
39 | ||
40 | // yes, we use some UNIX (non-mach) headers... | |
41 | #include <sys/types.h> | |
42 | #include <unistd.h> | |
43 | ||
44 | namespace Security { | |
45 | namespace MachPlusPlus { | |
46 | ||
47 | ||
48 | // | |
49 | // Exceptions thrown by the mach++ interface. | |
50 | // | |
51 | class Error : public CommonError { | |
52 | protected: | |
53 | // actually, kern_return_t can be just about any subsystem type return code | |
54 | Error(kern_return_t err); | |
55 | public: | |
d64be36e | 56 | virtual ~Error() _NOEXCEPT; |
b1ab9ed8 A |
57 | |
58 | virtual OSStatus osStatus() const; | |
59 | virtual int unixError() const; | |
60 | ||
61 | const kern_return_t error; | |
62 | ||
63 | static void check(kern_return_t err); | |
64 | static void throwMe(kern_return_t err) __attribute__((noreturn)); | |
65 | }; | |
66 | ||
67 | // generic return code checker | |
68 | inline void check(kern_return_t status) | |
69 | { Error::check(status); } | |
70 | ||
71 | ||
72 | // | |
73 | // Simple vm_allocate/deallocate glue | |
74 | // | |
75 | void *allocate(size_t size); | |
76 | void deallocate(vm_address_t addr, size_t size); | |
77 | ||
78 | inline void deallocate(const void *addr, size_t size) | |
79 | { deallocate(reinterpret_cast<vm_address_t>(addr), size); } | |
80 | ||
81 | ||
82 | // | |
83 | // An encapsulation of a Mach 3 port | |
84 | // | |
85 | class Port { | |
86 | protected: | |
87 | static mach_port_t self() { return mach_task_self(); } | |
88 | ||
89 | public: | |
90 | Port() { mPort = MACH_PORT_NULL; } | |
91 | Port(mach_port_t port) { mPort = port; } | |
92 | ||
93 | // devolve to Mach primitive type | |
94 | operator mach_port_t () const { return mPort; } | |
95 | ||
96 | // access reference (for primitives storing into &mach_port_t) | |
97 | mach_port_t &port () { return mPort; } | |
98 | const mach_port_t &port () const { return mPort; } | |
99 | ||
100 | // status checks | |
101 | mach_port_type_t type() const | |
102 | { mach_port_type_t typ; check(mach_port_type(self(), mPort, &typ)); return typ; } | |
103 | ||
104 | bool isType(mach_port_type_t typ) const { return type() & typ; } | |
105 | bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME); } | |
106 | ||
107 | // port allocation and management | |
108 | void allocate(mach_port_right_t right = MACH_PORT_RIGHT_RECEIVE) | |
109 | { check(mach_port_allocate(self(), right, &mPort)); } | |
d64be36e A |
110 | /* |
111 | * (╯ರ ~ ರ)╯︵ ┻━┻ | |
112 | * mach_port_deallocate() only deallocates send, send-once, dead-name, or port-set. | |
113 | * Since allocate() defaults to receive, allocate() and deallocate() do not actually | |
114 | * balance each other; deallocate() will fail with an invalid-right error. | |
115 | */ | |
116 | void deallocate() { check(mach_port_deallocate(self(), mPort)); mPort = MACH_PORT_NULL;} | |
b1ab9ed8 A |
117 | |
118 | void insertRight(mach_msg_type_name_t type) | |
119 | { check(mach_port_insert_right(self(), mPort, mPort, type)); } | |
120 | ||
121 | void modRefs(mach_port_right_t right, mach_port_delta_t delta = 1) | |
122 | { check(mach_port_mod_refs(self(), mPort, right, delta)); } | |
123 | ||
124 | mach_port_urefs_t getRefs(mach_port_right_t right); | |
125 | ||
126 | // port notification interface | |
127 | mach_port_t requestNotify(mach_port_t notify, | |
128 | mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME, mach_port_mscount_t sync = 1); | |
129 | mach_port_t cancelNotify(mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME); | |
130 | ||
131 | // queue state management | |
132 | mach_port_msgcount_t qlimit() const; | |
133 | void qlimit(mach_port_msgcount_t limit); | |
134 | ||
135 | IFDUMP(void dump(const char *name = NULL)); | |
136 | ||
137 | protected: | |
138 | mach_port_t mPort; | |
139 | }; | |
140 | ||
141 | ||
b1ab9ed8 A |
142 | // |
143 | // Ports representing PortSets | |
144 | // | |
145 | class PortSet : public Port { | |
146 | public: | |
147 | PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET); } | |
d64be36e | 148 | ~PortSet() { deallocate(); } |
b1ab9ed8 A |
149 | |
150 | void operator += (const Port &port) | |
151 | { check(mach_port_move_member(self(), port, mPort)); } | |
152 | ||
153 | void operator -= (const Port &port) | |
154 | { check(mach_port_move_member(self(), port, MACH_PORT_NULL)); } | |
155 | ||
156 | set<Port> members() const; | |
157 | bool contains(Port member) const; // relatively slow | |
158 | }; | |
159 | ||
160 | ||
161 | // | |
162 | // Ports that are bootstrap ports | |
163 | // | |
164 | class Bootstrap : public Port { | |
165 | public: | |
166 | Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort)); } | |
167 | Bootstrap(mach_port_t bootp) : Port(bootp) { } | |
168 | ||
169 | mach_port_t checkIn(const char *name) const; | |
170 | mach_port_t checkInOptional(const char *name) const; | |
171 | ||
172 | void registerAs(mach_port_t port, const char *name) const; | |
173 | ||
174 | mach_port_t lookup(const char *name) const; | |
175 | mach_port_t lookup2(const char *name) const; | |
176 | mach_port_t lookupOptional(const char *name) const; | |
177 | ||
178 | Bootstrap subset(Port requestor); | |
179 | ||
180 | IFDUMP(void dump()); | |
181 | ||
182 | private: | |
183 | // officially, the register/lookup IPCs take an array of 128 characters (not a zero-end string) | |
184 | mutable char nameBuffer[BOOTSTRAP_MAX_NAME_LEN]; | |
185 | ||
186 | protected: | |
187 | char *makeName(const char *s) const | |
188 | { return strncpy(nameBuffer, s, BOOTSTRAP_MAX_NAME_LEN); } | |
189 | }; | |
190 | ||
191 | ||
192 | // | |
193 | // Ports that are Task Ports | |
194 | // | |
195 | class TaskPort : public Port { | |
196 | public: | |
197 | TaskPort() { mPort = self(); } | |
198 | TaskPort(mach_port_t p) : Port(p) { } | |
199 | TaskPort(const Port &p) : Port(p) { } | |
200 | TaskPort(pid_t pid); | |
201 | ||
202 | Bootstrap bootstrap() const | |
203 | { mach_port_t boot; check(task_get_bootstrap_port(mPort, &boot)); return boot; } | |
204 | void bootstrap(Bootstrap boot) | |
205 | { check(task_set_bootstrap_port(mPort, boot)); } | |
206 | ||
207 | pid_t pid() const; | |
208 | }; | |
209 | ||
210 | ||
211 | // | |
212 | // Ports that are are self-allocated and have receive rights | |
213 | // | |
214 | class ReceivePort : public Port { | |
215 | public: | |
216 | ReceivePort() { allocate(); } | |
217 | ReceivePort(const char *name, const Bootstrap &bootstrap, bool tryCheckin = true); | |
d64be36e | 218 | ~ReceivePort() { modRefs(MACH_PORT_RIGHT_RECEIVE, -1); } |
b1ab9ed8 A |
219 | }; |
220 | ||
221 | ||
222 | // | |
223 | // A little stack utility for temporarily switching your bootstrap around. | |
224 | // Essentially, it restores your bootstrap port when it dies. Since the | |
225 | // "current bootstrap port" is a process-global item, this uses a global | |
226 | // zone of exclusion (aka critical region). There's no protection against | |
227 | // someone else calling the underlying system service, of course. | |
228 | // | |
229 | class StBootstrap { | |
230 | public: | |
231 | StBootstrap(const Bootstrap &boot, const TaskPort &task = TaskPort()); | |
232 | ~StBootstrap(); | |
233 | ||
234 | private: | |
235 | Bootstrap mOldBoot; | |
236 | TaskPort mTask; | |
237 | StLock<Mutex> locker; | |
238 | static ModuleNexus<Mutex> critical; // critical region guard (of a sort) | |
239 | }; | |
240 | ||
241 | ||
242 | // | |
243 | // A Mach-level memory guard. | |
244 | // This will vm_deallocate its argument when it gets destroyed. | |
245 | // | |
246 | class VMGuard { | |
247 | public: | |
248 | VMGuard(void *addr, size_t length) : mAddr(addr), mLength(length) { } | |
249 | ~VMGuard() { deallocate(mAddr, mLength); } | |
250 | ||
251 | private: | |
252 | void *mAddr; | |
253 | size_t mLength; | |
254 | }; | |
255 | ||
256 | ||
257 | // | |
258 | // Message buffers for Mach messages. | |
259 | // The logic here is somewhat inverted from the usual: send/receive | |
260 | // are methods on the buffers (rather than buffers being arguments to send/receive). | |
261 | // It's rather handy once you get used to that view. | |
262 | // | |
263 | class Message { | |
264 | public: | |
427c49bc A |
265 | Message(void *buffer, mach_msg_size_t size); // use buffer with size |
266 | Message(mach_msg_size_t size); // allocate buffer with size | |
267 | Message(); // set buffer later | |
b1ab9ed8 A |
268 | virtual ~Message(); |
269 | ||
427c49bc A |
270 | void setBuffer(void *buffer, mach_msg_size_t size); // use buffer with size |
271 | void setBuffer(mach_msg_size_t size); // allocate buffer with size | |
79b9da22 | 272 | void clearBuffer(void); |
427c49bc | 273 | void release(); // discard buffer (if any) |
b1ab9ed8 A |
274 | |
275 | operator mig_reply_error_t & () const { return *mBuffer; } | |
276 | operator mach_msg_header_t & () const { return mBuffer->Head; } | |
277 | operator mig_reply_error_t * () const { return mBuffer; } | |
278 | operator mach_msg_header_t * () const { return &mBuffer->Head; } | |
279 | operator NDR_record_t & () const { return mBuffer->NDR; } | |
280 | ||
281 | void *data() const { return mBuffer; } | |
427c49bc | 282 | mach_msg_size_t length() const { return mBuffer->Head.msgh_size; } |
b1ab9ed8 A |
283 | Port localPort() const { return mBuffer->Head.msgh_local_port; } |
284 | Port remotePort() const { return mBuffer->Head.msgh_remote_port; } | |
285 | mach_msg_id_t msgId() const { return mBuffer->Head.msgh_id; } | |
286 | mach_msg_bits_t bits() const { return mBuffer->Head.msgh_bits; } | |
287 | kern_return_t returnCode() const { return mBuffer->RetCode; } | |
0e1db9d1 | 288 | mach_msg_audit_trailer_t *auditTrailer(); |
b1ab9ed8 A |
289 | |
290 | void localPort(mach_port_t p) { mBuffer->Head.msgh_local_port = p; } | |
291 | void remotePort(mach_port_t p) { mBuffer->Head.msgh_remote_port = p; } | |
292 | ||
293 | public: | |
294 | bool send(mach_msg_option_t options = 0, | |
295 | mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, | |
296 | mach_port_name_t notify = MACH_PORT_NULL); | |
297 | bool receive(mach_port_t receivePort, | |
298 | mach_msg_option_t options = 0, | |
299 | mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, | |
300 | mach_port_name_t notify = MACH_PORT_NULL); | |
301 | bool sendReceive(mach_port_t receivePort, | |
302 | mach_msg_option_t options = 0, | |
303 | mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, | |
304 | mach_port_name_t notify = MACH_PORT_NULL); | |
305 | ||
306 | void destroy() { mach_msg_destroy(*this); } | |
307 | ||
308 | protected: | |
309 | bool check(kern_return_t status); | |
310 | ||
311 | private: | |
312 | mig_reply_error_t *mBuffer; | |
427c49bc | 313 | mach_msg_size_t mSize; |
b1ab9ed8 A |
314 | bool mRelease; |
315 | }; | |
316 | ||
317 | ||
318 | } // end namespace MachPlusPlus | |
319 | } // end namespace Security | |
320 | ||
321 | #endif //_H_MACHPP |