xref: /xnu-12377.41.6/osfmk/kern/ipc_kobject.h (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 /*
32  * Mach Operating System
33  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34  * All Rights Reserved.
35  *
36  * Permission to use, copy, modify and distribute this software and its
37  * documentation is hereby granted, provided that both the copyright
38  * notice and this permission notice appear in all copies of the
39  * software, derivative works or modified versions, and any portions
40  * thereof, and that both notices appear in supporting documentation.
41  *
42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45  *
46  * Carnegie Mellon requests users of this software to return to
47  *
48  *  Software Distribution Coordinator  or  [email protected]
49  *  School of Computer Science
50  *  Carnegie Mellon University
51  *  Pittsburgh PA 15213-3890
52  *
53  * any improvements or extensions that they make and grant Carnegie Mellon
54  * the rights to redistribute these changes.
55  */
56 /*
57  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
58  * support for mandatory and extensible security protections.  This notice
59  * is included in support of clause 2.2 (b) of the Apple Public License,
60  * Version 2.0.
61  */
62 /*
63  */
64 /*
65  *	File:	kern/ipc_kobject.h
66  *	Author:	Rich Draves
67  *	Date:	1989
68  *
69  *	Declarations for letting a port represent a kernel object.
70  */
71 
72 #ifndef _KERN_IPC_KOBJECT_H_
73 #define _KERN_IPC_KOBJECT_H_
74 
75 #ifdef MACH_KERNEL_PRIVATE
76 #include <ipc/ipc_kmsg.h>
77 #include <ipc/ipc_port.h>
78 #include <kern/startup.h>
79 #endif /* MACH_KERNEL_PRIVATE */
80 #include <mach/machine/vm_types.h>
81 #include <mach/mach_types.h>
82 #include <ipc/ipc_types.h>
83 
84 __BEGIN_DECLS
85 #pragma GCC visibility push(hidden)
86 
87 typedef ipc_object_type_t ipc_kobject_type_t;
88 
89 /* set the bitstring index for kobject */
90 extern kern_return_t ipc_kobject_set_kobjidx(
91 	int                         msgid,
92 	int                         index);
93 
94 #ifdef MACH_KERNEL_PRIVATE
95 
96 /*!
97  * @typedef ipc_kobject_ops_t
98  *
99  * @brief
100  * Describes the operations for a given kobject.
101  *
102  * @field iko_ko_type
103  * An @c IOT_* value.
104  *
105  * @field iko_op_stable
106  * The kobject/port association is stable:
107  * - ipc_kobject_dealloc_port() cannot be called
108  *   while there are outstanding send rights,
109  * - ipc_kobject_enable() is never called.
110  * - ipc_kobject_disable() is never called.
111  *
112  * @field iko_op_permanent
113  * The port is never destroyed.
114  * This doesn't necessarily imply iko_op_stable.
115  *
116  * @field iko_op_no_senders
117  * A callback to run when a NO_SENDERS notification fires.
118  *
119  * This callback is called each time a kobject port reaches 0 send rights
120  * (from a non 0 value). There is no need to actively arm no-senders.
121  *
122  * Kobjects that destroy their port on no senders only are guaranteed
123  * to be called with an active port only.
124  *
125  * However kobject ports that can be destroyed concurrently need
126  * to be prepared for no senders to fail to acquire the kobject port.
127  *
128  * When this callback is set, @c ipc_kobject_dealloc_port()
129  * will not implicitly call @c ipc_kobject_disable().
130  *
131  * The callback runs after the port has been marked inactive,
132  * hence @c ipc_kobject_get_raw() needs to be used to get to the port.
133  *
134  * @field iko_op_label_free
135  * How to free the label on this kobject port (if it supports one).
136  *
137  * @field iko_op_movable_send
138  * Whether send rights created to this kobject are movable
139  */
140 typedef const struct ipc_kobject_ops {
141 	ipc_kobject_type_t iko_op_type;
142 	unsigned long
143 	    iko_op_stable               : 1,
144 	    iko_op_permanent            : 1,
145 	    iko_op_movable_send         : 1;
146 	const char        *iko_op_name;
147 	void (*iko_op_no_senders)(ipc_port_t port, mach_port_mscount_t mscount);
148 	void (*iko_op_label_free)(ipc_object_label_t label);
149 } *ipc_kobject_ops_t;
150 
151 #define IPC_KOBJECT_DEFINE(type, ...) \
152 	__startup_data \
153 	static struct ipc_kobject_ops ipc_kobject_ops_##type = { \
154 	    .iko_op_type = type, \
155 	    .iko_op_name = #type, \
156 	    __VA_ARGS__ \
157 	}; \
158 	STARTUP_ARG(MACH_IPC, STARTUP_RANK_FIRST, ipc_kobject_register_startup, \
159 	    &ipc_kobject_ops_##type)
160 
161 struct ipc_kobject_label {
162 	ipc_label_t   ikol_label;       /* [private] mandatory access label */
163 	ipc_port_t XNU_PTRAUTH_SIGNED_PTR("ipc_kobject_label.ikol_alt_port") ikol_alt_port;
164 };
165 
166 extern ipc_object_label_t ipc_kobject_label_alloc(
167 	ipc_object_type_t       otype,
168 	ipc_label_t             label_tag,
169 	ipc_port_t              alt_port);
170 
171 extern void ipc_kobject_label_free(
172 	ipc_object_label_t      label);
173 
174 __options_decl(ipc_kobject_alloc_options_t, uint32_t, {
175 	/* Just make the naked port */
176 	IPC_KOBJECT_ALLOC_NONE      = 0x00000000,
177 	/* Make a send right */
178 	IPC_KOBJECT_ALLOC_MAKE_SEND = 0x00000001,
179 });
180 
181 /* Allocates a kobject port, never fails */
182 extern ipc_port_t ipc_kobject_alloc_port(
183 	ipc_kobject_t               kobject,
184 	ipc_object_label_t          label,
185 	ipc_kobject_alloc_options_t options);
186 
187 __attribute__((always_inline, overloadable))
188 static inline ipc_port_t
ipc_kobject_alloc_port(ipc_kobject_t kobject,ipc_object_type_t otype,ipc_kobject_alloc_options_t options)189 ipc_kobject_alloc_port(
190 	ipc_kobject_t               kobject,
191 	ipc_object_type_t           otype,
192 	ipc_kobject_alloc_options_t options)
193 {
194 	return ipc_kobject_alloc_port(kobject, IPC_OBJECT_LABEL(otype), options);
195 }
196 
197 /*!
198  * @function ipc_kobject_make_send_lazy_alloc_port()
199  *
200  * @brief
201  * Make a send once for a kobject port, lazily allocating the port.
202  *
203  * @discussion
204  * A location owning this port is passed in port_store.
205  * If no port exists, a port is made lazily.
206  *
207  * A send right is made for the port, and if this is the first one
208  * (possibly not for the first time), then the no-more-senders
209  * notification is rearmed.
210  *
211  * When a notification is armed, the kobject must donate
212  * one of its references to the port. It is expected
213  * the no-more-senders notification will consume this reference.
214  *
215  * In order to use this function, the kobject type requested must:
216  * - be use stable objects (iko_op_stable is true),
217  * - have a no-senders callback (iko_op_no_senders is set).
218  *
219  * @returns
220  * - true, if this was the first send right made for this port,
221  *   and an object reference must be donated to the port;
222  * - false otherwise.
223  */
224 extern bool ipc_kobject_make_send_lazy_alloc_port(
225 	ipc_port_t                 *port_store,
226 	ipc_kobject_t               kobject,
227 	ipc_kobject_type_t          type);
228 
229 /*!
230  * @function ipc_kobject_is_mscount_current()
231  *
232  * @brief
233  * Returns whether the current make-send count is the current one.
234  *
235  * @discussion
236  * This is meant to be called from the context of a no-senders notification
237  * callout to determine whether the object/port has since been rematerialized.
238  *
239  * Most kobjects are uniquely owned by their port, and the object is otherwise
240  * not reachable from any place in the system (see semaphores, eventlink, etc),
241  * and die when the port has no more senders.
242  *
243  * However some kobjects might still be reachable from other means,
244  * and can make new send rights in a way that isn't synchronized with Mach IPC.
245  * (See IKOT_TASK_RESUME for an example of that).
246  *
247  * This function allows for such kobject types to verify under the
248  * synchronization it uses whether this no-senders callout is the last one,
249  * or if there has been new send rights made concurrently.
250  *
251  * @param port          The target port.
252  * @param mscount       The make-send count for which the no-senders
253  *                      notification was issued.
254  */
255 extern bool ipc_kobject_is_mscount_current(
256 	ipc_port_t                  port,
257 	mach_port_mscount_t         mscount);
258 
259 extern bool ipc_kobject_is_mscount_current_locked(
260 	ipc_port_t                  port,
261 	mach_port_mscount_t         mscount);
262 
263 /*!
264  * @function ipc_kobject_copy_send()
265  *
266  * @brief
267  * Copies a naked send right for the specified kobject port.
268  *
269  * @decription
270  * This function will validate that the specified port is pointing
271  * to the expected kobject pointer and type (by calling ipc_kobject_require()).
272  *
273  * @param port          The target port.
274  * @param kobject       The kobject pointer this port should be associated to.
275  * @param kotype        The kobject type this port should have.
276  *
277  * @returns
278  * - IP_DEAD            if @c port was dead.
279  * - @c port            if @c port was valid, in which case
280  *                      a naked send right was made.
281  */
282 extern ipc_port_t ipc_kobject_copy_send(
283 	ipc_port_t                  port,
284 	ipc_kobject_t               kobject,
285 	ipc_kobject_type_t          kotype) __result_use_check;
286 
287 /*!
288  * @function ipc_kobject_make_send()
289  *
290  * @brief
291  * Makes a naked send right for the specified kobject port.
292  *
293  * @decription
294  * @see ipc_port_make_send_any_locked() for a general warning about
295  * making send rights.
296  *
297  * This function will validate that the specified port is pointing
298  * to the expected kobject pointer and type (by calling ipc_kobject_require()).
299  *
300  * @param port          The target port.
301  * @param kobject       The kobject pointer this port should be associated to.
302  * @param kotype        The kobject type this port should have.
303  *
304  * @returns
305  * - IP_DEAD            if @c port was dead.
306  * - @c port            if @c port was valid, in which case
307  *                      a naked send right was made.
308  */
309 extern ipc_port_t ipc_kobject_make_send(
310 	ipc_port_t                  port,
311 	ipc_kobject_t               kobject,
312 	ipc_kobject_type_t          kotype) __result_use_check;
313 
314 #define IPC_KOBJECT_NO_MSCOUNT      (~0ull)
315 
316 extern ipc_kobject_t ipc_kobject_dealloc_port_and_unlock(
317 	ipc_port_t                  port,
318 	uint64_t                    mscount,
319 	ipc_kobject_type_t          type);
320 
321 extern ipc_kobject_t ipc_kobject_dealloc_port(
322 	ipc_port_t                  port,
323 	uint64_t                    mscount,
324 	ipc_kobject_type_t          type);
325 
326 extern void         ipc_kobject_enable(
327 	ipc_port_t                  port,
328 	ipc_kobject_t               kobject,
329 	ipc_kobject_type_t          type);
330 
331 /*!
332  * @function ipc_kobject_require()
333  *
334  * @brief
335  * Asserts that a given port is of the specified type
336  * with the expected kobject pointer.
337  *
338  * @decription
339  * Port type confusion can lead to catastrophic system compromise,
340  * this function can be used in choke points to ensure ports are
341  * what they're expected to be before their use.
342  *
343  * @note It is allowed for the kobject pointer to be NULL,
344  *       as in some cases ipc_kobject_disable() can be raced with this check.
345  *
346  * @param port          The target port.
347  * @param kobject       The kobject pointer this port should be associated to.
348  * @param kotype        The kobject type this port should have.
349  */
350 extern void         ipc_kobject_require(
351 	ipc_port_t                  port,
352 	ipc_kobject_t               kobject,
353 	ipc_kobject_type_t          kotype);
354 
355 extern ipc_kobject_t ipc_kobject_get_raw(
356 	ipc_port_t                  port,
357 	ipc_kobject_type_t          type);
358 
359 extern ipc_kobject_t ipc_kobject_get_locked(
360 	ipc_port_t                  port,
361 	ipc_kobject_type_t          type);
362 
363 extern ipc_kobject_t ipc_kobject_get_stable(
364 	ipc_port_t                  port,
365 	ipc_kobject_type_t          type);
366 
367 extern ipc_kobject_t ipc_kobject_disable_locked(
368 	ipc_port_t                  port,
369 	ipc_kobject_type_t          type);
370 
371 extern ipc_kobject_t ipc_kobject_disable(
372 	ipc_port_t                  port,
373 	ipc_kobject_type_t          type);
374 
375 /* Check if a kobject can be copied out to a given space */
376 extern bool     ipc_kobject_label_check_or_substitute(
377 	ipc_space_t                 space,
378 	ipc_port_t                  port,
379 	ipc_object_label_t         *label,
380 	mach_msg_type_name_t        msgt_name,
381 	ipc_port_t                 *subst_portp) __result_use_check;
382 
383 /*!
384  * @brief
385  * Evaluate a port for substitution and kobject label rules.
386  *
387  * @discussion
388  * This function has a really cumbersome calling convention.
389  *
390  * If it returns false, then it means that some policy was violated,
391  * in that case, @c port has been unlocked, and @c label put.
392  *
393  * If it returns true, and subst_portp is not IP_NULL, then @c port
394  * has been unlocked, and @c label put, and the caller is expected
395  * to redrive evaluation with that substitution port.
396  *
397  * If it returns true, and subst_port is IP_NULL, then @c port
398  * is still locked, and @c label still valid, and the caller is expected
399  * to proceed further.
400  *
401  * @param space         The current space
402  * @param port          The port to evaluate (must be locked and active)
403  * @param label         (In/out) the label for @c port.
404  * @param msgt_name     The disposition for @c port in the message.
405  * @param subst_portp   (out) an optional substitution port,
406  *                      to replace @c port with.
407  */
408 __result_use_check
409 static inline bool
ip_label_check_or_substitute(ipc_space_t space,ipc_port_t port,ipc_object_label_t * label,mach_msg_type_name_t msgt_name,ipc_port_t * subst_portp)410 ip_label_check_or_substitute(
411 	ipc_space_t                 space,
412 	ipc_port_t                  port,
413 	ipc_object_label_t         *label,
414 	mach_msg_type_name_t        msgt_name,
415 	ipc_port_t                 *subst_portp)
416 {
417 	if (!io_is_kobject_type(label->io_type) || !label->iol_kobject) {
418 		*subst_portp = IP_NULL;
419 		return true;
420 	}
421 	return ipc_kobject_label_check_or_substitute(space, port, label, msgt_name, subst_portp);
422 }
423 
424 /* implementation details */
425 
426 __startup_func
427 extern void ipc_kobject_register_startup(
428 	ipc_kobject_ops_t           ops);
429 
430 /* Dispatch a kernel server function */
431 extern ipc_kmsg_t ipc_kobject_server(
432 	ipc_port_t                  receiver,
433 	ipc_kmsg_t                  request,
434 	mach_msg_option64_t         option);
435 
436 #define null_conversion(port)   (port)
437 
438 extern void ipc_kobject_notify_send_once_and_unlock(
439 	ipc_port_t                  port);
440 
441 extern kern_return_t uext_server(
442 	ipc_port_t                  receiver,
443 	ipc_kmsg_t                  request,
444 	ipc_kmsg_t                  *reply);
445 
446 #endif /* MACH_KERNEL_PRIVATE */
447 #if XNU_KERNEL_PRIVATE
448 
449 /*!
450  * @function ipc_typed_port_copyin_send()
451  *
452  * @brief
453  * Copies in a naked send right for the specified typed port.
454  *
455  * @decription
456  * This function will validate that the specified port is pointing
457  * to the expected kobject type, unless @c kotype is IOT_ANY,
458  * in which case any right is accepted.
459  *
460  * @param space         The space to copyin in from.
461  * @param name          The name to copyin.
462  * @param kotype        The kobject type this port should have.
463  * @param port          The resulting port or IP_NULL.
464  *
465  * @returns
466  * - KERN_SUCCESS       Acquired an object, possibly IP_DEAD.
467  * - KERN_INVALID_TASK  The space is dead.
468  * - KERN_INVALID_NAME  Name doesn't exist in space.
469  * - KERN_INVALID_RIGHT Name doesn't denote correct right.
470  * - KERN_INVALID_CAPABILITY
471  *                      The right isn't of the right kobject type.
472  */
473 extern kern_return_t ipc_typed_port_copyin_send(
474 	ipc_space_t                 space,
475 	mach_port_name_t            name,
476 	ipc_kobject_type_t          kotype,
477 	ipc_port_t                 *port);
478 
479 /*!
480  * @function ipc_typed_port_release_send()
481  *
482  * @brief
483  * Release a send right for a typed port.
484  *
485  * @description
486  * This is an alias for ipc_port_release_send() that the BSD side can use.
487  * If @c kotype is IOT_ANY, any right is accepted.
488  */
489 extern void       ipc_typed_port_release_send(
490 	ipc_port_t                  port,
491 	ipc_kobject_type_t          kotype);
492 
493 #endif /* XNU_KERNEL_PRIVATE */
494 #pragma GCC visibility pop
495 __END_DECLS
496 
497 #endif /* _KERN_IPC_KOBJECT_H_ */
498