1 /* $NetBSD: mach_message.c,v 1.58 2009/03/14 21:04:18 dsl Exp $ */
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.58 2009/03/14 21:04:18 dsl Exp $");
35 #include "opt_compat_mach.h" /* For COMPAT_MACH in <sys/ktrace.h> */
36 #include "opt_compat_darwin.h"
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/signal.h>
43 #include <sys/kernel.h>
44 #include <sys/queue.h>
45 #include <sys/malloc.h>
47 #include <sys/ktrace.h>
49 #include <uvm/uvm_extern.h>
50 #include <uvm/uvm_map.h>
52 #include <compat/mach/mach_types.h>
53 #include <compat/mach/mach_message.h>
54 #include <compat/mach/mach_port.h>
55 #include <compat/mach/mach_exec.h>
56 #include <compat/mach/mach_clock.h>
57 #include <compat/mach/mach_syscallargs.h>
60 #include <compat/darwin/darwin_exec.h>
63 /* Mach message pool */
64 static struct pool mach_message_pool
;
67 int mach_msg_send(struct lwp
*, mach_msg_header_t
*, int *, size_t);
68 static inline int mach_msg_recv(struct lwp
*, mach_msg_header_t
*,
69 int, size_t, unsigned int, mach_port_t
);
71 struct lwp
*mach_get_target_task(struct lwp
*, struct mach_port
*);
72 static inline void mach_drop_rights(struct mach_right
*, int);
74 void mach_trade_rights(struct lwp
*, struct lwp
*, mach_port_t
*, int);
76 int mach_trade_rights_complex(struct lwp
*, struct mach_message
*);
79 mach_sys_msg_overwrite_trap(struct lwp
*l
, const struct mach_sys_msg_overwrite_trap_args
*uap
, register_t
*retval
)
82 syscallarg(mach_msg_header_t *) msg;
83 syscallarg(mach_msg_option_t) option;
84 syscallarg(mach_msg_size_t) send_size;
85 syscallarg(mach_msg_size_t) rcv_size;
86 syscallarg(mach_port_name_t) rcv_name;
87 syscallarg(mach_msg_timeout_t) timeout;
88 syscallarg(mach_port_name_t) notify;
89 syscallarg(mach_msg_header_t *) rcv_msg;
90 syscallarg(mach_msg_size_t) scatter_list_size;
92 size_t send_size
, recv_size
;
93 mach_msg_header_t
*msg
;
96 *retval
= MACH_MSG_SUCCESS
;
97 send_size
= SCARG(uap
, send_size
);
98 recv_size
= SCARG(uap
, rcv_size
);
99 opt
= SCARG(uap
, option
);
101 /* XXX not safe enough: lots of big messages will kill us */
102 if (send_size
> MACH_MAX_MSG_LEN
) {
103 *retval
= MACH_SEND_TOO_LARGE
;
106 if (recv_size
> MACH_MAX_MSG_LEN
) {
107 *retval
= MACH_RCV_TOO_LARGE
;
112 * Two options: receive or send. If both are
113 * set, we must send, and then receive. If
114 * send fail, then we skip recieve.
116 msg
= SCARG(uap
, msg
);
117 if (opt
& MACH_SEND_MSG
)
118 *retval
= mach_msg_send(l
, msg
, &opt
, send_size
);
120 if ((opt
& MACH_RCV_MSG
) && (*retval
== MACH_MSG_SUCCESS
)) {
122 * Find a buffer for the reply.
124 if (SCARG(uap
, rcv_msg
) != NULL
)
125 msg
= SCARG(uap
, rcv_msg
);
126 else if (SCARG(uap
, msg
) != NULL
)
127 msg
= SCARG(uap
, msg
);
129 *retval
= MACH_RCV_INVALID_DATA
;
133 *retval
= mach_msg_recv(l
, msg
, opt
, recv_size
,
134 SCARG(uap
, timeout
), SCARG(uap
, rcv_name
));
141 * Send a Mach message. This returns a Mach message error code.
144 mach_msg_send(struct lwp
*l
, mach_msg_header_t
*msg
, int *option
, size_t send_size
)
146 struct mach_emuldata
*med
;
147 struct mach_port
*mp
;
148 struct proc
*p
= l
->l_proc
;
149 mach_msg_header_t
*sm
;
150 struct mach_service
*srv
;
153 struct mach_right
*lr
= NULL
;
154 struct mach_right
*rr
;
162 return MACH_SEND_INVALID_DATA
;
165 * Allocate memory for the message and its reply,
166 * and copy the whole message in the kernel.
168 sm
= malloc(send_size
, M_EMULDATA
, M_WAITOK
);
169 if ((error
= copyin(msg
, sm
, send_size
)) != 0) {
170 ret
= MACH_SEND_INVALID_DATA
;
174 /* Dump the Mach message */
175 ktrmmsg((char *)sm
, send_size
);
178 * Handle rights in the message
180 ln
= sm
->msgh_local_port
;
181 rn
= sm
->msgh_remote_port
;
183 lr
= mach_right_check(ln
, l
, MACH_PORT_TYPE_ALL_RIGHTS
);
184 rr
= mach_right_check(rn
, l
, MACH_PORT_TYPE_ALL_RIGHTS
);
185 if ((rr
== NULL
) || (rr
->mr_port
== NULL
)) {
187 printf("msg id %d: invalid dest\n", sm
->msgh_id
);
189 ret
= MACH_SEND_INVALID_DEST
;
194 * Check that the process has a send right on
197 rights
= (MACH_PORT_TYPE_SEND
| MACH_PORT_TYPE_SEND_ONCE
);
198 if (mach_right_check(rn
, l
, rights
) == NULL
) {
199 ret
= MACH_SEND_INVALID_RIGHT
;
204 * If the remote port is a special port (host, kernel,
205 * clock, or io_master), the message will be handled
208 med
= (struct mach_emuldata
*)p
->p_emuldata
;
210 if (mp
->mp_flags
& MACH_MP_INKERNEL
) {
211 struct mach_trap_args args
;
212 mach_msg_header_t
*rm
;
213 size_t min_reqlen
, max_replen
;
216 * Look for the function that will handle it,
217 * using the message id.
219 for (srv
= mach_services_table
; srv
->srv_id
; srv
++)
220 if (srv
->srv_id
== sm
->msgh_id
)
224 * If no match, give up, and display a warning.
226 if (srv
->srv_handler
== NULL
) {
227 uprintf("No mach server for id = %d\n",
229 ret
= MACH_SEND_INVALID_DEST
;
232 min_reqlen
= srv
->srv_reqlen
;
233 max_replen
= srv
->srv_replen
;
236 * Special case when the kernel behaves as
237 * the client: replies to exceptions and
238 * notifications. There will be no reply,
239 * as we already receive a reply.
240 * - request and reply are swapped
241 * - there will be no reply, so set lr to NULL.
242 * - skip the lr == NULL tests
243 * XXX This is inelegant.
245 if ((sm
->msgh_id
>= 2501) && (sm
->msgh_id
<= 2503)) {
246 min_reqlen
= srv
->srv_replen
;
247 max_replen
= srv
->srv_reqlen
;
253 * Check that the local port is valid, else
254 * we will not be able to send the reply
257 (lr
->mr_port
== NULL
) ||
258 (lr
->mr_port
->mp_recv
== NULL
)) {
260 printf("msg id %d: invalid src\n", sm
->msgh_id
);
262 ret
= MACH_SEND_INVALID_REPLY
;
268 * Sanity check message length. We do not want the
270 * 1) use kernel memory located after
271 * the end of the request message.
273 if (send_size
< min_reqlen
) {
275 printf("mach server %s: smsg overflow: "
276 "send = %d, min = %d\n",
277 srv
->srv_name
, send_size
, min_reqlen
);
279 ret
= MACH_SEND_MSG_TOO_SMALL
;
284 * 2) Overwrite kernel memory after the end of the
285 * reply message buffer. This check is the
286 * responsibility of the server.
291 * Invoke the server. We give it the opportunity
292 * to shorten recv_size if there is less data in
293 * the reply than what the sender expected.
294 * If lr is NULL, this is a no reply operation.
296 reply_size
= max_replen
;
298 rm
= malloc(reply_size
, M_EMULDATA
, M_WAITOK
| M_ZERO
);
303 args
.tl
= mach_get_target_task(l
, mp
);
306 args
.rsize
= &reply_size
;
307 args
.ssize
= send_size
;
308 if ((ret
= (*srv
->srv_handler
)(&args
)) != 0)
312 * No-reply opration: everything is done.
313 * Change option so that we skip the
317 *option
&= ~MACH_RCV_MSG
;
318 return MACH_MSG_SUCCESS
;
323 * Catch potential bug in the server (sanity
324 * check #2): did it output a larger message
325 * then the one that was allocated?
327 if ((*option
& MACH_RCV_MSG
) && (reply_size
> max_replen
)) {
328 uprintf("mach_msg: reply too big in %s\n",
337 (void)mach_message_get(rm
, reply_size
, mp
, NULL
);
338 #ifdef DEBUG_MACH_MSG
339 printf("pid %d: message queued on port %p (%d) [%p]\n",
340 p
->p_pid
, mp
, rm
->msgh_id
,
341 mp
->mp_recv
->mr_sethead
);
342 if (sm
->msgh_id
== 404)
343 printf("*** msg to bootstrap. port = %p, "
344 "recv = %p [%p]\n", mach_bootstrap_port
,
345 mach_bootstrap_port
->mp_recv
,
346 mach_bootstrap_port
->mp_recv
->mr_sethead
);
348 wakeup(mp
->mp_recv
->mr_sethead
);
349 ret
= MACH_MSG_SUCCESS
;
351 free(sm
, M_EMULDATA
);
357 * The message is not to be handled by the kernel.
358 * Check that there is a valid receiver, and
359 * queue the message in the remote port.
361 mp
= rr
->mr_port
; /* (mp != NULL) already checked */
362 if (mp
->mp_recv
== NULL
) {
364 printf("msg id %d: invalid dst\n", sm
->msgh_id
);
366 free(sm
, M_EMULDATA
);
367 return MACH_SEND_INVALID_DEST
;
370 (void)mach_message_get(sm
, send_size
, mp
, l
);
371 #ifdef DEBUG_MACH_MSG
372 printf("pid %d: message queued on port %p (%d) [%p]\n",
373 p
->p_pid
, mp
, sm
->msgh_id
,
374 mp
->mp_recv
->mr_sethead
);
377 * Drop any right carried by the message.
380 bits
= MACH_MSGH_LOCAL_BITS(sm
->msgh_bits
);
381 mach_drop_rights(lr
, bits
);
385 bits
= MACH_MSGH_REMOTE_BITS(sm
->msgh_bits
);
386 mach_drop_rights(rr
, bits
);
390 * Wakeup any process awaiting for this message.
392 wakeup(mp
->mp_recv
->mr_sethead
);
394 return MACH_MSG_SUCCESS
;
398 * Receive a Mach message. This returns a Mach message error code.
401 mach_msg_recv(struct lwp
*l
, mach_msg_header_t
*urm
, int option
, size_t recv_size
, unsigned int timeout
, mach_port_t mn
)
403 struct mach_port
*mp
;
404 #if defined(DEBUG_MACH_MSG) || defined(KTRACE)
405 struct proc
*p
= l
->l_proc
;
407 struct mach_message
*mm
;
409 struct mach_right
*cmr
;
410 struct mach_right
*mr
;
417 if (option
& MACH_RCV_TIMEOUT
)
418 timeout
= timeout
* hz
/ 1000;
423 * Check for receive right on the port.
425 mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_RECEIVE
);
431 mr
= mach_right_check(mn
, l
, MACH_PORT_TYPE_PORT_SET
);
433 return MACH_RCV_INVALID_NAME
;
436 * This is a port set. For each port in the
437 * port set, check we have receive right, and
438 * and check if we have some message.
440 LIST_FOREACH(cmr
, &mr
->mr_set
, mr_setlist
) {
441 if ((mach_right_check(cmr
->mr_name
, l
,
442 MACH_PORT_TYPE_RECEIVE
)) == NULL
)
443 return MACH_RCV_INVALID_NAME
;
447 if (mp
->mp_recv
!= cmr
)
448 uprintf("mach_msg_trap: bad receive "
451 if (mp
->mp_count
!= 0)
456 * If cmr is NULL then we found no message on
457 * any port. Sleep on the port set until we get
458 * some or until we get a timeout.
461 #ifdef DEBUG_MACH_MSG
462 printf("pid %d: wait on port %p [%p]\n",
463 p
->p_pid
, mp
, mr
->mr_sethead
);
465 error
= tsleep(mr
->mr_sethead
, PZERO
|PCATCH
,
466 "mach_msg", timeout
);
467 if ((error
== ERESTART
) || (error
== EINTR
))
468 return MACH_RCV_INTERRUPTED
;
471 * Check we did not loose the receive right
472 * while we were sleeping.
474 if ((mach_right_check(mn
, l
,
475 MACH_PORT_TYPE_PORT_SET
)) == NULL
)
476 return MACH_RCV_PORT_DIED
;
479 * Is there any pending message for
480 * a port in the port set?
482 LIST_FOREACH(cmr
, &mr
->mr_set
, mr_setlist
) {
484 if (mp
->mp_count
!= 0)
489 return MACH_RCV_TIMED_OUT
;
493 * We found a port with a pending message.
499 * This is a receive on a simple port (no port set).
500 * If there is no message queued on the port,
501 * block until we get some.
506 if (mp
->mp_recv
!= mr
)
507 uprintf("mach_msg_trap: bad receive "
510 #ifdef DEBUG_MACH_MSG
511 printf("pid %d: wait on port %p [%p]\n",
512 p
->p_pid
, mp
, mr
->mr_sethead
);
514 if (mp
->mp_count
== 0) {
515 error
= tsleep(mr
->mr_sethead
, PZERO
|PCATCH
,
516 "mach_msg", timeout
);
517 if ((error
== ERESTART
) || (error
== EINTR
))
518 return MACH_RCV_INTERRUPTED
;
521 * Check we did not lose the receive right
522 * while we were sleeping.
524 if ((mach_right_check(mn
, l
,
525 MACH_PORT_TYPE_RECEIVE
)) == NULL
)
526 return MACH_RCV_PORT_DIED
;
528 if (mp
->mp_count
== 0)
529 return MACH_RCV_TIMED_OUT
;
534 * Dequeue the message.
535 * XXX Do we really need to lock here? There could be
536 * only one reader process, so mm will not disapear
537 * except if there is a port refcount error in our code.
539 rw_enter(&mp
->mp_msglock
, RW_READER
);
540 mm
= TAILQ_FIRST(&mp
->mp_msglist
);
541 #ifdef DEBUG_MACH_MSG
542 printf("pid %d: dequeue message on port %p (id %d)\n",
543 p
->p_pid
, mp
, mm
->mm_msg
->msgh_id
);
546 ret
= MACH_MSG_SUCCESS
;
547 if (mm
->mm_size
> recv_size
) {
548 struct mach_short_reply sr
;
550 ret
= MACH_RCV_TOO_LARGE
;
552 * If MACH_RCV_LARGE was not set, destroy the message.
554 if ((option
& MACH_RCV_LARGE
) == 0) {
555 free(mm
->mm_msg
, M_EMULDATA
);
556 mach_message_put_shlocked(mm
);
561 * If MACH_RCV_TOO_LARGE is set, then return
562 * a message with just header and trailer. The
563 * size in the header should correspond to the
564 * whole message, so just copy the whole header.
566 memcpy(&sr
, mm
->mm_msg
, sizeof(mach_msg_header_t
));
567 mach_set_trailer(&sr
, sizeof(sr
));
569 if ((error
= copyout(&sr
, urm
, sizeof(sr
))) != 0) {
570 ret
= MACH_RCV_INVALID_DATA
;
574 /* Dump the Mach message */
575 ktrmmsg((char *)&sr
, sizeof(sr
));
580 * Get rights carried by the message if it is not a
581 * reply from the kernel.
582 * XXX mm->mm_l could contain stall data. Reference
583 * the thread's kernel port instead?
585 if (mm
->mm_l
!= NULL
) {
588 printf("mach_msg: non kernel-reply message\n");
591 * Turn local and remote port names into
592 * names in the local process namespace.
594 bits
= MACH_MSGH_LOCAL_BITS(mm
->mm_msg
->msgh_bits
);
595 mnp
= &mm
->mm_msg
->msgh_local_port
;
596 mach_trade_rights(l
, mm
->mm_l
, mnp
, bits
);
598 bits
= MACH_MSGH_REMOTE_BITS(mm
->mm_msg
->msgh_bits
);
599 mnp
= &mm
->mm_msg
->msgh_remote_port
;
600 mach_trade_rights(l
, mm
->mm_l
, mnp
, bits
);
603 * The same operation must be done to all
604 * port descriptors carried with the message.
606 if ((mm
->mm_msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) &&
607 ((ret
= mach_trade_rights_complex(l
, mm
)) != 0))
611 * swap local and remote ports, and
612 * corresponding bits as well.
614 bits
= (bits
& 0xffff0000) |
615 ((bits
& 0xff00) >> 8) |
616 ((bits
& 0x00ff) << 8);
617 tmp
= mm
->mm_msg
->msgh_remote_port
;
618 mm
->mm_msg
->msgh_remote_port
=
619 mm
->mm_msg
->msgh_local_port
;
620 mm
->mm_msg
->msgh_local_port
= tmp
;
624 * Copy the message to userland.
626 if ((error
= copyout(mm
->mm_msg
, urm
, mm
->mm_size
)) != 0) {
627 ret
= MACH_RCV_INVALID_DATA
;
631 /* Dump the Mach message */
632 ktrmmsg((char *)mm
->mm_msg
, mm
->mm_size
);
634 free(mm
->mm_msg
, M_EMULDATA
);
635 mach_message_put_shlocked(mm
); /* decrease mp_count */
637 rw_exit(&mp
->mp_msglock
);
644 mach_sys_msg_trap(struct lwp
*l
, const struct mach_sys_msg_trap_args
*uap
, register_t
*retval
)
647 syscallarg(mach_msg_header_t *) msg;
648 syscallarg(mach_msg_option_t) option;
649 syscallarg(mach_msg_size_t) send_size;
650 syscallarg(mach_msg_size_t) rcv_size;
651 syscallarg(mach_port_name_t) rcv_name;
652 syscallarg(mach_msg_timeout_t) timeout;
653 syscallarg(mach_port_name_t) notify;
655 struct mach_sys_msg_overwrite_trap_args cup
;
657 SCARG(&cup
, msg
) = SCARG(uap
, msg
);
658 SCARG(&cup
, option
) = SCARG(uap
, option
);
659 SCARG(&cup
, send_size
) = SCARG(uap
, send_size
);
660 SCARG(&cup
, rcv_size
) = SCARG(uap
, rcv_size
);
661 SCARG(&cup
, rcv_name
) = SCARG(uap
, rcv_name
);
662 SCARG(&cup
, timeout
) = SCARG(uap
, timeout
);
663 SCARG(&cup
, notify
) = SCARG(uap
, notify
);
664 SCARG(&cup
, rcv_msg
) = NULL
;
665 SCARG(&cup
, scatter_list_size
) = 0;
667 return mach_sys_msg_overwrite_trap(l
, &cup
, retval
);
670 static inline struct lwp
*
671 mach_get_target_task(struct lwp
*l
, struct mach_port
*mp
)
676 switch (mp
->mp_datatype
) {
678 tp
= (struct proc
*)mp
->mp_data
;
679 tl
= LIST_FIRST(&tp
->p_lwps
);
684 tl
= (struct lwp
*)mp
->mp_data
;
696 mach_drop_rights(struct mach_right
*mr
, int bits
)
701 case MACH_MSG_TYPE_MOVE_SEND
:
702 rights
= MACH_PORT_TYPE_SEND
;
704 case MACH_MSG_TYPE_MOVE_SEND_ONCE
:
705 rights
= MACH_PORT_TYPE_SEND_ONCE
;
707 case MACH_MSG_TYPE_MOVE_RECEIVE
:
708 /* Recv. right is lost when msg is received */
709 case MACH_MSG_TYPE_MAKE_SEND
:
710 case MACH_MSG_TYPE_COPY_SEND
:
711 case MACH_MSG_TYPE_MAKE_SEND_ONCE
:
718 mach_right_put(mr
, rights
);
724 * When a messages is transmitted from one process to another,
725 * we need to make sure the port names are in the receiver process
729 mach_trade_rights(struct lwp
*ll
, struct lwp
*rl
, mach_port_t
*mnp
, int bits
)
730 /* ll: local lwp (receiver, current lwp) */
731 /* rl: remote lwp (sender) */
732 /* mnp: pointer to the port name */
733 /* bits: right bits */
735 int lr
; /* local right type (to be added) */
736 int rr
; /* remote right type */
737 struct mach_right
*lmr
; /* right in the local process */
738 struct mach_right
*rmr
; /* right in the remote process */
741 case MACH_MSG_TYPE_MAKE_SEND
:
742 rr
= MACH_PORT_TYPE_RECEIVE
;
743 lr
= MACH_PORT_TYPE_SEND
;
746 case MACH_MSG_TYPE_COPY_SEND
:
747 case MACH_MSG_TYPE_MOVE_SEND
:
748 rr
= MACH_PORT_TYPE_SEND
;
749 lr
= MACH_PORT_TYPE_SEND
;
752 case MACH_MSG_TYPE_MAKE_SEND_ONCE
:
753 rr
= MACH_PORT_TYPE_RECEIVE
;
754 lr
= MACH_PORT_TYPE_SEND_ONCE
;
757 case MACH_MSG_TYPE_MOVE_SEND_ONCE
:
758 rr
= MACH_PORT_TYPE_SEND_ONCE
;
759 lr
= MACH_PORT_TYPE_SEND_ONCE
;
762 case MACH_MSG_TYPE_MOVE_RECEIVE
:
763 rr
= MACH_PORT_TYPE_RECEIVE
;
764 lr
= MACH_PORT_TYPE_RECEIVE
;
773 /* Get the right in the remote process (sender) */
776 rmr
= mach_right_check(*mnp
, rl
, rr
);
778 /* Translate it into a right in the local process (receiver) */
780 lmr
= mach_right_get(rmr
->mr_port
, ll
, lr
, 0);
790 * Turn rights carried by complex messages into rights in
791 * the local namespace. Returns a Mach messsage error
792 * XXX Nothing is there yet to remove the rights from the
793 * sender namespace, it should be done at send time and it
797 mach_trade_rights_complex(struct lwp
*l
, struct mach_message
*mm
)
799 struct mach_complex_msg
*mcm
;
800 unsigned int i
, count
;
801 unsigned long begin
, end
;
804 * Sanity check the descriptor count.
805 * Note that all descriptor types
806 * have the same size, hence it is
807 * safe to not take the descriptor
808 * type into account here.
810 mcm
= (struct mach_complex_msg
*)mm
->mm_msg
;
811 count
= mcm
->mcm_body
.msgh_descriptor_count
;
813 end
= (u_long
)&mcm
->mcm_desc
.gen
[count
];
815 if ((end
- begin
) > mm
->mm_size
) {
817 printf("msg id %d: invalid count\n", mm
->mm_msg
->msgh_id
);
819 return MACH_SEND_INVALID_DATA
;
822 for (i
= 0; i
< count
; i
++) {
823 switch (mcm
->mcm_desc
.gen
[i
].type
) {
824 case MACH_MSG_PORT_DESCRIPTOR
:
825 mach_trade_rights(l
, mm
->mm_l
,
826 &mcm
->mcm_desc
.port
[i
].name
,
827 mcm
->mcm_desc
.port
[i
].disposition
);
830 case MACH_MSG_OOL_PORTS_DESCRIPTOR
: { /* XXX untested */
831 struct lwp
*rl
; /* remote LWP */
832 void *lumnp
; /* local user address */
833 void *rumnp
; /* remote user address */
834 int disp
; /* disposition*/
835 size_t size
; /* data size */
836 int mcount
; /* descriptor count */
843 disp
= mcm
->mcm_desc
.ool_ports
[i
].disposition
;
844 rumnp
= mcm
->mcm_desc
.ool_ports
[i
].address
;
845 mcount
= mcm
->mcm_desc
.ool_ports
[i
].count
;
846 size
= mcount
* sizeof(*kmnp
);
850 /* This allocates kmnp */
851 error
= mach_ool_copyin(rl
, rumnp
, &kaddr
, size
, 0);
853 return MACH_SEND_INVALID_DATA
;
855 kmnp
= (mach_port_t
*)kaddr
;
856 for (j
= 0; j
< mcount
; j
++)
857 mach_trade_rights(l
, mm
->mm_l
, &kmnp
[j
], disp
);
859 /* This frees kmnp */
860 if ((error
= mach_ool_copyout(l
, kmnp
, &lumnp
,
861 size
, MACH_OOL_FREE
|MACH_OOL_TRACE
)) != 0)
862 return MACH_SEND_INVALID_DATA
;
864 mcm
->mcm_desc
.ool_ports
[i
].address
= lumnp
;
868 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR
:
870 printf("MACH_MSG_OOL_VOLATILE_DESCRIPTOR\n");
873 case MACH_MSG_OOL_DESCRIPTOR
: { /* XXX untested */
874 struct lwp
*rl
; /* remote LWP */
875 void *ludata
; /* local user address */
876 void *rudata
; /* remote user address */
877 size_t size
; /* data size */
882 rudata
= mcm
->mcm_desc
.ool
[i
].address
;
883 size
= mcm
->mcm_desc
.ool
[i
].size
;
888 * XXX This is inefficient for large chunk of OOL
889 * memory. Think about remapping COW when possible.
892 /* This allocates kdata */
893 error
= mach_ool_copyin(rl
, rudata
, &kdata
, size
, 0);
895 return MACH_SEND_INVALID_DATA
;
897 /* This frees kdata */
898 if ((error
= mach_ool_copyout(l
, kdata
, &ludata
,
899 size
, MACH_OOL_FREE
|MACH_OOL_TRACE
)) != 0)
900 return MACH_SEND_INVALID_DATA
;
902 mcm
->mcm_desc
.ool_ports
[i
].address
= ludata
;
907 printf("unknown descriptor type %d\n",
908 mcm
->mcm_desc
.gen
[i
].type
);
914 return MACH_MSG_SUCCESS
;
918 mach_ool_copyin(struct lwp
*l
, const void *uaddr
, void **kaddr
, size_t size
, int flags
)
922 struct proc
*p
= l
->l_proc
;
925 * Sanity check OOL size to avoid DoS on malloc: useless once
926 * we remap data instead of copying it. In the meantime,
927 * disabled since it makes some OOL transfer fail.
930 if (size
> MACH_MAX_OOL_LEN
)
935 kbuf
= malloc(size
, M_EMULDATA
, M_WAITOK
);
939 if ((error
= copyin_proc(p
, uaddr
, kbuf
, size
)) != 0) {
941 free(kbuf
, M_EMULDATA
);
945 if (size
> PAGE_SIZE
)
947 if ((flags
& MACH_OOL_TRACE
))
948 ktrmool(kaddr
, size
, uaddr
);
955 mach_ool_copyout(struct lwp
*l
, const void *kaddr
, void **uaddr
, size_t size
, int flags
)
959 struct proc
*p
= l
->l_proc
;
962 * Sanity check OOL size to avoid DoS on malloc: useless once
963 * we remap data instead of copying it. In the meantime,
964 * disabled since it makes some OOL transfer fail.
967 if (size
> MACH_MAX_OOL_LEN
) {
974 ubuf
= (vaddr_t
)vm_map_min(&p
->p_vmspace
->vm_map
);
976 ubuf
= (vaddr_t
)*uaddr
;
978 /* Never map anything at address zero: this is a red zone */
979 if (ubuf
== (vaddr_t
)NULL
)
982 if ((error
= uvm_map(&p
->p_vmspace
->vm_map
, &ubuf
,
983 round_page(size
), NULL
, UVM_UNKNOWN_OFFSET
, 0,
984 UVM_MAPFLAG(UVM_PROT_RW
, UVM_PROT_ALL
,
985 UVM_INH_COPY
, UVM_ADV_NORMAL
, UVM_FLAG_COPYONW
))) != 0)
988 if ((error
= copyout_proc(p
, kaddr
, (void *)ubuf
, size
)) != 0)
991 if (size
> PAGE_SIZE
)
993 if ((flags
& MACH_OOL_TRACE
))
994 ktrmool(kaddr
, size
, (void *)ubuf
);
997 if (flags
& MACH_OOL_FREE
)
998 free(__UNCONST(kaddr
), M_EMULDATA
); /*XXXUNCONST*/
1001 *uaddr
= (void *)ubuf
;
1007 mach_set_trailer(void *msgh
, size_t size
)
1009 mach_msg_trailer_t
*trailer
;
1010 char *msg
= (char *)msgh
;
1012 trailer
= (mach_msg_trailer_t
*)&msg
[size
- sizeof(*trailer
)];
1013 trailer
->msgh_trailer_type
= MACH_MSG_TRAILER_FORMAT_0
;
1014 trailer
->msgh_trailer_size
= sizeof(*trailer
);
1020 mach_set_header(void *rep
, void *req
, size_t size
)
1022 mach_msg_header_t
*rephdr
= rep
;
1023 mach_msg_header_t
*reqhdr
= req
;
1026 MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
);
1027 rephdr
->msgh_size
= size
- sizeof(mach_msg_trailer_t
);
1028 rephdr
->msgh_local_port
= reqhdr
->msgh_local_port
;
1029 rephdr
->msgh_remote_port
= 0;
1030 rephdr
->msgh_id
= reqhdr
->msgh_id
+ 100;
1036 mach_add_port_desc(void *msg
, mach_port_name_t name
)
1038 struct mach_complex_msg
*mcm
= msg
;
1041 if ((mcm
->mcm_header
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) == 0) {
1042 mcm
->mcm_header
.msgh_bits
|= MACH_MSGH_BITS_COMPLEX
;
1043 mcm
->mcm_body
.msgh_descriptor_count
= 0;
1046 i
= mcm
->mcm_body
.msgh_descriptor_count
;
1048 mcm
->mcm_desc
.port
[i
].name
= name
;
1049 mcm
->mcm_desc
.port
[i
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1050 mcm
->mcm_desc
.port
[i
].type
= MACH_MSG_PORT_DESCRIPTOR
;
1052 mcm
->mcm_body
.msgh_descriptor_count
++;
1057 mach_add_ool_ports_desc(void *msg
, void *addr
, int count
)
1059 struct mach_complex_msg
*mcm
= msg
;
1062 if ((mcm
->mcm_header
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) == 0) {
1063 mcm
->mcm_header
.msgh_bits
|= MACH_MSGH_BITS_COMPLEX
;
1064 mcm
->mcm_body
.msgh_descriptor_count
= 0;
1067 i
= mcm
->mcm_body
.msgh_descriptor_count
;
1069 mcm
->mcm_desc
.ool_ports
[i
].address
= addr
;
1070 mcm
->mcm_desc
.ool_ports
[i
].count
= count
;
1071 mcm
->mcm_desc
.ool_ports
[i
].copy
= MACH_MSG_ALLOCATE
;
1072 mcm
->mcm_desc
.ool_ports
[i
].disposition
= MACH_MSG_TYPE_MOVE_SEND
;
1073 mcm
->mcm_desc
.ool_ports
[i
].type
= MACH_MSG_OOL_PORTS_DESCRIPTOR
;
1075 mcm
->mcm_body
.msgh_descriptor_count
++;
1079 inline void mach_add_ool_desc(msg
, addr
, size
)
1084 struct mach_complex_msg
*mcm
= msg
;
1087 if ((mcm
->mcm_header
.msgh_bits
& MACH_MSGH_BITS_COMPLEX
) == 0) {
1088 mcm
->mcm_header
.msgh_bits
|= MACH_MSGH_BITS_COMPLEX
;
1089 mcm
->mcm_body
.msgh_descriptor_count
= 0;
1092 i
= mcm
->mcm_body
.msgh_descriptor_count
;
1094 mcm
->mcm_desc
.ool
[i
].address
= addr
;
1095 mcm
->mcm_desc
.ool
[i
].size
= size
;
1096 mcm
->mcm_desc
.ool
[i
].deallocate
= 0;
1097 mcm
->mcm_desc
.ool
[i
].copy
= MACH_MSG_ALLOCATE
;
1098 mcm
->mcm_desc
.ool
[i
].type
= MACH_MSG_OOL_DESCRIPTOR
;
1100 mcm
->mcm_body
.msgh_descriptor_count
++;
1105 mach_message_init(void)
1107 pool_init(&mach_message_pool
, sizeof (struct mach_message
),
1108 0, 0, 0, "mach_message_pool", NULL
, IPL_NONE
);
1112 struct mach_message
*
1113 mach_message_get(mach_msg_header_t
*msgh
, size_t size
, struct mach_port
*mp
, struct lwp
*l
)
1115 struct mach_message
*mm
;
1117 mm
= (struct mach_message
*)pool_get(&mach_message_pool
, PR_WAITOK
);
1118 memset(mm
, 0, sizeof(*mm
));
1124 rw_enter(&mp
->mp_msglock
, RW_WRITER
);
1125 TAILQ_INSERT_TAIL(&mp
->mp_msglist
, mm
, mm_list
);
1127 rw_exit(&mp
->mp_msglock
);
1133 mach_message_put(struct mach_message
*mm
)
1135 struct mach_port
*mp
;
1139 rw_enter(&mp
->mp_msglock
, RW_WRITER
);
1140 mach_message_put_exclocked(mm
);
1141 rw_exit(&mp
->mp_msglock
);
1147 mach_message_put_shlocked(struct mach_message
*mm
)
1149 struct mach_port
*mp
;
1153 if (!rw_tryupgrade(&mp
->mp_msglock
)) {
1155 rw_exit(&mp
->mp_msglock
);
1156 rw_enter(&mp
->mp_msglock
, RW_WRITER
);
1158 mach_message_put_exclocked(mm
);
1159 rw_downgrade(&mp
->mp_msglock
);
1165 mach_message_put_exclocked(struct mach_message
*mm
)
1167 struct mach_port
*mp
;
1171 TAILQ_REMOVE(&mp
->mp_msglist
, mm
, mm_list
);
1174 pool_put(&mach_message_pool
, mm
);
1181 mach_debug_message(void)
1184 struct mach_emuldata
*med
;
1185 struct mach_right
*mr
;
1186 struct mach_right
*mrs
;
1187 struct mach_port
*mp
;
1188 struct mach_message
*mm
;
1190 LIST_FOREACH(l
, &alllwp
, l_list
) {
1191 if ((l
->l_proc
->p_emul
!= &emul_mach
) &&
1192 #ifdef COMPAT_DARWIN
1193 (l
->l_proc
->p_emul
!= &emul_darwin
) &&
1198 med
= l
->l_proc
->p_emuldata
;
1199 LIST_FOREACH(mr
, &med
->med_right
, mr_list
)
1200 if ((mr
->mr_type
& MACH_PORT_TYPE_PORT_SET
) == 0) {
1205 printf("port %p(%d) ", mp
, mp
->mp_count
);
1207 TAILQ_FOREACH(mm
, &mp
->mp_msglist
, mm_list
)
1208 printf("%d ", mm
->mm_msg
->msgh_id
);
1214 LIST_FOREACH(mrs
, &mr
->mr_set
, mr_setlist
) {
1219 printf("port %p(%d) ", mp
, mp
->mp_count
);
1221 TAILQ_FOREACH(mm
, &mp
->mp_msglist
, mm_list
)
1222 printf("%d ", mm
->mm_msg
->msgh_id
);
1230 #endif /* DEBUG_MACH */