* iconv/gconv_charset.h (upstr): Add inline keyword, quiets warning.
[jlayton/glibc.git] / 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 }