xref: /freebsd/sys/compat/linux/linux_fork.c (revision 3460fab5fced39c7ea597cc7de0ebc3e4c88989a)
1222198abSDmitry Chagin /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
3281338031SDmitry Chagin #include <sys/ktr.h>
33222198abSDmitry Chagin #include <sys/lock.h>
34222198abSDmitry Chagin #include <sys/mutex.h>
35222198abSDmitry Chagin #include <sys/proc.h>
3631665c1aSKonstantin Belousov #include <sys/ptrace.h>
3781338031SDmitry Chagin #include <sys/racct.h>
38222198abSDmitry Chagin #include <sys/sched.h>
3981338031SDmitry Chagin #include <sys/syscallsubr.h>
40222198abSDmitry Chagin #include <sys/sx.h>
417a718f29SDmitry Chagin #include <sys/umtxvar.h>
42222198abSDmitry Chagin #include <sys/unistd.h>
43222198abSDmitry Chagin 
4481338031SDmitry Chagin #include <vm/vm.h>
4581338031SDmitry Chagin #include <vm/pmap.h>
4681338031SDmitry Chagin #include <vm/vm_map.h>
4781338031SDmitry Chagin 
48222198abSDmitry Chagin #ifdef COMPAT_LINUX32
49222198abSDmitry Chagin #include <machine/../linux32/linux.h>
50222198abSDmitry Chagin #include <machine/../linux32/linux32_proto.h>
51222198abSDmitry Chagin #else
52222198abSDmitry Chagin #include <machine/../linux/linux.h>
53222198abSDmitry Chagin #include <machine/../linux/linux_proto.h>
54222198abSDmitry Chagin #endif
550a4b664aSDmitry Chagin #include <compat/linux/linux.h>
56222198abSDmitry Chagin #include <compat/linux/linux_emul.h>
570a4b664aSDmitry Chagin #include <compat/linux/linux_fork.h>
58bc273677SDmitry Chagin #include <compat/linux/linux_futex.h>
5943851475SDmitry Chagin #include <compat/linux/linux_mib.h>
60d825ce0aSJohn Baldwin #include <compat/linux/linux_misc.h>
6181338031SDmitry Chagin #include <compat/linux/linux_util.h>
62222198abSDmitry Chagin 
63931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
64222198abSDmitry Chagin int
linux_fork(struct thread * td,struct linux_fork_args * args)65222198abSDmitry Chagin linux_fork(struct thread *td, struct linux_fork_args *args)
66222198abSDmitry Chagin {
6733fd9b9aSMateusz Guzik 	struct fork_req fr;
68222198abSDmitry Chagin 	int error;
69222198abSDmitry Chagin 	struct proc *p2;
70222198abSDmitry Chagin 	struct thread *td2;
71222198abSDmitry Chagin 
7233fd9b9aSMateusz Guzik 	bzero(&fr, sizeof(fr));
7333fd9b9aSMateusz Guzik 	fr.fr_flags = RFFDG | RFPROC | RFSTOPPED;
7433fd9b9aSMateusz Guzik 	fr.fr_procp = &p2;
7533fd9b9aSMateusz Guzik 	if ((error = fork1(td, &fr)) != 0)
76222198abSDmitry Chagin 		return (error);
77222198abSDmitry Chagin 
78222198abSDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p2);
79222198abSDmitry Chagin 
800a4b664aSDmitry Chagin 	linux_proc_init(td, td2, false);
8181338031SDmitry Chagin 
8281338031SDmitry Chagin 	td->td_retval[0] = p2->p_pid;
8381338031SDmitry Chagin 
84222198abSDmitry Chagin 	/*
85222198abSDmitry Chagin 	 * Make this runnable after we are finished with it.
86222198abSDmitry Chagin 	 */
87222198abSDmitry Chagin 	thread_lock(td2);
88222198abSDmitry Chagin 	TD_SET_CAN_RUN(td2);
89222198abSDmitry Chagin 	sched_add(td2, SRQ_BORING);
90222198abSDmitry Chagin 
91222198abSDmitry Chagin 	return (0);
92222198abSDmitry Chagin }
93222198abSDmitry Chagin 
94222198abSDmitry Chagin int
linux_vfork(struct thread * td,struct linux_vfork_args * args)95222198abSDmitry Chagin linux_vfork(struct thread *td, struct linux_vfork_args *args)
96222198abSDmitry Chagin {
9733fd9b9aSMateusz Guzik 	struct fork_req fr;
98222198abSDmitry Chagin 	int error;
99222198abSDmitry Chagin 	struct proc *p2;
100222198abSDmitry Chagin 	struct thread *td2;
101222198abSDmitry Chagin 
10233fd9b9aSMateusz Guzik 	bzero(&fr, sizeof(fr));
10333fd9b9aSMateusz Guzik 	fr.fr_flags = RFFDG | RFPROC | RFMEM | RFPPWAIT | RFSTOPPED;
10433fd9b9aSMateusz Guzik 	fr.fr_procp = &p2;
10533fd9b9aSMateusz Guzik 	if ((error = fork1(td, &fr)) != 0)
106222198abSDmitry Chagin 		return (error);
107cfa57401SDmitry Chagin 
10881338031SDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p2);
10981338031SDmitry Chagin 
1100a4b664aSDmitry Chagin 	linux_proc_init(td, td2, false);
111222198abSDmitry Chagin 
11281338031SDmitry Chagin 	td->td_retval[0] = p2->p_pid;
113222198abSDmitry Chagin 
114222198abSDmitry Chagin 	/*
115222198abSDmitry Chagin 	 * Make this runnable after we are finished with it.
116222198abSDmitry Chagin 	 */
117222198abSDmitry Chagin 	thread_lock(td2);
118222198abSDmitry Chagin 	TD_SET_CAN_RUN(td2);
119222198abSDmitry Chagin 	sched_add(td2, SRQ_BORING);
120222198abSDmitry Chagin 
121222198abSDmitry Chagin 	return (0);
122222198abSDmitry Chagin }
123931e2a1aSEd Maste #endif
124222198abSDmitry Chagin 
12581338031SDmitry Chagin static int
linux_clone_proc(struct thread * td,struct l_clone_args * args)1260a4b664aSDmitry Chagin linux_clone_proc(struct thread *td, struct l_clone_args *args)
127222198abSDmitry Chagin {
12833fd9b9aSMateusz Guzik 	struct fork_req fr;
1291af0780bSDmitry Chagin 	int error, ff, f2;
130222198abSDmitry Chagin 	struct proc *p2;
131222198abSDmitry Chagin 	struct thread *td2;
132222198abSDmitry Chagin 	int exit_signal;
133222198abSDmitry Chagin 	struct linux_emuldata *em;
134222198abSDmitry Chagin 
135f8f74aaaSConrad Meyer 	f2 = 0;
1361af0780bSDmitry Chagin 	ff = RFPROC | RFSTOPPED;
1370a4b664aSDmitry Chagin 	if (LINUX_SIG_VALID(args->exit_signal)) {
1380a4b664aSDmitry Chagin 		exit_signal = linux_to_bsd_signal(args->exit_signal);
1390a4b664aSDmitry Chagin 	} else if (args->exit_signal != 0)
140222198abSDmitry Chagin 		return (EINVAL);
1410a4b664aSDmitry Chagin 	else
1420a4b664aSDmitry Chagin 		exit_signal = 0;
143222198abSDmitry Chagin 
144222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_VM)
145222198abSDmitry Chagin 		ff |= RFMEM;
146222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_SIGHAND)
147222198abSDmitry Chagin 		ff |= RFSIGSHARE;
148c5fc9fe7SDmitry Chagin 	if ((args->flags & LINUX_CLONE_CLEAR_SIGHAND) != 0)
149c5fc9fe7SDmitry Chagin 		f2 |= FR2_DROPSIG_CAUGHT;
150f8f74aaaSConrad Meyer 	if (args->flags & LINUX_CLONE_FILES) {
151f8f74aaaSConrad Meyer 		if (!(args->flags & LINUX_CLONE_FS))
152f8f74aaaSConrad Meyer 			f2 |= FR2_SHARE_PATHS;
153f8f74aaaSConrad Meyer 	} else {
154222198abSDmitry Chagin 		ff |= RFFDG;
155f8f74aaaSConrad Meyer 		if (args->flags & LINUX_CLONE_FS)
156f8f74aaaSConrad Meyer 			f2 |= FR2_SHARE_PATHS;
157f8f74aaaSConrad Meyer 	}
158222198abSDmitry Chagin 
159222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
1600a4b664aSDmitry Chagin 		if (args->parent_tid == NULL)
161222198abSDmitry Chagin 			return (EINVAL);
162222198abSDmitry Chagin 
163a7306730SBryan Drewery 	if (args->flags & LINUX_CLONE_VFORK)
164a7306730SBryan Drewery 		ff |= RFPPWAIT;
165a7306730SBryan Drewery 
16633fd9b9aSMateusz Guzik 	bzero(&fr, sizeof(fr));
16733fd9b9aSMateusz Guzik 	fr.fr_flags = ff;
168f8f74aaaSConrad Meyer 	fr.fr_flags2 = f2;
16933fd9b9aSMateusz Guzik 	fr.fr_procp = &p2;
17033fd9b9aSMateusz Guzik 	error = fork1(td, &fr);
171222198abSDmitry Chagin 	if (error)
172222198abSDmitry Chagin 		return (error);
173222198abSDmitry Chagin 
17481338031SDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p2);
175222198abSDmitry Chagin 
176222198abSDmitry Chagin 	/* create the emuldata */
1770a4b664aSDmitry Chagin 	linux_proc_init(td, td2, false);
178222198abSDmitry Chagin 
17981338031SDmitry Chagin 	em = em_find(td2);
18081338031SDmitry Chagin 	KASSERT(em != NULL, ("clone_proc: emuldata not found.\n"));
181222198abSDmitry Chagin 
182222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
1830a4b664aSDmitry Chagin 		em->child_set_tid = args->child_tid;
184222198abSDmitry Chagin 	else
185222198abSDmitry Chagin 		em->child_set_tid = NULL;
186222198abSDmitry Chagin 
187222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
1880a4b664aSDmitry Chagin 		em->child_clear_tid = args->child_tid;
189222198abSDmitry Chagin 	else
190222198abSDmitry Chagin 		em->child_clear_tid = NULL;
191222198abSDmitry Chagin 
192222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
1930a4b664aSDmitry Chagin 		error = copyout(&p2->p_pid, args->parent_tid,
194222198abSDmitry Chagin 		    sizeof(p2->p_pid));
195222198abSDmitry Chagin 		if (error)
196c5156c77SDmitry Chagin 			linux_msg(td, "copyout p_pid failed!");
197222198abSDmitry Chagin 	}
198222198abSDmitry Chagin 
199222198abSDmitry Chagin 	PROC_LOCK(p2);
200222198abSDmitry Chagin 	p2->p_sigparent = exit_signal;
201222198abSDmitry Chagin 	PROC_UNLOCK(p2);
202222198abSDmitry Chagin 	/*
203222198abSDmitry Chagin 	 * In a case of stack = NULL, we are supposed to COW calling process
204222198abSDmitry Chagin 	 * stack. This is what normal fork() does, so we just keep tf_rsp arg
205222198abSDmitry Chagin 	 * intact.
206222198abSDmitry Chagin 	 */
207f1c45049SDmitry Chagin 	linux_set_upcall(td2, args->stack);
208222198abSDmitry Chagin 
209222198abSDmitry Chagin 	if (args->flags & LINUX_CLONE_SETTLS)
210f1c45049SDmitry Chagin 		linux_set_cloned_tls(td2, PTRIN(args->tls));
211222198abSDmitry Chagin 
2129f4e66afSDmitry Chagin 	/*
2139f4e66afSDmitry Chagin 	 * If CLONE_PARENT is set, then the parent of the new process will be
2149f4e66afSDmitry Chagin 	 * the same as that of the calling process.
2159f4e66afSDmitry Chagin 	 */
2169f4e66afSDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT) {
2179f4e66afSDmitry Chagin 		sx_xlock(&proctree_lock);
2189f4e66afSDmitry Chagin 		PROC_LOCK(p2);
2192c054ce9SMateusz Guzik 		proc_reparent(p2, td->td_proc->p_pptr, true);
2209f4e66afSDmitry Chagin 		PROC_UNLOCK(p2);
2219f4e66afSDmitry Chagin 		sx_xunlock(&proctree_lock);
2229f4e66afSDmitry Chagin 	}
2239f4e66afSDmitry Chagin 
224222198abSDmitry Chagin 	/*
225222198abSDmitry Chagin 	 * Make this runnable after we are finished with it.
226222198abSDmitry Chagin 	 */
227222198abSDmitry Chagin 	thread_lock(td2);
228222198abSDmitry Chagin 	TD_SET_CAN_RUN(td2);
229222198abSDmitry Chagin 	sched_add(td2, SRQ_BORING);
230222198abSDmitry Chagin 
231222198abSDmitry Chagin 	td->td_retval[0] = p2->p_pid;
232222198abSDmitry Chagin 
233222198abSDmitry Chagin 	return (0);
234222198abSDmitry Chagin }
235161acbb6SDmitry Chagin 
23681338031SDmitry Chagin static int
linux_clone_thread(struct thread * td,struct l_clone_args * args)2370a4b664aSDmitry Chagin linux_clone_thread(struct thread *td, struct l_clone_args *args)
23881338031SDmitry Chagin {
23981338031SDmitry Chagin 	struct linux_emuldata *em;
24081338031SDmitry Chagin 	struct thread *newtd;
24181338031SDmitry Chagin 	struct proc *p;
24281338031SDmitry Chagin 	int error;
24381338031SDmitry Chagin 
2447d96520bSDmitry Chagin 	LINUX_CTR4(clone_thread, "thread(%d) flags %x ptid %p ctid %p",
24581338031SDmitry Chagin 	    td->td_tid, (unsigned)args->flags,
2460a4b664aSDmitry Chagin 	    args->parent_tid, args->child_tid);
24781338031SDmitry Chagin 
248d9565182SMark Johnston 	if ((args->flags & LINUX_CLONE_PARENT) != 0)
249d9565182SMark Johnston 		return (EINVAL);
25081338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID)
2510a4b664aSDmitry Chagin 		if (args->parent_tid == NULL)
25281338031SDmitry Chagin 			return (EINVAL);
25381338031SDmitry Chagin 
25481338031SDmitry Chagin 	/* Threads should be created with own stack */
255f1c45049SDmitry Chagin 	if (PTRIN(args->stack) == NULL)
25681338031SDmitry Chagin 		return (EINVAL);
25781338031SDmitry Chagin 
25881338031SDmitry Chagin 	p = td->td_proc;
25981338031SDmitry Chagin 
260089d3293SEdward Tomasz Napierala #ifdef RACCT
261089d3293SEdward Tomasz Napierala 	if (racct_enable) {
262089d3293SEdward Tomasz Napierala 		PROC_LOCK(p);
263089d3293SEdward Tomasz Napierala 		error = racct_add(p, RACCT_NTHR, 1);
264089d3293SEdward Tomasz Napierala 		PROC_UNLOCK(p);
265089d3293SEdward Tomasz Napierala 		if (error != 0)
266089d3293SEdward Tomasz Napierala 			return (EPROCLIM);
267089d3293SEdward Tomasz Napierala 	}
268089d3293SEdward Tomasz Napierala #endif
269089d3293SEdward Tomasz Napierala 
27081338031SDmitry Chagin 	/* Initialize our td */
27181338031SDmitry Chagin 	error = kern_thr_alloc(p, 0, &newtd);
27281338031SDmitry Chagin 	if (error)
273089d3293SEdward Tomasz Napierala 		goto fail;
27481338031SDmitry Chagin 
27581338031SDmitry Chagin 	bzero(&newtd->td_startzero,
27681338031SDmitry Chagin 	    __rangeof(struct thread, td_startzero, td_endzero));
27781338031SDmitry Chagin 	bcopy(&td->td_startcopy, &newtd->td_startcopy,
27881338031SDmitry Chagin 	    __rangeof(struct thread, td_startcopy, td_endcopy));
27981338031SDmitry Chagin 
28081338031SDmitry Chagin 	newtd->td_proc = p;
2816871c7c3SMateusz Guzik 	thread_cow_get(newtd, td);
28281338031SDmitry Chagin 
2831b0a4974SKonstantin Belousov 	cpu_copy_thread(newtd, td);
2841b0a4974SKonstantin Belousov 
28581338031SDmitry Chagin 	/* create the emuldata */
2860a4b664aSDmitry Chagin 	linux_proc_init(td, newtd, true);
28781338031SDmitry Chagin 
28881338031SDmitry Chagin 	em = em_find(newtd);
28981338031SDmitry Chagin 	KASSERT(em != NULL, ("clone_thread: emuldata not found.\n"));
29081338031SDmitry Chagin 
29181338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_SETTLS)
292f1c45049SDmitry Chagin 		linux_set_cloned_tls(newtd, PTRIN(args->tls));
29381338031SDmitry Chagin 
29481338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_SETTID)
2950a4b664aSDmitry Chagin 		em->child_set_tid = args->child_tid;
29681338031SDmitry Chagin 	else
29781338031SDmitry Chagin 		em->child_set_tid = NULL;
29881338031SDmitry Chagin 
29981338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_CHILD_CLEARTID)
3000a4b664aSDmitry Chagin 		em->child_clear_tid = args->child_tid;
30181338031SDmitry Chagin 	else
30281338031SDmitry Chagin 		em->child_clear_tid = NULL;
30381338031SDmitry Chagin 
30481338031SDmitry Chagin 	cpu_thread_clean(newtd);
30581338031SDmitry Chagin 
306f1c45049SDmitry Chagin 	linux_set_upcall(newtd, args->stack);
30781338031SDmitry Chagin 
30881338031SDmitry Chagin 	PROC_LOCK(p);
30981338031SDmitry Chagin 	p->p_flag |= P_HADTHREADS;
31081338031SDmitry Chagin 	thread_link(newtd, p);
311d9565182SMark Johnston 	bcopy(p->p_comm, newtd->td_name, sizeof(newtd->td_name));
31281338031SDmitry Chagin 
31381338031SDmitry Chagin 	thread_lock(td);
31481338031SDmitry Chagin 	/* let the scheduler know about these things. */
31581338031SDmitry Chagin 	sched_fork_thread(td, newtd);
31681338031SDmitry Chagin 	thread_unlock(td);
31781338031SDmitry Chagin 	if (P_SHOULDSTOP(p))
318c6d31b83SKonstantin Belousov 		ast_sched(newtd, TDA_SUSPEND);
31931665c1aSKonstantin Belousov 
32031665c1aSKonstantin Belousov 	if (p->p_ptevents & PTRACE_LWP)
32131665c1aSKonstantin Belousov 		newtd->td_dbgflags |= TDB_BORN;
32281338031SDmitry Chagin 	PROC_UNLOCK(p);
32381338031SDmitry Chagin 
32481338031SDmitry Chagin 	tidhash_add(newtd);
32581338031SDmitry Chagin 
3267d96520bSDmitry Chagin 	LINUX_CTR2(clone_thread, "thread(%d) successful clone to %d",
32781338031SDmitry Chagin 	    td->td_tid, newtd->td_tid);
32881338031SDmitry Chagin 
32981338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_PARENT_SETTID) {
3300a4b664aSDmitry Chagin 		error = copyout(&newtd->td_tid, args->parent_tid,
33181338031SDmitry Chagin 		    sizeof(newtd->td_tid));
33281338031SDmitry Chagin 		if (error)
333c5156c77SDmitry Chagin 			linux_msg(td, "clone_thread: copyout td_tid failed!");
33481338031SDmitry Chagin 	}
33581338031SDmitry Chagin 
33681338031SDmitry Chagin 	/*
33781338031SDmitry Chagin 	 * Make this runnable after we are finished with it.
33881338031SDmitry Chagin 	 */
33981338031SDmitry Chagin 	thread_lock(newtd);
34081338031SDmitry Chagin 	TD_SET_CAN_RUN(newtd);
34181338031SDmitry Chagin 	sched_add(newtd, SRQ_BORING);
34281338031SDmitry Chagin 
34381338031SDmitry Chagin 	td->td_retval[0] = newtd->td_tid;
34481338031SDmitry Chagin 
34581338031SDmitry Chagin 	return (0);
346089d3293SEdward Tomasz Napierala 
347089d3293SEdward Tomasz Napierala fail:
348089d3293SEdward Tomasz Napierala #ifdef RACCT
349089d3293SEdward Tomasz Napierala 	if (racct_enable) {
350089d3293SEdward Tomasz Napierala 		PROC_LOCK(p);
351089d3293SEdward Tomasz Napierala 		racct_sub(p, RACCT_NTHR, 1);
352089d3293SEdward Tomasz Napierala 		PROC_UNLOCK(p);
353089d3293SEdward Tomasz Napierala 	}
354089d3293SEdward Tomasz Napierala #endif
355089d3293SEdward Tomasz Napierala 	return (error);
35681338031SDmitry Chagin }
35781338031SDmitry Chagin 
35881338031SDmitry Chagin int
linux_clone(struct thread * td,struct linux_clone_args * args)35981338031SDmitry Chagin linux_clone(struct thread *td, struct linux_clone_args *args)
36081338031SDmitry Chagin {
3610a4b664aSDmitry Chagin 	struct l_clone_args ca = {
3620a4b664aSDmitry Chagin 		.flags = (lower_32_bits(args->flags) & ~LINUX_CSIGNAL),
3630a4b664aSDmitry Chagin 		.child_tid = args->child_tidptr,
3640a4b664aSDmitry Chagin 		.parent_tid = args->parent_tidptr,
3650a4b664aSDmitry Chagin 		.exit_signal = (lower_32_bits(args->flags) & LINUX_CSIGNAL),
3660a4b664aSDmitry Chagin 		.stack = args->stack,
3670a4b664aSDmitry Chagin 		.tls = args->tls,
3680a4b664aSDmitry Chagin 	};
36981338031SDmitry Chagin 
37081338031SDmitry Chagin 	if (args->flags & LINUX_CLONE_THREAD)
3710a4b664aSDmitry Chagin 		return (linux_clone_thread(td, &ca));
37281338031SDmitry Chagin 	else
3730a4b664aSDmitry Chagin 		return (linux_clone_proc(td, &ca));
37481338031SDmitry Chagin }
37581338031SDmitry Chagin 
37617913b0bSDmitry Chagin 
37717913b0bSDmitry Chagin static int
linux_clone3_args_valid(struct l_user_clone_args * uca)37817913b0bSDmitry Chagin linux_clone3_args_valid(struct l_user_clone_args *uca)
37917913b0bSDmitry Chagin {
38017913b0bSDmitry Chagin 
38117913b0bSDmitry Chagin 	/* Verify that no unknown flags are passed along. */
38217913b0bSDmitry Chagin 	if ((uca->flags & ~(LINUX_CLONE_LEGACY_FLAGS |
38317913b0bSDmitry Chagin 	    LINUX_CLONE_CLEAR_SIGHAND | LINUX_CLONE_INTO_CGROUP)) != 0)
38417913b0bSDmitry Chagin 		return (EINVAL);
38517913b0bSDmitry Chagin 	if ((uca->flags & (LINUX_CLONE_DETACHED | LINUX_CSIGNAL)) != 0)
38617913b0bSDmitry Chagin 		return (EINVAL);
38717913b0bSDmitry Chagin 
38817913b0bSDmitry Chagin 	if ((uca->flags & (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND)) ==
38917913b0bSDmitry Chagin 	    (LINUX_CLONE_SIGHAND | LINUX_CLONE_CLEAR_SIGHAND))
39017913b0bSDmitry Chagin 		return (EINVAL);
39117913b0bSDmitry Chagin 	if ((uca->flags & (LINUX_CLONE_THREAD | LINUX_CLONE_PARENT)) != 0 &&
39217913b0bSDmitry Chagin 	    uca->exit_signal != 0)
39317913b0bSDmitry Chagin 		return (EINVAL);
39417913b0bSDmitry Chagin 
39517913b0bSDmitry Chagin 	/* We don't support set_tid, only validate input. */
39617913b0bSDmitry Chagin 	if (uca->set_tid_size > LINUX_MAX_PID_NS_LEVEL)
39717913b0bSDmitry Chagin 		return (EINVAL);
39817913b0bSDmitry Chagin 	if (uca->set_tid == 0 && uca->set_tid_size > 0)
39917913b0bSDmitry Chagin 		return (EINVAL);
40017913b0bSDmitry Chagin 	if (uca->set_tid != 0 && uca->set_tid_size == 0)
40117913b0bSDmitry Chagin 		return (EINVAL);
40217913b0bSDmitry Chagin 
40317913b0bSDmitry Chagin 	if (uca->stack == 0 && uca->stack_size > 0)
40417913b0bSDmitry Chagin 		return (EINVAL);
40517913b0bSDmitry Chagin 	if (uca->stack != 0 && uca->stack_size == 0)
40617913b0bSDmitry Chagin 		return (EINVAL);
40717913b0bSDmitry Chagin 
408c2cc5345SDmitry Chagin 	/* Verify that higher 32bits of exit_signal are unset. */
409c2cc5345SDmitry Chagin 	if ((uca->exit_signal & ~(uint64_t)LINUX_CSIGNAL) != 0)
410c2cc5345SDmitry Chagin 		return (EINVAL);
411c2cc5345SDmitry Chagin 
41243851475SDmitry Chagin 	/* Verify that no unsupported flags are passed along. */
41343851475SDmitry Chagin 	if ((uca->flags & LINUX_CLONE_NEWTIME) != 0) {
41443851475SDmitry Chagin 		LINUX_RATELIMIT_MSG("unsupported clone3 option CLONE_NEWTIME");
41543851475SDmitry Chagin 		return (ENOSYS);
41643851475SDmitry Chagin 	}
41743851475SDmitry Chagin 	if ((uca->flags & LINUX_CLONE_INTO_CGROUP) != 0) {
41843851475SDmitry Chagin 		LINUX_RATELIMIT_MSG("unsupported clone3 option CLONE_INTO_CGROUP");
41943851475SDmitry Chagin 		return (ENOSYS);
42043851475SDmitry Chagin 	}
42143851475SDmitry Chagin 	if (uca->set_tid != 0 || uca->set_tid_size != 0) {
42243851475SDmitry Chagin 		LINUX_RATELIMIT_MSG("unsupported clone3 set_tid");
42343851475SDmitry Chagin 		return (ENOSYS);
42443851475SDmitry Chagin 	}
42543851475SDmitry Chagin 
42617913b0bSDmitry Chagin 	return (0);
42717913b0bSDmitry Chagin }
42817913b0bSDmitry Chagin 
42917913b0bSDmitry Chagin int
linux_clone3(struct thread * td,struct linux_clone3_args * args)43017913b0bSDmitry Chagin linux_clone3(struct thread *td, struct linux_clone3_args *args)
43117913b0bSDmitry Chagin {
43217913b0bSDmitry Chagin 	struct l_user_clone_args *uca;
43317913b0bSDmitry Chagin 	struct l_clone_args *ca;
43417913b0bSDmitry Chagin 	size_t size;
43517913b0bSDmitry Chagin 	int error;
43617913b0bSDmitry Chagin 
43717913b0bSDmitry Chagin 	if (args->usize > PAGE_SIZE)
43817913b0bSDmitry Chagin 		return (E2BIG);
43917913b0bSDmitry Chagin 	if (args->usize < LINUX_CLONE_ARGS_SIZE_VER0)
44017913b0bSDmitry Chagin 		return (EINVAL);
44117913b0bSDmitry Chagin 
44217913b0bSDmitry Chagin 	/*
44317913b0bSDmitry Chagin 	 * usize can be less than size of struct clone_args, to avoid using
44417913b0bSDmitry Chagin 	 * of uninitialized data of struct clone_args, allocate at least
44517913b0bSDmitry Chagin 	 * sizeof(struct clone_args) storage and zero it.
44617913b0bSDmitry Chagin 	 */
44717913b0bSDmitry Chagin 	size = max(args->usize, sizeof(*uca));
44817913b0bSDmitry Chagin 	uca = malloc(size, M_LINUX, M_WAITOK | M_ZERO);
44917913b0bSDmitry Chagin 	error = copyin(args->uargs, uca, args->usize);
45017913b0bSDmitry Chagin 	if (error != 0)
45117913b0bSDmitry Chagin 		goto out;
45217913b0bSDmitry Chagin 	error = linux_clone3_args_valid(uca);
45317913b0bSDmitry Chagin 	if (error != 0)
45417913b0bSDmitry Chagin 		goto out;
45517913b0bSDmitry Chagin 	ca = malloc(sizeof(*ca), M_LINUX, M_WAITOK | M_ZERO);
45617913b0bSDmitry Chagin 	ca->flags = uca->flags;
45717913b0bSDmitry Chagin 	ca->child_tid = PTRIN(uca->child_tid);
45817913b0bSDmitry Chagin 	ca->parent_tid = PTRIN(uca->parent_tid);
45917913b0bSDmitry Chagin 	ca->exit_signal = uca->exit_signal;
46017913b0bSDmitry Chagin 	ca->stack = uca->stack + uca->stack_size;
46117913b0bSDmitry Chagin 	ca->stack_size = uca->stack_size;
46217913b0bSDmitry Chagin 	ca->tls = uca->tls;
46317913b0bSDmitry Chagin 
46417913b0bSDmitry Chagin 	if ((ca->flags & LINUX_CLONE_THREAD) != 0)
46517913b0bSDmitry Chagin 		error = linux_clone_thread(td, ca);
46617913b0bSDmitry Chagin 	else
46717913b0bSDmitry Chagin 		error = linux_clone_proc(td, ca);
46817913b0bSDmitry Chagin 	free(ca, M_LINUX);
46917913b0bSDmitry Chagin out:
47017913b0bSDmitry Chagin 	free(uca, M_LINUX);
47117913b0bSDmitry Chagin 	return (error);
47217913b0bSDmitry Chagin }
47317913b0bSDmitry Chagin 
474161acbb6SDmitry Chagin int
linux_exit(struct thread * td,struct linux_exit_args * args)475161acbb6SDmitry Chagin linux_exit(struct thread *td, struct linux_exit_args *args)
476161acbb6SDmitry Chagin {
477a089c17dSEdward Tomasz Napierala 	struct linux_emuldata *em __diagused;
478161acbb6SDmitry Chagin 
47981338031SDmitry Chagin 	em = em_find(td);
48081338031SDmitry Chagin 	KASSERT(em != NULL, ("exit: emuldata not found.\n"));
481161acbb6SDmitry Chagin 
48281338031SDmitry Chagin 	LINUX_CTR2(exit, "thread(%d) (%d)", em->em_tid, args->rval);
48381338031SDmitry Chagin 
48481338031SDmitry Chagin 	linux_thread_detach(td);
48581338031SDmitry Chagin 
48681338031SDmitry Chagin 	/*
48781338031SDmitry Chagin 	 * XXX. When the last two threads of a process
48881338031SDmitry Chagin 	 * exit via pthread_exit() try thr_exit() first.
48981338031SDmitry Chagin 	 */
49081338031SDmitry Chagin 	kern_thr_exit(td);
491b4490c6eSKonstantin Belousov 	exit1(td, args->rval, 0);
492161acbb6SDmitry Chagin 		/* NOTREACHED */
493161acbb6SDmitry Chagin }
494bc273677SDmitry Chagin 
495bc273677SDmitry Chagin int
linux_set_tid_address(struct thread * td,struct linux_set_tid_address_args * args)496bc273677SDmitry Chagin linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args)
497bc273677SDmitry Chagin {
498bc273677SDmitry Chagin 	struct linux_emuldata *em;
499bc273677SDmitry Chagin 
500bc273677SDmitry Chagin 	em = em_find(td);
501bc273677SDmitry Chagin 	KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n"));
502bc273677SDmitry Chagin 
503bc273677SDmitry Chagin 	em->child_clear_tid = args->tidptr;
504bc273677SDmitry Chagin 
505bc273677SDmitry Chagin 	td->td_retval[0] = em->em_tid;
506bc273677SDmitry Chagin 
507bc273677SDmitry Chagin 	LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d",
508bc273677SDmitry Chagin 	    em->em_tid, args->tidptr, td->td_retval[0]);
509bc273677SDmitry Chagin 
510bc273677SDmitry Chagin 	return (0);
511bc273677SDmitry Chagin }
512bc273677SDmitry Chagin 
513bc273677SDmitry Chagin void
linux_thread_detach(struct thread * td)514bc273677SDmitry Chagin linux_thread_detach(struct thread *td)
515bc273677SDmitry Chagin {
516bc273677SDmitry Chagin 	struct linux_emuldata *em;
517bc273677SDmitry Chagin 	int *child_clear_tid;
518bc273677SDmitry Chagin 	int error;
519bc273677SDmitry Chagin 
520bc273677SDmitry Chagin 	em = em_find(td);
521bc273677SDmitry Chagin 	KASSERT(em != NULL, ("thread_detach: emuldata not found.\n"));
522bc273677SDmitry Chagin 
5237d96520bSDmitry Chagin 	LINUX_CTR1(thread_detach, "thread(%d)", em->em_tid);
524bc273677SDmitry Chagin 
525bc273677SDmitry Chagin 	release_futexes(td, em);
526bc273677SDmitry Chagin 
527bc273677SDmitry Chagin 	child_clear_tid = em->child_clear_tid;
528bc273677SDmitry Chagin 
529bc273677SDmitry Chagin 	if (child_clear_tid != NULL) {
5307d96520bSDmitry Chagin 		LINUX_CTR2(thread_detach, "thread(%d) %p",
531bc273677SDmitry Chagin 		    em->em_tid, child_clear_tid);
532bc273677SDmitry Chagin 
533bc273677SDmitry Chagin 		error = suword32(child_clear_tid, 0);
534bc273677SDmitry Chagin 		if (error != 0)
535bc273677SDmitry Chagin 			return;
536bc273677SDmitry Chagin 
5370dc38e33SDmitry Chagin 		error = futex_wake(td, child_clear_tid, 1, false);
538bc273677SDmitry Chagin 		/*
539bc273677SDmitry Chagin 		 * this cannot happen at the moment and if this happens it
540bc273677SDmitry Chagin 		 * probably means there is a user space bug
541bc273677SDmitry Chagin 		 */
542bc273677SDmitry Chagin 		if (error != 0)
543bc273677SDmitry Chagin 			linux_msg(td, "futex stuff in thread_detach failed.");
544bc273677SDmitry Chagin 	}
5457a718f29SDmitry Chagin 
5467a718f29SDmitry Chagin 	/*
5477a718f29SDmitry Chagin 	 * Do not rely on the robust list which is maintained by userspace,
5487a718f29SDmitry Chagin 	 * cleanup remaining pi (if any) after release_futexes anyway.
5497a718f29SDmitry Chagin 	 */
5507a718f29SDmitry Chagin 	umtx_thread_exit(td);
551bc273677SDmitry Chagin }
552