Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/compat/mach When a task to task message carries ports, t...



details:   https://anonhg.NetBSD.org/src/rev/a35dbfeff2fb
branches:  trunk
changeset: 556142:a35dbfeff2fb
user:      manu <manu%NetBSD.org@localhost>
date:      Sun Dec 07 23:44:14 2003 +0000

description:
When a task to task message carries ports, translate the port names into the
receiver namespace.

While we are there, refactor mach_msg_overwrite by splitting it into
several smaller functions. It had grown too big to be easily maintainable.

diffstat:

 sys/compat/mach/mach_message.c |  1258 ++++++++++++++++++++-------------------
 sys/compat/mach/mach_message.h |    12 +-
 2 files changed, 666 insertions(+), 604 deletions(-)

diffs (truncated from 1393 to 300 lines):

diff -r 3e226cc603a0 -r a35dbfeff2fb sys/compat/mach/mach_message.c
--- a/sys/compat/mach/mach_message.c    Sun Dec 07 23:16:03 2003 +0000
+++ b/sys/compat/mach/mach_message.c    Sun Dec 07 23:44:14 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mach_message.c,v 1.33 2003/12/03 18:18:43 manu Exp $ */
+/*     $NetBSD: mach_message.c,v 1.34 2003/12/07 23:44:14 manu Exp $ */
 
 /*-
  * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.33 2003/12/03 18:18:43 manu Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.34 2003/12/07 23:44:14 manu Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_compat_mach.h" /* For COMPAT_MACH in <sys/ktrace.h> */
@@ -70,7 +70,17 @@
 /* Mach message pool */
 static struct pool mach_message_pool;
 
-static struct lwp *mach_get_target_task(struct lwp *, struct mach_port *);
+static inline 
+    int mach_msg_send(struct lwp *, mach_msg_header_t *, int *, size_t);
+static inline int mach_msg_recv(struct lwp *, mach_msg_header_t *, 
+    int, size_t, unsigned int, mach_port_t);
+static inline 
+    struct lwp *mach_get_target_task(struct lwp *, struct mach_port *);
+static inline void mach_drop_rights(struct mach_right *, int);
+static inline 
+    void mach_trade_rights(struct lwp *, struct lwp *, mach_port_t *, int);
+static inline 
+    int mach_trade_rights_complex(struct lwp *, struct mach_message *);
 
 int
 mach_sys_msg_overwrite_trap(l, v, retval)
@@ -89,672 +99,569 @@
                syscallarg(mach_msg_header_t *) rcv_msg;
                syscallarg(mach_msg_size_t) scatter_list_size;
        } */ *uap = v;
-       struct mach_emuldata *med;
-       struct mach_port *mp;
-       struct proc *p = l->l_proc;
-       size_t send_size, rcv_size;
-       int error = 0;
+       size_t send_size, recv_size;
+       mach_msg_header_t *msg;
+       int opt;
 
-       *retval = 0;
-
+       *retval = MACH_MSG_SUCCESS;
        send_size = SCARG(uap, send_size);
-       rcv_size = SCARG(uap, rcv_size);
+       recv_size = SCARG(uap, rcv_size);
+       opt = SCARG(uap, option);
 
        /* XXX not safe enough: lots of big messages will kill us */
        if (send_size > MACH_MAX_MSG_LEN) {
                *retval = MACH_SEND_TOO_LARGE;
                return 0;
        }
