Fix computation of inflated errlist size
[glibc.git] / hurd / hurdexec.c
blobcefdcddd3168a0e8384990fc25dc1925e06cc2bb
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.
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.
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.
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/>. */
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>
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[])
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)
47 _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
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;
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;
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 ())
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])))
75 while (--i > 0)
76 free_port (i);
77 goto outenv;
80 else
81 ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
84 /* Load up the ints to give the new program. */
85 for (i = 0; i < INIT_INT_MAX; ++i)
86 switch (i)
88 case INIT_UMASK:
89 ints[i] = _hurd_umask;
90 break;
92 case INIT_SIGMASK:
93 case INIT_SIGIGN:
94 case INIT_SIGPENDING:
95 /* We will set these all below. */
96 break;
98 case INIT_TRACEMASK:
99 ints[i] = _hurdsig_traced;
100 break;
102 default:
103 ints[i] = 0;
106 ss = _hurd_self_sigstate ();
108 assert (! __spin_lock_locked (&ss->critical_section_lock));
109 __spin_lock (&ss->critical_section_lock);
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);
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. */
127 __spin_unlock (&ss->lock);
129 /* Pack up the descriptor table to give the new program. */
130 __mutex_lock (&_hurd_dtable_lock);
132 dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
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;
147 if (_hurd_dtable != NULL)
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)
154 struct hurd_fd *const d = _hurd_dtable[i];
155 if (d == NULL)
157 dtable[i] = MACH_PORT_NULL;
158 continue;
160 __spin_lock (&d->port.lock);
161 if (d->flags & FD_CLOEXEC)
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)
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;
173 __spin_unlock (&d->port.lock);
175 else
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;
188 else
190 dtable = _hurd_init_dtable;
191 ulink_dtable = NULL;
192 dtable_cells = NULL;
195 /* Prune trailing null ports from the descriptor table. */
196 while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
197 --dtablesize;
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])))
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. */
222 auth_t newauth;
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)
229 __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
230 _hurd_id.rid_auth = MACH_PORT_NULL;
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)
242 /* Now we have to reauthenticate the ports with this new ID.
245 inline error_t reauth_io (io_t port, io_t *newport)
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;
258 inline void reauth_port (unsigned int idx)
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;
268 if (pdp)
269 *pdp++ = ports[INIT_PORT_AUTH];
270 free_port (INIT_PORT_AUTH);
271 ports[INIT_PORT_AUTH] = newauth;
273 reauth_port (INIT_PORT_CRDIR);
274 reauth_port (INIT_PORT_CWDIR);
276 if (!err)
278 /* Now we'll reauthenticate each file descriptor. */
279 if (ulink_dtable == NULL)
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)
286 if (pdp)
287 *pdp++ = _hurd_init_dtable[i];
288 err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
289 if (err)
291 while (++i < dtablesize)
292 dtable[i] = MACH_PORT_NULL;
293 break;
296 else
297 dtable[i] = MACH_PORT_NULL;
299 else
301 if (pdp)
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;
308 for (i = 0; i < dtablesize; ++i)
309 if (dtable[i] != MACH_PORT_NULL)
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)
318 while (++i < dtablesize)
319 _hurd_port_free (dtable_cells[i],
320 &ulink_dtable[i], dtable[i]);
321 break;
324 ulink_dtable = NULL;
325 dtable_cells = NULL;
330 reauth = 1;
332 __mutex_unlock (&_hurd_id.lock);
334 /* The information is all set up now. Try to exec the file. */
335 if (!err)
337 int flags;
339 if (pdp)
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. */
349 for (i = 0; i < _hurd_nports; ++i)
350 *pdp++ = ports[i];
351 for (i = 0; i < dtablesize; ++i)
352 *pdp++ = dtable[i];
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);
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);
382 /* Release references to the file descriptor ports. */
383 if (ulink_dtable != NULL)
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]);
389 else if (dtable && dtable != _hurd_init_dtable)
390 for (i = 0; i < dtablesize; ++i)
391 __mach_port_deallocate (__mach_task_self (), dtable[i]);
393 /* Release lock on the file descriptor table. */
394 __mutex_unlock (&_hurd_dtable_lock);
396 /* Safe to let signals happen now. */
397 _hurd_critical_section_unlock (ss);
399 outargs:
400 free (args);
401 outenv:
402 free (env);
403 return err;