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