1 /* Copyright (C) 1991-2021 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 <https://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.
34 Deprecated: use _hurd_exec_paths instead. */
36 _hurd_exec (task_t task
, file_t file
,
37 char *const argv
[], char *const envp
[])
39 return _hurd_exec_paths (task
, file
, NULL
, NULL
, argv
, envp
);
42 link_warning (_hurd_exec
,
43 "_hurd_exec is deprecated, use _hurd_exec_paths instead");
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
53 _hurd_exec_paths (task_t task
, file_t file
,
54 const char *path
, const char *abspath
,
55 char *const argv
[], char *const envp
[])
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
)
65 _hurd_port_free (&_hurd_ports
[i
], &ulink_ports
[i
], ports
[i
]);
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
;
75 /* XXX needs to be hurdmalloc XXX */
77 args
= NULL
, argslen
= 0;
78 else if (err
= __argz_create (argv
, &args
, &argslen
))
81 env
= NULL
, envlen
= 0;
82 else if (err
= __argz_create (envp
, &env
, &envlen
))
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 ())
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
])))
99 ports
[i
] = _hurd_port_get (&_hurd_ports
[i
], &ulink_ports
[i
]);
102 /* Load up the ints to give the new program. */
103 for (i
= 0; i
< INIT_INT_MAX
; ++i
)
107 ints
[i
] = _hurd_umask
;
112 case INIT_SIGPENDING
:
113 /* We will set these all below. */
117 ints
[i
] = _hurdsig_traced
;
124 ss
= _hurd_self_sigstate ();
126 assert (! __spin_lock_locked (&ss
->critical_section_lock
));
127 __spin_lock (&ss
->critical_section_lock
);
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
);
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
146 _hurd_sigstate_unlock (ss
);
148 /* Pack up the descriptor table to give the new program. */
149 __mutex_lock (&_hurd_dtable_lock
);
151 dtablesize
= _hurd_dtable
? _hurd_dtablesize
: _hurd_init_dtablesize
;
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
));
163 please_dealloc
= NULL
;
164 pdp
= please_dealloc
;
166 if (_hurd_dtable
!= NULL
)
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
)
173 struct hurd_fd
*const d
= _hurd_dtable
[i
];
176 dtable
[i
] = MACH_PORT_NULL
;
179 __spin_lock (&d
->port
.lock
);
180 if (d
->flags
& FD_CLOEXEC
)
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
)
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
;
192 __spin_unlock (&d
->port
.lock
);
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
;
209 dtable
= _hurd_init_dtable
;
214 /* Prune trailing null ports from the descriptor table. */
215 while (dtablesize
> 0 && dtable
[dtablesize
- 1] == MACH_PORT_NULL
)
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])))
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. */
243 _hurd_id
.aux
.uids
[1] = _hurd_id
.gen
.uids
[0];
244 _hurd_id
.aux
.gids
[1] = _hurd_id
.gen
.gids
[0];
246 if (_hurd_id
.rid_auth
!= MACH_PORT_NULL
)
248 __mach_port_deallocate (__mach_task_self (), _hurd_id
.rid_auth
);
249 _hurd_id
.rid_auth
= MACH_PORT_NULL
;
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
,
261 /* Now we have to reauthenticate the ports with this new ID.
264 inline error_t
reauth_io (io_t port
, io_t
*newport
)
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
);
271 err
= __auth_user_authenticate (newauth
,
272 ref
, MACH_MSG_TYPE_MAKE_SEND
,
274 __mach_port_destroy (__mach_task_self (), ref
);
277 inline void reauth_port (unsigned int idx
)
280 err
= reauth_io (ports
[idx
], &newport
) ?: err
;
282 *pdp
++ = ports
[idx
]; /* XXX presumed still in _hurd_ports */
284 ports
[idx
] = newport
;
288 *pdp
++ = ports
[INIT_PORT_AUTH
];
289 free_port (INIT_PORT_AUTH
);
290 ports
[INIT_PORT_AUTH
] = newauth
;
292 reauth_port (INIT_PORT_CRDIR
);
293 reauth_port (INIT_PORT_CWDIR
);
297 /* Now we'll reauthenticate each file descriptor. */
298 if (ulink_dtable
== NULL
)
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
)
306 *pdp
++ = _hurd_init_dtable
[i
];
307 err
= reauth_io (_hurd_init_dtable
[i
], &dtable
[i
]);
310 while (++i
< dtablesize
)
311 dtable
[i
] = MACH_PORT_NULL
;
316 dtable
[i
] = MACH_PORT_NULL
;
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]);
327 for (i
= 0; i
< dtablesize
; ++i
)
328 if (dtable
[i
] != MACH_PORT_NULL
)
331 err
= reauth_io (dtable
[i
], &newport
);
332 _hurd_port_free (dtable_cells
[i
], &ulink_dtable
[i
],
337 while (++i
< dtablesize
)
338 _hurd_port_free (dtable_cells
[i
],
339 &ulink_dtable
[i
], dtable
[i
]);
351 __mutex_unlock (&_hurd_id
.lock
);
353 /* The information is all set up now. Try to exec the file. */
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
368 for (i
= 0; i
< _hurd_nports
; ++i
)
370 for (i
= 0; i
< dtablesize
; ++i
)
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
;
383 err
= __file_exec_paths (file
, task
, flags
,
385 abspath
? abspath
: "",
386 args
, argslen
, env
, envlen
,
387 dtable
, MACH_MSG_TYPE_COPY_SEND
, dtablesize
,
388 ports
, MACH_MSG_TYPE_COPY_SEND
,
391 please_dealloc
, pdp
- please_dealloc
,
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
,
402 please_dealloc
, pdp
- please_dealloc
,
404 task
== __mach_task_self () ? 1 : 0);
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
]);
416 /* Release references to the file descriptor ports. */
417 if (ulink_dtable
!= NULL
)
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
]);
423 else if (dtable
&& dtable
!= _hurd_init_dtable
)
424 for (i
= 0; i
< dtablesize
; ++i
)
425 __mach_port_deallocate (__mach_task_self (), dtable
[i
]);
427 /* Release lock on the file descriptor table. */
428 __mutex_unlock (&_hurd_dtable_lock
);
430 /* Safe to let signals happen now. */
431 _hurd_critical_section_unlock (ss
);
439 libc_hidden_def (_hurd_exec_paths
)