libio: Multiple fixes for open_{w}memstram (BZ#18241 and BZ#20181)
[glibc.git] / hurd / hurdexec.c
blob9978607be6d4936c042da1b9adbca9bb56ba066c
1 /* Copyright (C) 1991-2016 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/>. */
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>
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[])
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)
46 _hurd_port_free (&_hurd_ports[i], &ulink_ports[i], ports[i]);
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;
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;
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])))
74 while (--i > 0)
75 free_port (i);
76 goto outenv;
79 else
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)
85 switch (i)
87 case INIT_UMASK:
88 ints[i] = _hurd_umask;
89 break;
91 case INIT_SIGMASK:
92 case INIT_SIGIGN:
93 case INIT_SIGPENDING:
94 /* We will set these all below. */
95 break;
97 case INIT_TRACEMASK:
98 ints[i] = _hurdsig_traced;
99 break;
101 default:
102 ints[i] = 0;
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
124 sigstate lock. */
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));
142 else
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];
154 if (d == NULL)
156 dtable[i] = MACH_PORT_NULL;
157 continue;
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);
174 else
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;
187 else
189 dtable = _hurd_init_dtable;
190 ulink_dtable = NULL;
191 dtable_cells = NULL;
194 /* Prune trailing null ports from the descriptor table. */
195 while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
196 --dtablesize;
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. */
221 auth_t newauth;
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)
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,
238 &newauth);
239 if (err == 0)
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);
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;
257 inline void reauth_port (unsigned int idx)
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;
267 if (pdp)
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);
275 if (!err)
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)
285 if (pdp)
286 *pdp++ = _hurd_init_dtable[i];
287 err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
288 if (err)
290 while (++i < dtablesize)
291 dtable[i] = MACH_PORT_NULL;
292 break;
295 else
296 dtable[i] = MACH_PORT_NULL;
298 else
300 if (pdp)
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;
307 for (i = 0; i < dtablesize; ++i)
308 if (dtable[i] != MACH_PORT_NULL)
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)
317 while (++i < dtablesize)
318 _hurd_port_free (dtable_cells[i],
319 &ulink_dtable[i], dtable[i]);
320 break;
323 ulink_dtable = NULL;
324 dtable_cells = NULL;
329 reauth = 1;
331 __mutex_unlock (&_hurd_id.lock);
333 /* The information is all set up now. Try to exec the file. */
334 if (!err)
336 int flags;
338 if (pdp)
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. */
348 for (i = 0; i < _hurd_nports; ++i)
349 *pdp++ = ports[i];
350 for (i = 0; i < dtablesize; ++i)
351 *pdp++ = dtable[i];
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);
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);
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);
398 outargs:
399 free (args);
400 outenv:
401 free (env);
402 return err;