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