]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_utilities/lib/mach++.h
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_utilities / lib / mach++.h
CommitLineData
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
44namespace Security {
45namespace MachPlusPlus {
46
47
48//
49// Exceptions thrown by the mach++ interface.
50//
51class Error : public CommonError {
52protected:
53 // actually, kern_return_t can be just about any subsystem type return code
54 Error(kern_return_t err);
55public:
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
68inline void check(kern_return_t status)
69{ Error::check(status); }
70
71
72//
73// Simple vm_allocate/deallocate glue
74//
75void *allocate(size_t size);
76void deallocate(vm_address_t addr, size_t size);
77
78inline 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//
85class Port {
86protected:
87 static mach_port_t self() { return mach_task_self(); }
88
89public:
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
137protected:
138 mach_port_t mPort;
139};
140
141
b1ab9ed8
A
142//
143// Ports representing PortSets
144//
145class PortSet : public Port {
146public:
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//
164class Bootstrap : public Port {
165public:
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
182private:
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
186protected:
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//
195class TaskPort : public Port {
196public:
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//
214class ReceivePort : public Port {
215public:
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//
229class StBootstrap {
230public:
231 StBootstrap(const Bootstrap &boot, const TaskPort &task = TaskPort());
232 ~StBootstrap();
233
234private:
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//
246class VMGuard {
247public:
248 VMGuard(void *addr, size_t length) : mAddr(addr), mLength(length) { }
249 ~VMGuard() { deallocate(mAddr, mLength); }
250
251private:
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//
263class Message {
264public:
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
293public:
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
308protected:
309 bool check(kern_return_t status);
310
311private:
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