1 /* Copyright (C) 1991-2018 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.
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 __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
);
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
145 __spin_unlock (&ss
->lock
);
147 /* Pack up the descriptor table to give the new program. */
148 __mutex_lock (&_hurd_dtable_lock
);
150 dtablesize
= _hurd_dtable
? _hurd_dtablesize
: _hurd_init_dtablesize
;
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
));
162 please_dealloc
= NULL
;
163 pdp
= please_dealloc
;
165 if (_hurd_dtable
!= NULL
)
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
)
172 struct hurd_fd
*const d
= _hurd_dtable
[i
];
175 dtable
[i
] = MACH_PORT_NULL
;
178 __spin_lock (&d
->port
.lock
);
179 if (d
->flags
& FD_CLOEXEC
)
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
)
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
;
191 __spin_unlock (&d
->port
.lock
);
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
;
208 dtable
= _hurd_init_dtable
;
213 /* Prune trailing null ports from the descriptor table. */
214 while (dtablesize
> 0 && dtable
[dtablesize
- 1] == MACH_PORT_NULL
)
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])))
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. */
242 _hurd_id
.aux
.uids
[1] = _hurd_id
.gen
.uids
[0];
243 _hurd_id
.aux
.gids
[1] = _hurd_id
.gen
.gids
[0];
245 if (_hurd_id
.rid_auth
!= MACH_PORT_NULL
)
247 __mach_port_deallocate (__mach_task_self (), _hurd_id
.rid_auth
);
248 _hurd_id
.rid_auth
= MACH_PORT_NULL
;
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
,
260 /* Now we have to reauthenticate the ports with this new ID.
263 inline error_t
reauth_io (io_t port
, io_t
*newport
)
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
);
270 err
= __auth_user_authenticate (newauth
,
271 ref
, MACH_MSG_TYPE_MAKE_SEND
,
273 __mach_port_destroy (__mach_task_self (), ref
);
276 inline void reauth_port (unsigned int idx
)
279 err
= reauth_io (ports
[idx
], &newport
) ?: err
;
281 *pdp
++ = ports
[idx
]; /* XXX presumed still in _hurd_ports */
283 ports
[idx
] = newport
;
287 *pdp
++ = ports
[INIT_PORT_AUTH
];
288 free_port (INIT_PORT_AUTH
);
289 ports
[INIT_PORT_AUTH
] = newauth
;
291 reauth_port (INIT_PORT_CRDIR
);
292 reauth_port (INIT_PORT_CWDIR
);
296 /* Now we'll reauthenticate each file descriptor. */
297 if (ulink_dtable
== NULL
)
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
)
305 *pdp
++ = _hurd_init_dtable
[i
];
306 err
= reauth_io (_hurd_init_dtable
[i
], &dtable
[i
]);
309 while (++i
< dtablesize
)
310 dtable
[i
] = MACH_PORT_NULL
;
315 dtable
[i
] = MACH_PORT_NULL
;
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]);
326 for (i
= 0; i
< dtablesize
; ++i
)
327 if (dtable
[i
] != MACH_PORT_NULL
)
330 err
= reauth_io (dtable
[i
], &newport
);
331 _hurd_port_free (dtable_cells
[i
], &ulink_dtable
[i
],
336 while (++i
< dtablesize
)
337 _hurd_port_free (dtable_cells
[i
],
338 &ulink_dtable
[i
], dtable
[i
]);
350 __mutex_unlock (&_hurd_id
.lock
);
352 /* The information is all set up now. Try to exec the file. */
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
367 for (i
= 0; i
< _hurd_nports
; ++i
)
369 for (i
= 0; i
< dtablesize
; ++i
)
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
;
382 err
= __file_exec_paths (file
, task
, flags
,
384 abspath
? abspath
: "",
385 args
, argslen
, env
, envlen
,
386 dtable
, MACH_MSG_TYPE_COPY_SEND
, dtablesize
,
387 ports
, MACH_MSG_TYPE_COPY_SEND
,
390 please_dealloc
, pdp
- please_dealloc
,
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
,
401 please_dealloc
, pdp
- please_dealloc
,
403 task
== __mach_task_self () ? 1 : 0);
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
]);
415 /* Release references to the file descriptor ports. */
416 if (ulink_dtable
!= NULL
)
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
]);
422 else if (dtable
&& dtable
!= _hurd_init_dtable
)
423 for (i
= 0; i
< dtablesize
; ++i
)
424 __mach_port_deallocate (__mach_task_self (), dtable
[i
]);
426 /* Release lock on the file descriptor table. */
427 __mutex_unlock (&_hurd_dtable_lock
);
429 /* Safe to let signals happen now. */
430 _hurd_critical_section_unlock (ss
);