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