1 /* Copyright (C) 1991-2015 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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/>. */
26 #include <hurd/signal.h>
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. */
35 _hurd_exec (task_t task, file_t file,
36 char *const argv[], char *const envp[])
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)
46 _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
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;
56 /* XXX needs to be hurdmalloc XXX */
58 args = NULL, argslen = 0;
59 else if (err = __argz_create (argv, &args, &argslen))
62 env = NULL, envlen = 0;
63 else if (err = __argz_create (envp, &env, &envlen))
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 ())
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])))
80 ports[i] = _hurd_port_get (&_hurd_ports[i], &ulink_ports[i]);
83 /* Load up the ints to give the new program. */
84 for (i = 0; i < INIT_INT_MAX; ++i)
88 ints[i] = _hurd_umask;
94 /* We will set these all below. */
98 ints[i] = _hurdsig_traced;
105 ss = _hurd_self_sigstate ();
107 assert (! __spin_lock_locked (&ss->critical_section_lock));
108 __spin_lock (&ss->critical_section_lock);
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);
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
126 __spin_unlock (&ss->lock);
128 /* Pack up the descriptor table to give the new program. */
129 __mutex_lock (&_hurd_dtable_lock);
131 dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
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));
143 please_dealloc = NULL;
144 pdp = please_dealloc;
146 if (_hurd_dtable != NULL)
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)
153 struct hurd_fd *const d = _hurd_dtable[i];
156 dtable[i] = MACH_PORT_NULL;
159 __spin_lock (&d->port.lock);
160 if (d->flags & FD_CLOEXEC)
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)
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;
172 __spin_unlock (&d->port.lock);
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;
189 dtable = _hurd_init_dtable;
194 /* Prune trailing null ports from the descriptor table. */
195 while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
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])))
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. */
223 _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
224 _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
226 if (_hurd_id.rid_auth != MACH_PORT_NULL)
228 __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
229 _hurd_id.rid_auth = MACH_PORT_NULL;
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,
241 /* Now we have to reauthenticate the ports with this new ID.
244 inline error_t reauth_io (io_t port, io_t *newport)
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);
251 err = __auth_user_authenticate (newauth,
252 ref, MACH_MSG_TYPE_MAKE_SEND,
254 __mach_port_destroy (__mach_task_self (), ref);
257 inline void reauth_port (unsigned int idx)
260 err = reauth_io (ports[idx], &newport) ?: err;
262 *pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
264 ports[idx] = newport;
268 *pdp++ = ports[INIT_PORT_AUTH];
269 free_port (INIT_PORT_AUTH);
270 ports[INIT_PORT_AUTH] = newauth;
272 reauth_port (INIT_PORT_CRDIR);
273 reauth_port (INIT_PORT_CWDIR);
277 /* Now we'll reauthenticate each file descriptor. */
278 if (ulink_dtable == NULL)
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)
286 *pdp++ = _hurd_init_dtable[i];
287 err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
290 while (++i < dtablesize)
291 dtable[i] = MACH_PORT_NULL;
296 dtable[i] = MACH_PORT_NULL;
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]);
307 for (i = 0; i < dtablesize; ++i)
308 if (dtable[i] != MACH_PORT_NULL)
311 err = reauth_io (dtable[i], &newport);
312 _hurd_port_free (dtable_cells[i], &ulink_dtable[i],
317 while (++i < dtablesize)
318 _hurd_port_free (dtable_cells[i],
319 &ulink_dtable[i], dtable[i]);
331 __mutex_unlock (&_hurd_id.lock);
333 /* The information is all set up now. Try to exec the file. */
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
348 for (i = 0; i < _hurd_nports; ++i)
350 for (i = 0; i < dtablesize; ++i)
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;
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,
368 please_dealloc, pdp - please_dealloc,
369 &_hurd_msgport, task == __mach_task_self () ? 1 : 0);
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]);
381 /* Release references to the file descriptor ports. */
382 if (ulink_dtable != NULL)
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]);
388 else if (dtable && dtable != _hurd_init_dtable)
389 for (i = 0; i < dtablesize; ++i)
390 __mach_port_deallocate (__mach_task_self (), dtable[i]);
392 /* Release lock on the file descriptor table. */
393 __mutex_unlock (&_hurd_dtable_lock);
395 /* Safe to let signals happen now. */
396 _hurd_critical_section_unlock (ss);