(linenum→info "unix/slp.c:2238")

glibc/2.7/hurd/hurdexec.c

    1: /* Copyright (C) 1991,92,93,94,95,96,97,99,2001,02
    2:         Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <errno.h>
   21: #include <unistd.h>
   22: #include <fcntl.h>
   23: #include <limits.h>
   24: #include <stdlib.h>
   25: #include <string.h>
   26: #include <hurd.h>
   27: #include <hurd/fd.h>
   28: #include <hurd/signal.h>
   29: #include <hurd/id.h>
   30: #include <assert.h>
   31: #include <argz.h>
   32: 
   33: /* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
   34:    If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
   35:    ARGV and ENVP are terminated by NULL pointers.  */
   36: error_t
   37: _hurd_exec (task_t task, file_t file,
   38:             char *const argv[], char *const envp[])
   39: {
   40:   error_t err;
   41:   char *args, *env;
   42:   size_t argslen, envlen;
   43:   int ints[INIT_INT_MAX];
   44:   mach_port_t ports[_hurd_nports];
   45:   struct hurd_userlink ulink_ports[_hurd_nports];
   46:   inline void free_port (unsigned int i)
   47:     {
   48:       _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
   49:     }
   50:   file_t *dtable;
   51:   unsigned int dtablesize, i;
   52:   struct hurd_port **dtable_cells;
   53:   struct hurd_userlink *ulink_dtable;
   54:   struct hurd_sigstate *ss;
   55:   mach_port_t *please_dealloc, *pdp;
   56:   int reauth = 0;
   57: 
   58:   /* XXX needs to be hurdmalloc XXX */
   59:   if (argv == NULL)
   60:     args = NULL, argslen = 0;
   61:   else if (err = __argz_create (argv, &args, &argslen))
   62:     return err;
   63:   if (envp == NULL)
   64:     env = NULL, envlen = 0;
   65:   else if (err = __argz_create (envp, &env, &envlen))
   66:     goto outargs;
   67: 
   68:   /* Load up the ports to give to the new program.  */
   69:   for (i = 0; i < _hurd_nports; ++i)
   70:     if (i == INIT_PORT_PROC && task != __mach_task_self ())
   71:       {
   72:         /* This is another task, so we need to ask the proc server
   73:            for the right proc server port for it.  */
   74:         if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
   75:           {
   76:             while (--i > 0)
   77:               free_port (i);
   78:             goto outenv;
   79:           }
   80:       }
   81:     else
   82:       ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
   83: 
   84: 
   85:   /* Load up the ints to give the new program.  */
   86:   for (i = 0; i < INIT_INT_MAX; ++i)
   87:     switch (i)
   88:       {
   89:       case INIT_UMASK:
   90:         ints[i] = _hurd_umask;
   91:         break;
   92: 
   93:       case INIT_SIGMASK:
   94:       case INIT_SIGIGN:
   95:       case INIT_SIGPENDING:
   96:         /* We will set these all below.  */
   97:         break;
   98: 
   99:       case INIT_TRACEMASK:
  100:         ints[i] = _hurdsig_traced;
  101:         break;
  102: 
  103:       default:
  104:         ints[i] = 0;
  105:       }
  106: 
  107:   ss = _hurd_self_sigstate ();
  108: 
  109:   assert (! __spin_lock_locked (&ss->critical_section_lock));
  110:   __spin_lock (&ss->critical_section_lock);
  111: 
  112:   __spin_lock (&ss->lock);
  113:   ints[INIT_SIGMASK] = ss->blocked;
  114:   ints[INIT_SIGPENDING] = ss->pending;
  115:   ints[INIT_SIGIGN] = 0;
  116:   for (i = 1; i < NSIG; ++i)
  117:     if (ss->actions[i].sa_handler == SIG_IGN)
  118:       ints[INIT_SIGIGN] |= __sigmask (i);
  119: 
  120:   /* We hold the sigstate lock until the exec has failed so that no signal
  121:      can arrive between when we pack the blocked and ignored signals, and
  122:      when the exec actually happens.  A signal handler could change what
  123:      signals are blocked and ignored.  Either the change will be reflected
  124:      in the exec, or the signal will never be delivered.  Setting the
  125:      critical section flag avoids anything we call trying to acquire the
  126:      sigstate lock.  */
  127: 
  128:   __spin_unlock (&ss->lock);
  129: 
  130:   /* Pack up the descriptor table to give the new program.  */
  131:   __mutex_lock (&_hurd_dtable_lock);
  132: 
  133:   dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
  134: 
  135:   if (task == __mach_task_self ())
  136:     /* Request the exec server to deallocate some ports from us if the exec
  137:        succeeds.  The init ports and descriptor ports will arrive in the
  138:        new program's exec_startup message.  If we failed to deallocate
  139:        them, the new program would have duplicate user references for them.
  140:        But we cannot deallocate them ourselves, because we must still have
  141:        them after a failed exec call.  */
  142:     please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
  143:                                 * sizeof (mach_port_t));
  144:   else
  145:     please_dealloc = NULL;
  146:   pdp = please_dealloc;
  147: 
  148:   if (_hurd_dtable != NULL)
  149:     {
  150:       dtable = __alloca (dtablesize * sizeof (dtable[0]));
  151:       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
  152:       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
  153:       for (i = 0; i < dtablesize; ++i)
  154:         {
  155:           struct hurd_fd *const d = _hurd_dtable[i];
  156:           if (d == NULL)
  157:             {
  158:               dtable[i] = MACH_PORT_NULL;
  159:               continue;
  160:             }
  161:           __spin_lock (&d->port.lock);
  162:           if (d->flags & FD_CLOEXEC)
  163:             {
  164:               /* This descriptor is marked to be closed on exec.
  165:                  So don't pass it to the new program.  */
  166:               dtable[i] = MACH_PORT_NULL;
  167:               if (pdp && d->port.port != MACH_PORT_NULL)
  168:                 {
  169:                   /* We still need to deallocate the ports.  */
  170:                   *pdp++ = d->port.port;
  171:                   if (d->ctty.port != MACH_PORT_NULL)
  172:                     *pdp++ = d->ctty.port;
  173:                 }
  174:               __spin_unlock (&d->port.lock);
  175:             }
  176:           else
  177:             {
  178:               if (pdp && d->ctty.port != MACH_PORT_NULL)
  179:                 /* All the elements of DTABLE are added to PLEASE_DEALLOC
  180:                    below, so we needn't add the port itself.
  181:                    But we must deallocate the ctty port as well as
  182:                    the normal port that got installed in DTABLE[I].  */
  183:                 *pdp++ = d->ctty.port;
  184:               dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
  185:               dtable_cells[i] = &d->port;
  186:             }
  187:         }
  188:     }
  189:   else
  190:     {
  191:       dtable = _hurd_init_dtable;
  192:       ulink_dtable = NULL;
  193:       dtable_cells = NULL;
  194:     }
  195: 
  196:   /* Prune trailing null ports from the descriptor table.  */
  197:   while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
  198:     --dtablesize;
  199: 
  200:   /* See if we need to diddle the auth port of the new program.
  201:      The purpose of this is to get the effect setting the saved-set UID and
  202:      GID to the respective effective IDs after the exec, as POSIX.1 requires.
  203:      Note that we don't reauthenticate with the proc server; that would be a
  204:      no-op since it only keeps track of the effective UIDs, and if it did
  205:      keep track of the available IDs we would have the problem that we'd be
  206:      changing the IDs before the exec and have to change them back after a
  207:      failure.  Arguably we could skip all the reauthentications because the
  208:      available IDs have no bearing on any filesystem.  But the conservative
  209:      approach is to reauthenticate all the io ports so that no state anywhere
  210:      reflects that our whole ID set differs from what we've set it to.  */
  211:   __mutex_lock (&_hurd_id.lock);
  212:   err = _hurd_check_ids ();
  213:   if (err == 0 && ((_hurd_id.aux.nuids >= 2 && _hurd_id.gen.nuids >= 1
  214:                     && _hurd_id.aux.uids[1] != _hurd_id.gen.uids[0])
  215:                    || (_hurd_id.aux.ngids >= 2 && _hurd_id.gen.ngids >= 1
  216:                        && _hurd_id.aux.gids[1] != _hurd_id.gen.gids[0])))
  217:     {
  218:       /* We have euid != svuid or egid != svgid.  POSIX.1 says that exec
  219:          sets svuid = euid and svgid = egid.  So we must get a new auth
  220:          port and reauthenticate everything with it.  We'll pass the new
  221:          ports in file_exec instead of our own ports.  */
  222: 
  223:       auth_t newauth;
  224: 
  225:       _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
  226:       _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
  227:       _hurd_id.valid = 0;
  228:       if (_hurd_id.rid_auth != MACH_PORT_NULL)
  229:         {
  230:           __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
  231:           _hurd_id.rid_auth = MACH_PORT_NULL;
  232:         }
  233: 
  234:       err = __auth_makeauth (ports[INIT_PORT_AUTH],
  235:                              NULL, MACH_MSG_TYPE_COPY_SEND, 0,
  236:                              _hurd_id.gen.uids, _hurd_id.gen.nuids,
  237:                              _hurd_id.aux.uids, _hurd_id.aux.nuids,
  238:                              _hurd_id.gen.gids, _hurd_id.gen.ngids,
  239:                              _hurd_id.aux.gids, _hurd_id.aux.ngids,
  240:                              &newauth);
  241:       if (err == 0)
  242:         {
  243:           /* Now we have to reauthenticate the ports with this new ID.
  244:            */
  245: 
  246:           inline error_t reauth_io (io_t port, io_t *newport)
  247:             {
  248:               mach_port_t ref = __mach_reply_port ();
  249:               *newport = MACH_PORT_NULL;
  250:               error_t err = __io_reauthenticate (port,
  251:                                                  ref, MACH_MSG_TYPE_MAKE_SEND);
  252:               if (!err)
  253:                 err = __auth_user_authenticate (newauth,
  254:                                                 ref, MACH_MSG_TYPE_MAKE_SEND,
  255:                                                 newport);
  256:               __mach_port_destroy (__mach_task_self (), ref);
  257:               return err;
  258:             }
  259:           inline void reauth_port (unsigned int idx)
  260:             {
  261:               io_t newport;
  262:               err = reauth_io (ports[idx], &newport) ?: err;
  263:               if (pdp)
  264:                 *pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
  265:               free_port (idx);
  266:               ports[idx] = newport;
  267:             }
  268: 
  269:           if (pdp)
  270:             *pdp++ = ports[INIT_PORT_AUTH];
  271:           free_port (INIT_PORT_AUTH);
  272:           ports[INIT_PORT_AUTH] = newauth;
  273: 
  274:           reauth_port (INIT_PORT_CRDIR);
  275:           reauth_port (INIT_PORT_CWDIR);
  276: 
  277:           if (!err)
  278:             {
  279:               /* Now we'll reauthenticate each file descriptor.  */
  280:               if (ulink_dtable == NULL)
  281:                 {
  282:                   assert (dtable == _hurd_init_dtable);
  283:                   dtable = __alloca (dtablesize * sizeof (dtable[0]));
  284:                   for (i = 0; i < dtablesize; ++i)
  285:                     if (_hurd_init_dtable[i] != MACH_PORT_NULL)
  286:                       {
  287:                         if (pdp)
  288:                           *pdp++ = _hurd_init_dtable[i];
  289:                         err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
  290:                         if (err)
  291:                           {
  292:                             while (++i < dtablesize)
  293:                               dtable[i] = MACH_PORT_NULL;
  294:                             break;
  295:                           }
  296:                       }
  297:                     else
  298:                       dtable[i] = MACH_PORT_NULL;
  299:                 }
  300:               else
  301:                 {
  302:                   if (pdp)
  303:                     {
  304:                       /* Ask to deallocate all the old fd ports,
  305:                          since we will have new ones in DTABLE.  */
  306:                       memcpy (pdp, dtable, dtablesize * sizeof pdp[0]);
  307:                       pdp += dtablesize;
  308:                     }
  309:                   for (i = 0; i < dtablesize; ++i)
  310:                     if (dtable[i] != MACH_PORT_NULL)
  311:                       {
  312:                         io_t newport;
  313:                         err = reauth_io (dtable[i], &newport);
  314:                         _hurd_port_free (dtable_cells[i], &ulink_dtable[i],
  315:                                          dtable[i]);
  316:                         dtable[i] = newport;
  317:                         if (err)
  318:                           {
  319:                             while (++i < dtablesize)
  320:                               _hurd_port_free (dtable_cells[i],
  321:                                                &ulink_dtable[i], dtable[i]);
  322:                             break;
  323:                           }
  324:                       }
  325:                   ulink_dtable = NULL;
  326:                   dtable_cells = NULL;
  327:                 }
  328:             }
  329:         }
  330: 
  331:       reauth = 1;
  332:     }
  333:   __mutex_unlock (&_hurd_id.lock);
  334: 
  335:   /* The information is all set up now.  Try to exec the file.  */
  336:   if (!err)
  337:     {
  338:       int flags;
  339: 
  340:       if (pdp)
  341:         {
  342:           /* Request the exec server to deallocate some ports from us if
  343:              the exec succeeds.  The init ports and descriptor ports will
  344:              arrive in the new program's exec_startup message.  If we
  345:              failed to deallocate them, the new program would have
  346:              duplicate user references for them.  But we cannot deallocate
  347:              them ourselves, because we must still have them after a failed
  348:              exec call.  */
  349: 
  350:           for (i = 0; i < _hurd_nports; ++i)
  351:             *pdp++ = ports[i];
  352:           for (i = 0; i < dtablesize; ++i)
  353:             *pdp++ = dtable[i];
  354:         }
  355: 
  356:       flags = 0;
  357: #ifdef EXEC_SIGTRAP
  358:       /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is
  359:          propagated through exec by INIT_TRACEMASK, so this checks if
  360:          PTRACE_TRACEME has been called in this process in any of its
  361:          current or prior lives.  */
  362:       if (__sigismember (&_hurdsig_traced, SIGKILL))
  363:         flags |= EXEC_SIGTRAP;
  364: #endif
  365:       err = __file_exec (file, task, flags,
  366:                          args, argslen, env, envlen,
  367:                          dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
  368:                          ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
  369:                          ints, INIT_INT_MAX,
  370:                          please_dealloc, pdp - please_dealloc,
  371:                          &_hurd_msgport, task == __mach_task_self () ? 1 : 0);
  372:     }
  373: 
  374:   /* Release references to the standard ports.  */
  375:   for (i = 0; i < _hurd_nports; ++i)
  376:     if ((i == INIT_PORT_PROC && task != __mach_task_self ())
  377:         || (reauth && (i == INIT_PORT_AUTH
  378:                        || i == INIT_PORT_CRDIR || i == INIT_PORT_CWDIR)))
  379:       __mach_port_deallocate (__mach_task_self (), ports[i]);
  380:     else
  381:       free_port (i);
  382: 
  383:   /* Release references to the file descriptor ports.  */
  384:   if (ulink_dtable != NULL)
  385:     {
  386:       for (i = 0; i < dtablesize; ++i)
  387:         if (dtable[i] != MACH_PORT_NULL)
  388:           _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
  389:     }
  390:   else if (dtable && dtable != _hurd_init_dtable)
  391:     for (i = 0; i < dtablesize; ++i)
  392:       __mach_port_deallocate (__mach_task_self (), dtable[i]);
  393: 
  394:   /* Release lock on the file descriptor table. */
  395:   __mutex_unlock (&_hurd_dtable_lock);
  396: 
  397:   /* Safe to let signals happen now.  */
  398:   _hurd_critical_section_unlock (ss);
  399: 
  400:  outargs:
  401:   free (args);
  402:  outenv:
  403:   free (env);
  404:   return err;
  405: }
Syntax (Markdown)