xref: /freebsd-14.2/sys/compat/linux/linux_fork.c (revision bc273677)
1 /*-
2  * Copyright (c) 2004 Tim J. Robbins
3  * Copyright (c) 2002 Doug Rabson
4  * Copyright (c) 2000 Marcel Moolenaar
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include "opt_compat.h"
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/imgact.h>
37 #include <sys/ktr.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/proc.h>
41 #include <sys/racct.h>
42 #include <sys/sched.h>
43 #include <sys/syscallsubr.h>
44 #include <sys/sx.h>
45 #include <sys/unistd.h>
46 #include <sys/wait.h>
47 
48 #include <vm/vm.h>
49 #include <vm/pmap.h>
50 #include <vm/vm_map.h>
51 
52 #ifdef COMPAT_LINUX32
53 #include <machine/../linux32/linux.h>
54 #include <machine/../linux32/linux32_proto.h>
55 #else
56 #include <machine/../linux/linux.h>
57 #include <machine/../linux/linux_proto.h>
58 #endif
59 #include <compat/linux/linux_signal.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 int
66 linux_fork(struct thread *td, struct linux_fork_args *args)
67 {
68 	int error;
69 	struct proc *p2;
70 	struct thread *td2;
71 
72 #ifdef DEBUG
73 	if (ldebug(fork))
74 		printf(ARGS(fork, ""));
75 #endif
76 
77 	if ((error = fork1(td, RFFDG | RFPROC | RFSTOPPED, 0, &p2, NULL, 0))
78 	    != 0)
79 		return (error);
80 
81 	td2 = FIRST_THREAD_IN_PROC(p2);
82 
83 	linux_proc_init(td, td2, 0);
84 
85 	td->td_retval[0] = p2->p_pid;
86 
87 	/*
88 	 * Make this runnable after we are finished with it.
89 	 */
90 	thread_lock(td2);
91 	TD_SET_CAN_RUN(td2);
92 	sched_add(td2, SRQ_BORING);
93 	thread_unlock(td2);
94 
95 	return (0);
96 }
97 
98 int
99 linux_vfork(struct thread *td, struct linux_vfork_args *args)
100 {
101 	int error;
102 	struct proc *p2;
103 	struct thread *td2;
104 
105 #ifdef DEBUG
106 	if (ldebug(vfork))
107 		printf(ARGS(vfork, ""));
108 #endif
109 
110 	/* Exclude RFPPWAIT */
111 	if ((error = fork1(td, RFFDG | RFPROC | RFMEM | RFSTOPPED, 0, &p2,
112 	    NULL, 0)) != 0)
113 		return (error);
114 
115 
116 	td2 = FIRST_THREAD_IN_PROC(p2);
117 
118 	linux_proc_init(td, td2, 0);
119 
120 	PROC_LOCK(p2);
121 	p2->p_flag |= P_PPWAIT;
122 	PROC_UNLOCK(p2);
123 
124    	td->td_retval[0] = p2->p_pid;
125 
126 	/*
127 	 * Make this runnable after we are finished with it.
128 	 */
129 	thread_lock(td2);
130 	TD_SET_CAN_RUN(td2);
131 	sched_add(td2, SRQ_BORING);
132 	thread_unlock(td2);
133 
134 	/* wait for the children to exit, ie. emulate vfork */
135 	PROC_LOCK(p2);
136 	while (p2->p_flag & P_PPWAIT)
137 		cv_wait(&p2->p_pwait, &p2->p_mtx);
138 	PROC_UNLOCK(p2);
139 
140 	return (0);
141 }
142 
143 static int
144 linux_clone_proc(struct thread *td, struct linux_clone_args *args)
145 {
146 	int error, ff = RFPROC | RFSTOPPED;
147 	struct proc *p2;
148 	struct thread *td2;
149 	int exit_signal;
150 	struct linux_emuldata *em;
151 
152 #ifdef DEBUG
153 	if (ldebug(clone)) {
154 		printf(ARGS(clone, "flags %x, stack %p, parent tid: %p, "
155 		    "child tid: %p"), (unsigned)args->flags,
156 		    args->stack, args->parent_tidptr, args->child_tidptr);
157 	}
158 #endif
159 
160 	exit_signal = args->flags & 0x000000ff;
161 	if (LINUX_SIG_VALID(exit_signal)) {
162 		if (exit_signal <= LINUX_SIGTBLSZ)
163 			exit_signal =
164 			    linux_to_bsd_signal[_SIG_IDX(exit_signal)];
165 	} else if (exit_signal != 0)
166 		return (EINVAL);
167 
168 	if (args->flags & LINUX_CLONE_VM)
169 		ff |= RFMEM;
170 	if (args->flags & LINUX_CLONE_SIGHAND)
171 		ff |= RFSIGSHARE;
172 	/*
173 	 * XXX: In Linux, sharing of fs info (chroot/cwd/umask)
174 	 * and open files is independant.  In FreeBSD, its in one
175 	 * structure but in reality it does not cause any problems
176 	 * because both of these flags are usually set together.
177 	 */
178 	if (!(args->flags & (LINUX_CLONE_FILES | LINUX_CLONE_FS)))
179 		ff |= RFFDG;
180 
181 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
182 		if (args->parent_tidptr == NULL)
183 			return (EINVAL);
184 
185 	error = fork1(td, ff, 0, &p2, NULL, 0);
186 	if (error)
187 		return (error);
188 
189 	td2 = FIRST_THREAD_IN_PROC(p2);
190 
191 	/* create the emuldata */
192 	linux_proc_init(td, td2, args->flags);
193 
194 	em = em_find(td2);
195 	KASSERT(em != NULL, ("clone_proc: emuldata not found.\n"));
196 
197 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
198 		em->child_set_tid = args->child_tidptr;
199 	else
200 	   	em->child_set_tid = NULL;
201 
202 	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
203 		em->child_clear_tid = args->child_tidptr;
204 	else
205 	   	em->child_clear_tid = NULL;
206 
207 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
208 		error = copyout(&p2->p_pid, args->parent_tidptr,
209 		    sizeof(p2->p_pid));
210 		if (error)
211 			printf(LMSG("copyout failed!"));
212 	}
213 
214 	PROC_LOCK(p2);
215 	p2->p_sigparent = exit_signal;
216 	PROC_UNLOCK(p2);
217 	/*
218 	 * In a case of stack = NULL, we are supposed to COW calling process
219 	 * stack. This is what normal fork() does, so we just keep tf_rsp arg
220 	 * intact.
221 	 */
222 	linux_set_upcall_kse(td2, PTROUT(args->stack));
223 
224 	if (args->flags & LINUX_CLONE_SETTLS)
225 		linux_set_cloned_tls(td2, args->tls);
226 
227 #ifdef DEBUG
228 	if (ldebug(clone))
229 		printf(LMSG("clone: successful rfork to %d, "
230 		    "stack %p sig = %d"), (int)p2->p_pid, args->stack,
231 		    exit_signal);
232 #endif
233 
234 	if (args->flags & LINUX_CLONE_VFORK) {
235 	   	PROC_LOCK(p2);
236 	   	p2->p_flag |= P_PPWAIT;
237 	   	PROC_UNLOCK(p2);
238 	}
239 
240 	/*
241 	 * Make this runnable after we are finished with it.
242 	 */
243 	thread_lock(td2);
244 	TD_SET_CAN_RUN(td2);
245 	sched_add(td2, SRQ_BORING);
246 	thread_unlock(td2);
247 
248 	td->td_retval[0] = p2->p_pid;
249 
250 	if (args->flags & LINUX_CLONE_VFORK) {
251 		/* wait for the children to exit, ie. emulate vfork */
252 		PROC_LOCK(p2);
253 		while (p2->p_flag & P_PPWAIT)
254 			cv_wait(&p2->p_pwait, &p2->p_mtx);
255 		PROC_UNLOCK(p2);
256 	}
257 
258 	return (0);
259 }
260 
261 static int
262 linux_clone_thread(struct thread *td, struct linux_clone_args *args)
263 {
264 	struct linux_emuldata *em;
265 	struct thread *newtd;
266 	struct proc *p;
267 	int error;
268 
269 #ifdef DEBUG
270 	if (ldebug(clone)) {
271 		printf(ARGS(clone, "thread: flags %x, stack %p, parent tid: %p, "
272 		    "child tid: %p"), (unsigned)args->flags,
273 		    args->stack, args->parent_tidptr, args->child_tidptr);
274 	}
275 #endif
276 
277 	LINUX_CTR4(clone, "thread(%d) flags %x ptid %p ctid %p",
278 	    td->td_tid, (unsigned)args->flags,
279 	    args->parent_tidptr, args->child_tidptr);
280 
281 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
282 		if (args->parent_tidptr == NULL)
283 			return (EINVAL);
284 
285 	/* Threads should be created with own stack */
286 	if (args->stack == NULL)
287 		return (EINVAL);
288 
289 	p = td->td_proc;
290 
291 	/* Initialize our td */
292 	error = kern_thr_alloc(p, 0, &newtd);
293 	if (error)
294 		return (error);
295 
296 	cpu_set_upcall(newtd, td);
297 
298 	bzero(&newtd->td_startzero,
299 	    __rangeof(struct thread, td_startzero, td_endzero));
300 	bcopy(&td->td_startcopy, &newtd->td_startcopy,
301 	    __rangeof(struct thread, td_startcopy, td_endcopy));
302 
303 	newtd->td_proc = p;
304 	newtd->td_ucred = crhold(td->td_ucred);
305 
306 	/* create the emuldata */
307 	linux_proc_init(td, newtd, args->flags);
308 
309 	em = em_find(newtd);
310 	KASSERT(em != NULL, ("clone_thread: emuldata not found.\n"));
311 
312 	if (args->flags & LINUX_CLONE_SETTLS)
313 		linux_set_cloned_tls(newtd, args->tls);
314 
315 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
316 		em->child_set_tid = args->child_tidptr;
317 	else
318 	   	em->child_set_tid = NULL;
319 
320 	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
321 		em->child_clear_tid = args->child_tidptr;
322 	else
323 	   	em->child_clear_tid = NULL;
324 
325 	cpu_thread_clean(newtd);
326 
327 	linux_set_upcall_kse(newtd, PTROUT(args->stack));
328 
329 	PROC_LOCK(p);
330 	p->p_flag |= P_HADTHREADS;
331 	newtd->td_sigmask = td->td_sigmask;
332 	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
333 
334 	if (args->flags & LINUX_CLONE_PARENT)
335 		thread_link(newtd, p->p_pptr);
336 	else
337 		thread_link(newtd, p);
338 
339 	thread_lock(td);
340 	/* let the scheduler know about these things. */
341 	sched_fork_thread(td, newtd);
342 	thread_unlock(td);
343 	if (P_SHOULDSTOP(p))
344 		newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
345 	PROC_UNLOCK(p);
346 
347 	tidhash_add(newtd);
348 
349 #ifdef DEBUG
350 	if (ldebug(clone))
351 		printf(ARGS(clone, "successful clone to %d, stack %p"),
352 		(int)newtd->td_tid, args->stack);
353 #endif
354 
355 	LINUX_CTR2(clone, "thread(%d) successful clone to %d",
356 	    td->td_tid, newtd->td_tid);
357 
358 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
359 		error = copyout(&newtd->td_tid, args->parent_tidptr,
360 		    sizeof(newtd->td_tid));
361 		if (error)
362 			printf(LMSG("clone_thread: copyout failed!"));
363 	}
364 
365 	/*
366 	 * Make this runnable after we are finished with it.
367 	 */
368 	thread_lock(newtd);
369 	TD_SET_CAN_RUN(newtd);
370 	sched_add(newtd, SRQ_BORING);
371 	thread_unlock(newtd);
372 
373 	td->td_retval[0] = newtd->td_tid;
374 
375 	return (0);
376 }
377 
378 int
379 linux_clone(struct thread *td, struct linux_clone_args *args)
380 {
381 
382 	if (args->flags & LINUX_CLONE_THREAD)
383 		return (linux_clone_thread(td, args));
384 	else
385 		return (linux_clone_proc(td, args));
386 }
387 
388 int
389 linux_exit(struct thread *td, struct linux_exit_args *args)
390 {
391 	struct linux_emuldata *em;
392 
393 	em = em_find(td);
394 	KASSERT(em != NULL, ("exit: emuldata not found.\n"));
395 
396 	LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval);
397 
398 	linux_thread_detach(td);
399 
400 	/*
401 	 * XXX. When the last two threads of a process
402 	 * exit via pthread_exit() try thr_exit() first.
403 	 */
404 	kern_thr_exit(td);
405 	exit1(td, W_EXITCODE(args->rval, 0));
406 		/* NOTREACHED */
407 }
408 
409 int
410 linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
411 {
412 	struct linux_emuldata *em;
413 
414 	em = em_find(td);
415 	KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
416 
417 	em->child_clear_tid = args->tidptr;
418 
419 	td->td_retval[0] = em->em_tid;
420 
421 	LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
422 	    em->em_tid, args->tidptr, td->td_retval[0]);
423 
424 	return (0);
425 }
426 
427 void
428 linux_thread_detach(struct thread *td)
429 {
430 	struct linux_sys_futex_args cup;
431 	struct linux_emuldata *em;
432 	int *child_clear_tid;
433 	int error;
434 
435 	em = em_find(td);
436 	KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
437 
438 	LINUX_CTR1(exit, "thread detach(%d)", em->em_tid);
439 
440 	release_futexes(td, em);
441 
442 	child_clear_tid = em->child_clear_tid;
443 
444 	if (child_clear_tid != NULL) {
445 
446 		LINUX_CTR2(exit, "thread detach(%d) %p",
447 		    em->em_tid, child_clear_tid);
448 
449 		error = suword32(child_clear_tid, 0);
450 		if (error != 0)
451 			return;
452 
453 		cup.uaddr = child_clear_tid;
454 		cup.op = LINUX_FUTEX_WAKE;
455 		cup.val = 1;		/* wake one */
456 		cup.timeout = NULL;
457 		cup.uaddr2 = NULL;
458 		cup.val3 = 0;
459 		error = linux_sys_futex(td, &cup);
460 		/*
461 		 * this cannot happen at the moment and if this happens it
462 		 * probably means there is a user space bug
463 		 */
464 		if (error != 0)
465 			linux_msg(td, "futex stuff in thread_detach failed.");
466 	}
467 }
468