]> git.ipfire.org Git - thirdparty/glibc.git/blob - hurd/hurdexec.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / hurd / hurdexec.c
1 /* Copyright (C) 1991-2020 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 <https://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. */
35 error_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
42 link_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. */
52 error_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 _hurd_sigstate_lock (ss);
130 struct sigaction *actions = _hurd_sigstate_actions (ss);
131 ints[INIT_SIGMASK] = ss->blocked;
132 ints[INIT_SIGPENDING] = _hurd_sigstate_pending (ss);
133 ints[INIT_SIGIGN] = 0;
134 for (i = 1; i < NSIG; ++i)
135 if (actions[i].sa_handler == SIG_IGN)
136 ints[INIT_SIGIGN] |= __sigmask (i);
137
138 /* We hold the sigstate lock until the exec has failed so that no signal
139 can arrive between when we pack the blocked and ignored signals, and
140 when the exec actually happens. A signal handler could change what
141 signals are blocked and ignored. Either the change will be reflected
142 in the exec, or the signal will never be delivered. Setting the
143 critical section flag avoids anything we call trying to acquire the
144 sigstate lock. */
145
146 _hurd_sigstate_unlock (ss);
147
148 /* Pack up the descriptor table to give the new program. */
149 __mutex_lock (&_hurd_dtable_lock);
150
151 dtablesize = _hurd_dtable ? _hurd_dtablesize : _hurd_init_dtablesize;
152
153 if (task == __mach_task_self ())
154 /* Request the exec server to deallocate some ports from us if the exec
155 succeeds. The init ports and descriptor ports will arrive in the
156 new program's exec_startup message. If we failed to deallocate
157 them, the new program would have duplicate user references for them.
158 But we cannot deallocate them ourselves, because we must still have
159 them after a failed exec call. */
160 please_dealloc = __alloca ((_hurd_nports + 3 + (3 * dtablesize))
161 * sizeof (mach_port_t));
162 else
163 please_dealloc = NULL;
164 pdp = please_dealloc;
165
166 if (_hurd_dtable != NULL)
167 {
168 dtable = __alloca (dtablesize * sizeof (dtable[0]));
169 ulink_dtable = __alloca (dtablesize * sizeof (ulink_dtable[0]));
170 dtable_cells = __alloca (dtablesize * sizeof (dtable_cells[0]));
171 for (i = 0; i < dtablesize; ++i)
172 {
173 struct hurd_fd *const d = _hurd_dtable[i];
174 if (d == NULL)
175 {
176 dtable[i] = MACH_PORT_NULL;
177 continue;
178 }
179 __spin_lock (&d->port.lock);
180 if (d->flags & FD_CLOEXEC)
181 {
182 /* This descriptor is marked to be closed on exec.
183 So don't pass it to the new program. */
184 dtable[i] = MACH_PORT_NULL;
185 if (pdp && d->port.port != MACH_PORT_NULL)
186 {
187 /* We still need to deallocate the ports. */
188 *pdp++ = d->port.port;
189 if (d->ctty.port != MACH_PORT_NULL)
190 *pdp++ = d->ctty.port;
191 }
192 __spin_unlock (&d->port.lock);
193 }
194 else
195 {
196 if (pdp && d->ctty.port != MACH_PORT_NULL)
197 /* All the elements of DTABLE are added to PLEASE_DEALLOC
198 below, so we needn't add the port itself.
199 But we must deallocate the ctty port as well as
200 the normal port that got installed in DTABLE[I]. */
201 *pdp++ = d->ctty.port;
202 dtable[i] = _hurd_port_locked_get (&d->port, &ulink_dtable[i]);
203 dtable_cells[i] = &d->port;
204 }
205 }
206 }
207 else
208 {
209 dtable = _hurd_init_dtable;
210 ulink_dtable = NULL;
211 dtable_cells = NULL;
212 }
213
214 /* Prune trailing null ports from the descriptor table. */
215 while (dtablesize > 0 && dtable[dtablesize - 1] == MACH_PORT_NULL)
216 --dtablesize;
217
218 /* See if we need to diddle the auth port of the new program.
219 The purpose of this is to get the effect setting the saved-set UID and
220 GID to the respective effective IDs after the exec, as POSIX.1 requires.
221 Note that we don't reauthenticate with the proc server; that would be a
222 no-op since it only keeps track of the effective UIDs, and if it did
223 keep track of the available IDs we would have the problem that we'd be
224 changing the IDs before the exec and have to change them back after a
225 failure. Arguably we could skip all the reauthentications because the
226 available IDs have no bearing on any filesystem. But the conservative
227 approach is to reauthenticate all the io ports so that no state anywhere
228 reflects that our whole ID set differs from what we've set it to. */
229 __mutex_lock (&_hurd_id.lock);
230 err = _hurd_check_ids ();
231 if (err == 0 && ((_hurd_id.aux.nuids >= 2 && _hurd_id.gen.nuids >= 1
232 && _hurd_id.aux.uids[1] != _hurd_id.gen.uids[0])
233 || (_hurd_id.aux.ngids >= 2 && _hurd_id.gen.ngids >= 1
234 && _hurd_id.aux.gids[1] != _hurd_id.gen.gids[0])))
235 {
236 /* We have euid != svuid or egid != svgid. POSIX.1 says that exec
237 sets svuid = euid and svgid = egid. So we must get a new auth
238 port and reauthenticate everything with it. We'll pass the new
239 ports in file_exec_paths instead of our own ports. */
240
241 auth_t newauth;
242
243 _hurd_id.aux.uids[1] = _hurd_id.gen.uids[0];
244 _hurd_id.aux.gids[1] = _hurd_id.gen.gids[0];
245 _hurd_id.valid = 0;
246 if (_hurd_id.rid_auth != MACH_PORT_NULL)
247 {
248 __mach_port_deallocate (__mach_task_self (), _hurd_id.rid_auth);
249 _hurd_id.rid_auth = MACH_PORT_NULL;
250 }
251
252 err = __auth_makeauth (ports[INIT_PORT_AUTH],
253 NULL, MACH_MSG_TYPE_COPY_SEND, 0,
254 _hurd_id.gen.uids, _hurd_id.gen.nuids,
255 _hurd_id.aux.uids, _hurd_id.aux.nuids,
256 _hurd_id.gen.gids, _hurd_id.gen.ngids,
257 _hurd_id.aux.gids, _hurd_id.aux.ngids,
258 &newauth);
259 if (err == 0)
260 {
261 /* Now we have to reauthenticate the ports with this new ID.
262 */
263
264 inline error_t reauth_io (io_t port, io_t *newport)
265 {
266 mach_port_t ref = __mach_reply_port ();
267 *newport = MACH_PORT_NULL;
268 error_t err = __io_reauthenticate (port,
269 ref, MACH_MSG_TYPE_MAKE_SEND);
270 if (!err)
271 err = __auth_user_authenticate (newauth,
272 ref, MACH_MSG_TYPE_MAKE_SEND,
273 newport);
274 __mach_port_destroy (__mach_task_self (), ref);
275 return err;
276 }
277 inline void reauth_port (unsigned int idx)
278 {
279 io_t newport;
280 err = reauth_io (ports[idx], &newport) ?: err;
281 if (pdp)
282 *pdp++ = ports[idx]; /* XXX presumed still in _hurd_ports */
283 free_port (idx);
284 ports[idx] = newport;
285 }
286
287 if (pdp)
288 *pdp++ = ports[INIT_PORT_AUTH];
289 free_port (INIT_PORT_AUTH);
290 ports[INIT_PORT_AUTH] = newauth;
291
292 reauth_port (INIT_PORT_CRDIR);
293 reauth_port (INIT_PORT_CWDIR);
294
295 if (!err)
296 {
297 /* Now we'll reauthenticate each file descriptor. */
298 if (ulink_dtable == NULL)
299 {
300 assert (dtable == _hurd_init_dtable);
301 dtable = __alloca (dtablesize * sizeof (dtable[0]));
302 for (i = 0; i < dtablesize; ++i)
303 if (_hurd_init_dtable[i] != MACH_PORT_NULL)
304 {
305 if (pdp)
306 *pdp++ = _hurd_init_dtable[i];
307 err = reauth_io (_hurd_init_dtable[i], &dtable[i]);
308 if (err)
309 {
310 while (++i < dtablesize)
311 dtable[i] = MACH_PORT_NULL;
312 break;
313 }
314 }
315 else
316 dtable[i] = MACH_PORT_NULL;
317 }
318 else
319 {
320 if (pdp)
321 {
322 /* Ask to deallocate all the old fd ports,
323 since we will have new ones in DTABLE. */
324 memcpy (pdp, dtable, dtablesize * sizeof pdp[0]);
325 pdp += dtablesize;
326 }
327 for (i = 0; i < dtablesize; ++i)
328 if (dtable[i] != MACH_PORT_NULL)
329 {
330 io_t newport;
331 err = reauth_io (dtable[i], &newport);
332 _hurd_port_free (dtable_cells[i], &ulink_dtable[i],
333 dtable[i]);
334 dtable[i] = newport;
335 if (err)
336 {
337 while (++i < dtablesize)
338 _hurd_port_free (dtable_cells[i],
339 &ulink_dtable[i], dtable[i]);
340 break;
341 }
342 }
343 ulink_dtable = NULL;
344 dtable_cells = NULL;
345 }
346 }
347 }
348
349 reauth = 1;
350 }
351 __mutex_unlock (&_hurd_id.lock);
352
353 /* The information is all set up now. Try to exec the file. */
354 if (!err)
355 {
356 int flags;
357
358 if (pdp)
359 {
360 /* Request the exec server to deallocate some ports from us if
361 the exec succeeds. The init ports and descriptor ports will
362 arrive in the new program's exec_startup message. If we
363 failed to deallocate them, the new program would have
364 duplicate user references for them. But we cannot deallocate
365 them ourselves, because we must still have them after a failed
366 exec call. */
367
368 for (i = 0; i < _hurd_nports; ++i)
369 *pdp++ = ports[i];
370 for (i = 0; i < dtablesize; ++i)
371 *pdp++ = dtable[i];
372 }
373
374 flags = 0;
375 #ifdef EXEC_SIGTRAP
376 /* PTRACE_TRACEME sets all bits in _hurdsig_traced, which is
377 propagated through exec by INIT_TRACEMASK, so this checks if
378 PTRACE_TRACEME has been called in this process in any of its
379 current or prior lives. */
380 if (__sigismember (&_hurdsig_traced, SIGKILL))
381 flags |= EXEC_SIGTRAP;
382 #endif
383 err = __file_exec_paths (file, task, flags,
384 path ? path : "",
385 abspath ? abspath : "",
386 args, argslen, env, envlen,
387 dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
388 ports, MACH_MSG_TYPE_COPY_SEND,
389 _hurd_nports,
390 ints, INIT_INT_MAX,
391 please_dealloc, pdp - please_dealloc,
392 &_hurd_msgport,
393 task == __mach_task_self () ? 1 : 0);
394 /* Fall back for backwards compatibility. This can just be removed
395 when __file_exec goes away. */
396 if (err == MIG_BAD_ID)
397 err = __file_exec (file, task, flags,
398 args, argslen, env, envlen,
399 dtable, MACH_MSG_TYPE_COPY_SEND, dtablesize,
400 ports, MACH_MSG_TYPE_COPY_SEND, _hurd_nports,
401 ints, INIT_INT_MAX,
402 please_dealloc, pdp - please_dealloc,
403 &_hurd_msgport,
404 task == __mach_task_self () ? 1 : 0);
405 }
406
407 /* Release references to the standard ports. */
408 for (i = 0; i < _hurd_nports; ++i)
409 if ((i == INIT_PORT_PROC && task != __mach_task_self ())
410 || (reauth && (i == INIT_PORT_AUTH
411 || i == INIT_PORT_CRDIR || i == INIT_PORT_CWDIR)))
412 __mach_port_deallocate (__mach_task_self (), ports[i]);
413 else
414 free_port (i);
415
416 /* Release references to the file descriptor ports. */
417 if (ulink_dtable != NULL)
418 {
419 for (i = 0; i < dtablesize; ++i)
420 if (dtable[i] != MACH_PORT_NULL)
421 _hurd_port_free (dtable_cells[i], &ulink_dtable[i], dtable[i]);
422 }
423 else if (dtable && dtable != _hurd_init_dtable)
424 for (i = 0; i < dtablesize; ++i)
425 __mach_port_deallocate (__mach_task_self (), dtable[i]);
426
427 /* Release lock on the file descriptor table. */
428 __mutex_unlock (&_hurd_dtable_lock);
429
430 /* Safe to let signals happen now. */
431 _hurd_critical_section_unlock (ss);
432
433 outargs:
434 free (args);
435 outenv:
436 free (env);
437 return err;
438 }
439 libc_hidden_def (_hurd_exec_paths)