Fix execution of linux binary from multithreaded non-Linux process.

If multithreaded non-Linux process execs Linux binary, then non-Linux
threads different from the one that execing are cleared by
single-threading at boundary, and then terminating them in
post_execve(). Since at that time the process is already switched to
linux ABI, linuxolator is involved in the thread clearing on boundary,
but cannot find the emul data.

Handle it by pre-creating emuldata for all threads in the execing process.

Also remove a code in linux_proc_exec() handler that cleared emul data
for other threads when execing from multithreaded Linux process. It is
excessive.

PR:	247020
Reported by:	Martin FIlla <freebsd@sysctl.cz>
Reported by:	Henrique L. Amorim, Independent Security Researcher
Reported by:	Rodrigo Rubira Branco (BSDaemon), Amazon Web Services
Reviewed by:	markj
Tested by:	trasz
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D25293
This commit is contained in:
Konstantin Belousov 2020-06-18 20:49:56 +00:00
parent b32fb2a4ea
commit 8a15ac8378
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=362342

View File

@ -291,22 +291,13 @@ linux_common_execve(struct thread *td, struct image_args *eargs)
void
linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
{
struct thread *td = curthread;
struct thread *td;
struct thread *othertd;
#if defined(__amd64__)
struct linux_pemuldata *pem;
#endif
/*
* In a case of execing from Linux binary properly detach
* other threads from the user space.
*/
if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) {
FOREACH_THREAD_IN_PROC(p, othertd) {
if (td != othertd)
(p->p_sysent->sv_thread_detach)(othertd);
}
}
td = curthread;
/*
* In a case of execing to Linux binary we create Linux
@ -314,11 +305,32 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
*/
if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
SV_ABI_LINUX)) {
if (SV_PROC_ABI(p) == SV_ABI_LINUX)
if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
/*
* Process already was under Linuxolator
* before exec. Update emuldata to reflect
* single-threaded cleaned state after exec.
*/
linux_proc_init(td, NULL, 0);
else
} else {
/*
* We are switching the process to Linux emulator.
*/
linux_proc_init(td, td, 0);
/*
* Create a transient td_emuldata for all suspended
* threads, so that p->p_sysent->sv_thread_detach() ==
* linux_thread_detach() can find expected but unused
* emuldata.
*/
FOREACH_THREAD_IN_PROC(td->td_proc, othertd) {
if (othertd != td) {
linux_proc_init(td, othertd,
LINUX_CLONE_THREAD);
}
}
}
#if defined(__amd64__)
/*
* An IA32 executable which has executable stack will have the