]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/mach++.h
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / mach++.h
1 /*
2 * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved.
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:
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
274 virtual ~Message();
275
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)
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; }
287 mach_msg_size_t length() const { return mBuffer->Head.msgh_size; }
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;
317 mach_msg_size_t mSize;
318 bool mRelease;
319 };
320
321
322 } // end namespace MachPlusPlus
323 } // end namespace Security
324
325 #endif //_H_MACHPP