1161304Snetchild/*-
2161304Snetchild * Copyright (c) 2006 Roman Divacky
3293493Sdchagin * Copyright (c) 2013 Dmitry Chagin
4161304Snetchild * All rights reserved.
5161304Snetchild *
6161304Snetchild * Redistribution and use in source and binary forms, with or without
7161304Snetchild * modification, are permitted provided that the following conditions
8161304Snetchild * are met:
9161304Snetchild * 1. Redistributions of source code must retain the above copyright
10161304Snetchild *    notice, this list of conditions and the following disclaimer
11161304Snetchild *    in this position and unchanged.
12161304Snetchild * 2. Redistributions in binary form must reproduce the above copyright
13161304Snetchild *    notice, this list of conditions and the following disclaimer in the
14161304Snetchild *    documentation and/or other materials provided with the distribution.
15161304Snetchild * 3. The name of the author may not be used to endorse or promote products
16161304Snetchild *    derived from this software without specific prior written permission
17161304Snetchild *
18161304Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19161304Snetchild * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20161304Snetchild * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21161304Snetchild * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22161304Snetchild * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23161304Snetchild * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24161304Snetchild * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25161304Snetchild * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26161304Snetchild * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27161304Snetchild * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28161304Snetchild */
29161304Snetchild
30161304Snetchild#include <sys/cdefs.h>
31161304Snetchild__FBSDID("$FreeBSD$");
32161304Snetchild
33161304Snetchild#include <sys/param.h>
34161304Snetchild#include <sys/systm.h>
35161304Snetchild#include <sys/imgact.h>
36166420Skib#include <sys/kernel.h>
37293493Sdchagin#include <sys/ktr.h>
38161304Snetchild#include <sys/lock.h>
39161304Snetchild#include <sys/malloc.h>
40161304Snetchild#include <sys/mutex.h>
41161304Snetchild#include <sys/sx.h>
42161304Snetchild#include <sys/proc.h>
43161304Snetchild#include <sys/syscallsubr.h>
44215706Sdim#include <sys/sysent.h>
45161304Snetchild
46178976Srdivacky#include <compat/linux/linux_emul.h>
47246085Sjhb#include <compat/linux/linux_misc.h>
48302962Sdchagin#include <compat/linux/linux_persona.h>
49293493Sdchagin#include <compat/linux/linux_util.h>
50178976Srdivacky
51235063Snetchild
52293493Sdchagin/*
53293528Sdchagin * This returns reference to the thread emuldata entry (if found)
54293493Sdchagin *
55293493Sdchagin * Hold PROC_LOCK when referencing emuldata from other threads.
56293493Sdchagin */
57161304Snetchildstruct linux_emuldata *
58293493Sdchaginem_find(struct thread *td)
59161304Snetchild{
60161304Snetchild	struct linux_emuldata *em;
61161304Snetchild
62293493Sdchagin	em = td->td_emuldata;
63161304Snetchild
64161304Snetchild	return (em);
65161304Snetchild}
66161304Snetchild
67293528Sdchagin/*
68293528Sdchagin * This returns reference to the proc pemuldata entry (if found)
69293528Sdchagin *
70293528Sdchagin * Hold PROC_LOCK when referencing proc pemuldata from other threads.
71293528Sdchagin * Hold LINUX_PEM_LOCK wher referencing pemuldata members.
72293528Sdchagin */
73293528Sdchaginstruct linux_pemuldata *
74293528Sdchaginpem_find(struct proc *p)
75293528Sdchagin{
76293528Sdchagin	struct linux_pemuldata *pem;
77293528Sdchagin
78293528Sdchagin	pem = p->p_emuldata;
79293528Sdchagin
80293528Sdchagin	return (pem);
81293528Sdchagin}
82293528Sdchagin
83293493Sdchaginvoid
84293493Sdchaginlinux_proc_init(struct thread *td, struct thread *newtd, int flags)
85161304Snetchild{
86293493Sdchagin	struct linux_emuldata *em;
87293528Sdchagin	struct linux_pemuldata *pem;
88293546Sdchagin	struct epoll_emuldata *emd;
89293559Sdchagin	struct proc *p;
90161304Snetchild
91293493Sdchagin	if (newtd != NULL) {
92293559Sdchagin		p = newtd->td_proc;
93293559Sdchagin
94293493Sdchagin		/* non-exec call */
95293493Sdchagin		em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
96167157Sjkim		if (flags & LINUX_CLONE_THREAD) {
97293546Sdchagin			LINUX_CTR1(proc_init, "thread newtd(%d)",
98293546Sdchagin			    newtd->td_tid);
99293546Sdchagin
100293493Sdchagin			em->em_tid = newtd->td_tid;
101161304Snetchild		} else {
102293559Sdchagin			LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid);
103235063Snetchild
104293559Sdchagin			em->em_tid = p->p_pid;
105293528Sdchagin
106293532Sdchagin			pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO);
107293528Sdchagin			sx_init(&pem->pem_sx, "lpemlk");
108293559Sdchagin			p->p_emuldata = pem;
109161304Snetchild		}
110293493Sdchagin		newtd->td_emuldata = em;
111161304Snetchild	} else {
112293559Sdchagin		p = td->td_proc;
113293559Sdchagin
114235063Snetchild		/* exec */
115293559Sdchagin		LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid);
116235063Snetchild
117161304Snetchild		/* lookup the old one */
118293493Sdchagin		em = em_find(td);
119161304Snetchild		KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
120293493Sdchagin
121293559Sdchagin		em->em_tid = p->p_pid;
122293558Sdchagin		em->flags = 0;
123293558Sdchagin		em->pdeath_signal = 0;
124293558Sdchagin		em->robust_futexes = NULL;
125293558Sdchagin		em->child_clear_tid = NULL;
126293558Sdchagin		em->child_set_tid = NULL;
127293546Sdchagin
128293546Sdchagin		 /* epoll should be destroyed in a case of exec. */
129293559Sdchagin		pem = pem_find(p);
130293546Sdchagin		KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n"));
131302962Sdchagin		pem->persona = 0;
132293546Sdchagin		if (pem->epoll != NULL) {
133293546Sdchagin			emd = pem->epoll;
134293546Sdchagin			pem->epoll = NULL;
135293546Sdchagin			free(emd, M_EPOLL);
136293546Sdchagin		}
137161304Snetchild	}
138161304Snetchild
139293493Sdchagin}
140293493Sdchagin
141293493Sdchaginvoid
142293493Sdchaginlinux_proc_exit(void *arg __unused, struct proc *p)
143293493Sdchagin{
144293528Sdchagin	struct linux_pemuldata *pem;
145293546Sdchagin	struct epoll_emuldata *emd;
146293493Sdchagin	struct thread *td = curthread;
147293493Sdchagin
148293528Sdchagin	if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX))
149293528Sdchagin		return;
150293528Sdchagin
151293560Sdchagin	LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p",
152293560Sdchagin	    td->td_tid, p->p_pid, p);
153293560Sdchagin
154293528Sdchagin	pem = pem_find(p);
155293528Sdchagin	if (pem == NULL)
156293528Sdchagin		return;
157293528Sdchagin	(p->p_sysent->sv_thread_detach)(td);
158293528Sdchagin
159293528Sdchagin	p->p_emuldata = NULL;
160293528Sdchagin
161293546Sdchagin	if (pem->epoll != NULL) {
162293546Sdchagin		emd = pem->epoll;
163293546Sdchagin		pem->epoll = NULL;
164293546Sdchagin		free(emd, M_EPOLL);
165293546Sdchagin	}
166293546Sdchagin
167293528Sdchagin	sx_destroy(&pem->pem_sx);
168293532Sdchagin	free(pem, M_LINUX);
169293493Sdchagin}
170293493Sdchagin
171293493Sdchaginint
172293493Sdchaginlinux_common_execve(struct thread *td, struct image_args *eargs)
173293493Sdchagin{
174293528Sdchagin	struct linux_pemuldata *pem;
175293546Sdchagin	struct epoll_emuldata *emd;
176293600Sdchagin	struct vmspace *oldvmspace;
177293493Sdchagin	struct linux_emuldata *em;
178293493Sdchagin	struct proc *p;
179293493Sdchagin	int error;
180293493Sdchagin
181293493Sdchagin	p = td->td_proc;
182293493Sdchagin
183293600Sdchagin	error = pre_execve(td, &oldvmspace);
184293600Sdchagin	if (error != 0)
185293600Sdchagin		return (error);
186235063Snetchild
187293493Sdchagin	error = kern_execve(td, eargs, NULL);
188293600Sdchagin	post_execve(td, error, oldvmspace);
189293493Sdchagin	if (error != 0)
190293493Sdchagin		return (error);
191161304Snetchild
192293493Sdchagin	/*
193293493Sdchagin	 * In a case of transition from Linux binary execing to
194293528Sdchagin	 * FreeBSD binary we destroy linux emuldata thread & proc entries.
195293493Sdchagin	 */
196293493Sdchagin	if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
197293493Sdchagin		PROC_LOCK(p);
198293493Sdchagin		em = em_find(td);
199293528Sdchagin		KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
200293493Sdchagin		td->td_emuldata = NULL;
201293528Sdchagin
202293528Sdchagin		pem = pem_find(p);
203293528Sdchagin		KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n"));
204293528Sdchagin		p->p_emuldata = NULL;
205162184Snetchild		PROC_UNLOCK(p);
206161304Snetchild
207293546Sdchagin		if (pem->epoll != NULL) {
208293546Sdchagin			emd = pem->epoll;
209293546Sdchagin			pem->epoll = NULL;
210293546Sdchagin			free(emd, M_EPOLL);
211293546Sdchagin		}
212293546Sdchagin
213293493Sdchagin		free(em, M_TEMP);
214293532Sdchagin		free(pem, M_LINUX);
215293493Sdchagin	}
216165688Snetchild	return (0);
217161304Snetchild}
218161304Snetchild
219293493Sdchaginvoid
220293493Sdchaginlinux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
221293493Sdchagin{
222293493Sdchagin	struct thread *td = curthread;
223293603Sdchagin	struct thread *othertd;
224302962Sdchagin#if defined(__amd64__)
225302962Sdchagin	struct linux_pemuldata *pem;
226302962Sdchagin#endif
227293493Sdchagin
228293493Sdchagin	/*
229293603Sdchagin	 * In a case of execing from linux binary properly detach
230293603Sdchagin	 * other threads from the user space.
231293603Sdchagin	 */
232293603Sdchagin	if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) {
233293603Sdchagin		FOREACH_THREAD_IN_PROC(p, othertd) {
234293603Sdchagin			if (td != othertd)
235293603Sdchagin				(p->p_sysent->sv_thread_detach)(othertd);
236293603Sdchagin		}
237293603Sdchagin	}
238293603Sdchagin
239293603Sdchagin	/*
240293493Sdchagin	 * In a case of execing to linux binary we create linux
241293493Sdchagin	 * emuldata thread entry.
242293493Sdchagin	 */
243293493Sdchagin	if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
244293493Sdchagin	    SV_ABI_LINUX)) {
245293546Sdchagin
246293493Sdchagin		if (SV_PROC_ABI(p) == SV_ABI_LINUX)
247293493Sdchagin			linux_proc_init(td, NULL, 0);
248293493Sdchagin		else
249293493Sdchagin			linux_proc_init(td, td, 0);
250302962Sdchagin#if defined(__amd64__)
251302962Sdchagin		/*
252302962Sdchagin		 * An IA32 executable which has executable stack will have the
253302962Sdchagin		 * READ_IMPLIES_EXEC personality flag set automatically.
254302962Sdchagin		 */
255302962Sdchagin		if (SV_PROC_FLAG(td->td_proc, SV_ILP32) &&
256302962Sdchagin		    imgp->stack_prot & VM_PROT_EXECUTE) {
257302962Sdchagin			pem = pem_find(p);
258302962Sdchagin			pem->persona |= LINUX_READ_IMPLIES_EXEC;
259302962Sdchagin		}
260302962Sdchagin#endif
261293493Sdchagin	}
262293493Sdchagin}
263293493Sdchagin
264161304Snetchildvoid
265293493Sdchaginlinux_thread_dtor(void *arg __unused, struct thread *td)
266161304Snetchild{
267293493Sdchagin	struct linux_emuldata *em;
268161304Snetchild
269293493Sdchagin	em = em_find(td);
270293493Sdchagin	if (em == NULL)
271293493Sdchagin		return;
272293493Sdchagin	td->td_emuldata = NULL;
273161304Snetchild
274293560Sdchagin	LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid);
275165688Snetchild
276293493Sdchagin	free(em, M_TEMP);
277161304Snetchild}
278161304Snetchild
279161304Snetchildvoid
280219405Sdchaginlinux_schedtail(struct thread *td)
281161304Snetchild{
282161304Snetchild	struct linux_emuldata *em;
283219405Sdchagin	struct proc *p;
284161304Snetchild	int error = 0;
285161304Snetchild	int *child_set_tid;
286161304Snetchild
287219405Sdchagin	p = td->td_proc;
288219405Sdchagin
289293493Sdchagin	em = em_find(td);
290293528Sdchagin	KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n"));
291161304Snetchild	child_set_tid = em->child_set_tid;
292161304Snetchild
293235063Snetchild	if (child_set_tid != NULL) {
294293557Sdchagin		error = copyout(&em->em_tid, child_set_tid,
295293493Sdchagin		    sizeof(em->em_tid));
296293560Sdchagin		LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d",
297293493Sdchagin		    td->td_tid, child_set_tid, em->em_tid, error);
298293493Sdchagin	} else
299293560Sdchagin		LINUX_CTR1(schedtail, "thread(%d)", em->em_tid);
300161304Snetchild}
301