1*25a6599fSriastradh /* $NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $ */ 21c807dbeSpgoyette 31c807dbeSpgoyette /*- 41c807dbeSpgoyette * Copyright (c) 2008 The NetBSD Foundation, Inc. 51c807dbeSpgoyette * All rights reserved. 61c807dbeSpgoyette * 71c807dbeSpgoyette * This code is derived from software contributed to The NetBSD Foundation 81c807dbeSpgoyette * by Jason R. Thorpe. 91c807dbeSpgoyette * 101c807dbeSpgoyette * Redistribution and use in source and binary forms, with or without 111c807dbeSpgoyette * modification, are permitted provided that the following conditions 121c807dbeSpgoyette * are met: 131c807dbeSpgoyette * 1. Redistributions of source code must retain the above copyright 141c807dbeSpgoyette * notice, this list of conditions and the following disclaimer. 151c807dbeSpgoyette * 2. Redistributions in binary form must reproduce the above copyright 161c807dbeSpgoyette * notice, this list of conditions and the following disclaimer in the 171c807dbeSpgoyette * documentation and/or other materials provided with the distribution. 181c807dbeSpgoyette * 191c807dbeSpgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201c807dbeSpgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211c807dbeSpgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221c807dbeSpgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231c807dbeSpgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241c807dbeSpgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251c807dbeSpgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261c807dbeSpgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271c807dbeSpgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281c807dbeSpgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291c807dbeSpgoyette * POSSIBILITY OF SUCH DAMAGE. 301c807dbeSpgoyette */ 311c807dbeSpgoyette 321c807dbeSpgoyette #include <sys/cdefs.h> 331c807dbeSpgoyette __COPYRIGHT("@(#) Copyright (c) 2008\ 341c807dbeSpgoyette The NetBSD Foundation, inc. All rights reserved."); 35*25a6599fSriastradh __RCSID("$NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $"); 361c807dbeSpgoyette 3785fd21ccSchristos #include <sys/param.h> 3885fd21ccSchristos #include <sys/types.h> 391c807dbeSpgoyette #include <sys/mman.h> 401c807dbeSpgoyette #include <sys/resource.h> 411c807dbeSpgoyette #include <sys/wait.h> 421c807dbeSpgoyette 431c807dbeSpgoyette #include <errno.h> 441c807dbeSpgoyette #include <sched.h> 451c807dbeSpgoyette #include <signal.h> 461c807dbeSpgoyette #include <stdio.h> 471c807dbeSpgoyette #include <stdlib.h> 481c807dbeSpgoyette #include <string.h> 491c807dbeSpgoyette #include <unistd.h> 501c807dbeSpgoyette 511c807dbeSpgoyette #include <atf-c.h> 521c807dbeSpgoyette 531c807dbeSpgoyette #define STACKSIZE (8 * 1024) 541c807dbeSpgoyette #define FROBVAL 41973 551c807dbeSpgoyette #define CHILDEXIT 0xa5 561c807dbeSpgoyette 5785fd21ccSchristos static void * 5885fd21ccSchristos getstack(void) 5985fd21ccSchristos { 6085fd21ccSchristos void *stack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE, 6185fd21ccSchristos MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); 6285fd21ccSchristos ATF_REQUIRE_ERRNO(errno, stack != MAP_FAILED); 6385fd21ccSchristos #ifndef __MACHINE_STACK_GROWS_UP 6485fd21ccSchristos stack = (char *)stack + STACKSIZE; 6585fd21ccSchristos #endif 6685fd21ccSchristos return stack; 6785fd21ccSchristos } 6885fd21ccSchristos 6985fd21ccSchristos static void 7085fd21ccSchristos putstack(void *stack) 7185fd21ccSchristos { 7285fd21ccSchristos #ifndef __MACHINE_STACK_GROWS_UP 7385fd21ccSchristos stack = (char *)stack - STACKSIZE; 7485fd21ccSchristos #endif 7585fd21ccSchristos ATF_REQUIRE_ERRNO(errno, munmap(stack, STACKSIZE) != -1); 7685fd21ccSchristos } 7785fd21ccSchristos 781c807dbeSpgoyette static int 791c807dbeSpgoyette dummy(void *arg) 801c807dbeSpgoyette { 811c807dbeSpgoyette 821c807dbeSpgoyette return 0; 831c807dbeSpgoyette } 841c807dbeSpgoyette 851c807dbeSpgoyette static int 861c807dbeSpgoyette clone_func(void *arg) 871c807dbeSpgoyette { 881c807dbeSpgoyette long *frobp = arg, diff; 891c807dbeSpgoyette 901c807dbeSpgoyette printf("child: stack ~= %p, frobme = %p\n", &frobp, frobp); 911c807dbeSpgoyette fflush(stdout); 921c807dbeSpgoyette 931c807dbeSpgoyette if (frobp[0] != getppid()) 941c807dbeSpgoyette return 1; 951c807dbeSpgoyette 961c807dbeSpgoyette if (frobp[0] == getpid()) 971c807dbeSpgoyette return 2; 981c807dbeSpgoyette 991c807dbeSpgoyette diff = labs(frobp[1] - (long) &frobp); 1001c807dbeSpgoyette 1011c807dbeSpgoyette if (diff > 1024) 1021c807dbeSpgoyette return 3; 1031c807dbeSpgoyette 1041c807dbeSpgoyette frobp[1] = FROBVAL; 1051c807dbeSpgoyette 1061c807dbeSpgoyette return (CHILDEXIT); 1071c807dbeSpgoyette } 1081c807dbeSpgoyette 109b238e6b2Sjruoho ATF_TC(clone_basic); 110b238e6b2Sjruoho ATF_TC_HEAD(clone_basic, tc) 111b238e6b2Sjruoho { 112b238e6b2Sjruoho 113b238e6b2Sjruoho atf_tc_set_md_var(tc, "descr", "Checks clone(2)"); 114b238e6b2Sjruoho } 115b238e6b2Sjruoho 116b238e6b2Sjruoho ATF_TC_BODY(clone_basic, tc) 1171c807dbeSpgoyette { 1181c807dbeSpgoyette sigset_t mask; 11985fd21ccSchristos void *stack = getstack(); 1201c807dbeSpgoyette pid_t pid; 1211c807dbeSpgoyette volatile long frobme[2]; 1221c807dbeSpgoyette int stat; 1231c807dbeSpgoyette 1241c807dbeSpgoyette printf("parent: stack = %p, frobme = %p\n", stack, frobme); 1251c807dbeSpgoyette fflush(stdout); 1261c807dbeSpgoyette 1271c807dbeSpgoyette frobme[0] = (long)getpid(); 1281c807dbeSpgoyette frobme[1] = (long)stack; 1291c807dbeSpgoyette 1301c807dbeSpgoyette sigemptyset(&mask); 1311c807dbeSpgoyette sigaddset(&mask, SIGUSR1); 1321c807dbeSpgoyette 1331c807dbeSpgoyette ATF_REQUIRE_ERRNO(errno, sigprocmask(SIG_BLOCK, &mask, NULL) != -1); 1341c807dbeSpgoyette 1351c807dbeSpgoyette switch (pid = __clone(clone_func, stack, 1361c807dbeSpgoyette CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGUSR1, 1371c807dbeSpgoyette __UNVOLATILE(frobme))) { 1381c807dbeSpgoyette case 0: 1391c807dbeSpgoyette atf_tc_fail("clone() returned 0"); 1401c807dbeSpgoyette /*NOTREACHED*/ 1411c807dbeSpgoyette case -1: 1421c807dbeSpgoyette atf_tc_fail("clone() failed: %s", strerror(errno)); 1431c807dbeSpgoyette /*NOTREACHED*/ 1441c807dbeSpgoyette default: 1451c807dbeSpgoyette while (waitpid(pid, &stat, __WCLONE) != pid) 1461c807dbeSpgoyette continue; 1471c807dbeSpgoyette } 1481c807dbeSpgoyette 1491c807dbeSpgoyette ATF_REQUIRE_MSG(WIFEXITED(stat) != 0, "child didn't exit"); 1501c807dbeSpgoyette 1511c807dbeSpgoyette printf("parent: childexit = 0x%x, frobme = %ld\n", 1521c807dbeSpgoyette WEXITSTATUS(stat), frobme[1]); 1531c807dbeSpgoyette 1541c807dbeSpgoyette switch (WEXITSTATUS(stat)) { 1551c807dbeSpgoyette case CHILDEXIT: 1561c807dbeSpgoyette ATF_REQUIRE_EQ(frobme[1], FROBVAL); 1571c807dbeSpgoyette break; 1581c807dbeSpgoyette case 1: 1591c807dbeSpgoyette atf_tc_fail("child: argument does not contain parent's pid"); 1601c807dbeSpgoyette /*NOTREACHED*/ 1611c807dbeSpgoyette case 2: 1621c807dbeSpgoyette atf_tc_fail("child: called in parent's pid"); 1631c807dbeSpgoyette /*NOTREACHED*/ 1641c807dbeSpgoyette case 3: 1651c807dbeSpgoyette atf_tc_fail("child: called with bad stack"); 1661c807dbeSpgoyette /*NOTREACHED*/ 1671c807dbeSpgoyette default: 1681c807dbeSpgoyette atf_tc_fail("child returned unknown code: %d", 1691c807dbeSpgoyette WEXITSTATUS(stat)); 1701c807dbeSpgoyette /*NOTREACHED*/ 1711c807dbeSpgoyette } 1721c807dbeSpgoyette 17385fd21ccSchristos putstack(stack); 1741c807dbeSpgoyette } 1751c807dbeSpgoyette 176b238e6b2Sjruoho ATF_TC(clone_null_stack); 177b238e6b2Sjruoho ATF_TC_HEAD(clone_null_stack, tc) 1781c807dbeSpgoyette { 1791c807dbeSpgoyette 1801c807dbeSpgoyette atf_tc_set_md_var(tc, "descr", 1811c807dbeSpgoyette "Checks that clone(2) fails when stack pointer is NULL"); 1821c807dbeSpgoyette } 1831c807dbeSpgoyette 184b238e6b2Sjruoho ATF_TC_BODY(clone_null_stack, tc) 1851c807dbeSpgoyette { 1861c807dbeSpgoyette int rv; 1871c807dbeSpgoyette 1881c807dbeSpgoyette rv = __clone(dummy, NULL, 1891c807dbeSpgoyette CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); 1901c807dbeSpgoyette 1911c807dbeSpgoyette ATF_REQUIRE_EQ(rv, -1); 1921c807dbeSpgoyette ATF_REQUIRE_EQ(errno, EINVAL); 1931c807dbeSpgoyette } 1941c807dbeSpgoyette 195b238e6b2Sjruoho ATF_TC(clone_null_func); 196b238e6b2Sjruoho ATF_TC_HEAD(clone_null_func, tc) 1971c807dbeSpgoyette { 1981c807dbeSpgoyette 1991c807dbeSpgoyette atf_tc_set_md_var(tc, "descr", 2001c807dbeSpgoyette "Checks that clone(2) fails when function pointer is NULL"); 2011c807dbeSpgoyette } 2021c807dbeSpgoyette 203b238e6b2Sjruoho ATF_TC_BODY(clone_null_func, tc) 2041c807dbeSpgoyette { 20585fd21ccSchristos void *stack = getstack(); 2063d408b59Sjoerg int rv; 2071c807dbeSpgoyette 2081c807dbeSpgoyette 2091c807dbeSpgoyette errno = 0; 2101c807dbeSpgoyette rv = __clone(0, stack, 2111c807dbeSpgoyette CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); 2121c807dbeSpgoyette 2131c807dbeSpgoyette ATF_REQUIRE_EQ(rv, -1); 2141c807dbeSpgoyette ATF_REQUIRE_EQ(errno, EINVAL); 2151c807dbeSpgoyette 21685fd21ccSchristos putstack(stack); 2171c807dbeSpgoyette } 2181c807dbeSpgoyette 219b238e6b2Sjruoho ATF_TC(clone_out_of_proc); 220b238e6b2Sjruoho ATF_TC_HEAD(clone_out_of_proc, tc) 2211c807dbeSpgoyette { 2221c807dbeSpgoyette 2231c807dbeSpgoyette atf_tc_set_md_var(tc, "descr", 2241c807dbeSpgoyette "Checks that clone(2) fails when running out of processes"); 2251c807dbeSpgoyette atf_tc_set_md_var(tc, "require.user", "unprivileged"); 2261c807dbeSpgoyette } 2271c807dbeSpgoyette 228b238e6b2Sjruoho ATF_TC_BODY(clone_out_of_proc, tc) 2291c807dbeSpgoyette { 23085fd21ccSchristos char *stack = getstack(); 2311c807dbeSpgoyette struct rlimit rl; 2321c807dbeSpgoyette int rv; 2331c807dbeSpgoyette 2341c807dbeSpgoyette ATF_REQUIRE_ERRNO(errno, getrlimit(RLIMIT_NPROC, &rl) != -1); 2351c807dbeSpgoyette 2361c807dbeSpgoyette rl.rlim_cur = 0; 2371c807dbeSpgoyette rl.rlim_max = 0; 2381c807dbeSpgoyette 2391c807dbeSpgoyette ATF_REQUIRE_ERRNO(errno, setrlimit(RLIMIT_NPROC, &rl) != -1); 2401c807dbeSpgoyette 2411c807dbeSpgoyette errno = 0; 24285fd21ccSchristos rv = __clone(dummy, stack, 2431c807dbeSpgoyette CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, (void *)&rl); 2441c807dbeSpgoyette 2451c807dbeSpgoyette ATF_REQUIRE_EQ(rv, -1); 2461c807dbeSpgoyette ATF_REQUIRE_EQ(errno, EAGAIN); 24785fd21ccSchristos putstack(stack); 2481c807dbeSpgoyette } 2491c807dbeSpgoyette 2501c807dbeSpgoyette ATF_TP_ADD_TCS(tp) 2511c807dbeSpgoyette { 2521c807dbeSpgoyette 253b238e6b2Sjruoho ATF_TP_ADD_TC(tp, clone_basic); 254b238e6b2Sjruoho ATF_TP_ADD_TC(tp, clone_null_stack); 255b238e6b2Sjruoho ATF_TP_ADD_TC(tp, clone_null_func); 256b238e6b2Sjruoho ATF_TP_ADD_TC(tp, clone_out_of_proc); 2571c807dbeSpgoyette 2581c807dbeSpgoyette return atf_no_error(); 2591c807dbeSpgoyette } 260