1 /* $NetBSD: mach_message.c,v 1.45 2005/02/26 23:10:19 perry Exp $ */
2
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.45 2005/02/26 23:10:19 perry Exp $");
41
42 #include "opt_ktrace.h"
43 #include "opt_compat_mach.h" /* For COMPAT_MACH in <sys/ktrace.h> */
44 #include "opt_compat_darwin.h"
45
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/signal.h>
50 #include <sys/proc.h>
51 #include <sys/kernel.h>
52 #include <sys/queue.h>
53 #include <sys/malloc.h>
54 #include <sys/pool.h>
55 #ifdef KTRACE
56 #include <sys/ktrace.h>
57 #endif
58
59 #include <uvm/uvm_extern.h>
60 #include <uvm/uvm_map.h>
61
62 #include <compat/mach/mach_types.h>
63 #include <compat/mach/mach_message.h>
64 #include <compat/mach/mach_port.h>
65 #include <compat/mach/mach_exec.h>
66 #include <compat/mach/mach_clock.h>
67 #include <compat/mach/mach_syscallargs.h>
68
69 #ifdef COMPAT_DARWIN
70 #include <compat/darwin/darwin_exec.h>
71 #endif
72
73 /* Mach message pool */
74 static struct pool mach_message_pool;
75
76 static inline
77 int mach_msg_send(struct lwp *, mach_msg_header_t *, int *, size_t);
78 static inline int mach_msg_recv(struct lwp *, mach_msg_header_t *,
79 int, size_t, unsigned int, mach_port_t);
80 static inline
81 struct lwp *mach_get_target_task(struct lwp *, struct mach_port *);
82 static inline void mach_drop_rights(struct mach_right *, int);
83 static inline
84 void mach_trade_rights(struct lwp *, struct lwp *, mach_port_t *, int);
85 static inline
86 int mach_trade_rights_complex(struct lwp *, struct mach_message *);
87
88 int
89 mach_sys_msg_overwrite_trap(l, v, retval)
90 struct lwp *l;
91 void *v;
92 register_t *retval;
93 {
94 struct mach_sys_msg_overwrite_trap_args /* {
95 syscallarg(mach_msg_header_t *) msg;
96 syscallarg(mach_msg_option_t) option;
97 syscallarg(mach_msg_size_t) send_size;
98 syscallarg(mach_msg_size_t) rcv_size;
99 syscallarg(mach_port_name_t) rcv_name;
100 syscallarg(mach_msg_timeout_t) timeout;
101 syscallarg(mach_port_name_t) notify;
102 syscallarg(mach_msg_header_t *) rcv_msg;
103 syscallarg(mach_msg_size_t) scatter_list_size;
104 } */ *uap = v;
105 size_t send_size, recv_size;
106 mach_msg_header_t *msg;
107 int opt;
108
109 *retval = MACH_MSG_SUCCESS;
110 send_size = SCARG(uap, send_size);
111 recv_size = SCARG(uap, rcv_size);
112 opt = SCARG(uap, option);
113
114 /* XXX not safe enough: lots of big messages will kill us */
115 if (send_size > MACH_MAX_MSG_LEN) {
116 *retval = MACH_SEND_TOO_LARGE;
117 return 0;
118 }
119 if (recv_size > MACH_MAX_MSG_LEN) {
120 *retval = MACH_RCV_TOO_LARGE;
121 return 0;
122 }
123
124 /*
125 * Two options: receive or send. If both are
126 * set, we must send, and then receive. If
127 * send fail, then we skip recieve.
128 */
129 msg = SCARG(uap, msg);
130 if (opt & MACH_SEND_MSG)
131 *retval = mach_msg_send(l, msg, &opt, send_size);
132
133 if ((opt & MACH_RCV_MSG) && (*retval == MACH_MSG_SUCCESS)) {
134 /*
135 * Find a buffer for the reply.
136 */
137 if (SCARG(uap, rcv_msg) != NULL)
138 msg = SCARG(uap, rcv_msg);
139 else if (SCARG(uap, msg) != NULL)
140 msg = SCARG(uap, msg);
141 else {
142 *retval = MACH_RCV_INVALID_DATA;
143 return 0;
144 }
145
146 *retval = mach_msg_recv(l, msg, opt, recv_size,
147 SCARG(uap, timeout), SCARG(uap, rcv_name));
148 }
149
150 return 0;
151 }
152
153 /*
154 * Send a Mach message. This returns a Mach message error code.
155 */
156 static inline int
157 mach_msg_send(l, msg, option, send_size)
158 struct lwp *l;
159 mach_msg_header_t *msg;
160 int *option;
161 size_t send_size;
162 {
163 struct mach_emuldata *med;
164 struct mach_port *mp;
165 struct proc *p = l->l_proc;
166 mach_msg_header_t *sm;
167 struct mach_service *srv;
168 mach_port_t ln;
169 mach_port_t rn;
170 struct mach_right *lr = NULL;
171 struct mach_right *rr;
172 int rights;
173 int bits;
174 int ret;
175 size_t reply_size;
176 int error = 0;
177
178 if (msg == NULL)
179 return MACH_SEND_INVALID_DATA;
180
181 /*
182 * Allocate memory for the message and its reply,
183 * and copy the whole message in the kernel.
184 */
185 sm = malloc(send_size, M_EMULDATA, M_WAITOK);
186 if ((error = copyin(msg, sm, send_size)) != 0) {
187 ret = MACH_SEND_INVALID_DATA;
188 goto out1;
189 }
190
191 #ifdef KTRACE
192 /* Dump the Mach message */
193 if (KTRPOINT(p, KTR_MMSG))
194 ktrmmsg(p, (char *)sm, send_size);
195 #endif
196 /*
197 * Handle rights in the message
198 */
199 ln = sm->msgh_local_port;
200 rn = sm->msgh_remote_port;
201
202 lr = mach_right_check(ln, l, MACH_PORT_TYPE_ALL_RIGHTS);
203 rr = mach_right_check(rn, l, MACH_PORT_TYPE_ALL_RIGHTS);
204 if ((rr == NULL) || (rr->mr_port == NULL)) {
205 #ifdef DEBUG_MACH
206 printf("msg id %d: invalid dest\n", sm->msgh_id);
207 #endif
208 ret = MACH_SEND_INVALID_DEST;
209 goto out1;
210 }
211
212 /*
213 * Check that the process has a send right on
214 * the remote port.
215 */
216 rights = (MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_SEND_ONCE);
217 if (mach_right_check(rn, l, rights) == NULL) {
218 ret = MACH_SEND_INVALID_RIGHT;
219 goto out1;
220 }
221
222 /*
223 * If the remote port is a special port (host, kernel,
224 * clock, or io_master), the message will be handled
225 * by the kernel.
226 */
227 med = (struct mach_emuldata *)p->p_emuldata;
228 mp = rr->mr_port;
229 if (mp->mp_flags & MACH_MP_INKERNEL) {
230 struct mach_trap_args args;
231 mach_msg_header_t *rm;
232 size_t min_reqlen, max_replen;
233
234 /*
235 * Look for the function that will handle it,
236 * using the message id.
237 */
238 for (srv = mach_services_table; srv->srv_id; srv++)
239 if (srv->srv_id == sm->msgh_id)
240 break;
241
242 /*
243 * If no match, give up, and display a warning.
244 */
245 if (srv->srv_handler == NULL) {
246 uprintf("No mach server for id = %d\n",
247 sm->msgh_id);
248 ret = MACH_SEND_INVALID_DEST;
249 goto out1;
250 }
251 min_reqlen = srv->srv_reqlen;
252 max_replen = srv->srv_replen;
253
254 /*
255 * Special case when the kernel behaves as
256 * the client: replies to exceptions and
257 * notifications. There will be no reply,
258 * as we already receive a reply.
259 * - request and reply are swapped
260 * - there will be no reply, so set lr to NULL.
261 * - skip the lr == NULL tests
262 * XXX This is inelegant.
263 */
264 if ((sm->msgh_id >= 2501) && (sm->msgh_id <= 2503)) {
265 min_reqlen = srv->srv_replen;
266 max_replen = srv->srv_reqlen;
267 lr = NULL;
268 goto skip_null_lr;
269 }
270
271 /*
272 * Check that the local port is valid, else
273 * we will not be able to send the reply
274 */
275 if ((lr == NULL) ||
276 (lr->mr_port == NULL) ||
277 (lr->mr_port->mp_recv == NULL)) {
278 #ifdef DEBUG_MACH
279 printf("msg id %d: invalid src\n", sm->msgh_id);
280 #endif
281 ret = MACH_SEND_INVALID_REPLY;
282 goto out1;
283 }
284 skip_null_lr:
285
286 /*
287 * Sanity check message length. We do not want the
288 * server to:
289 * 1) use kernel memory located after
290 * the end of the request message.
291 */
292 if (send_size < min_reqlen) {
293 #ifdef DEBUG_MACH
294 printf("mach server %s: smsg overflow: "
295 "send = %d, min = %d\n",
296 srv->srv_name, send_size, min_reqlen);
297 #endif
298 ret = MACH_SEND_MSG_TOO_SMALL;
299 goto out1;
300 }
301
302 /*
303 * 2) Overwrite kernel memory after the end of the
304 * reply message buffer. This check is the
305 * responsibility of the server.
306 */
307
308
309 /*
310 * Invoke the server. We give it the opportunity
311 * to shorten recv_size if there is less data in
312 * the reply than what the sender expected.
313 * If lr is NULL, this is a no reply operation.
314 */
315 reply_size = max_replen;
316 if (lr != NULL)
317 rm = malloc(reply_size, M_EMULDATA, M_WAITOK | M_ZERO);
318 else
319 rm = NULL;
320
321 args.l = l;
322 args.tl = mach_get_target_task(l, mp);
323 args.smsg = sm;
324 args.rmsg = rm;
325 args.rsize = &reply_size;
326 args.ssize = send_size;
327 if ((ret = (*srv->srv_handler)(&args)) != 0)
328 goto out1;
329
330 /*
331 * No-reply opration: everything is done.
332 * Change option so that we skip the
333 * receive stage.
334 */
335 if (lr == NULL) {
336 *option &= ~MACH_RCV_MSG;
337 return MACH_MSG_SUCCESS;
338 }
339
340 #ifdef DIAGNOSTIC
341 /*
342 * Catch potential bug in the server (sanity
343 * check #2): did it output a larger message
344 * then the one that was allocated?
345 */
346 if ((*option & MACH_RCV_MSG) && (reply_size > max_replen)) {
347 uprintf("mach_msg: reply too big in %s\n",
348 srv->srv_name);
349 }
350 #endif
351
352 /*
353 * Queue the reply.
354 */
355 mp = lr->mr_port;
356 (void)mach_message_get(rm, reply_size, mp, NULL);
357 #ifdef DEBUG_MACH_MSG
358 printf("pid %d: message queued on port %p (%d) [%p]\n",
359 p->p_pid, mp, rm->msgh_id,
360 mp->mp_recv->mr_sethead);
361 if (sm->msgh_id == 404)
362 printf("*** msg to bootstrap. port = %p, "
363 "recv = %p [%p]\n", mach_bootstrap_port,
364 mach_bootstrap_port->mp_recv,
365 mach_bootstrap_port->mp_recv->mr_sethead);
366 #endif
367 wakeup(mp->mp_recv->mr_sethead);
368 ret = MACH_MSG_SUCCESS;
369 out1:
370 free(sm, M_EMULDATA);
371
372 return ret;
373 }
374
375 /*
376 * The message is not to be handled by the kernel.
377 * Check that there is a valid receiver, and
378 * queue the message in the remote port.
379 */
380 mp = rr->mr_port; /* (mp != NULL) already checked */
381 if (mp->mp_recv == NULL) {
382 #ifdef DEBUG_MACH
383 printf("msg id %d: invalid dst\n", sm->msgh_id);
384 #endif
385 free(sm, M_EMULDATA);
386 return MACH_SEND_INVALID_DEST;
387 }
388
389 (void)mach_message_get(sm, send_size, mp, l);
390 #ifdef DEBUG_MACH_MSG
391 printf("pid %d: message queued on port %p (%d) [%p]\n",
392 p->p_pid, mp, sm->msgh_id,
393 mp->mp_recv->mr_sethead);
394 #endif
395 /*
396 * Drop any right carried by the message.
397 */
398 if (lr != NULL) {
399 bits = MACH_MSGH_LOCAL_BITS(sm->msgh_bits);
400 mach_drop_rights(lr, bits);
401 }
402
403 if (rr != NULL) {
404 bits = MACH_MSGH_REMOTE_BITS(sm->msgh_bits);
405 mach_drop_rights(rr, bits);
406 }
407
408 /*
409 * Wakeup any process awaiting for this message.
410 */
411 wakeup(mp->mp_recv->mr_sethead);
412
413 return MACH_MSG_SUCCESS;
414 }
415
416 /*
417 * Receive a Mach message. This returns a Mach message error code.
418 */
419 static inline int
420 mach_msg_recv(l, urm, option, recv_size, timeout, mn)
421 struct lwp *l;
422 mach_msg_header_t *urm;
423 int option;
424 size_t recv_size;
425 unsigned int timeout;
426 mach_port_t mn;
427 {
428 struct mach_port *mp;
429 struct proc *p = l->l_proc;
430 struct mach_message *mm;
431 mach_port_t tmp;
432 struct mach_right *cmr;
433 struct mach_right *mr;
434 int bits;
435 int ret;
436 int error = 0;
437
438
439 if (option & MACH_RCV_TIMEOUT)
440 timeout = timeout * hz / 1000;
441 else
442 timeout = 0;
443
444 /*
445 * Check for receive right on the port.
446 */
447 mr = mach_right_check(mn, l, MACH_PORT_TYPE_RECEIVE);
448 if (mr == NULL) {
449
450 /*
451 * Is it a port set?
452 */
453 mr = mach_right_check(mn, l, MACH_PORT_TYPE_PORT_SET);
454 if (mr == NULL)
455 return MACH_RCV_INVALID_NAME;
456
457 /*
458 * This is a port set. For each port in the
459 * port set, check we have receive right, and
460 * and check if we have some message.
461 */
462 LIST_FOREACH(cmr, &mr->mr_set, mr_setlist) {
463 if ((mach_right_check(cmr->mr_name, l,
464 MACH_PORT_TYPE_RECEIVE)) == NULL)
465 return MACH_RCV_INVALID_NAME;
466
467 mp = cmr->mr_port;
468 #ifdef DEBUG_MACH
469 if (mp->mp_recv != cmr)
470 uprintf("mach_msg_trap: bad receive "
471 "port/right\n");
472 #endif
473 if (mp->mp_count != 0)
474 break;
475 }
476
477 /*
478 * If cmr is NULL then we found no message on
479 * any port. Sleep on the port set until we get
480 * some or until we get a timeout.
481 */
482 if (cmr == NULL) {
483 #ifdef DEBUG_MACH_MSG
484 printf("pid %d: wait on port %p [%p]\n",
485 p->p_pid, mp, mr->mr_sethead);
486 #endif
487 error = tsleep(mr->mr_sethead, PZERO|PCATCH,
488 "mach_msg", timeout);
489 if ((error == ERESTART) || (error == EINTR))
490 return MACH_RCV_INTERRUPTED;
491
492 /*
493 * Check we did not loose the receive right
494 * while we were sleeping.
495 */
496 if ((mach_right_check(mn, l,
497 MACH_PORT_TYPE_PORT_SET)) == NULL)
498 return MACH_RCV_PORT_DIED;
499
500 /*
501 * Is there any pending message for
502 * a port in the port set?
503 */
504 LIST_FOREACH(cmr, &mr->mr_set, mr_setlist) {
505 mp = cmr->mr_port;
506 if (mp->mp_count != 0)
507 break;
508 }
509
510 if (cmr == NULL)
511 return MACH_RCV_TIMED_OUT;
512 }
513
514 /*
515 * We found a port with a pending message.
516 */
517 mp = cmr->mr_port;
518
519 } else {
520 /*
521 * This is a receive on a simple port (no port set).
522 * If there is no message queued on the port,
523 * block until we get some.
524 */
525 mp = mr->mr_port;
526
527 #ifdef DEBUG_MACH
528 if (mp->mp_recv != mr)
529 uprintf("mach_msg_trap: bad receive "
530 "port/right\n");
531 #endif
532 #ifdef DEBUG_MACH_MSG
533 printf("pid %d: wait on port %p [%p]\n",
534 p->p_pid, mp, mr->mr_sethead);
535 #endif
536 if (mp->mp_count == 0) {
537 error = tsleep(mr->mr_sethead, PZERO|PCATCH,
538 "mach_msg", timeout);
539 if ((error == ERESTART) || (error == EINTR))
540 return MACH_RCV_INTERRUPTED;
541
542 /*
543 * Check we did not lose the receive right
544 * while we were sleeping.
545 */
546 if ((mach_right_check(mn, l,
547 MACH_PORT_TYPE_RECEIVE)) == NULL)
548 return MACH_RCV_PORT_DIED;
549
550 if (mp->mp_count == 0)
551 return MACH_RCV_TIMED_OUT;
552 }
553 }
554
555 /*
556 * Dequeue the message.
557 * XXX Do we really need to lock here? There could be
558 * only one reader process, so mm will not disapear
559 * except if there is a port refcount error in our code.
560 */
561 lockmgr(&mp->mp_msglock, LK_SHARED, NULL);
562 mm = TAILQ_FIRST(&mp->mp_msglist);
563 #ifdef DEBUG_MACH_MSG
564 printf("pid %d: dequeue message on port %p (id %d)\n",
565 p->p_pid, mp, mm->mm_msg->msgh_id);
566 #endif
567
568 ret = MACH_MSG_SUCCESS;
569 if (mm->mm_size > recv_size) {
570 struct mach_short_reply sr;
571
572 ret = MACH_RCV_TOO_LARGE;
573 /*
574 * If MACH_RCV_LARGE was not set, destroy the message.
575 */
576 if ((option & MACH_RCV_LARGE) == 0) {
577 free(mm->mm_msg, M_EMULDATA);
578 mach_message_put_shlocked(mm);
579 goto unlock;
580 }
581
582 /*
583 * If MACH_RCV_TOO_LARGE is set, then return
584 * a message with just header and trailer. The
585 * size in the header should correspond to the
586 * whole message, so just copy the whole header.
587 */
588 memcpy(&sr, mm->mm_msg, sizeof(mach_msg_header_t));
589 mach_set_trailer(&sr, sizeof(sr));
590
591 if ((error = copyout(&sr, urm, sizeof(sr))) != 0) {
592 ret = MACH_RCV_INVALID_DATA;
593 goto unlock;
594 }
595 #ifdef KTRACE
596 /* Dump the Mach message */
597 if (KTRPOINT(p, KTR_MMSG))
598 ktrmmsg(p, (char *)&sr, sizeof(sr));
599 #endif
600 goto unlock;
601 }
602
603 /*
604 * Get rights carried by the message if it is not a
605 * reply from the kernel.
606 * XXX mm->mm_l could contain stall data. Reference
607 * the thread's kernel port instead?
608 */
609 if (mm->mm_l != NULL) {
610 mach_port_t *mnp;
611 #ifdef DEBUG_MACH
612 printf("mach_msg: non kernel-reply message\n");
613 #endif
614 /*
615 * Turn local and remote port names into
616 * names in the local process namespace.
617 */
618 bits = MACH_MSGH_LOCAL_BITS(mm->mm_msg->msgh_bits);
619 mnp = &mm->mm_msg->msgh_local_port;
620 mach_trade_rights(l, mm->mm_l, mnp, bits);
621
622 bits = MACH_MSGH_REMOTE_BITS(mm->mm_msg->msgh_bits);
623 mnp = &mm->mm_msg->msgh_remote_port;
624 mach_trade_rights(l, mm->mm_l, mnp, bits);
625
626 /*
627 * The same operation must be done to all
628 * port descriptors carried with the message.
629 */
630 if ((mm->mm_msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
631 ((ret = mach_trade_rights_complex(l, mm)) != 0))
632 goto unlock;
633
634 /*
635 * swap local and remote ports, and
636 * corresponding bits as well.
637 */
638 bits = (bits & 0xffff0000) |
639 ((bits & 0xff00) >> 8) |
640 ((bits & 0x00ff) << 8);
641 tmp = mm->mm_msg->msgh_remote_port;
642 mm->mm_msg->msgh_remote_port =
643 mm->mm_msg->msgh_local_port;
644 mm->mm_msg->msgh_local_port = tmp;
645 }
646
647 /*
648 * Copy the message to userland.
649 */
650 if ((error = copyout(mm->mm_msg, urm, mm->mm_size)) != 0) {
651 ret = MACH_RCV_INVALID_DATA;
652 goto unlock;
653 }
654 #ifdef KTRACE
655 /* Dump the Mach message */
656 if (KTRPOINT(p, KTR_MMSG))
657 ktrmmsg(p, (char *)mm->mm_msg, mm->mm_size);
658 #endif
659
660 free(mm->mm_msg, M_EMULDATA);
661 mach_message_put_shlocked(mm); /* decrease mp_count */
662 unlock:
663 lockmgr(&mp->mp_msglock, LK_RELEASE, NULL);
664
665 return ret;
666 }
667
668
669 int
670 mach_sys_msg_trap(l, v, retval)
671 struct lwp *l;
672 void *v;
673 register_t *retval;
674 {
675 struct mach_sys_msg_trap_args /* {
676 syscallarg(mach_msg_header_t *) msg;
677 syscallarg(mach_msg_option_t) option;
678 syscallarg(mach_msg_size_t) send_size;
679 syscallarg(mach_msg_size_t) rcv_size;
680 syscallarg(mach_port_name_t) rcv_name;
681 syscallarg(mach_msg_timeout_t) timeout;
682 syscallarg(mach_port_name_t) notify;
683 } */ *uap = v;
684 struct mach_sys_msg_overwrite_trap_args cup;
685
686 SCARG(&cup, msg) = SCARG(uap, msg);
687 SCARG(&cup, option) = SCARG(uap, option);
688 SCARG(&cup, send_size) = SCARG(uap, send_size);
689 SCARG(&cup, rcv_size) = SCARG(uap, rcv_size);
690 SCARG(&cup, rcv_name) = SCARG(uap, rcv_name);
691 SCARG(&cup, timeout) = SCARG(uap, timeout);
692 SCARG(&cup, notify) = SCARG(uap, notify);
693 SCARG(&cup, rcv_msg) = NULL;
694 SCARG(&cup, scatter_list_size) = 0;
695
696 return mach_sys_msg_overwrite_trap(l, &cup, retval);
697 }
698
699 static inline struct lwp *
700 mach_get_target_task(l, mp)
701 struct lwp *l;
702 struct mach_port *mp;
703 {
704 struct proc *tp;
705 struct lwp *tl;
706
707 switch (mp->mp_datatype) {
708 case MACH_MP_PROC:
709 tp = (struct proc *)mp->mp_data;
710 tl = proc_representative_lwp(tp);
711 break;
712
713 case MACH_MP_LWP:
714 tl = (struct lwp *)mp->mp_data;
715 break;
716
717 default:
718 tl = l;
719 break;
720 }
721
722 return tl;
723 }
724
725 static inline void
726 mach_drop_rights(mr, bits)
727 struct mach_right *mr;
728 int bits;
729 {
730 int rights;
731
732 switch (bits) {
733 case MACH_MSG_TYPE_MOVE_SEND:
734 rights = MACH_PORT_TYPE_SEND;
735 break;
736 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
737 rights = MACH_PORT_TYPE_SEND_ONCE;
738 break;
739 case MACH_MSG_TYPE_MOVE_RECEIVE:
740 /* Recv. right is lost when msg is received */
741 case MACH_MSG_TYPE_MAKE_SEND:
742 case MACH_MSG_TYPE_COPY_SEND:
743 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
744 default:
745 rights = 0;
746 break;
747 }
748
749 if (rights != 0)
750 mach_right_put(mr, rights);
751
752 return;
753 }
754
755 /*
756 * When a messages is transmitted from one process to another,
757 * we need to make sure the port names are in the receiver process
758 * namespace.
759 */
760 static inline void
761 mach_trade_rights(ll, rl, mnp, bits)
762 struct lwp *ll; /* local lwp (receiver, current lwp) */
763 struct lwp *rl; /* remote lwp (sender) */
764 mach_port_t *mnp; /* pointer to the port name */
765 int bits; /* right bits */
766 {
767 int lr; /* local right type (to be added) */
768 int rr; /* remote right type */
769 struct mach_right *lmr; /* right in the local process */
770 struct mach_right *rmr; /* right in the remote process */
771
772 switch (bits) {
773 case MACH_MSG_TYPE_MAKE_SEND:
774 rr = MACH_PORT_TYPE_RECEIVE;
775 lr = MACH_PORT_TYPE_SEND;
776 break;
777
778 case MACH_MSG_TYPE_COPY_SEND:
779 case MACH_MSG_TYPE_MOVE_SEND:
780 rr = MACH_PORT_TYPE_SEND;
781 lr = MACH_PORT_TYPE_SEND;
782 break;
783
784 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
785 rr = MACH_PORT_TYPE_RECEIVE;
786 lr = MACH_PORT_TYPE_SEND_ONCE;
787 break;
788
789 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
790 rr = MACH_PORT_TYPE_SEND_ONCE;
791 lr = MACH_PORT_TYPE_SEND_ONCE;
792 break;
793
794 case MACH_MSG_TYPE_MOVE_RECEIVE:
795 rr = MACH_PORT_TYPE_RECEIVE;
796 lr = MACH_PORT_TYPE_RECEIVE;
797 break;
798
799 default:
800 rr = 0;
801 lr = 0;
802 break;
803 }
804
805 /* Get the right in the remote process (sender) */
806 rmr = NULL;
807 if (lr != 0)
808 rmr = mach_right_check(*mnp, rl, rr);
809
810 /* Translate it into a right in the local process (receiver) */
811 if (rmr != NULL) {
812 lmr = mach_right_get(rmr->mr_port, ll, lr, 0);
813 *mnp = lmr->mr_name;
814 } else {
815 *mnp = 0;
816 }
817
818 return;
819 }
820
821 /*
822 * Turn rights carried by complex messages into rights in
823 * the local namespace. Returns a Mach messsage error
824 * XXX Nothing is there yet to remove the rights from the
825 * sender namespace, it should be done at send time and it
826 * is not done yet.
827 */
828 static inline int
829 mach_trade_rights_complex(l, mm)
830 struct lwp *l;
831 struct mach_message *mm;
832 {
833 struct mach_complex_msg *mcm;
834 unsigned int i, count;
835 unsigned long begin, end;
836
837 /*
838 * Sanity check the descriptor count.
839 * Note that all descriptor types
840 * have the same size, hence it is
841 * safe to not take the descriptor
842 * type into account here.
843 */
844 mcm = (struct mach_complex_msg *)mm->mm_msg;
845 count = mcm->mcm_body.msgh_descriptor_count;
846 begin = (u_long)mcm;
847 end = (u_long)&mcm->mcm_desc.gen[count];
848
849 if ((end - begin) > mm->mm_size) {
850 #ifdef DEBUG_MACH
851 printf("msg id %d: invalid count\n", mm->mm_msg->msgh_id);
852 #endif
853 return MACH_SEND_INVALID_DATA;
854 }
855
856 for (i = 0; i < count; i++) {
857 switch (mcm->mcm_desc.gen[i].type) {
858 case MACH_MSG_PORT_DESCRIPTOR:
859 mach_trade_rights(l, mm->mm_l,
860 &mcm->mcm_desc.port[i].name,
861 mcm->mcm_desc.port[i].disposition);
862 break;
863
864 case MACH_MSG_OOL_PORTS_DESCRIPTOR: { /* XXX untested */
865 struct proc *rp; /* remote process */
866 struct proc *lp; /* local process */
867 void *lumnp; /* local user address */
868 void *rumnp; /* remote user address */
869 int disp; /* disposition*/
870 size_t size; /* data size */
871 int count; /* descriptor count */
872 mach_port_t *kmnp;
873 void *kaddr;
874 int error;
875 int j;
876
877 rp = mm->mm_l->l_proc;
878 lp = l->l_proc;
879 disp = mcm->mcm_desc.ool_ports[i].disposition;
880 rumnp = mcm->mcm_desc.ool_ports[i].address;
881 count = mcm->mcm_desc.ool_ports[i].count;
882 size = count * sizeof(*kmnp);
883 kaddr = NULL;
884 lumnp = NULL;
885
886 /* This allocates kmnp */
887 error = mach_ool_copyin(rp, rumnp, &kaddr, size, 0);
888 if (error != 0)
889 return MACH_SEND_INVALID_DATA;
890
891 kmnp = (mach_port_t *)kaddr;
892 for (j = 0; j < count; j++)
893 mach_trade_rights(l, mm->mm_l, &kmnp[j], disp);
894
895 /* This frees kmnp */
896 if ((error = mach_ool_copyout(lp, kmnp, &lumnp,
897 size, MACH_OOL_FREE|MACH_OOL_TRACE)) != 0)
898 return MACH_SEND_INVALID_DATA;
899
900 mcm->mcm_desc.ool_ports[i].address = lumnp;
901 break;
902 }
903
904 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
905 #ifdef DEBUG_MACH
906 printf("MACH_MSG_OOL_VOLATILE_DESCRIPTOR\n");
907 #endif
908 /* FALLTHROUGH */
909 case MACH_MSG_OOL_DESCRIPTOR: { /* XXX untested */
910 struct proc *rp; /* remote process */
911 struct proc *lp; /* local process */
912 void *ludata; /* local user address */
913 void *rudata; /* remote user address */
914 size_t size; /* data size */
915 void *kdata;
916 int error;
917
918 rp = mm->mm_l->l_proc;
919 lp = l->l_proc;
920 rudata = mcm->mcm_desc.ool[i].address;
921 size = mcm->mcm_desc.ool[i].size;
922 kdata = NULL;
923 ludata = NULL;
924
925 /*
926 * XXX This is inefficient for large chunk of OOL
927 * memory. Think about remapping COW when possible.
928 */
929
930 /* This allocates kdata */
931 error = mach_ool_copyin(rp, rudata, &kdata, size, 0);
932 if (error != 0)
933 return MACH_SEND_INVALID_DATA;
934
935 /* This frees kdata */
936 if ((error = mach_ool_copyout(lp, kdata, &ludata,
937 size, MACH_OOL_FREE|MACH_OOL_TRACE)) != 0)
938 return MACH_SEND_INVALID_DATA;
939
940 mcm->mcm_desc.ool_ports[i].address = ludata;
941 break;
942 }
943 default:
944 #ifdef DEBUG_MACH
945 printf("unknown descriptor type %d\n",
946 mcm->mcm_desc.gen[i].type);
947 #endif
948 break;
949 }
950 }
951
952 return MACH_MSG_SUCCESS;
953 }
954
955 inline int
956 mach_ool_copyin(p, uaddr, kaddr, size, flags)
957 struct proc *p;
958 const void *uaddr;
959 void **kaddr;
960 size_t size;
961 int flags;
962 {
963 int error;
964 void *kbuf;
965
966 /*
967 * Sanity check OOL size to avoid DoS on malloc: useless once
968 * we remap data instead of copying it. In the meantime,
969 * disabled since it makes some OOL transfer fail.
970 */
971 #if 0
972 if (size > MACH_MAX_OOL_LEN)
973 return ENOMEM;
974 #endif
975
976 if (*kaddr == NULL)
977 kbuf = malloc(size, M_EMULDATA, M_WAITOK);
978 else
979 kbuf = *kaddr;
980
981 if ((error = copyin_proc(p, (void *)uaddr, kbuf, size)) != 0) {
982 if (*kaddr == NULL)
983 free(kbuf, M_EMULDATA);
984 return error;
985 }
986
987 #ifdef KTRACE
988 if (size > PAGE_SIZE)
989 size = PAGE_SIZE;
990 if ((flags & MACH_OOL_TRACE) && KTRPOINT(p, KTR_MOOL))
991 ktrmool(p, kaddr, size, uaddr);
992 #endif
993
994 *kaddr = kbuf;
995 return 0;
996 }
997
998 inline int
999 mach_ool_copyout(p, kaddr, uaddr, size, flags)
1000 struct proc *p;
1001 void *kaddr;
1002 void **uaddr;
1003 size_t size;
1004 int flags;
1005 {
1006 vaddr_t ubuf;
1007 int error = 0;
1008
1009 /*
1010 * Sanity check OOL size to avoid DoS on malloc: useless once
1011 * we remap data instead of copying it. In the meantime,
1012 * disabled since it makes some OOL transfer fail.
1013 */
1014 #if 0
1015 if (size > MACH_MAX_OOL_LEN) {
1016 error = ENOMEM;
1017 goto out;
1018 }
1019 #endif
1020
1021 if (*uaddr == NULL)
1022 ubuf = (vaddr_t)vm_map_min(&p->p_vmspace->vm_map);
1023 else
1024 ubuf = (vaddr_t)*uaddr;
1025
1026 /* Never map anything at address zero: this is a red zone */
1027 if (ubuf == (vaddr_t)NULL)
1028 ubuf += PAGE_SIZE;
1029
1030 if ((error = uvm_map(&p->p_vmspace->vm_map, &ubuf,
1031 round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0,
1032 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL,
1033 UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0)
1034 goto out;
1035
1036 if ((error = copyout_proc(p, kaddr, (void *)ubuf, size)) != 0)
1037 goto out;
1038
1039 #ifdef KTRACE
1040 if (size > PAGE_SIZE)
1041 size = PAGE_SIZE;
1042 if ((flags & MACH_OOL_TRACE) && KTRPOINT(p, KTR_MOOL))
1043 ktrmool(p, kaddr, size, (void *)ubuf);
1044 #endif
1045
1046 out:
1047 if (flags & MACH_OOL_FREE)
1048 free(kaddr, M_EMULDATA);
1049
1050 if (error == 0)
1051 *uaddr = (void *)ubuf;
1052 return error;
1053 }
1054
1055
1056 inline void
1057 mach_set_trailer(msgh, size)
1058 void *msgh;
1059 size_t size;
1060 {
1061 mach_msg_trailer_t *trailer;
1062 char *msg = (char *)msgh;
1063
1064 trailer = (mach_msg_trailer_t *)&msg[size - sizeof(*trailer)];
1065 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
1066 trailer->msgh_trailer_size = sizeof(*trailer);
1067
1068 return;
1069 }
1070
1071 inline void
1072 mach_set_header(rep, req, size)
1073 void *rep;
1074 void *req;
1075 size_t size;
1076 {
1077 mach_msg_header_t *rephdr = rep;
1078 mach_msg_header_t *reqhdr = req;
1079
1080 rephdr->msgh_bits =
1081 MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE);
1082 rephdr->msgh_size = size - sizeof(mach_msg_trailer_t);
1083 rephdr->msgh_local_port = reqhdr->msgh_local_port;
1084 rephdr->msgh_remote_port = 0;
1085 rephdr->msgh_id = reqhdr->msgh_id + 100;
1086
1087 return;
1088 }
1089
1090 inline void
1091 mach_add_port_desc(msg, name)
1092 void *msg;
1093 mach_port_name_t name;
1094 {
1095 struct mach_complex_msg *mcm = msg;
1096 int i;
1097
1098 if ((mcm->mcm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
1099 mcm->mcm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
1100 mcm->mcm_body.msgh_descriptor_count = 0;
1101 }
1102
1103 i = mcm->mcm_body.msgh_descriptor_count;
1104
1105 mcm->mcm_desc.port[i].name = name;
1106 mcm->mcm_desc.port[i].disposition = MACH_MSG_TYPE_MOVE_SEND;
1107 mcm->mcm_desc.port[i].type = MACH_MSG_PORT_DESCRIPTOR;
1108
1109 mcm->mcm_body.msgh_descriptor_count++;
1110 return;
1111 }
1112
1113 inline void
1114 mach_add_ool_ports_desc(msg, addr, count)
1115 void *msg;
1116 void *addr;
1117 int count;
1118 {
1119 struct mach_complex_msg *mcm = msg;
1120 int i;
1121
1122 if ((mcm->mcm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
1123 mcm->mcm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
1124 mcm->mcm_body.msgh_descriptor_count = 0;
1125 }
1126
1127 i = mcm->mcm_body.msgh_descriptor_count;
1128
1129 mcm->mcm_desc.ool_ports[i].address = addr;
1130 mcm->mcm_desc.ool_ports[i].count = count;
1131 mcm->mcm_desc.ool_ports[i].copy = MACH_MSG_ALLOCATE;
1132 mcm->mcm_desc.ool_ports[i].disposition = MACH_MSG_TYPE_MOVE_SEND;
1133 mcm->mcm_desc.ool_ports[i].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
1134
1135 mcm->mcm_body.msgh_descriptor_count++;
1136 return;
1137 }
1138
1139 inline void mach_add_ool_desc(msg, addr, size)
1140 void *msg;
1141 void *addr;
1142 size_t size;
1143 {
1144 struct mach_complex_msg *mcm = msg;
1145 int i;
1146
1147 if ((mcm->mcm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
1148 mcm->mcm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
1149 mcm->mcm_body.msgh_descriptor_count = 0;
1150 }
1151
1152 i = mcm->mcm_body.msgh_descriptor_count;
1153
1154 mcm->mcm_desc.ool[i].address = addr;
1155 mcm->mcm_desc.ool[i].size = size;
1156 mcm->mcm_desc.ool[i].deallocate = 0;
1157 mcm->mcm_desc.ool[i].copy = MACH_MSG_ALLOCATE;
1158 mcm->mcm_desc.ool[i].type = MACH_MSG_OOL_DESCRIPTOR;
1159
1160 mcm->mcm_body.msgh_descriptor_count++;
1161 return;
1162 }
1163
1164 void
1165 mach_message_init(void)
1166 {
1167 pool_init(&mach_message_pool, sizeof (struct mach_message),
1168 0, 0, 0, "mach_message_pool", NULL);
1169 return;
1170 }
1171
1172 struct mach_message *
1173 mach_message_get(msgh, size, mp, l)
1174 mach_msg_header_t *msgh;
1175 size_t size;
1176 struct mach_port *mp;
1177 struct lwp *l;
1178 {
1179 struct mach_message *mm;
1180
1181 mm = (struct mach_message *)pool_get(&mach_message_pool, PR_WAITOK);
1182 bzero(mm, sizeof(*mm));
1183 mm->mm_msg = msgh;
1184 mm->mm_size = size;
1185 mm->mm_port = mp;
1186 mm->mm_l = l;
1187
1188 lockmgr(&mp->mp_msglock, LK_EXCLUSIVE, NULL);
1189 TAILQ_INSERT_TAIL(&mp->mp_msglist, mm, mm_list);
1190 mp->mp_count++;
1191 lockmgr(&mp->mp_msglock, LK_RELEASE, NULL);
1192
1193 return mm;
1194 }
1195
1196 void
1197 mach_message_put(mm)
1198 struct mach_message *mm;
1199 {
1200 struct mach_port *mp;
1201
1202 mp = mm->mm_port;
1203
1204 lockmgr(&mp->mp_msglock, LK_EXCLUSIVE, NULL);
1205 mach_message_put_exclocked(mm);
1206 lockmgr(&mp->mp_msglock, LK_RELEASE, NULL);
1207
1208 return;
1209 }
1210
1211 void
1212 mach_message_put_shlocked(mm)
1213 struct mach_message *mm;
1214 {
1215 struct mach_port *mp;
1216
1217 mp = mm->mm_port;
1218
1219 lockmgr(&mp->mp_msglock, LK_UPGRADE, NULL);
1220 mach_message_put_exclocked(mm);
1221 lockmgr(&mp->mp_msglock, LK_DOWNGRADE, NULL);
1222
1223 return;
1224 }
1225
1226 void
1227 mach_message_put_exclocked(mm)
1228 struct mach_message *mm;
1229 {
1230 struct mach_port *mp;
1231
1232 mp = mm->mm_port;
1233
1234 TAILQ_REMOVE(&mp->mp_msglist, mm, mm_list);
1235 mp->mp_count--;
1236
1237 pool_put(&mach_message_pool, mm);
1238
1239 return;
1240 }
1241
1242 #ifdef DEBUG_MACH
1243 void
1244 mach_debug_message(void)
1245 {
1246 struct lwp *l;
1247 struct mach_emuldata *med;
1248 struct mach_right *mr;
1249 struct mach_right *mrs;
1250 struct mach_port *mp;
1251 struct mach_message *mm;
1252
1253 LIST_FOREACH(l, &alllwp, l_list) {
1254 if ((l->l_proc->p_emul != &emul_mach) &&
1255 #ifdef COMPAT_DARWIN
1256 (l->l_proc->p_emul != &emul_darwin) &&
1257 #endif
1258 1)
1259 continue;
1260
1261 med = l->l_proc->p_emuldata;
1262 LIST_FOREACH(mr, &med->med_right, mr_list)
1263 if ((mr->mr_type & MACH_PORT_TYPE_PORT_SET) == 0) {
1264 mp = mr->mr_port;
1265 if (mp == NULL)
1266 continue;
1267
1268 printf("port %p(%d) ", mp, mp->mp_count);
1269
1270 TAILQ_FOREACH(mm, &mp->mp_msglist, mm_list)
1271 printf("%d ", mm->mm_msg->msgh_id);
1272
1273 printf("\n");
1274 continue;
1275 }
1276 /* Port set... */
1277 LIST_FOREACH(mrs, &mr->mr_set, mr_setlist) {
1278 mp = mrs->mr_port;
1279 if (mp == NULL)
1280 continue;
1281
1282 printf("port %p(%d) ", mp, mp->mp_count);
1283
1284 TAILQ_FOREACH(mm, &mp->mp_msglist, mm_list)
1285 printf("%d ", mm->mm_msg->msgh_id);
1286
1287 printf("\n");
1288 }
1289 }
1290 return;
1291 }
1292
1293 #endif /* DEBUG_MACH */
Cache object: 7a12ed73c5948bb9984993d8ff726520
|