]> git.ipfire.org Git - thirdparty/glibc.git/blame - hurd/hurdexec.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / hurd / hurdexec.c
CommitLineData
b168057a 1/* Copyright (C) 1991-2015 Free Software Foundation, Inc.
c84142e8 2 This file is part of the GNU C Library.
28f540f4 3
c84142e8 4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
28f540f4 8
c84142e8
UD
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
41bdb6e2 12 Lesser General Public License for more details.
28f540f4 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
28f540f4
RM
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>
98e1c93a 27#include <hurd/id.h>
8f0c527e 28#include <assert.h>
75cd5204 29#include <argz.h>
28f540f4
RM
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. */
34error_t
75914335 35_hurd_exec (task_t task, file_t file,
28f540f4
RM
36 char *const argv[], char *const envp[])
37{
38 error_t err;
8f0c527e 39 char *args, *env;
28f540f4
RM
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];
98e1c93a
RM
44 inline void free_port (unsigned int i)
45 {
46 _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
47 }
28f540f4 48 file_t *dtable;
1e9dc039 49 unsigned int dtablesize, i;
28f540f4
RM
50 struct hurd_port **dtable_cells;
51 struct hurd_userlink *ulink_dtable;
28f540f4
RM
52 struct hurd_sigstate *ss;
53 mach_port_t *please_dealloc, *pdp;
98e1c93a 54 int reauth = 0;
28f540f4 55
8f0c527e 56 /* XXX needs to be hurdmalloc XXX */
8c4b8cbc
RM
57 if (argv == NULL)
58 args = NULL, argslen = 0;
59 else if (err = __argz_create (argv, &args, &argslen))
75cd5204 60 return err;
8c4b8cbc
RM
61 if (envp == NULL)
62 env = NULL, envlen = 0;
1d88de3d 63 else if (err = __argz_create (envp, &env, &envlen))
75cd5204 64 goto outargs;
28f540f4
RM
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)
98e1c93a 75 free_port (i);
75cd5204 76 goto outenv;
28f540f4
RM
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
fe4d0ab7
MB
97 case INIT_TRACEMASK:
98 ints[i] = _hurdsig_traced;
99 break;
100
28f540f4
RM
101 default:
102 ints[i] = 0;
103 }
104
105 ss = _hurd_self_sigstate ();
8f0c527e
RM
106
107 assert (! __spin_lock_locked (&ss->critical_section_lock));
108 __spin_lock (&ss->critical_section_lock);
109
28f540f4
RM
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. */
75914335 125
28f540f4
RM
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. */
98e1c93a 140 please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
28f540f4
RM
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
57d58860 194 /* Prune trailing null ports from the descriptor table. */
21bc421f 195 while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
57d58860
RM
196 --dtablesize;
197
98e1c93a
RM
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. */
28f540f4 220
98e1c93a 221 auth_t newauth;
20d13812 222
98e1c93a
RM
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;
28f540f4 337
98e1c93a
RM
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;
20d13812 355#ifdef EXEC_SIGTRAP
98e1c93a
RM
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;
20d13812 362#endif
98e1c93a
RM
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 }
28f540f4
RM
371
372 /* Release references to the standard ports. */
373 for (i = 0; i < _hurd_nports; ++i)
98e1c93a
RM
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)))
28f540f4
RM
377 __mach_port_deallocate (__mach_task_self (), ports[i]);
378 else
98e1c93a 379 free_port (i);
28f540f4 380
98e1c93a 381 /* Release references to the file descriptor ports. */
28f540f4 382 if (ulink_dtable != NULL)
98e1c93a
RM
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)
28f540f4 389 for (i = 0; i < dtablesize; ++i)
98e1c93a 390 __mach_port_deallocate (__mach_task_self (), dtable[i]);
28f540f4
RM
391
392 /* Release lock on the file descriptor table. */
393 __mutex_unlock (&_hurd_dtable_lock);
394
395 /* Safe to let signals happen now. */
8f0c527e 396 _hurd_critical_section_unlock (ss);
28f540f4 397
75cd5204
RM
398 outargs:
399 free (args);
400 outenv:
401 free (env);
28f540f4
RM
402 return err;
403}