]>
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> | |
35 | #include <mach/mach.h> | |
36 | #include <servers/bootstrap.h> | |
37 | #include <set> | |
38 | ||
39 | // yes, we use some UNIX (non-mach) headers... | |
40 | #include <sys/types.h> | |
41 | #include <unistd.h> | |
42 | ||
43 | namespace Security { | |
44 | namespace MachPlusPlus { | |
45 | ||
46 | ||
47 | // | |
48 | // Exceptions thrown by the mach++ interface. | |
49 | // | |
50 | class Error : public CommonError { | |
51 | protected: | |
52 | // actually, kern_return_t can be just about any subsystem type return code | |
53 | Error(kern_return_t err); | |
54 | public: | |
55 | virtual ~Error() throw(); | |
56 | ||
57 | virtual OSStatus osStatus() const; | |
58 | virtual int unixError() const; | |
59 | ||
60 | const kern_return_t error; | |
61 | ||
62 | static void check(kern_return_t err); | |
63 | static void throwMe(kern_return_t err) __attribute__((noreturn)); | |
64 | }; | |
65 | ||
66 | // generic return code checker | |
67 | inline void check(kern_return_t status) | |
68 | { Error::check(status); } | |
69 | ||
70 | ||
71 | // | |
72 | // Simple vm_allocate/deallocate glue | |
73 | // | |
74 | void *allocate(size_t size); | |
75 | void deallocate(vm_address_t addr, size_t size); | |
76 | ||
77 | inline void deallocate(const void *addr, size_t size) | |
78 | { deallocate(reinterpret_cast<vm_address_t>(addr), size); } | |
79 | ||
80 | ||
81 | // | |
82 | // An encapsulation of a Mach 3 port | |
83 | // | |
84 | class Port { | |
85 | protected: | |
86 | static mach_port_t self() { return mach_task_self(); } | |
87 | ||
88 | public: | |
89 | Port() { mPort = MACH_PORT_NULL; } | |
90 | Port(mach_port_t port) { mPort = port; } | |
91 | ||
92 | // devolve to Mach primitive type | |
93 | operator mach_port_t () const { return mPort; } | |
94 | ||
95 | // access reference (for primitives storing into &mach_port_t) | |
96 | mach_port_t &port () { return mPort; } | |
97 | const mach_port_t &port () const { return mPort; } | |
98 | ||
99 | // status checks | |
100 | mach_port_type_t type() const | |
101 | { mach_port_type_t typ; check(mach_port_type(self(), mPort, &typ)); return typ; } | |
102 | ||
103 | bool isType(mach_port_type_t typ) const { return type() & typ; } | |
104 | bool isDead() const { return isType(MACH_PORT_TYPE_DEAD_NAME); } | |
105 | ||
106 | // port allocation and management | |
107 | void allocate(mach_port_right_t right = MACH_PORT_RIGHT_RECEIVE) | |
108 | { check(mach_port_allocate(self(), right, &mPort)); } | |
109 | void deallocate() { check(mach_port_deallocate(self(), mPort)); } | |
110 | void destroy() { check(mach_port_destroy(self(), mPort)); } | |
111 | ||
112 | void insertRight(mach_msg_type_name_t type) | |
113 | { check(mach_port_insert_right(self(), mPort, mPort, type)); } | |
114 | ||
115 | void modRefs(mach_port_right_t right, mach_port_delta_t delta = 1) | |
116 | { check(mach_port_mod_refs(self(), mPort, right, delta)); } | |
117 | ||
118 | mach_port_urefs_t getRefs(mach_port_right_t right); | |
119 | ||
120 | // port notification interface | |
121 | mach_port_t requestNotify(mach_port_t notify, | |
122 | mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME, mach_port_mscount_t sync = 1); | |
123 | mach_port_t cancelNotify(mach_msg_id_t type = MACH_NOTIFY_DEAD_NAME); | |
124 | ||
125 | // queue state management | |
126 | mach_port_msgcount_t qlimit() const; | |
127 | void qlimit(mach_port_msgcount_t limit); | |
128 | ||
129 | IFDUMP(void dump(const char *name = NULL)); | |
130 | ||
131 | protected: | |
132 | mach_port_t mPort; | |
133 | }; | |
134 | ||
135 | ||
136 | // | |
137 | // A simple Port that deallocates itself on destruction. | |
138 | // If you need a subclass of Port, just assign it to a separate AutoPort. | |
139 | // | |
140 | class AutoPort : public Port { | |
141 | public: | |
142 | AutoPort() { } | |
143 | AutoPort(mach_port_t port) : Port(port) { } | |
144 | ~AutoPort() { if (mPort != MACH_PORT_NULL) deallocate(); } | |
145 | }; | |
146 | ||
147 | ||
148 | // | |
149 | // Ports representing PortSets | |
150 | // | |
151 | class PortSet : public Port { | |
152 | public: | |
153 | PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET); } | |
154 | ~PortSet() { destroy(); } | |
155 | ||
156 | void operator += (const Port &port) | |
157 | { check(mach_port_move_member(self(), port, mPort)); } | |
158 | ||
159 | void operator -= (const Port &port) | |
160 | { check(mach_port_move_member(self(), port, MACH_PORT_NULL)); } | |
161 | ||
162 | set<Port> members() const; | |
163 | bool contains(Port member) const; // relatively slow | |
164 | }; | |
165 | ||
166 | ||
167 | // | |
168 | // Ports that are bootstrap ports | |
169 | // | |
170 | class Bootstrap : public Port { | |
171 | public: | |
172 | Bootstrap() { check(task_get_bootstrap_port(mach_task_self(), &mPort)); } | |
173 | Bootstrap(mach_port_t bootp) : Port(bootp) { } | |
174 | ||
175 | mach_port_t checkIn(const char *name) const; | |
176 | mach_port_t checkInOptional(const char *name) const; | |
177 | ||
178 | void registerAs(mach_port_t port, const char *name) const; | |
179 | ||
180 | mach_port_t lookup(const char *name) const; | |
181 | mach_port_t lookup2(const char *name) const; | |
182 | mach_port_t lookupOptional(const char *name) const; | |
183 | ||
184 | Bootstrap subset(Port requestor); | |
185 | ||
186 | IFDUMP(void dump()); | |
187 | ||
188 | private: | |
189 | // officially, the register/lookup IPCs take an array of 128 characters (not a zero-end string) | |
190 | mutable char nameBuffer[BOOTSTRAP_MAX_NAME_LEN]; | |
191 | ||
192 | protected: | |
193 | char *makeName(const char *s) const | |
194 | { return strncpy(nameBuffer, s, BOOTSTRAP_MAX_NAME_LEN); } | |
195 | }; | |
196 | ||
197 | ||
198 | // | |
199 | // Ports that are Task Ports | |
200 | // | |
201 | class TaskPort : public Port { | |
202 | public: | |
203 | TaskPort() { mPort = self(); } | |
204 | TaskPort(mach_port_t p) : Port(p) { } | |
205 | TaskPort(const Port &p) : Port(p) { } | |
206 | TaskPort(pid_t pid); | |
207 | ||
208 | Bootstrap bootstrap() const | |
209 | { mach_port_t boot; check(task_get_bootstrap_port(mPort, &boot)); return boot; } | |
210 | void bootstrap(Bootstrap boot) | |
211 | { check(task_set_bootstrap_port(mPort, boot)); } | |
212 | ||
213 | pid_t pid() const; | |
214 | }; | |
215 | ||
216 | ||
217 | // | |
218 | // Ports that are are self-allocated and have receive rights | |
219 | // | |
220 | class ReceivePort : public Port { | |
221 | public: | |
222 | ReceivePort() { allocate(); } | |
223 | ReceivePort(const char *name, const Bootstrap &bootstrap, bool tryCheckin = true); | |
224 | ~ReceivePort() { destroy(); } | |
225 | }; | |
226 | ||
227 | ||
228 | // | |
229 | // A little stack utility for temporarily switching your bootstrap around. | |
230 | // Essentially, it restores your bootstrap port when it dies. Since the | |
231 | // "current bootstrap port" is a process-global item, this uses a global | |
232 | // zone of exclusion (aka critical region). There's no protection against | |
233 | // someone else calling the underlying system service, of course. | |
234 | // | |
235 | class StBootstrap { | |
236 | public: | |
237 | StBootstrap(const Bootstrap &boot, const TaskPort &task = TaskPort()); | |
238 | ~StBootstrap(); | |
239 | ||
240 | private: | |
241 | Bootstrap mOldBoot; | |
242 | TaskPort mTask; | |
243 | StLock<Mutex> locker; | |
244 | static ModuleNexus<Mutex> critical; // critical region guard (of a sort) | |
245 | }; | |
246 | ||
247 | ||
248 | // | |
249 | // A Mach-level memory guard. | |
250 | // This will vm_deallocate its argument when it gets destroyed. | |
251 | // | |
252 | class VMGuard { | |
253 | public: | |
254 | VMGuard(void *addr, size_t length) : mAddr(addr), mLength(length) { } | |
255 | ~VMGuard() { deallocate(mAddr, mLength); } | |
256 | ||
257 | private: | |
258 | void *mAddr; | |
259 | size_t mLength; | |
260 | }; | |
261 | ||
262 | ||
263 | // | |
264 | // Message buffers for Mach messages. | |
265 | // The logic here is somewhat inverted from the usual: send/receive | |
266 | // are methods on the buffers (rather than buffers being arguments to send/receive). | |
267 | // It's rather handy once you get used to that view. | |
268 | // | |
269 | class Message { | |
270 | public: | |
427c49bc A |
271 | Message(void *buffer, mach_msg_size_t size); // use buffer with size |
272 | Message(mach_msg_size_t size); // allocate buffer with size | |
273 | Message(); // set buffer later | |
b1ab9ed8 A |
274 | virtual ~Message(); |
275 | ||
427c49bc A |
276 | void setBuffer(void *buffer, mach_msg_size_t size); // use buffer with size |
277 | void setBuffer(mach_msg_size_t size); // allocate buffer with size | |
278 | void release(); // discard buffer (if any) | |
b1ab9ed8 A |
279 | |
280 | operator mig_reply_error_t & () const { return *mBuffer; } | |
281 | operator mach_msg_header_t & () const { return mBuffer->Head; } | |
282 | operator mig_reply_error_t * () const { return mBuffer; } | |
283 | operator mach_msg_header_t * () const { return &mBuffer->Head; } | |
284 | operator NDR_record_t & () const { return mBuffer->NDR; } | |
285 | ||
286 | void *data() const { return mBuffer; } | |
427c49bc | 287 | mach_msg_size_t length() const { return mBuffer->Head.msgh_size; } |
b1ab9ed8 A |
288 | Port localPort() const { return mBuffer->Head.msgh_local_port; } |
289 | Port remotePort() const { return mBuffer->Head.msgh_remote_port; } | |
290 | mach_msg_id_t msgId() const { return mBuffer->Head.msgh_id; } | |
291 | mach_msg_bits_t bits() const { return mBuffer->Head.msgh_bits; } | |
292 | kern_return_t returnCode() const { return mBuffer->RetCode; } | |
293 | ||
294 | void localPort(mach_port_t p) { mBuffer->Head.msgh_local_port = p; } | |
295 | void remotePort(mach_port_t p) { mBuffer->Head.msgh_remote_port = p; } | |
296 | ||
297 | public: | |
298 | bool send(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 receive(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 | bool sendReceive(mach_port_t receivePort, | |
306 | mach_msg_option_t options = 0, | |
307 | mach_msg_timeout_t timeout = MACH_MSG_TIMEOUT_NONE, | |
308 | mach_port_name_t notify = MACH_PORT_NULL); | |
309 | ||
310 | void destroy() { mach_msg_destroy(*this); } | |
311 | ||
312 | protected: | |
313 | bool check(kern_return_t status); | |
314 | ||
315 | private: | |
316 | mig_reply_error_t *mBuffer; | |
427c49bc | 317 | mach_msg_size_t mSize; |
b1ab9ed8 A |
318 | bool mRelease; |
319 | }; | |
320 | ||
321 | ||
322 | } // end namespace MachPlusPlus | |
323 | } // end namespace Security | |
324 | ||
325 | #endif //_H_MACHPP |