xref: /freebsd/sys/compat/linux/linux_emul.c (revision ec513841b3ac59ce581ffb5eb859926555f6834b)
1 /*-
2  * Copyright (c) 2006 Roman Divacky
3  * Copyright (c) 2013 Dmitry Chagin
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer
11  *    in this position and unchanged.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include "opt_compat.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/imgact.h>
38 #include <sys/kernel.h>
39 #include <sys/ktr.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/mutex.h>
43 #include <sys/sdt.h>
44 #include <sys/sx.h>
45 #include <sys/proc.h>
46 #include <sys/syscallsubr.h>
47 #include <sys/sysent.h>
48 #include <sys/sysproto.h>
49 #include <sys/unistd.h>
50 
51 #ifdef COMPAT_LINUX32
52 #include <machine/../linux32/linux.h>
53 #include <machine/../linux32/linux32_proto.h>
54 #else
55 #include <machine/../linux/linux.h>
56 #include <machine/../linux/linux_proto.h>
57 #endif
58 
59 #include <compat/linux/linux_dtrace.h>
60 #include <compat/linux/linux_emul.h>
61 #include <compat/linux/linux_futex.h>
62 #include <compat/linux/linux_misc.h>
63 #include <compat/linux/linux_util.h>
64 
65 /**
66  * Special DTrace provider for the linuxulator.
67  *
68  * In this file we define the provider for the entire linuxulator. All
69  * modules (= files of the linuxulator) use it.
70  *
71  * We define a different name depending on the emulated bitsize, see
72  * ../../<ARCH>/linux{,32}/linux.h, e.g.:
73  *      native bitsize          = linuxulator
74  *      amd64, 32bit emulation  = linuxulator32
75  */
76 LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE);
77 
78 /**
79  * DTrace probes in this module.
80  */
81 LIN_SDT_PROBE_DEFINE1(emul, em_find, entry, "struct thread *");
82 LIN_SDT_PROBE_DEFINE0(emul, em_find, return);
83 LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *",
84     "struct thread *", "int");
85 LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread);
86 LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork);
87 LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec);
88 LIN_SDT_PROBE_DEFINE0(emul, proc_init, return);
89 LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *");
90 LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, entry, "struct thread *");
91 LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, futex_failed);
92 LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, child_clear_tid_error, "int");
93 LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, return);
94 LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *",
95     "struct image_params *");
96 LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return);
97 LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry);
98 LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int");
99 LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return);
100 LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *");
101 LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return);
102 
103 /*
104  * This returns reference to the emuldata entry (if found)
105  *
106  * Hold PROC_LOCK when referencing emuldata from other threads.
107  */
108 struct linux_emuldata *
109 em_find(struct thread *td)
110 {
111 	struct linux_emuldata *em;
112 
113 	LIN_SDT_PROBE1(emul, em_find, entry, td);
114 
115 	em = td->td_emuldata;
116 
117 	LIN_SDT_PROBE1(emul, em_find, return, em);
118 
119 	return (em);
120 }
121 
122 void
123 linux_proc_init(struct thread *td, struct thread *newtd, int flags)
124 {
125 	struct linux_emuldata *em;
126 
127 	LIN_SDT_PROBE3(emul, proc_init, entry, td, newtd, flags);
128 
129 	if (newtd != NULL) {
130 		/* non-exec call */
131 		em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
132 		em->pdeath_signal = 0;
133 		em->flags = 0;
134 		em->robust_futexes = NULL;
135 		if (flags & LINUX_CLONE_THREAD) {
136 			LIN_SDT_PROBE0(emul, proc_init, create_thread);
137 
138 			em->em_tid = newtd->td_tid;
139 		} else {
140 			LIN_SDT_PROBE0(emul, proc_init, fork);
141 
142 			em->em_tid = newtd->td_proc->p_pid;
143 		}
144 		newtd->td_emuldata = em;
145 	} else {
146 		/* exec */
147 		LIN_SDT_PROBE0(emul, proc_init, exec);
148 
149 		/* lookup the old one */
150 		em = em_find(td);
151 		KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n"));
152 
153 		em->em_tid = td->td_proc->p_pid;
154 	}
155 
156 	em->child_clear_tid = NULL;
157 	em->child_set_tid = NULL;
158 
159 	LIN_SDT_PROBE0(emul, proc_init, return);
160 }
161 
162 void
163 linux_proc_exit(void *arg __unused, struct proc *p)
164 {
165 	struct thread *td = curthread;
166 
167 	if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) {
168 		LIN_SDT_PROBE1(emul, proc_exit, entry, p);
169 		(p->p_sysent->sv_thread_detach)(td);
170 	}
171 }
172 
173 int
174 linux_common_execve(struct thread *td, struct image_args *eargs)
175 {
176 	struct linux_emuldata *em;
177 	struct proc *p;
178 	int error;
179 
180 	p = td->td_proc;
181 
182 	/*
183 	 * Unlike FreeBSD abort all other threads before
184 	 * proceeding exec.
185 	 */
186 	PROC_LOCK(p);
187 	/* See exit1() comments. */
188 	thread_suspend_check(0);
189 	while (p->p_flag & P_HADTHREADS) {
190 		if (!thread_single(p, SINGLE_EXIT))
191 			break;
192 		thread_suspend_check(0);
193 	}
194 	PROC_UNLOCK(p);
195 
196 	error = kern_execve(td, eargs, NULL);
197 	if (error != 0)
198 		return (error);
199 
200 	/*
201 	 * In a case of transition from Linux binary execing to
202 	 * FreeBSD binary we destroy linux emuldata thread entry.
203 	 */
204 	if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
205 		PROC_LOCK(p);
206 		em = em_find(td);
207 		KASSERT(em != NULL, ("proc_exec: emuldata not found.\n"));
208 		td->td_emuldata = NULL;
209 		PROC_UNLOCK(p);
210 
211 		free(em, M_TEMP);
212 	}
213 	return (0);
214 }
215 
216 void
217 linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp)
218 {
219 	struct thread *td = curthread;
220 
221 	/*
222 	 * In a case of execing to linux binary we create linux
223 	 * emuldata thread entry.
224 	 */
225 	if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) ==
226 	    SV_ABI_LINUX)) {
227 		LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp);
228 		if (SV_PROC_ABI(p) == SV_ABI_LINUX)
229 			linux_proc_init(td, NULL, 0);
230 		else
231 			linux_proc_init(td, td, 0);
232 
233 		LIN_SDT_PROBE0(emul, proc_exec, return);
234 	}
235 }
236 
237 void
238 linux_thread_detach(struct thread *td)
239 {
240 	struct linux_sys_futex_args cup;
241 	struct linux_emuldata *em;
242 	int *child_clear_tid;
243 	int null = 0;
244 	int error;
245 
246 	LIN_SDT_PROBE1(emul, linux_thread_detach, entry, td);
247 
248 	em = em_find(td);
249 	KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
250 
251 	LINUX_CTR1(exit, "thread detach(%d)", em->em_tid);
252 
253 	release_futexes(td, em);
254 
255 	child_clear_tid = em->child_clear_tid;
256 
257 	if (child_clear_tid != NULL) {
258 
259 		LINUX_CTR2(exit, "thread detach(%d) %p",
260 		    em->em_tid, child_clear_tid);
261 
262 		error = copyout(&null, child_clear_tid, sizeof(null));
263 		if (error) {
264 			LIN_SDT_PROBE1(emul, linux_thread_detach,
265 			    child_clear_tid_error, error);
266 
267 			LIN_SDT_PROBE0(emul, linux_thread_detach, return);
268 			return;
269 		}
270 
271 		cup.uaddr = child_clear_tid;
272 		cup.op = LINUX_FUTEX_WAKE;
273 		cup.val = 1;		/* wake one */
274 		cup.timeout = NULL;
275 		cup.uaddr2 = NULL;
276 		cup.val3 = 0;
277 		error = linux_sys_futex(td, &cup);
278 		/*
279 		 * this cannot happen at the moment and if this happens it
280 		 * probably means there is a user space bug
281 		 */
282 		if (error) {
283 			LIN_SDT_PROBE0(emul, linux_thread_detach, futex_failed);
284 			printf(LMSG("futex stuff in thread_detach failed.\n"));
285 		}
286 	}
287 
288 	LIN_SDT_PROBE0(emul, linux_thread_detach, return);
289 }
290 
291 void
292 linux_thread_dtor(void *arg __unused, struct thread *td)
293 {
294 	struct linux_emuldata *em;
295 
296 	em = em_find(td);
297 	if (em == NULL)
298 		return;
299 	td->td_emuldata = NULL;
300 
301 	LINUX_CTR1(exit, "thread dtor(%d)", em->em_tid);
302 
303 	free(em, M_TEMP);
304 }
305 
306 void
307 linux_schedtail(struct thread *td)
308 {
309 	struct linux_emuldata *em;
310 	struct proc *p;
311 	int error = 0;
312 	int *child_set_tid;
313 
314 	LIN_SDT_PROBE1(emul, linux_schedtail, entry, td);
315 
316 	p = td->td_proc;
317 
318 	em = em_find(td);
319 	KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n"));
320 	child_set_tid = em->child_set_tid;
321 
322 	if (child_set_tid != NULL) {
323 		error = copyout(&em->em_tid, (int *)child_set_tid,
324 		    sizeof(em->em_tid));
325 		LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d",
326 		    td->td_tid, child_set_tid, em->em_tid, error);
327 
328 		if (error != 0) {
329 			LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error,
330 			    error);
331 		}
332 	} else
333 		LINUX_CTR1(clone, "schedtail(%d)", em->em_tid);
334 
335 	LIN_SDT_PROBE0(emul, linux_schedtail, return);
336 }
337 
338 int
339 linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
340 {
341 	struct linux_emuldata *em;
342 
343 	LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr);
344 
345 	em = em_find(td);
346 	KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
347 
348 	em->child_clear_tid = args->tidptr;
349 
350 	td->td_retval[0] = em->em_tid;
351 
352 	LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
353 	    em->em_tid, args->tidptr, td->td_retval[0]);
354 
355 	LIN_SDT_PROBE0(emul, linux_set_tid_address, return);
356 	return (0);
357 }
358