-       if (rcv_size > MACH_MAX_MSG_LEN) {
+       if (recv_size > MACH_MAX_MSG_LEN) {
                *retval = MACH_RCV_TOO_LARGE;
                return 0;
        }
 
-
        /* 
         * Two options: receive or send. If both are 
         * set, we must send, and then receive. If
         * send fail, then we skip recieve.
         */
-       if (SCARG(uap, option) & MACH_SEND_MSG) {
-               mach_msg_header_t *sm;
-               struct mach_service *srv;
-               mach_port_t ln;
-               mach_port_t rn;
-               struct mach_right *lr = NULL;
-               struct mach_right *rr;
-               int bits, rights;
-
-               if (SCARG(uap, msg) == NULL) {
-                       *retval = MACH_SEND_INVALID_DATA;
-                       return 0;
-               }
-
-               /* 
-                * Allocate memory for the message and its reply,
-                * and copy the whole message in the kernel.
-                */
-               sm = malloc(send_size, M_EMULDATA, M_WAITOK);
-               if ((error = copyin(SCARG(uap, msg), sm, send_size)) != 0) {
-                       *retval = MACH_SEND_INVALID_DATA;       
-                       goto out1;
-               }
-
-#ifdef KTRACE
-               /* Dump the Mach message */
-               if (KTRPOINT(p, KTR_MMSG))
-                       ktrmmsg(p, (char *)sm, send_size); 
-#endif
-               /*
-                * Handle rights in the message
-                */
-               ln = sm->msgh_local_port;
-               rn = sm->msgh_remote_port;
-
-               lr = mach_right_check(ln, l, MACH_PORT_TYPE_ALL_RIGHTS);
-               rr = mach_right_check(rn, l, MACH_PORT_TYPE_ALL_RIGHTS);
-               if ((rr == NULL) || (rr->mr_port == NULL)) {
-#ifdef DEBUG_MACH
-                       printf("msg id %d: invalid dest\n", sm->msgh_id);
-#endif
-                       *retval = MACH_SEND_INVALID_DEST;
-                       goto out1;
-               }
-
-               /* 
-                * Check that the process has send a send right on 
-                * the remote port. 
-                */
-               rights = (MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_SEND_ONCE);
-               if (mach_right_check(rn, l, rights) == NULL) {
-                       *retval = MACH_SEND_INVALID_RIGHT;
-                       goto out1;
-               }
-
-               /*
-                * If the remote port is a special port (host, kernel,
-                * clock, or io_master), the message will be handled 
-                * by the kernel.
-                */
-               med = (struct mach_emuldata *)p->p_emuldata;
-               mp = rr->mr_port;
-               if (mp->mp_flags & MACH_MP_INKERNEL) {
-                       struct mach_trap_args args;
-                       mach_msg_header_t *rm;
-                       size_t min_reqlen, max_replen;
-
-                       /* 
-                        * Look for the function that will handle it,
-                        * using the message id.
-                        */
-                       for (srv = mach_services_table; srv->srv_id; srv++)
-                               if (srv->srv_id == sm->msgh_id)
-                                       break;
-                       
-                       /* 
-                        * If no match, give up, and display a warning.
-                        */
-                       if (srv->srv_handler == NULL) {
-                               uprintf("No mach server for id = %d\n",
-                                   sm->msgh_id);
-                               *retval = MACH_SEND_INVALID_DEST;
-                               goto out1;
-                       }
-                       min_reqlen = srv->srv_reqlen;
-                       max_replen = srv->srv_replen;
-
-                       /*
-                        * Special case when the kernel behaves as
-                        * the client: replies to exceptions and
-                        * notifications. There will be no reply,
-                        * as we already receive a reply.
-                        * - request and reply are swapped
-                        * - there will be no reply, so set lr to NULL.
-                        * - skip the lr == NULL tests
-                        * XXX This is inelegant.
-                        */
-                       if ((sm->msgh_id >= 2501) && (sm->msgh_id <= 2503)) {
-                               min_reqlen = srv->srv_replen;
-                               max_replen = srv->srv_reqlen;
-                               lr = NULL;
-                               goto skip_null_lr;
-                       }
-
-                       /*
-                        * Check that the local port is valid, else
-                        * we will not be able to send the reply
-                        */
-                       if ((lr == NULL) || 
-                           (lr->mr_port == NULL) || 
-                           (lr->mr_port->mp_recv == NULL)) {
-#ifdef DEBUG_MACH
-                               printf("msg id %d: invalid src\n", sm->msgh_id);
-#endif
-                               *retval = MACH_SEND_INVALID_REPLY;
-                               goto out1;
-                       }
-skip_null_lr:
-
-                       /*
-                        * Sanity check message length. We do not want the
-                        * server to: 
-                        * 1) use kernel memory located after
-                        *    the end of the request message.
-                        */
-                       if (send_size < min_reqlen) {
-#ifdef DEBUG_MACH
-                               printf("mach server %s: smsg overflow: "
-                                   "send = %d, min = %d\n",
-                                   srv->srv_name, send_size, min_reqlen);
-#endif
-                               *retval = MACH_SEND_MSG_TOO_SMALL;
-                               goto out1;
-                       }
-
-                       /*
-                        * 2) give away random kernel data to the user program
-                        *    when the reply message is copied out.
-                        */
-                       if (rcv_size > max_replen) {
-#ifdef DEBUG_MACH
-                               printf("mach server %s: rmsg overflow: "
-                                   "recv = %d, max = %d\n",
-                                   srv->srv_name, rcv_size, max_replen);
-#endif
-                               rcv_size = max_replen;
-                       }
-
-                       /*
-                        * 3) Overwrite kernel memory after the end of the
-                        *    reply message buffer. This check is the
-                        *    responsability of the server.
-                        */
-
+       msg = SCARG(uap, msg);
+       if (opt & MACH_SEND_MSG)
+               *retval = mach_msg_send(l, msg, &opt, send_size);
 
-                       /* 
-                        * Invoke the server. We give it the opportunity
-                        * to shorten rcv_size if there is less data in
-                        * the reply than what the sender expected.
-                        * If lr is NULL, this is a no reply operation.
-                        */
-                       if (lr != NULL)
-                               rm = malloc(max_replen, 
-                                   M_EMULDATA, M_WAITOK | M_ZERO);
-                       else
-                               rm = NULL;
-
-                       args.l = l;
-                       args.tl = mach_get_target_task(l, mp);
-                       args.smsg = sm;
-                       args.rmsg = rm;
-                       args.rsize = &rcv_size;
-                       args.ssize = send_size;
-                       if ((*retval = (*srv->srv_handler)(&args)) != 0) 
-                               goto out1;
-                       
-                       /*
-                        * No-reply opration: everything is done.
-                        */
-                       if (lr == NULL)
-                               goto out1;
-
-#ifdef DIAGNOSTIC
-                       /* 
-                        * Catch potential bug in the server (sanity
-                        * check #3): did it output a larger message
-                        * then the one that was allocated?
-                        */
-                       if ((SCARG(uap, option) & MACH_RCV_MSG) &&
-                           (rcv_size > max_replen)) {
-                               uprintf("mach_msg: reply too big in %s\n",
-                                   srv->srv_name);
-                       }
-#endif
-
-                       /*
-                        * Queue the reply
-                        */
-                       mp = lr->mr_port;
-                       (void)mach_message_get(rm, rcv_size, mp, NULL);
-#ifdef DEBUG_MACH_MSG
-                       printf("pid %d: message queued on port %p (%d) [%p]\n", 
-                           p->p_pid, mp, rm->msgh_id,
-                           mp->mp_recv->mr_sethead);
-                       if (sm->msgh_id == 404)
-                               printf("*** msg to bootstrap. port = %p, "
-                                   "recv = %p [%p]\n", mach_bootstrap_port, 
-                                   mach_bootstrap_port->mp_recv,
-                                   mach_bootstrap_port->mp_recv->mr_sethead);
-#endif
-                       wakeup(mp->mp_recv->mr_sethead);
-                       *retval = 0;
-out1:
-                       free(sm, M_EMULDATA);
-                       /* 
-                        * Skip the recieve part and return now if
-                        * - there has been an error in the send part
-                        * - this is a no-reply operation (lr == NULL)
-                        */
-                       if ((*retval != 0) || (lr == NULL))
-                               return 0;
-



Home | Main Index | Thread Index | Old Index