xref: /freebsd/sys/compat/linux/linux_fork.c (revision 17913b0b6b707568d63559255820f3212cd31cdf)
1222198abSDmitry Chagin /*-
27f2d13d6SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
37f2d13d6SPedro F. Giffuni  *
4222198abSDmitry Chagin  * Copyright (c) 2004 Tim J. Robbins
5222198abSDmitry Chagin  * Copyright (c) 2002 Doug Rabson
6222198abSDmitry Chagin  * Copyright (c) 2000 Marcel Moolenaar
7222198abSDmitry Chagin  * All rights reserved.
8222198abSDmitry Chagin  *
9222198abSDmitry Chagin  * Redistribution and use in source and binary forms, with or without
10222198abSDmitry Chagin  * modification, are permitted provided that the following conditions
11222198abSDmitry Chagin  * are met:
12222198abSDmitry Chagin  * 1. Redistributions of source code must retain the above copyright
13222198abSDmitry Chagin  *    notice, this list of conditions and the following disclaimer
14222198abSDmitry Chagin  *    in this position and unchanged.
15222198abSDmitry Chagin  * 2. Redistributions in binary form must reproduce the above copyright
16222198abSDmitry Chagin  *    notice, this list of conditions and the following disclaimer in the
17222198abSDmitry Chagin  *    documentation and/or other materials provided with the distribution.
18222198abSDmitry Chagin  *
19222198abSDmitry Chagin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20222198abSDmitry Chagin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21222198abSDmitry Chagin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22222198abSDmitry Chagin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23222198abSDmitry Chagin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24222198abSDmitry Chagin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25222198abSDmitry Chagin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26222198abSDmitry Chagin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27222198abSDmitry Chagin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28222198abSDmitry Chagin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29222198abSDmitry Chagin  */
30222198abSDmitry Chagin 
31222198abSDmitry Chagin #include <sys/cdefs.h>
32222198abSDmitry Chagin __FBSDID("$FreeBSD$");
33222198abSDmitry Chagin 
34222198abSDmitry Chagin #include "opt_compat.h"
35222198abSDmitry Chagin 
36222198abSDmitry Chagin #include <sys/param.h>
37222198abSDmitry Chagin #include <sys/systm.h>
38222198abSDmitry Chagin #include <sys/imgact.h>
3981338031SDmitry Chagin #include <sys/ktr.h>
40222198abSDmitry Chagin #include <sys/lock.h>
41222198abSDmitry Chagin #include <sys/mutex.h>
42222198abSDmitry Chagin #include <sys/proc.h>
4331665c1aSKonstantin Belousov #include <sys/ptrace.h>
4481338031SDmitry Chagin #include <sys/racct.h>
45222198abSDmitry Chagin #include <sys/sched.h>
4681338031SDmitry Chagin #include <sys/syscallsubr.h>
47222198abSDmitry Chagin #include <sys/sx.h>
487a718f29SDmitry Chagin #include <sys/umtxvar.h>
49222198abSDmitry Chagin #include <sys/unistd.h>
50161acbb6SDmitry Chagin #include <sys/wait.h>
51222198abSDmitry Chagin 
5281338031SDmitry Chagin #include <vm/vm.h>
5381338031SDmitry Chagin #include <vm/pmap.h>
5481338031SDmitry Chagin #include <vm/vm_map.h>
5581338031SDmitry Chagin 
56222198abSDmitry Chagin #ifdef COMPAT_LINUX32
57222198abSDmitry Chagin #include <machine/../linux32/linux.h>
58222198abSDmitry Chagin #include <machine/../linux32/linux32_proto.h>
59222198abSDmitry Chagin #else
60222198abSDmitry Chagin #include <machine/../linux/linux.h>
61222198abSDmitry Chagin #include <machine/../linux/linux_proto.h>
62222198abSDmitry Chagin #endif
630a4b664aSDmitry Chagin #include <compat/linux/linux.h>
64222198abSDmitry Chagin #include <compat/linux/linux_emul.h>
650a4b664aSDmitry Chagin #include <compat/linux/linux_fork.h>
66bc273677SDmitry Chagin #include <compat/linux/linux_futex.h>
67d825ce0aSJohn Baldwin #include <compat/linux/linux_misc.h>
6881338031SDmitry Chagin #include <compat/linux/linux_util.h>
69222198abSDmitry Chagin 
70931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
71222198abSDmitry Chagin int
72222198abSDmitry Chagin linux_fork(struct thread *td, struct linux_fork_args *args)
73222198abSDmitry Chagin {
7433fd9b9aSMateusz Guzik 	struct fork_req fr;
75222198abSDmitry Chagin 	int error;
76222198abSDmitry Chagin 	struct proc *p2;
77222198abSDmitry Chagin 	struct thread *td2;
78222198abSDmitry Chagin 
7933fd9b9aSMateusz Guzik 	bzero(&fr, sizeof(fr));
8033fd9b9aSMateusz Guzik 	fr.fr_flags = RFFDG | RFPROC | RFSTOPPED;
8133fd9b9aSMateusz Guzik 	fr.fr_procp = &p2;
8233fd9b9aSMateusz Guzik 	if ((error = fork1(td, &fr)) != 0)
83222198abSDmitry Chagin 		return (error);
84222198abSDmitry Chagin 
85222198abSDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p2);
86222198abSDmitry Chagin 
870a4b664aSDmitry Chagin 	linux_proc_init(td, td2, false);
8881338031SDmitry Chagin 
8981338031SDmitry Chagin 	td->td_retval[0] = p2->p_pid;
9081338031SDmitry Chagin 
91222198abSDmitry Chagin 	/*
92222198abSDmitry Chagin 	 * Make this runnable after we are finished with it.
93222198abSDmitry Chagin 	 */
94222198abSDmitry Chagin 	thread_lock(td2);
95222198abSDmitry Chagin 	TD_SET_CAN_RUN(td2);
96222198abSDmitry Chagin 	sched_add(td2, SRQ_BORING);
97222198abSDmitry Chagin 
98222198abSDmitry Chagin 	return (0);
99222198abSDmitry Chagin }
100222198abSDmitry Chagin 
101222198abSDmitry Chagin int
102222198abSDmitry Chagin linux_vfork(struct thread *td, struct linux_vfork_args *args)
103222198abSDmitry Chagin {
10433fd9b9aSMateusz Guzik 	struct fork_req fr;
105222198abSDmitry Chagin 	int error;
106222198abSDmitry Chagin 	struct proc *p2;
107222198abSDmitry Chagin 	struct thread *td2;
108222198abSDmitry Chagin 
10933fd9b9aSMateusz Guzik 	bzero(&fr, sizeof(fr));
11033fd9b9aSMateusz Guzik 	fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED;
11133fd9b9aSMateusz Guzik 	fr.fr_procp = &p2;
11233fd9b9aSMateusz Guzik 	if ((error = fork1(td, &fr)) != 0)
113222198abSDmitry Chagin 		return (error);
114cfa57401SDmitry Chagin 
11581338031SDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p2);
11681338031SDmitry Chagin 
1170a4b664aSDmitry Chagin 	linux_proc_init(td, td2, false);
118222198abSDmitry Chagin 
11981338031SDmitry Chagin 	td->td_retval[0] = p2->p_pid;
120222198abSDmitry Chagin 
121222198abSDmitry Chagin 	/*
122222198abSDmitry Chagin 	 * Make this runnable after we are finished with it.
123222198abSDmitry Chagin 	 */
124222198abSDmitry Chagin 	thread_lock(td2);
125222198abSDmitry Chagin 	TD_SET_CAN_RUN(td2);
126222198abSDmitry Chagin 	sched_add(td2, SRQ_BORING);
127222198abSDmitry Chagin 
128222198abSDmitry Chagin 	return (0);
129222198abSDmitry Chagin }
130931e2a1aSEd Maste #endif
131222198abSDmitry Chagin 
13281338031SDmitry Chagin static int
1330a4b664aSDmitry Chagin linux_clone_proc(struct thread *td, struct l_clone_args *args)
134222198abSDmitry Chagin {
13533fd9b9aSMateusz Guzik 	struct fork_req fr;
136f8f74aaaSConrad Meyer 	int error, ff = RFPROC | RFSTOPPED, f2;
137222198abSDmitry Chagin 	struct proc *p2;
138222198abSDmitry Chagin 	struct thread *td2;
139222198abSDmitry Chagin 	int exit_signal;
140222198abSDmitry Chagin 	struct linux_emuldata *em;
141222198abSDmitry Chagin 
142f8f74aaaSConrad Meyer 	f2 = 0;
1430a4b664aSDmitry Chagin 	if (LINUX_SIG_VALID(args->exit_signal)) {
1440a4b664aSDmitry Chagin 		exit_signal = linux_to_bsd_signal(args->exit_signal);
1450a4b664aSDmitry Chagin 	} else if (args->exit_signal != 0)
146222198abSDmitry Chagin 		return (EINVAL);
1470a4b664aSDmitry Chagin 	else
1480a4b664aSDmitry Chagin 		exit_signal = 0;
149222198abSDmitry Chagin 
150222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_VM)
151222198abSDmitry Chagin 		ff |= RFMEM;
152222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_SIGHAND)
153222198abSDmitry Chagin 		ff |= RFSIGSHARE;
154f8f74aaaSConrad Meyer 	if (args->flags & LINUX_CLONE_FILES) {
155f8f74aaaSConrad Meyer 		if (!(args->flags & LINUX_CLONE_FS))
156f8f74aaaSConrad Meyer 			f2 |= FR2_SHARE_PATHS;
157f8f74aaaSConrad Meyer 	} else {
158222198abSDmitry Chagin 		ff |= RFFDG;
159f8f74aaaSConrad Meyer 		if (args->flags & LINUX_CLONE_FS)
160f8f74aaaSConrad Meyer 			f2 |= FR2_SHARE_PATHS;
161f8f74aaaSConrad Meyer 	}
162222198abSDmitry Chagin 
163222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
1640a4b664aSDmitry Chagin 		if (args->parent_tid == NULL)
165222198abSDmitry Chagin 			return (EINVAL);
166222198abSDmitry Chagin 
167a7306730SBryan Drewery 	if (args->flags & LINUX_CLONE_VFORK)
168a7306730SBryan Drewery 		ff |= RFPPWAIT;
169a7306730SBryan Drewery 
17033fd9b9aSMateusz Guzik 	bzero(&fr, sizeof(fr));
17133fd9b9aSMateusz Guzik 	fr.fr_flags = ff;
172f8f74aaaSConrad Meyer 	fr.fr_flags2 = f2;
17333fd9b9aSMateusz Guzik 	fr.fr_procp = &p2;
17433fd9b9aSMateusz Guzik 	error = fork1(td, &fr);
175222198abSDmitry Chagin 	if (error)
176222198abSDmitry Chagin 		return (error);
177222198abSDmitry Chagin 
17881338031SDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p2);
179222198abSDmitry Chagin 
180222198abSDmitry Chagin 	/* create the emuldata */
1810a4b664aSDmitry Chagin 	linux_proc_init(td, td2, false);
182222198abSDmitry Chagin 
18381338031SDmitry Chagin 	em = em_find(td2);
18481338031SDmitry Chagin 	KASSERT(em != NULL, ("clone_proc: emuldata not found.\n"));
185222198abSDmitry Chagin 
186222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
1870a4b664aSDmitry Chagin 		em->child_set_tid = args->child_tid;
188222198abSDmitry Chagin 	else
189222198abSDmitry Chagin 		em->child_set_tid = NULL;
190222198abSDmitry Chagin 
191222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
1920a4b664aSDmitry Chagin 		em->child_clear_tid = args->child_tid;
193222198abSDmitry Chagin 	else
194222198abSDmitry Chagin 		em->child_clear_tid = NULL;
195222198abSDmitry Chagin 
196222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
1970a4b664aSDmitry Chagin 		error = copyout(&p2->p_pid, args->parent_tid,
198222198abSDmitry Chagin 		    sizeof(p2->p_pid));
199222198abSDmitry Chagin 		if (error)
200c5156c77SDmitry Chagin 			linux_msg(td, "copyout p_pid failed!");
201222198abSDmitry Chagin 	}
202222198abSDmitry Chagin 
203222198abSDmitry Chagin 	PROC_LOCK(p2);
204222198abSDmitry Chagin 	p2->p_sigparent = exit_signal;
205222198abSDmitry Chagin 	PROC_UNLOCK(p2);
206222198abSDmitry Chagin 	/*
207222198abSDmitry Chagin 	 * In a case of stack = NULL, we are supposed to COW calling process
208222198abSDmitry Chagin 	 * stack. This is what normal fork() does, so we just keep tf_rsp arg
209222198abSDmitry Chagin 	 * intact.
210222198abSDmitry Chagin 	 */
211f1c45049SDmitry Chagin 	linux_set_upcall(td2, args->stack);
212222198abSDmitry Chagin 
213222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_SETTLS)
214f1c45049SDmitry Chagin 		linux_set_cloned_tls(td2, PTRIN(args->tls));
215222198abSDmitry Chagin 
2169f4e66afSDmitry Chagin 	/*
2179f4e66afSDmitry Chagin 	 * If CLONE_PARENT is set, then the parent of the new process will be
2189f4e66afSDmitry Chagin 	 * the same as that of the calling process.
2199f4e66afSDmitry Chagin 	 */
2209f4e66afSDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT) {
2219f4e66afSDmitry Chagin 		sx_xlock(&proctree_lock);
2229f4e66afSDmitry Chagin 		PROC_LOCK(p2);
2232c054ce9SMateusz Guzik 		proc_reparent(p2, td->td_proc->p_pptr, true);
2249f4e66afSDmitry Chagin 		PROC_UNLOCK(p2);
2259f4e66afSDmitry Chagin 		sx_xunlock(&proctree_lock);
2269f4e66afSDmitry Chagin 	}
2279f4e66afSDmitry Chagin 
228222198abSDmitry Chagin 	/*
229222198abSDmitry Chagin 	 * Make this runnable after we are finished with it.
230222198abSDmitry Chagin 	 */
231222198abSDmitry Chagin 	thread_lock(td2);
232222198abSDmitry Chagin 	TD_SET_CAN_RUN(td2);
233222198abSDmitry Chagin 	sched_add(td2, SRQ_BORING);
234222198abSDmitry Chagin 
235222198abSDmitry Chagin 	td->td_retval[0] = p2->p_pid;
236222198abSDmitry Chagin 
237222198abSDmitry Chagin 	return (0);
238222198abSDmitry Chagin }
239161acbb6SDmitry Chagin 
24081338031SDmitry Chagin static int
2410a4b664aSDmitry Chagin linux_clone_thread(struct thread *td, struct l_clone_args *args)
24281338031SDmitry Chagin {
24381338031SDmitry Chagin 	struct linux_emuldata *em;
24481338031SDmitry Chagin 	struct thread *newtd;
24581338031SDmitry Chagin 	struct proc *p;
24681338031SDmitry Chagin 	int error;
24781338031SDmitry Chagin 
2487d96520bSDmitry Chagin 	LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p",
24981338031SDmitry Chagin 	    td->td_tid, (unsigned)args->flags,
2500a4b664aSDmitry Chagin 	    args->parent_tid, args->child_tid);
25181338031SDmitry Chagin 
252d9565182SMark Johnston 	if ((args->flags & LINUX_CLONE_PARENT) != 0)
253d9565182SMark Johnston 		return (EINVAL);
25481338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
2550a4b664aSDmitry Chagin 		if (args->parent_tid == NULL)
25681338031SDmitry Chagin 			return (EINVAL);
25781338031SDmitry Chagin 
25881338031SDmitry Chagin 	/* Threads should be created with own stack */
259f1c45049SDmitry Chagin 	if (PTRIN(args->stack) == NULL)
26081338031SDmitry Chagin 		return (EINVAL);
26181338031SDmitry Chagin 
26281338031SDmitry Chagin 	p = td->td_proc;
26381338031SDmitry Chagin 
264089d3293SEdward Tomasz Napierala #ifdef RACCT
265089d3293SEdward Tomasz Napierala 	if (racct_enable) {
266089d3293SEdward Tomasz Napierala 		PROC_LOCK(p);
267089d3293SEdward Tomasz Napierala 		error = racct_add(p, RACCT_NTHR, 1);
268089d3293SEdward Tomasz Napierala 		PROC_UNLOCK(p);
269089d3293SEdward Tomasz Napierala 		if (error != 0)
270089d3293SEdward Tomasz Napierala 			return (EPROCLIM);
271089d3293SEdward Tomasz Napierala 	}
272089d3293SEdward Tomasz Napierala #endif
273089d3293SEdward Tomasz Napierala 
27481338031SDmitry Chagin 	/* Initialize our td */
27581338031SDmitry Chagin 	error = kern_thr_alloc(p, 0, &newtd);
27681338031SDmitry Chagin 	if (error)
277089d3293SEdward Tomasz Napierala 		goto fail;
27881338031SDmitry Chagin 
2795c2cf818SKonstantin Belousov 	cpu_copy_thread(newtd, td);
28081338031SDmitry Chagin 
28181338031SDmitry Chagin 	bzero(&newtd->td_startzero,
28281338031SDmitry Chagin 	    __rangeof(struct thread, td_startzero, td_endzero));
28381338031SDmitry Chagin 	bcopy(&td->td_startcopy, &newtd->td_startcopy,
28481338031SDmitry Chagin 	    __rangeof(struct thread, td_startcopy, td_endcopy));
28581338031SDmitry Chagin 
28681338031SDmitry Chagin 	newtd->td_proc = p;
2876871c7c3SMateusz Guzik 	thread_cow_get(newtd, td);
28881338031SDmitry Chagin 
28981338031SDmitry Chagin 	/* create the emuldata */
2900a4b664aSDmitry Chagin 	linux_proc_init(td, newtd, true);
29181338031SDmitry Chagin 
29281338031SDmitry Chagin 	em = em_find(newtd);
29381338031SDmitry Chagin 	KASSERT(em != NULL, ("clone_thread: emuldata not found.\n"));
29481338031SDmitry Chagin 
29581338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_SETTLS)
296f1c45049SDmitry Chagin 		linux_set_cloned_tls(newtd, PTRIN(args->tls));
29781338031SDmitry Chagin 
29881338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
2990a4b664aSDmitry Chagin 		em->child_set_tid = args->child_tid;
30081338031SDmitry Chagin 	else
30181338031SDmitry Chagin 		em->child_set_tid = NULL;
30281338031SDmitry Chagin 
30381338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
3040a4b664aSDmitry Chagin 		em->child_clear_tid = args->child_tid;
30581338031SDmitry Chagin 	else
30681338031SDmitry Chagin 		em->child_clear_tid = NULL;
30781338031SDmitry Chagin 
30881338031SDmitry Chagin 	cpu_thread_clean(newtd);
30981338031SDmitry Chagin 
310f1c45049SDmitry Chagin 	linux_set_upcall(newtd, args->stack);
31181338031SDmitry Chagin 
31281338031SDmitry Chagin 	PROC_LOCK(p);
31381338031SDmitry Chagin 	p->p_flag |= P_HADTHREADS;
31481338031SDmitry Chagin 	thread_link(newtd, p);
315d9565182SMark Johnston 	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
31681338031SDmitry Chagin 
31781338031SDmitry Chagin 	thread_lock(td);
31881338031SDmitry Chagin 	/* let the scheduler know about these things. */
31981338031SDmitry Chagin 	sched_fork_thread(td, newtd);
32081338031SDmitry Chagin 	thread_unlock(td);
32181338031SDmitry Chagin 	if (P_SHOULDSTOP(p))
32281338031SDmitry Chagin 		newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
32331665c1aSKonstantin Belousov 
32431665c1aSKonstantin Belousov 	if (p->p_ptevents & PTRACE_LWP)
32531665c1aSKonstantin Belousov 		newtd->td_dbgflags |= TDB_BORN;
32681338031SDmitry Chagin 	PROC_UNLOCK(p);
32781338031SDmitry Chagin 
32881338031SDmitry Chagin 	tidhash_add(newtd);
32981338031SDmitry Chagin 
3307d96520bSDmitry Chagin 	LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d",
33181338031SDmitry Chagin 	    td->td_tid, newtd->td_tid);
33281338031SDmitry Chagin 
33381338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
3340a4b664aSDmitry Chagin 		error = copyout(&newtd->td_tid, args->parent_tid,
33581338031SDmitry Chagin 		    sizeof(newtd->td_tid));
33681338031SDmitry Chagin 		if (error)
337c5156c77SDmitry Chagin 			linux_msg(td, "clone_thread: copyout td_tid failed!");
33881338031SDmitry Chagin 	}
33981338031SDmitry Chagin 
34081338031SDmitry Chagin 	/*
34181338031SDmitry Chagin 	 * Make this runnable after we are finished with it.
34281338031SDmitry Chagin 	 */
34381338031SDmitry Chagin 	thread_lock(newtd);
34481338031SDmitry Chagin 	TD_SET_CAN_RUN(newtd);
34581338031SDmitry Chagin 	sched_add(newtd, SRQ_BORING);
34681338031SDmitry Chagin 
34781338031SDmitry Chagin 	td->td_retval[0] = newtd->td_tid;
34881338031SDmitry Chagin 
34981338031SDmitry Chagin 	return (0);
350089d3293SEdward Tomasz Napierala 
351089d3293SEdward Tomasz Napierala fail:
352089d3293SEdward Tomasz Napierala #ifdef RACCT
353089d3293SEdward Tomasz Napierala 	if (racct_enable) {
354089d3293SEdward Tomasz Napierala 		PROC_LOCK(p);
355089d3293SEdward Tomasz Napierala 		racct_sub(p, RACCT_NTHR, 1);
356089d3293SEdward Tomasz Napierala 		PROC_UNLOCK(p);
357089d3293SEdward Tomasz Napierala 	}
358089d3293SEdward Tomasz Napierala #endif
359089d3293SEdward Tomasz Napierala 	return (error);
36081338031SDmitry Chagin }
36181338031SDmitry Chagin 
36281338031SDmitry Chagin int
36381338031SDmitry Chagin linux_clone(struct thread *td, struct linux_clone_args *args)
36481338031SDmitry Chagin {
3650a4b664aSDmitry Chagin 	struct l_clone_args ca = {
3660a4b664aSDmitry Chagin 		.flags = (lower_32_bits(args->flags) & ~LINUX_CSIGNAL),
3670a4b664aSDmitry Chagin 		.child_tid = args->child_tidptr,
3680a4b664aSDmitry Chagin 		.parent_tid = args->parent_tidptr,
3690a4b664aSDmitry Chagin 		.exit_signal = (lower_32_bits(args->flags) & LINUX_CSIGNAL),
3700a4b664aSDmitry Chagin 		.stack = args->stack,
3710a4b664aSDmitry Chagin 		.tls = args->tls,
3720a4b664aSDmitry Chagin 	};
37381338031SDmitry Chagin 
37481338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_THREAD)
3750a4b664aSDmitry Chagin 		return (linux_clone_thread(td, &ca));
37681338031SDmitry Chagin 	else
3770a4b664aSDmitry Chagin 		return (linux_clone_proc(td, &ca));
37881338031SDmitry Chagin }
37981338031SDmitry Chagin 
380*17913b0bSDmitry Chagin 
381*17913b0bSDmitry Chagin static int
382*17913b0bSDmitry Chagin linux_clone3_args_valid(struct l_user_clone_args *uca)
383*17913b0bSDmitry Chagin {
384*17913b0bSDmitry Chagin 
385*17913b0bSDmitry Chagin 	/* Verify that no unknown flags are passed along. */
386*17913b0bSDmitry Chagin 	if ((uca->flags & ~(LINUX_CLONE_LEGACY_FLAGS |
387*17913b0bSDmitry Chagin 	    LINUX_CLONE_CLEAR_SIGHAND | LINUX_CLONE_INTO_CGROUP)) != 0)
388*17913b0bSDmitry Chagin 		return (EINVAL);
389*17913b0bSDmitry Chagin 	if ((uca->flags & (LINUX_CLONE_DETACHED | LINUX_CSIGNAL)) != 0)
390*17913b0bSDmitry Chagin 		return (EINVAL);
391*17913b0bSDmitry Chagin 
392*17913b0bSDmitry Chagin 	if ((uca->flags & (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) ==
393*17913b0bSDmitry Chagin 	    (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND))
394*17913b0bSDmitry Chagin 		return (EINVAL);
395*17913b0bSDmitry Chagin 	if ((uca->flags & (LINUX_CLONE_THREAD | LINUX_CLONE_PARENT)) != 0 &&
396*17913b0bSDmitry Chagin 	    uca->exit_signal != 0)
397*17913b0bSDmitry Chagin 		return (EINVAL);
398*17913b0bSDmitry Chagin 
399*17913b0bSDmitry Chagin 	/* We don't support set_tid, only validate input. */
400*17913b0bSDmitry Chagin 	if (uca->set_tid_size > LINUX_MAX_PID_NS_LEVEL)
401*17913b0bSDmitry Chagin 		return (EINVAL);
402*17913b0bSDmitry Chagin 	if (uca->set_tid == 0 && uca->set_tid_size > 0)
403*17913b0bSDmitry Chagin 		return (EINVAL);
404*17913b0bSDmitry Chagin 	if (uca->set_tid != 0 && uca->set_tid_size == 0)
405*17913b0bSDmitry Chagin 		return (EINVAL);
406*17913b0bSDmitry Chagin 
407*17913b0bSDmitry Chagin 	if (uca->stack == 0 && uca->stack_size > 0)
408*17913b0bSDmitry Chagin 		return (EINVAL);
409*17913b0bSDmitry Chagin 	if (uca->stack != 0 && uca->stack_size == 0)
410*17913b0bSDmitry Chagin 		return (EINVAL);
411*17913b0bSDmitry Chagin 
412*17913b0bSDmitry Chagin 	return (0);
413*17913b0bSDmitry Chagin }
414*17913b0bSDmitry Chagin 
415*17913b0bSDmitry Chagin int
416*17913b0bSDmitry Chagin linux_clone3(struct thread *td, struct linux_clone3_args *args)
417*17913b0bSDmitry Chagin {
418*17913b0bSDmitry Chagin 	struct l_user_clone_args *uca;
419*17913b0bSDmitry Chagin 	struct l_clone_args *ca;
420*17913b0bSDmitry Chagin 	size_t size;
421*17913b0bSDmitry Chagin 	int error;
422*17913b0bSDmitry Chagin 
423*17913b0bSDmitry Chagin 	if (args->usize > PAGE_SIZE)
424*17913b0bSDmitry Chagin 		return (E2BIG);
425*17913b0bSDmitry Chagin 	if (args->usize < LINUX_CLONE_ARGS_SIZE_VER0)
426*17913b0bSDmitry Chagin 		return (EINVAL);
427*17913b0bSDmitry Chagin 
428*17913b0bSDmitry Chagin 	/*
429*17913b0bSDmitry Chagin 	 * usize can be less than size of struct clone_args, to avoid using
430*17913b0bSDmitry Chagin 	 * of uninitialized data of struct clone_args, allocate at least
431*17913b0bSDmitry Chagin 	 * sizeof(struct clone_args) storage and zero it.
432*17913b0bSDmitry Chagin 	 */
433*17913b0bSDmitry Chagin 	size = max(args->usize, sizeof(*uca));
434*17913b0bSDmitry Chagin 	uca = malloc(size, M_LINUX, M_WAITOK | M_ZERO);
435*17913b0bSDmitry Chagin 	error = copyin(args->uargs, uca, args->usize);
436*17913b0bSDmitry Chagin 	if (error != 0)
437*17913b0bSDmitry Chagin 		goto out;
438*17913b0bSDmitry Chagin 	error = linux_clone3_args_valid(uca);
439*17913b0bSDmitry Chagin 	if (error != 0)
440*17913b0bSDmitry Chagin 		goto out;
441*17913b0bSDmitry Chagin 	ca = malloc(sizeof(*ca), M_LINUX, M_WAITOK | M_ZERO);
442*17913b0bSDmitry Chagin 	ca->flags = uca->flags;
443*17913b0bSDmitry Chagin 	ca->child_tid = PTRIN(uca->child_tid);
444*17913b0bSDmitry Chagin 	ca->parent_tid = PTRIN(uca->parent_tid);
445*17913b0bSDmitry Chagin 	ca->exit_signal = uca->exit_signal;
446*17913b0bSDmitry Chagin 	ca->stack = uca->stack + uca->stack_size;
447*17913b0bSDmitry Chagin 	ca->stack_size = uca->stack_size;
448*17913b0bSDmitry Chagin 	ca->tls = uca->tls;
449*17913b0bSDmitry Chagin 
450*17913b0bSDmitry Chagin 	if ((ca->flags & LINUX_CLONE_THREAD) != 0)
451*17913b0bSDmitry Chagin 		error = linux_clone_thread(td, ca);
452*17913b0bSDmitry Chagin 	else
453*17913b0bSDmitry Chagin 		error = linux_clone_proc(td, ca);
454*17913b0bSDmitry Chagin 	free(ca, M_LINUX);
455*17913b0bSDmitry Chagin out:
456*17913b0bSDmitry Chagin 	free(uca, M_LINUX);
457*17913b0bSDmitry Chagin 	return (error);
458*17913b0bSDmitry Chagin }
459*17913b0bSDmitry Chagin 
460161acbb6SDmitry Chagin int
461161acbb6SDmitry Chagin linux_exit(struct thread *td, struct linux_exit_args *args)
462161acbb6SDmitry Chagin {
46381338031SDmitry Chagin 	struct linux_emuldata *em;
464161acbb6SDmitry Chagin 
46581338031SDmitry Chagin 	em = em_find(td);
46681338031SDmitry Chagin 	KASSERT(em != NULL, ("exit: emuldata not found.\n"));
467161acbb6SDmitry Chagin 
46881338031SDmitry Chagin 	LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval);
46981338031SDmitry Chagin 
47081338031SDmitry Chagin 	linux_thread_detach(td);
47181338031SDmitry Chagin 
47281338031SDmitry Chagin 	/*
47381338031SDmitry Chagin 	 * XXX. When the last two threads of a process
47481338031SDmitry Chagin 	 * exit via pthread_exit() try thr_exit() first.
47581338031SDmitry Chagin 	 */
47681338031SDmitry Chagin 	kern_thr_exit(td);
477b4490c6eSKonstantin Belousov 	exit1(td, args->rval, 0);
478161acbb6SDmitry Chagin 		/* NOTREACHED */
479161acbb6SDmitry Chagin }
480bc273677SDmitry Chagin 
481bc273677SDmitry Chagin int
482bc273677SDmitry Chagin linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
483bc273677SDmitry Chagin {
484bc273677SDmitry Chagin 	struct linux_emuldata *em;
485bc273677SDmitry Chagin 
486bc273677SDmitry Chagin 	em = em_find(td);
487bc273677SDmitry Chagin 	KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
488bc273677SDmitry Chagin 
489bc273677SDmitry Chagin 	em->child_clear_tid = args->tidptr;
490bc273677SDmitry Chagin 
491bc273677SDmitry Chagin 	td->td_retval[0] = em->em_tid;
492bc273677SDmitry Chagin 
493bc273677SDmitry Chagin 	LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
494bc273677SDmitry Chagin 	    em->em_tid, args->tidptr, td->td_retval[0]);
495bc273677SDmitry Chagin 
496bc273677SDmitry Chagin 	return (0);
497bc273677SDmitry Chagin }
498bc273677SDmitry Chagin 
499bc273677SDmitry Chagin void
500bc273677SDmitry Chagin linux_thread_detach(struct thread *td)
501bc273677SDmitry Chagin {
502bc273677SDmitry Chagin 	struct linux_emuldata *em;
503bc273677SDmitry Chagin 	int *child_clear_tid;
504bc273677SDmitry Chagin 	int error;
505bc273677SDmitry Chagin 
506bc273677SDmitry Chagin 	em = em_find(td);
507bc273677SDmitry Chagin 	KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
508bc273677SDmitry Chagin 
5097d96520bSDmitry Chagin 	LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid);
510bc273677SDmitry Chagin 
511bc273677SDmitry Chagin 	release_futexes(td, em);
512bc273677SDmitry Chagin 
513bc273677SDmitry Chagin 	child_clear_tid = em->child_clear_tid;
514bc273677SDmitry Chagin 
515bc273677SDmitry Chagin 	if (child_clear_tid != NULL) {
5167d96520bSDmitry Chagin 		LINUX_CTR2(thread_detach, "thread(%d) %p",
517bc273677SDmitry Chagin 		    em->em_tid, child_clear_tid);
518bc273677SDmitry Chagin 
519bc273677SDmitry Chagin 		error = suword32(child_clear_tid, 0);
520bc273677SDmitry Chagin 		if (error != 0)
521bc273677SDmitry Chagin 			return;
522bc273677SDmitry Chagin 
5230dc38e33SDmitry Chagin 		error = futex_wake(td, child_clear_tid, 1, false);
524bc273677SDmitry Chagin 		/*
525bc273677SDmitry Chagin 		 * this cannot happen at the moment and if this happens it
526bc273677SDmitry Chagin 		 * probably means there is a user space bug
527bc273677SDmitry Chagin 		 */
528bc273677SDmitry Chagin 		if (error != 0)
529bc273677SDmitry Chagin 			linux_msg(td, "futex stuff in thread_detach failed.");
530bc273677SDmitry Chagin 	}
5317a718f29SDmitry Chagin 
5327a718f29SDmitry Chagin 	/*
5337a718f29SDmitry Chagin 	 * Do not rely on the robust list which is maintained by userspace,
5347a718f29SDmitry Chagin 	 * cleanup remaining pi (if any) after release_futexes anyway.
5357a718f29SDmitry Chagin 	 */
5367a718f29SDmitry Chagin 	umtx_thread_exit(td);
537bc273677SDmitry Chagin }
538