xref: /freebsd/sys/compat/linux/linux_emul.c (revision 023b850b62481007dd3bf305026e12845a4c189c)
1ad2056f2SAlexander Leidinger /*-
2*023b850bSEd Maste  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37f2d13d6SPedro F. Giffuni  *
4ad2056f2SAlexander Leidinger  * Copyright (c) 2006 Roman Divacky
581338031SDmitry Chagin  * Copyright (c) 2013 Dmitry Chagin
6ad2056f2SAlexander Leidinger  * All rights reserved.
7ad2056f2SAlexander Leidinger  *
8ad2056f2SAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
9ad2056f2SAlexander Leidinger  * modification, are permitted provided that the following conditions
10ad2056f2SAlexander Leidinger  * are met:
11ad2056f2SAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
12*023b850bSEd Maste  *    notice, this list of conditions and the following disclaimer.
13ad2056f2SAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
14ad2056f2SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
15ad2056f2SAlexander Leidinger  *    documentation and/or other materials provided with the distribution.
16ad2056f2SAlexander Leidinger  *
17*023b850bSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*023b850bSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*023b850bSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*023b850bSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*023b850bSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*023b850bSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*023b850bSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*023b850bSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*023b850bSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*023b850bSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*023b850bSEd Maste  * SUCH DAMAGE.
28ad2056f2SAlexander Leidinger  */
29ad2056f2SAlexander Leidinger 
30ad2056f2SAlexander Leidinger #include <sys/cdefs.h>
31ad2056f2SAlexander Leidinger __FBSDID("$FreeBSD$");
32ad2056f2SAlexander Leidinger 
33ad2056f2SAlexander Leidinger #include <sys/param.h>
34ad2056f2SAlexander Leidinger #include <sys/systm.h>
35ad2056f2SAlexander Leidinger #include <sys/imgact.h>
36b4bb5154SKonstantin Belousov #include <sys/kernel.h>
3781338031SDmitry Chagin #include <sys/ktr.h>
38ad2056f2SAlexander Leidinger #include <sys/lock.h>
39ad2056f2SAlexander Leidinger #include <sys/malloc.h>
40ad2056f2SAlexander Leidinger #include <sys/mutex.h>
41ad2056f2SAlexander Leidinger #include <sys/sx.h>
42ad2056f2SAlexander Leidinger #include <sys/proc.h>
43ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h>
4495353459SDimitry Andric #include <sys/sysent.h>
45ad2056f2SAlexander Leidinger 
464732e446SRoman Divacky #include <compat/linux/linux_emul.h>
47d825ce0aSJohn Baldwin #include <compat/linux/linux_misc.h>
4823e8912cSDmitry Chagin #include <compat/linux/linux_persona.h>
4981338031SDmitry Chagin #include <compat/linux/linux_util.h>
504732e446SRoman Divacky 
5119e252baSAlexander Leidinger 
5281338031SDmitry Chagin /*
53bc273677SDmitry Chagin  * This returns reference to the thread emuldata entry (if found)
5481338031SDmitry Chagin  *
5581338031SDmitry Chagin  * Hold PROC_LOCK when referencing emuldata from other threads.
5681338031SDmitry Chagin  */
57ad2056f2SAlexander Leidinger struct linux_emuldata *
5881338031SDmitry Chagin em_find(struct thread *td)
59ad2056f2SAlexander Leidinger {
60ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
61ad2056f2SAlexander Leidinger 
6281338031SDmitry Chagin 	em = td->td_emuldata;
63ad2056f2SAlexander Leidinger 
64ad2056f2SAlexander Leidinger 	return (em);
65ad2056f2SAlexander Leidinger }
66ad2056f2SAlexander Leidinger 
67bc273677SDmitry Chagin /*
68bc273677SDmitry Chagin  * This returns reference to the proc pemuldata entry (if found)
69bc273677SDmitry Chagin  *
70bc273677SDmitry Chagin  * Hold PROC_LOCK when referencing proc pemuldata from other threads.
71bc273677SDmitry Chagin  * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
72bc273677SDmitry Chagin  */
73bc273677SDmitry Chagin struct linux_pemuldata *
74bc273677SDmitry Chagin pem_find(struct proc *p)
75bc273677SDmitry Chagin {
76bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
77bc273677SDmitry Chagin 
78bc273677SDmitry Chagin 	pem = p->p_emuldata;
79bc273677SDmitry Chagin 
80bc273677SDmitry Chagin 	return (pem);
81bc273677SDmitry Chagin }
82bc273677SDmitry Chagin 
8381338031SDmitry Chagin void
8481338031SDmitry Chagin linux_proc_init(struct thread *td, struct thread *newtd, int flags)
85ad2056f2SAlexander Leidinger {
8681338031SDmitry Chagin 	struct linux_emuldata *em;
87bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
88e16fe1c7SDmitry Chagin 	struct epoll_emuldata *emd;
8968cf0367SDmitry Chagin 	struct proc *p;
9019e252baSAlexander Leidinger 
9181338031SDmitry Chagin 	if (newtd != NULL) {
9268cf0367SDmitry Chagin 		p = newtd->td_proc;
9368cf0367SDmitry Chagin 
9481338031SDmitry Chagin 		/* non-exec call */
9581338031SDmitry Chagin 		em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
96a4e3bad7SJung-uk Kim 		if (flags & LINUX_CLONE_THREAD) {
97e16fe1c7SDmitry Chagin 			LINUX_CTR1(proc_init, "thread newtd(%d)",
98e16fe1c7SDmitry Chagin 			    newtd->td_tid);
99e16fe1c7SDmitry Chagin 
10081338031SDmitry Chagin 			em->em_tid = newtd->td_tid;
10181338031SDmitry Chagin 		} else {
10268cf0367SDmitry Chagin 			LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid);
10319e252baSAlexander Leidinger 
10468cf0367SDmitry Chagin 			em->em_tid = p->p_pid;
105bc273677SDmitry Chagin 
106e0d3ea8cSDmitry Chagin 			pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO);
107bc273677SDmitry Chagin 			sx_init(&pem->pem_sx, "lpemlk");
10868cf0367SDmitry Chagin 			p->p_emuldata = pem;
109ad2056f2SAlexander Leidinger 		}
11081338031SDmitry Chagin 		newtd->td_emuldata = em;
111ad2056f2SAlexander Leidinger 	} else {
11268cf0367SDmitry Chagin 		p = td->td_proc;
11368cf0367SDmitry Chagin 
11419e252baSAlexander Leidinger 		/* exec */
11568cf0367SDmitry Chagin 		LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid);
11619e252baSAlexander Leidinger 
117ad2056f2SAlexander Leidinger 		/* lookup the old one */
11881338031SDmitry Chagin 		em = em_find(td);
119ad2056f2SAlexander Leidinger 		KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
12081338031SDmitry Chagin 
12168cf0367SDmitry Chagin 		em->em_tid = p->p_pid;
12297cfa5c8SDmitry Chagin 		em->flags = 0;
12397cfa5c8SDmitry Chagin 		em->pdeath_signal = 0;
12497cfa5c8SDmitry Chagin 		em->robust_futexes = NULL;
12597cfa5c8SDmitry Chagin 		em->child_clear_tid = NULL;
12697cfa5c8SDmitry Chagin 		em->child_set_tid = NULL;
127e16fe1c7SDmitry Chagin 
128e16fe1c7SDmitry Chagin 		 /* epoll should be destroyed in a case of exec. */
12968cf0367SDmitry Chagin 		pem = pem_find(p);
130e16fe1c7SDmitry Chagin 		KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n"));
13123e8912cSDmitry Chagin 		pem->persona = 0;
132e16fe1c7SDmitry Chagin 		if (pem->epoll != NULL) {
133e16fe1c7SDmitry Chagin 			emd = pem->epoll;
134e16fe1c7SDmitry Chagin 			pem->epoll = NULL;
135e16fe1c7SDmitry Chagin 			free(emd, M_EPOLL);
136e16fe1c7SDmitry Chagin 		}
137ad2056f2SAlexander Leidinger 	}
138ad2056f2SAlexander Leidinger 
139ad2056f2SAlexander Leidinger }
140ad2056f2SAlexander Leidinger 
141ad2056f2SAlexander Leidinger void
142ad2056f2SAlexander Leidinger linux_proc_exit(void *arg __unused, struct proc *p)
143ad2056f2SAlexander Leidinger {
144bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
145e16fe1c7SDmitry Chagin 	struct epoll_emuldata *emd;
14681338031SDmitry Chagin 	struct thread *td = curthread;
147ad2056f2SAlexander Leidinger 
148bc273677SDmitry Chagin 	if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX))
149bc273677SDmitry Chagin 		return;
150bc273677SDmitry Chagin 
1517d96520bSDmitry Chagin 	LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p",
1527d96520bSDmitry Chagin 	    td->td_tid, p->p_pid, p);
1537d96520bSDmitry Chagin 
154bc273677SDmitry Chagin 	pem = pem_find(p);
155bc273677SDmitry Chagin 	if (pem == NULL)
156bc273677SDmitry Chagin 		return;
15781338031SDmitry Chagin 	(p->p_sysent->sv_thread_detach)(td);
158bc273677SDmitry Chagin 
159bc273677SDmitry Chagin 	p->p_emuldata = NULL;
160bc273677SDmitry Chagin 
161e16fe1c7SDmitry Chagin 	if (pem->epoll != NULL) {
162e16fe1c7SDmitry Chagin 		emd = pem->epoll;
163e16fe1c7SDmitry Chagin 		pem->epoll = NULL;
164e16fe1c7SDmitry Chagin 		free(emd, M_EPOLL);
165e16fe1c7SDmitry Chagin 	}
166e16fe1c7SDmitry Chagin 
167bc273677SDmitry Chagin 	sx_destroy(&pem->pem_sx);
168e0d3ea8cSDmitry Chagin 	free(pem, M_LINUX);
169e8b8b834SAlexander Leidinger }
170ad2056f2SAlexander Leidinger 
17181338031SDmitry Chagin int
17281338031SDmitry Chagin linux_common_execve(struct thread *td, struct image_args *eargs)
17381338031SDmitry Chagin {
174bc273677SDmitry Chagin 	struct linux_pemuldata *pem;
175e16fe1c7SDmitry Chagin 	struct epoll_emuldata *emd;
176d707582fSDmitry Chagin 	struct vmspace *oldvmspace;
17781338031SDmitry Chagin 	struct linux_emuldata *em;
17881338031SDmitry Chagin 	struct proc *p;
17981338031SDmitry Chagin 	int error;
180ad2056f2SAlexander Leidinger 
18181338031SDmitry Chagin 	p = td->td_proc;
182ad2056f2SAlexander Leidinger 
183d707582fSDmitry Chagin 	error = pre_execve(td, &oldvmspace);
184d707582fSDmitry Chagin 	if (error != 0)
185d707582fSDmitry Chagin 		return (error);
18681338031SDmitry Chagin 
18781338031SDmitry Chagin 	error = kern_execve(td, eargs, NULL);
188d707582fSDmitry Chagin 	post_execve(td, error, oldvmspace);
189814629ddSEd Schouten 	if (error != EJUSTRETURN)
19081338031SDmitry Chagin 		return (error);
19181338031SDmitry Chagin 
19281338031SDmitry Chagin 	/*
19381338031SDmitry Chagin 	 * In a case of transition from Linux binary execing to
194eae594f7SEd Maste 	 * FreeBSD binary we destroy Linux emuldata thread & proc entries.
19581338031SDmitry Chagin 	 */
19681338031SDmitry Chagin 	if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
19781338031SDmitry Chagin 		PROC_LOCK(p);
19881338031SDmitry Chagin 		em = em_find(td);
199bc273677SDmitry Chagin 		KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
20081338031SDmitry Chagin 		td->td_emuldata = NULL;
201bc273677SDmitry Chagin 
202bc273677SDmitry Chagin 		pem = pem_find(p);
203bc273677SDmitry Chagin 		KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
204bc273677SDmitry Chagin 		p->p_emuldata = NULL;
20581338031SDmitry Chagin 		PROC_UNLOCK(p);
20681338031SDmitry Chagin 
207e16fe1c7SDmitry Chagin 		if (pem->epoll != NULL) {
208e16fe1c7SDmitry Chagin 			emd = pem->epoll;
209e16fe1c7SDmitry Chagin 			pem->epoll = NULL;
210e16fe1c7SDmitry Chagin 			free(emd, M_EPOLL);
211e16fe1c7SDmitry Chagin 		}
212e16fe1c7SDmitry Chagin 
21381338031SDmitry Chagin 		free(em, M_TEMP);
214e0d3ea8cSDmitry Chagin 		free(pem, M_LINUX);
21581338031SDmitry Chagin 	}
216814629ddSEd Schouten 	return (EJUSTRETURN);
21781338031SDmitry Chagin }
21881338031SDmitry Chagin 
21981338031SDmitry Chagin void
22081338031SDmitry Chagin linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
22181338031SDmitry Chagin {
22281338031SDmitry Chagin 	struct thread *td = curthread;
22332ba368bSDmitry Chagin 	struct thread *othertd;
22423e8912cSDmitry Chagin #if defined(__amd64__)
22523e8912cSDmitry Chagin 	struct linux_pemuldata *pem;
22623e8912cSDmitry Chagin #endif
22732ba368bSDmitry Chagin 
22832ba368bSDmitry Chagin 	/*
229eae594f7SEd Maste 	 * In a case of execing from Linux binary properly detach
23032ba368bSDmitry Chagin 	 * other threads from the user space.
23132ba368bSDmitry Chagin 	 */
23232ba368bSDmitry Chagin 	if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) {
23332ba368bSDmitry Chagin 		FOREACH_THREAD_IN_PROC(p, othertd) {
23432ba368bSDmitry Chagin 			if (td != othertd)
23532ba368bSDmitry Chagin 				(p->p_sysent->sv_thread_detach)(othertd);
23632ba368bSDmitry Chagin 		}
23732ba368bSDmitry Chagin 	}
23881338031SDmitry Chagin 
23981338031SDmitry Chagin 	/*
240eae594f7SEd Maste 	 * In a case of execing to Linux binary we create Linux
24181338031SDmitry Chagin 	 * emuldata thread entry.
24281338031SDmitry Chagin 	 */
24381338031SDmitry Chagin 	if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
24481338031SDmitry Chagin 	    SV_ABI_LINUX)) {
245e16fe1c7SDmitry Chagin 
24681338031SDmitry Chagin 		if (SV_PROC_ABI(p) == SV_ABI_LINUX)
24781338031SDmitry Chagin 			linux_proc_init(td, NULL, 0);
24881338031SDmitry Chagin 		else
24981338031SDmitry Chagin 			linux_proc_init(td, td, 0);
25023e8912cSDmitry Chagin #if defined(__amd64__)
25123e8912cSDmitry Chagin 		/*
25223e8912cSDmitry Chagin 		 * An IA32 executable which has executable stack will have the
25323e8912cSDmitry Chagin 		 * READ_IMPLIES_EXEC personality flag set automatically.
25423e8912cSDmitry Chagin 		 */
25523e8912cSDmitry Chagin 		if (SV_PROC_FLAG(td->td_proc, SV_ILP32) &&
25623e8912cSDmitry Chagin 		    imgp->stack_prot & VM_PROT_EXECUTE) {
25723e8912cSDmitry Chagin 			pem = pem_find(p);
25823e8912cSDmitry Chagin 			pem->persona |= LINUX_READ_IMPLIES_EXEC;
25923e8912cSDmitry Chagin 		}
26023e8912cSDmitry Chagin #endif
26181338031SDmitry Chagin 	}
26281338031SDmitry Chagin }
26381338031SDmitry Chagin 
26481338031SDmitry Chagin void
26581338031SDmitry Chagin linux_thread_dtor(void *arg __unused, struct thread *td)
266ad2056f2SAlexander Leidinger {
267ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
268ad2056f2SAlexander Leidinger 
26981338031SDmitry Chagin 	em = em_find(td);
27081338031SDmitry Chagin 	if (em == NULL)
27181338031SDmitry Chagin 		return;
27281338031SDmitry Chagin 	td->td_emuldata = NULL;
273ad2056f2SAlexander Leidinger 
2747d96520bSDmitry Chagin 	LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid);
275ad2056f2SAlexander Leidinger 
27681338031SDmitry Chagin 	free(em, M_TEMP);
277ad2056f2SAlexander Leidinger }
278ad2056f2SAlexander Leidinger 
279ad2056f2SAlexander Leidinger void
280e5d81ef1SDmitry Chagin linux_schedtail(struct thread *td)
281ad2056f2SAlexander Leidinger {
282ad2056f2SAlexander Leidinger 	struct linux_emuldata *em;
283e5d81ef1SDmitry Chagin 	struct proc *p;
284ad2056f2SAlexander Leidinger 	int error = 0;
285ad2056f2SAlexander Leidinger 	int *child_set_tid;
286ad2056f2SAlexander Leidinger 
287e5d81ef1SDmitry Chagin 	p = td->td_proc;
288e5d81ef1SDmitry Chagin 
28981338031SDmitry Chagin 	em = em_find(td);
290bc273677SDmitry Chagin 	KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
291ad2056f2SAlexander Leidinger 	child_set_tid = em->child_set_tid;
292ad2056f2SAlexander Leidinger 
29319e252baSAlexander Leidinger 	if (child_set_tid != NULL) {
294e0327ddbSDmitry Chagin 		error = copyout(&em->em_tid, child_set_tid,
29581338031SDmitry Chagin 		    sizeof(em->em_tid));
2967d96520bSDmitry Chagin 		LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d",
29781338031SDmitry Chagin 		    td->td_tid, child_set_tid, em->em_tid, error);
29881338031SDmitry Chagin 	} else
2997d96520bSDmitry Chagin 		LINUX_CTR1(schedtail, "thread(%d)", em->em_tid);
300bb63fddeSAlexander Leidinger }
301