Warning: That file was not part of the compilation database. It may have many parsing errors.

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

Warning: That file was not part of the compilation database. It may have many parsing errors.