]> git.saurik.com Git - apple/xnu.git/blame_incremental - osfmk/kern/ipc_kobject.c
xnu-3248.40.184.tar.gz
[apple/xnu.git] / osfmk / kern / ipc_kobject.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2010 Apple 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 Software.Distribution@CS.CMU.EDU
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 McAfee Research in 2004 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 * Copyright (c) 2005 SPARTA, Inc.
62 */
63/*
64 */
65/*
66 * File: kern/ipc_kobject.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Functions for letting a port represent a kernel object.
71 */
72
73#include <mach_debug.h>
74#include <mach_ipc_test.h>
75#include <mach_rt.h>
76
77#include <mach/mig.h>
78#include <mach/port.h>
79#include <mach/kern_return.h>
80#include <mach/message.h>
81#include <mach/mig_errors.h>
82#include <mach/notify.h>
83#include <mach/ndr.h>
84#include <mach/vm_param.h>
85
86#include <mach/mach_vm_server.h>
87#include <mach/mach_port_server.h>
88#include <mach/mach_host_server.h>
89#include <mach/host_priv_server.h>
90#include <mach/host_security_server.h>
91#include <mach/clock_server.h>
92#include <mach/clock_priv_server.h>
93#include <mach/lock_set_server.h>
94#include <default_pager/default_pager_object_server.h>
95#include <mach/memory_object_server.h>
96#include <mach/memory_object_control_server.h>
97#include <mach/memory_object_default_server.h>
98#include <mach/processor_server.h>
99#include <mach/processor_set_server.h>
100#include <mach/task_server.h>
101#include <mach/mach_voucher_server.h>
102#include <mach/mach_voucher_attr_control_server.h>
103#if VM32_SUPPORT
104#include <mach/vm32_map_server.h>
105#endif
106#include <mach/thread_act_server.h>
107
108#include <device/device_types.h>
109#include <device/device_server.h>
110
111#include <UserNotification/UNDReplyServer.h>
112
113#if CONFIG_AUDIT
114#include <kern/audit_sessionport.h>
115#endif
116
117#if MACH_MACHINE_ROUTINES
118#include <machine/machine_routines.h>
119#endif /* MACH_MACHINE_ROUTINES */
120#if XK_PROXY
121#include <uk_xkern/xk_uproxy_server.h>
122#endif /* XK_PROXY */
123
124#include <kern/ipc_tt.h>
125#include <kern/ipc_mig.h>
126#include <kern/ipc_misc.h>
127#include <kern/ipc_kobject.h>
128#include <kern/host_notify.h>
129#include <kern/mk_timer.h>
130#include <kern/misc_protos.h>
131#include <ipc/ipc_kmsg.h>
132#include <ipc/ipc_port.h>
133#include <ipc/ipc_voucher.h>
134#include <kern/sync_sema.h>
135#include <kern/counters.h>
136
137#include <vm/vm_protos.h>
138
139#include <security/mac_mach_internal.h>
140
141extern char *proc_name_address(void *p);
142extern int proc_pid(void *p);
143
144/*
145 * Routine: ipc_kobject_notify
146 * Purpose:
147 * Deliver notifications to kobjects that care about them.
148 */
149boolean_t
150ipc_kobject_notify(
151 mach_msg_header_t *request_header,
152 mach_msg_header_t *reply_header);
153
154typedef struct {
155 mach_msg_id_t num;
156 mig_routine_t routine;
157 int size;
158#if MACH_COUNTERS
159 mach_counter_t callcount;
160#endif
161} mig_hash_t;
162
163#define MAX_MIG_ENTRIES 1031
164#define MIG_HASH(x) (x)
165
166#ifndef max
167#define max(a,b) (((a) > (b)) ? (a) : (b))
168#endif /* max */
169
170static mig_hash_t mig_buckets[MAX_MIG_ENTRIES];
171static int mig_table_max_displ;
172static mach_msg_size_t mig_reply_size = sizeof(mig_reply_error_t);
173
174
175
176const struct mig_subsystem *mig_e[] = {
177 (const struct mig_subsystem *)&mach_vm_subsystem,
178 (const struct mig_subsystem *)&mach_port_subsystem,
179 (const struct mig_subsystem *)&mach_host_subsystem,
180 (const struct mig_subsystem *)&host_priv_subsystem,
181 (const struct mig_subsystem *)&host_security_subsystem,
182 (const struct mig_subsystem *)&clock_subsystem,
183 (const struct mig_subsystem *)&clock_priv_subsystem,
184 (const struct mig_subsystem *)&processor_subsystem,
185 (const struct mig_subsystem *)&processor_set_subsystem,
186 (const struct mig_subsystem *)&is_iokit_subsystem,
187 (const struct mig_subsystem *)&lock_set_subsystem,
188 (const struct mig_subsystem *)&task_subsystem,
189 (const struct mig_subsystem *)&thread_act_subsystem,
190#if VM32_SUPPORT
191 (const struct mig_subsystem *)&vm32_map_subsystem,
192#endif
193 (const struct mig_subsystem *)&UNDReply_subsystem,
194 (const struct mig_subsystem *)&default_pager_object_subsystem,
195 (const struct mig_subsystem *)&mach_voucher_subsystem,
196 (const struct mig_subsystem *)&mach_voucher_attr_control_subsystem,
197
198#if XK_PROXY
199 (const struct mig_subsystem *)&do_uproxy_xk_uproxy_subsystem,
200#endif /* XK_PROXY */
201#if MACH_MACHINE_ROUTINES
202 (const struct mig_subsystem *)&MACHINE_SUBSYSTEM,
203#endif /* MACH_MACHINE_ROUTINES */
204#if MCMSG && iPSC860
205 (const struct mig_subsystem *)&mcmsg_info_subsystem,
206#endif /* MCMSG && iPSC860 */
207};
208
209void
210mig_init(void)
211{
212 unsigned int i, n = sizeof(mig_e)/sizeof(const struct mig_subsystem *);
213 int howmany;
214 mach_msg_id_t j, pos, nentry, range;
215
216 for (i = 0; i < n; i++) {
217 range = mig_e[i]->end - mig_e[i]->start;
218 if (!mig_e[i]->start || range < 0)
219 panic("the msgh_ids in mig_e[] aren't valid!");
220
221 for (j = 0; j < range; j++) {
222 if (mig_e[i]->routine[j].stub_routine) {
223 /* Only put real entries in the table */
224 nentry = j + mig_e[i]->start;
225 for (pos = MIG_HASH(nentry) % MAX_MIG_ENTRIES, howmany = 1;
226 mig_buckets[pos].num;
227 pos++, pos = pos % MAX_MIG_ENTRIES, howmany++) {
228 if (mig_buckets[pos].num == nentry) {
229 printf("message id = %d\n", nentry);
230 panic("multiple entries with the same msgh_id");
231 }
232 if (howmany == MAX_MIG_ENTRIES)
233 panic("the mig dispatch table is too small");
234 }
235
236 mig_buckets[pos].num = nentry;
237 mig_buckets[pos].routine = mig_e[i]->routine[j].stub_routine;
238 if (mig_e[i]->routine[j].max_reply_msg)
239 mig_buckets[pos].size = mig_e[i]->routine[j].max_reply_msg;
240 else
241 mig_buckets[pos].size = mig_e[i]->maxsize;
242
243 mig_table_max_displ = max(howmany, mig_table_max_displ);
244 }
245 }
246 }
247 printf("mig_table_max_displ = %d\n", mig_table_max_displ);
248}
249
250
251/*
252 * Routine: ipc_kobject_server
253 * Purpose:
254 * Handle a message sent to the kernel.
255 * Generates a reply message.
256 * Version for Untyped IPC.
257 * Conditions:
258 * Nothing locked.
259 */
260
261ipc_kmsg_t
262ipc_kobject_server(
263 ipc_kmsg_t request)
264{
265 mach_msg_size_t reply_size;
266 ipc_kmsg_t reply;
267 kern_return_t kr;
268 ipc_port_t *destp;
269 ipc_port_t replyp = IPC_PORT_NULL;
270 mach_msg_format_0_trailer_t *trailer;
271 register mig_hash_t *ptr;
272
273 /*
274 * Find out corresponding mig_hash entry if any
275 */
276 {
277 register int key = request->ikm_header->msgh_id;
278 register int i = MIG_HASH(key);
279 register int max_iter = mig_table_max_displ;
280
281 do
282 ptr = &mig_buckets[i++ % MAX_MIG_ENTRIES];
283 while (key != ptr->num && ptr->num && --max_iter);
284
285 if (!ptr->routine || key != ptr->num) {
286 ptr = (mig_hash_t *)0;
287 reply_size = mig_reply_size;
288 } else {
289 reply_size = ptr->size;
290#if MACH_COUNTER
291 ptr->callcount++;
292#endif
293 }
294 }
295
296 /* round up for trailer size */
297 reply_size += MAX_TRAILER_SIZE;
298 reply = ipc_kmsg_alloc(reply_size);
299
300 if (reply == IKM_NULL) {
301 printf("ipc_kobject_server: dropping request\n");
302 ipc_kmsg_destroy(request);
303 return IKM_NULL;
304 }
305
306 /*
307 * Initialize reply message.
308 */
309 {
310#define InP ((mach_msg_header_t *) request->ikm_header)
311#define OutP ((mig_reply_error_t *) reply->ikm_header)
312
313 /*
314 * MIG should really assure no data leakage -
315 * but until it does, pessimistically zero the
316 * whole reply buffer.
317 */
318 bzero((void *)OutP, reply_size);
319
320 OutP->NDR = NDR_record;
321 OutP->Head.msgh_size = sizeof(mig_reply_error_t);
322
323 OutP->Head.msgh_bits =
324 MACH_MSGH_BITS_SET(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0, 0, 0);
325 OutP->Head.msgh_remote_port = InP->msgh_local_port;
326 OutP->Head.msgh_local_port = MACH_PORT_NULL;
327 OutP->Head.msgh_voucher_port = MACH_PORT_NULL;
328 OutP->Head.msgh_id = InP->msgh_id + 100;
329
330#undef InP
331#undef OutP
332 }
333
334 /*
335 * Find the routine to call, and call it
336 * to perform the kernel function
337 */
338 {
339 if (ptr) {
340 (*ptr->routine)(request->ikm_header, reply->ikm_header);
341 kernel_task->messages_received++;
342 }
343 else {
344 if (!ipc_kobject_notify(request->ikm_header, reply->ikm_header)){
345#if DEVELOPMENT || DEBUG
346 printf("ipc_kobject_server: bogus kernel message, id=%d\n",
347 request->ikm_header->msgh_id);
348#endif /* DEVELOPMENT || DEBUG */
349 _MIG_MSGID_INVALID(request->ikm_header->msgh_id);
350
351 ((mig_reply_error_t *) reply->ikm_header)->RetCode
352 = MIG_BAD_ID;
353 }
354 else
355 kernel_task->messages_received++;
356 }
357 kernel_task->messages_sent++;
358 }
359
360 /*
361 * Destroy destination. The following code differs from
362 * ipc_object_destroy in that we release the send-once
363 * right instead of generating a send-once notification
364 * (which would bring us here again, creating a loop).
365 * It also differs in that we only expect send or
366 * send-once rights, never receive rights.
367 *
368 * We set msgh_remote_port to IP_NULL so that the kmsg
369 * destroy routines don't try to destroy the port twice.
370 */
371 destp = (ipc_port_t *) &request->ikm_header->msgh_remote_port;
372 switch (MACH_MSGH_BITS_REMOTE(request->ikm_header->msgh_bits)) {
373 case MACH_MSG_TYPE_PORT_SEND:
374 ipc_port_release_send(*destp);
375 break;
376
377 case MACH_MSG_TYPE_PORT_SEND_ONCE:
378 ipc_port_release_sonce(*destp);
379 break;
380
381 default:
382 panic("ipc_kobject_server: strange destination rights");
383 }
384 *destp = IP_NULL;
385
386 /*
387 * Destroy voucher. The kernel MIG servers never take ownership
388 * of vouchers sent in messages. Swallow any such rights here.
389 */
390 if (IP_VALID(request->ikm_voucher)) {
391 assert(MACH_MSG_TYPE_PORT_SEND ==
392 MACH_MSGH_BITS_VOUCHER(request->ikm_header->msgh_bits));
393 ipc_port_release_send(request->ikm_voucher);
394 request->ikm_voucher = IP_NULL;
395 }
396
397 if (!(reply->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
398 ((mig_reply_error_t *) reply->ikm_header)->RetCode != KERN_SUCCESS)
399 kr = ((mig_reply_error_t *) reply->ikm_header)->RetCode;
400 else
401 kr = KERN_SUCCESS;
402
403 if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) {
404 /*
405 * The server function is responsible for the contents
406 * of the message. The reply port right is moved
407 * to the reply message, and we have deallocated
408 * the destination port right, so we just need
409 * to free the kmsg.
410 */
411 ipc_kmsg_free(request);
412
413 } else {
414 /*
415 * The message contents of the request are intact.
416 * Destroy everthing except the reply port right,
417 * which is needed in the reply message.
418 */
419 request->ikm_header->msgh_local_port = MACH_PORT_NULL;
420 ipc_kmsg_destroy(request);
421 }
422
423 replyp = (ipc_port_t)reply->ikm_header->msgh_remote_port;
424
425 if (kr == MIG_NO_REPLY) {
426 /*
427 * The server function will send a reply message
428 * using the reply port right, which it has saved.
429 */
430
431 ipc_kmsg_free(reply);
432
433 return IKM_NULL;
434 } else if (!IP_VALID(replyp)) {
435 /*
436 * Can't queue the reply message if the destination
437 * (the reply port) isn't valid.
438 */
439
440 ipc_kmsg_destroy(reply);
441
442 return IKM_NULL;
443 } else if (replyp->ip_receiver == ipc_space_kernel) {
444 /*
445 * Don't send replies to kobject kernel ports
446 */
447#if DEVELOPMENT || DEBUG
448 printf("%s: refusing to send reply to kobject %d port (id:%d)\n",
449 __func__, ip_kotype(replyp),
450 request->ikm_header->msgh_id);
451#endif /* DEVELOPMENT || DEBUG */
452 ipc_kmsg_destroy(reply);
453 return IKM_NULL;
454 }
455
456 trailer = (mach_msg_format_0_trailer_t *)
457 ((vm_offset_t)reply->ikm_header + (int)reply->ikm_header->msgh_size);
458
459 trailer->msgh_sender = KERNEL_SECURITY_TOKEN;
460 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
461 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
462
463 return reply;
464}
465
466/*
467 * Routine: ipc_kobject_set
468 * Purpose:
469 * Make a port represent a kernel object of the given type.
470 * The caller is responsible for handling refs for the
471 * kernel object, if necessary.
472 * Conditions:
473 * Nothing locked. The port must be active if setting
474 * a kobject linkage. Clearing a linkage is OK on an
475 * inactive port.
476 */
477void
478ipc_kobject_set(
479 ipc_port_t port,
480 ipc_kobject_t kobject,
481 ipc_kobject_type_t type)
482{
483 ip_lock(port);
484 ipc_kobject_set_atomically(port, kobject, type);
485 ip_unlock(port);
486}
487
488void
489ipc_kobject_set_atomically(
490 ipc_port_t port,
491 ipc_kobject_t kobject,
492 ipc_kobject_type_t type)
493{
494 assert(type == IKOT_NONE || ip_active(port));
495#if MACH_ASSERT
496 port->ip_spares[2] = (port->ip_bits & IO_BITS_KOTYPE);
497#endif /* MACH_ASSERT */
498 port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type;
499 port->ip_kobject = kobject;
500}
501
502/*
503 * Routine: ipc_kobject_destroy
504 * Purpose:
505 * Release any kernel object resources associated
506 * with the port, which is being destroyed.
507 *
508 * This should only be needed when resources are
509 * associated with a user's port. In the normal case,
510 * when the kernel is the receiver, the code calling
511 * ipc_port_dealloc_kernel should clean up the resources.
512 * Conditions:
513 * The port is not locked, but it is dead.
514 */
515
516void
517ipc_kobject_destroy(
518 ipc_port_t port)
519{
520 switch (ip_kotype(port)) {
521
522 case IKOT_TIMER:
523 mk_timer_port_destroy(port);
524 break;
525
526 case IKOT_NAMED_ENTRY:
527 mach_destroy_memory_entry(port);
528 break;
529
530 case IKOT_HOST_NOTIFY:
531 host_notify_port_destroy(port);
532 break;
533
534 default:
535 break;
536 }
537}
538
539
540boolean_t
541ipc_kobject_notify(
542 mach_msg_header_t *request_header,
543 mach_msg_header_t *reply_header)
544{
545 mach_msg_max_trailer_t * trailer;
546 ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
547
548 ((mig_reply_error_t *) reply_header)->RetCode = MIG_NO_REPLY;
549
550 trailer = (mach_msg_max_trailer_t *)
551 ((vm_offset_t)request_header + request_header->msgh_size);
552 if (0 != bcmp(&trailer->msgh_audit, &KERNEL_AUDIT_TOKEN,
553 sizeof(trailer->msgh_audit))) {
554 return FALSE;
555 }
556 if (0 != bcmp(&trailer->msgh_sender, &KERNEL_SECURITY_TOKEN,
557 sizeof(trailer->msgh_sender))) {
558 return FALSE;
559 }
560
561 switch (request_header->msgh_id) {
562 case MACH_NOTIFY_NO_SENDERS:
563 switch (ip_kotype(port)) {
564 case IKOT_VOUCHER:
565 ipc_voucher_notify(request_header);
566 return TRUE;
567
568 case IKOT_VOUCHER_ATTR_CONTROL:
569 ipc_voucher_attr_control_notify(request_header);
570 return TRUE;
571
572 case IKOT_SEMAPHORE:
573 semaphore_notify(request_header);
574 return TRUE;
575
576 case IKOT_NAMED_ENTRY:
577 ip_lock(port);
578
579 /*
580 * Bring the sequence number and mscount in
581 * line with ipc_port_destroy assertion.
582 */
583 port->ip_mscount = 0;
584 port->ip_messages.imq_seqno = 0;
585 ipc_port_destroy(port); /* releases lock */
586 return TRUE;
587
588 case IKOT_UPL:
589 upl_no_senders(
590 request_header->msgh_remote_port,
591 (mach_port_mscount_t)
592 ((mach_no_senders_notification_t *)
593 request_header)->not_count);
594 reply_header->msgh_remote_port = MACH_PORT_NULL;
595 return TRUE;
596
597#if CONFIG_AUDIT
598 case IKOT_AU_SESSIONPORT:
599 audit_session_nosenders(request_header);
600 return TRUE;
601#endif
602 case IKOT_FILEPORT:
603 fileport_notify(request_header);
604 return TRUE;
605 }
606 break;
607
608 case MACH_NOTIFY_PORT_DELETED:
609 case MACH_NOTIFY_PORT_DESTROYED:
610 case MACH_NOTIFY_SEND_ONCE:
611 case MACH_NOTIFY_DEAD_NAME:
612 break;
613
614 default:
615 return FALSE;
616 }
617 switch (ip_kotype(port)) {
618
619#ifdef IOKIT
620 case IKOT_IOKIT_OBJECT:
621 case IKOT_IOKIT_CONNECT:
622 case IKOT_IOKIT_SPARE:
623 {
624 return iokit_notify(request_header);
625 }
626#endif
627 case IKOT_TASK_RESUME:
628 {
629 return task_suspension_notify(request_header);
630 }
631
632 default:
633 return FALSE;
634 }
635}