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