Back to index

glibc  2.9
hurdexec.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92,93,94,95,96,97,99,2001,02
00002        Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <unistd.h>
00022 #include <fcntl.h>
00023 #include <limits.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <hurd.h>
00027 #include <hurd/fd.h>
00028 #include <hurd/signal.h>
00029 #include <hurd/id.h>
00030 #include <assert.h>
00031 #include <argz.h>
00032 
00033 /* Overlay TASK, executing FILE with arguments ARGV and environment ENVP.
00034    If TASK == mach_task_self (), some ports are dealloc'd by the exec server.
00035    ARGV and ENVP are terminated by NULL pointers.  */
00036 error_t
00037 _hurd_exec (task_t task, file_t file,
00038            char *const argv[], char *const envp[])
00039 {
00040   error_t err;
00041   char *args, *env;
00042   size_t argslen, envlen;
00043   int ints[INIT_INT_MAX];
00044   mach_port_t ports[_hurd_nports];
00045   struct hurd_userlink ulink_ports[_hurd_nports];
00046   inline void free_port (unsigned int i)
00047     {
00048       _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
00049     }
00050   file_t *dtable;
00051   unsigned int dtablesize, i;
00052   struct hurd_port **dtable_cells;
00053   struct hurd_userlink *ulink_dtable;
00054   struct hurd_sigstate *ss;
00055   mach_port_t *please_dealloc, *pdp;
00056   int reauth = 0;
00057 
00058   /* XXX needs to be hurdmalloc XXX */
00059   if (argv == NULL)
00060     args = NULL, argslen = 0;
00061   else if (err = __argz_create (argv, &args, &argslen))
00062     return err;
00063   if (envp == NULL)
00064     env = NULL, envlen = 0;
00065   else if (err = __argz_create (envp, &env, &envlen))
00066     goto outargs;
00067 
00068   /* Load up the ports to give to the new program.  */
00069   for (i = 0; i < _hurd_nports; ++i)
00070     if (i == INIT_PORT_PROC && task != __mach_task_self ())
00071       {
00072        /* This is another task, so we need to ask the proc server
00073           for the right proc server port for it.  */
00074        if (err = __USEPORT (PROC, __proc_task2proc (port, task, &ports[i])))
00075          {
00076            while (--i > 0)
00077              free_port (i);
00078            goto outenv;
00079          }
00080       }
00081     else
00082       ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
00083 
00084 
00085   /* Load up the ints to give the new program.  */
00086   for (i = 0; i < INIT_INT_MAX; ++i)
00087     switch (i)
00088       {
00089       case INIT_UMASK:
00090        ints[i] = _hurd_umask;
00091        break;
00092 
00093       case INIT_SIGMASK:
00094       case INIT_SIGIGN:
00095       case INIT_SIGPENDING:
00096        /* We will set these all below.  */
00097        break;
00098 
00099       case INIT_TRACEMASK:
00100        ints[i] = _hurdsig_traced;
00101        break;
00102 
00103       default:
00104        ints[i] = 0;
00105       }
00106 
00107   ss = _hurd_self_sigstate ();
00108 
00109   assert (! __spin_lock_locked (&ss->critical_section_lock));
00110   __spin_lock (&ss->critical_section_lock);
00111 
00112   __spin_lock (&ss->lock);
00113   ints[INIT_SIGMASK] = ss->blocked;
00114   ints[INIT_SIGPENDING] = ss->pending;
00115   ints[INIT_SIGIGN] = 0;
00116   for (i = 1; i < NSIG; ++i)
00117     if (ss->actions[i].sa_handler == SIG_IGN)
00118       ints[INIT_SIGIGN] |= __sigmask (i);
00119 
00120   /* We hold the sigstate lock until the exec has failed so that no signal
00121      can arrive between when we pack the blocked and ignored signals, and
00122      when the exec actually happens.  A signal handler could change what
00123      signals are blocked and ignored.  Either the change will be reflected
00124      in the exec, or the signal will never be delivered.  Setting the
00125      critical section flag avoids anything we call trying to acquire the
00126      sigstate lock.  */
00127 
00128   __spin_unlock (&ss->lock);
00129 
00130   /* Pack up the descriptor table to give the new program.  */
00131   __mutex_lock (&_hurd_dtable_lock);
00132 
00133   dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
00134 
00135   if (task == __mach_task_self ())
00136     /* Request the exec server to deallocate some ports from us if the exec
00137        succeeds.  The init ports and descriptor ports will arrive in the
00138        new program's exec_startup message.  If we failed to deallocate
00139        them, the new program would have duplicate user references for them.
00140        But we cannot deallocate them ourselves, because we must still have
00141        them after a failed exec call.  */
00142     please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
00143                             * sizeof (mach_port_t));
00144   else
00145     please_dealloc = NULL;
00146   pdp = please_dealloc;
00147 
00148   if (_hurd_dtable != NULL)
00149     {
00150       dtable = __alloca (dtablesize * sizeof (dtable[0]));
00151       ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
00152       dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
00153       for (i = 0; i < dtablesize; ++i)
00154        {
00155          struct hurd_fd *const d = _hurd_dtable[i];
00156          if (d == NULL)
00157            {
00158              dtable[i] = MACH_PORT_NULL;
00159              continue;
00160            }
00161          __spin_lock (&d->port.lock);
00162          if (d->flags & FD_CLOEXEC)
00163            {
00164              /* This descriptor is marked to be closed on exec.
00165                So don't pass it to the new program.  */
00166              dtable[i] = MACH_PORT_NULL;
00167              if (pdp && d->port.port != MACH_PORT_NULL)
00168               {
00169                 /* We still need to deallocate the ports.  */
00170                 *pdp++ = d->port.port;
00171                 if (d->ctty.port != MACH_PORT_NULL)
00172                   *pdp++ = d->ctty.port;
00173               }
00174              __spin_unlock (&d->port.lock);
00175            }
00176          else
00177            {
00178              if (pdp && d->ctty.port != MACH_PORT_NULL)
00179               /* All the elements of DTABLE are added to PLEASE_DEALLOC
00180                  below, so we needn't add the port itself.
00181                  But we must deallocate the ctty port as well as
00182                  the normal port that got installed in DTABLE[I].  */
00183               *pdp++ = d->ctty.port;
00184              dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
00185              dtable_cells[i] = &d->port;
00186            }
00187        }
00188     }
00189   else
00190     {
00191       dtable = _hurd_init_dtable;
00192       ulink_dtable = NULL;
00193       dtable_cells = NULL;
00194     }
00195 
00196   /* Prune trailing null ports from the descriptor table.  */
00197   while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
00198     --dtablesize;
00199 
00200   /* See if we need to diddle the auth port of the new program.
00201      The purpose of this is to get the effect setting the saved-set UID and
00202      GID to the respective effective IDs after the exec, as POSIX.1 requires.
00203      Note that we don't reauthenticate with the proc server; that would be a
00204      no-op since it only keeps track of the effective UIDs, and if it did
00205      keep track of the available IDs we would have the problem that we'd be
00206      changing the IDs before the exec and have to change them back after a
00207      failure.  Arguably we could skip all the reauthentications because the
00208      available IDs have no bearing on any filesystem.  But the conservative
00209      approach is to reauthenticate all the io ports so that no state anywhere
00210      reflects that our whole ID set differs from what we've set it to.  */
00211   __mutex_lock (&_hurd_id.lock);
00212   err = _hurd_check_ids ();
00213   if (err == 0 && ((_hurd_id.aux.nuids >= 2 && _hurd_id.gen.nuids >= 1
00214                   && _hurd_id.aux.uids[1] != _hurd_id.gen.uids[0])
00215                  || (_hurd_id.aux.ngids >= 2 && _hurd_id.gen.ngids >= 1
00216                      && _hurd_id.aux.gids[1] != _hurd_id.gen.gids[0])))
00217     {
00218       /* We have euid != svuid or egid != svgid.  POSIX.1 says that exec
00219         sets svuid = euid and svgid = egid.  So we must get a new auth
00220         port and reauthenticate everything with it.  We'll pass the new
00221         ports in file_exec instead of our own ports.  */
00222 
00223       auth_t newauth;
00224 
00225       _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
00226       _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
00227       _hurd_id.valid = 0;
00228       if (_hurd_id.rid_auth != MACH_PORT_NULL)
00229        {
00230          __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
00231          _hurd_id.rid_auth = MACH_PORT_NULL;
00232        }
00233 
00234       err = __auth_makeauth (ports[INIT_PORT_AUTH],
00235                           NULL, MACH_MSG_TYPE_COPY_SEND, 0,
00236                           _hurd_id.gen.uids, _hurd_id.gen.nuids,
00237                           _hurd_id.aux.uids, _hurd_id.aux.nuids,
00238                           _hurd_id.gen.gids, _hurd_id.gen.ngids,
00239                           _hurd_id.aux.gids, _hurd_id.aux.ngids,
00240                           &newauth);
00241       if (err == 0)
00242        {
00243          /* Now we have to reauthenticate the ports with this new ID.
00244           */
00245 
00246          inline error_t reauth_io (io_t port, io_t *newport)
00247            {
00248              mach_port_t ref = __mach_reply_port ();
00249              *newport = MACH_PORT_NULL;
00250              error_t err = __io_reauthenticate (port,
00251                                            ref, MACH_MSG_TYPE_MAKE_SEND);
00252              if (!err)
00253               err = __auth_user_authenticate (newauth,
00254                                           ref, MACH_MSG_TYPE_MAKE_SEND,
00255                                           newport);
00256              __mach_port_destroy (__mach_task_self (), ref);
00257              return err;
00258            }
00259          inline void reauth_port (unsigned int idx)
00260            {
00261              io_t newport;
00262              err = reauth_io (ports[idx], &newport) ?: err;
00263              if (pdp)
00264               *pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
00265              free_port (idx);
00266              ports[idx] = newport;
00267            }
00268 
00269          if (pdp)
00270            *pdp++ = ports[INIT_PORT_AUTH];
00271          free_port (INIT_PORT_AUTH);
00272          ports[INIT_PORT_AUTH] = newauth;
00273 
00274          reauth_port (INIT_PORT_CRDIR);
00275          reauth_port (INIT_PORT_CWDIR);
00276 
00277          if (!err)
00278            {
00279              /* Now we'll reauthenticate each file descriptor.  */
00280              if (ulink_dtable == NULL)
00281               {
00282                 assert (dtable == _hurd_init_dtable);
00283                 dtable = __alloca (dtablesize * sizeof (dtable[0]));
00284                 for (i = 0; i < dtablesize; ++i)
00285                   if (_hurd_init_dtable[i] != MACH_PORT_NULL)
00286                     {
00287                      if (pdp)
00288                        *pdp++ = _hurd_init_dtable[i];
00289                      err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
00290                      if (err)
00291                        {
00292                          while (++i < dtablesize)
00293                            dtable[i] = MACH_PORT_NULL;
00294                          break;
00295                        }
00296                     }
00297                   else
00298                     dtable[i] = MACH_PORT_NULL;
00299               }
00300              else
00301               {
00302                 if (pdp)
00303                   {
00304                     /* Ask to deallocate all the old fd ports,
00305                       since we will have new ones in DTABLE.  */
00306                     memcpy (pdp, dtable, dtablesize * sizeof pdp[0]);
00307                     pdp += dtablesize;
00308                   }
00309                 for (i = 0; i < dtablesize; ++i)
00310                   if (dtable[i] != MACH_PORT_NULL)
00311                     {
00312                      io_t newport;
00313                      err = reauth_io (dtable[i], &newport);
00314                      _hurd_port_free (dtable_cells[i], &ulink_dtable[i],
00315                                     dtable[i]);
00316                      dtable[i] = newport;
00317                      if (err)
00318                        {
00319                          while (++i < dtablesize)
00320                            _hurd_port_free (dtable_cells[i],
00321                                           &ulink_dtable[i], dtable[i]);
00322                          break;
00323                        }
00324                     }
00325                 ulink_dtable = NULL;
00326                 dtable_cells = NULL;
00327               }
00328            }
00329        }
00330 
00331       reauth = 1;
00332     }
00333   __mutex_unlock (&_hurd_id.lock);
00334 
00335   /* The information is all set up now.  Try to exec the file.  */
00336   if (!err)
00337     {
00338       int flags;
00339 
00340       if (pdp)
00341        {
00342          /* Request the exec server to deallocate some ports from us if
00343             the exec succeeds.  The init ports and descriptor ports will
00344             arrive in the new program's exec_startup message.  If we
00345             failed to deallocate them, the new program would have
00346             duplicate user references for them.  But we cannot deallocate
00347             them ourselves, because we must still have them after a failed
00348             exec call.  */
00349 
00350          for (i = 0; i < _hurd_nports; ++i)
00351            *pdp++ = ports[i];
00352          for (i = 0; i < dtablesize; ++i)
00353            *pdp++ = dtable[i];
00354        }
00355 
00356       flags = 0;
00357 #ifdef EXEC_SIGTRAP
00358       /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is
00359         propagated through exec by INIT_TRACEMASK, so this checks if
00360         PTRACE_TRACEME has been called in this process in any of its
00361         current or prior lives.  */
00362       if (__sigismember (&_hurdsig_traced, SIGKILL))
00363        flags |= EXEC_SIGTRAP;
00364 #endif
00365       err = __file_exec (file, task, flags,
00366                       args, argslen, env, envlen,
00367                       dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
00368                       ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
00369                       ints, INIT_INT_MAX,
00370                       please_dealloc, pdp - please_dealloc,
00371                       &_hurd_msgport, task == __mach_task_self () ? 1 : 0);
00372     }
00373 
00374   /* Release references to the standard ports.  */
00375   for (i = 0; i < _hurd_nports; ++i)
00376     if ((i == INIT_PORT_PROC && task != __mach_task_self ())
00377        || (reauth && (i == INIT_PORT_AUTH
00378                      || i == INIT_PORT_CRDIR || i == INIT_PORT_CWDIR)))
00379       __mach_port_deallocate (__mach_task_self (), ports[i]);
00380     else
00381       free_port (i);
00382 
00383   /* Release references to the file descriptor ports.  */
00384   if (ulink_dtable != NULL)
00385     {
00386       for (i = 0; i < dtablesize; ++i)
00387        if (dtable[i] != MACH_PORT_NULL)
00388          _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
00389     }
00390   else if (dtable && dtable != _hurd_init_dtable)
00391     for (i = 0; i < dtablesize; ++i)
00392       __mach_port_deallocate (__mach_task_self (), dtable[i]);
00393 
00394   /* Release lock on the file descriptor table. */
00395   __mutex_unlock (&_hurd_dtable_lock);
00396 
00397   /* Safe to let signals happen now.  */
00398   _hurd_critical_section_unlock (ss);
00399 
00400  outargs:
00401   free (args);
00402  outenv:
00403   free (env);
00404   return err;
00405 }