1 /* $NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __COPYRIGHT("@(#) Copyright (c) 2008\ 34 The NetBSD Foundation, inc. All rights reserved."); 35 __RCSID("$NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/mman.h> 40 #include <sys/resource.h> 41 #include <sys/wait.h> 42 43 #include <errno.h> 44 #include <sched.h> 45 #include <signal.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include <atf-c.h> 52 53 #define STACKSIZE (8 * 1024) 54 #define FROBVAL 41973 55 #define CHILDEXIT 0xa5 56 57 static void * 58 getstack(void) 59 { 60 void *stack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE, 61 MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); 62 ATF_REQUIRE_ERRNO(errno, stack != MAP_FAILED); 63 #ifndef __MACHINE_STACK_GROWS_UP 64 stack = (char *)stack + STACKSIZE; 65 #endif 66 return stack; 67 } 68 69 static void 70 putstack(void *stack) 71 { 72 #ifndef __MACHINE_STACK_GROWS_UP 73 stack = (char *)stack - STACKSIZE; 74 #endif 75 ATF_REQUIRE_ERRNO(errno, munmap(stack, STACKSIZE) != -1); 76 } 77 78 static int 79 dummy(void *arg) 80 { 81 82 return 0; 83 } 84 85 static int 86 clone_func(void *arg) 87 { 88 long *frobp = arg, diff; 89 90 printf("child: stack ~= %p, frobme = %p\n", &frobp, frobp); 91 fflush(stdout); 92 93 if (frobp[0] != getppid()) 94 return 1; 95 96 if (frobp[0] == getpid()) 97 return 2; 98 99 diff = labs(frobp[1] - (long) &frobp); 100 101 if (diff > 1024) 102 return 3; 103 104 frobp[1] = FROBVAL; 105 106 return (CHILDEXIT); 107 } 108 109 ATF_TC(clone_basic); 110 ATF_TC_HEAD(clone_basic, tc) 111 { 112 113 atf_tc_set_md_var(tc, "descr", "Checks clone(2)"); 114 } 115 116 ATF_TC_BODY(clone_basic, tc) 117 { 118 sigset_t mask; 119 void *stack = getstack(); 120 pid_t pid; 121 volatile long frobme[2]; 122 int stat; 123 124 printf("parent: stack = %p, frobme = %p\n", stack, frobme); 125 fflush(stdout); 126 127 frobme[0] = (long)getpid(); 128 frobme[1] = (long)stack; 129 130 sigemptyset(&mask); 131 sigaddset(&mask, SIGUSR1); 132 133 ATF_REQUIRE_ERRNO(errno, sigprocmask(SIG_BLOCK, &mask, NULL) != -1); 134 135 switch (pid = __clone(clone_func, stack, 136 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGUSR1, 137 __UNVOLATILE(frobme))) { 138 case 0: 139 atf_tc_fail("clone() returned 0"); 140 /*NOTREACHED*/ 141 case -1: 142 atf_tc_fail("clone() failed: %s", strerror(errno)); 143 /*NOTREACHED*/ 144 default: 145 while (waitpid(pid, &stat, __WCLONE) != pid) 146 continue; 147 } 148 149 ATF_REQUIRE_MSG(WIFEXITED(stat) != 0, "child didn't exit"); 150 151 printf("parent: childexit = 0x%x, frobme = %ld\n", 152 WEXITSTATUS(stat), frobme[1]); 153 154 switch (WEXITSTATUS(stat)) { 155 case CHILDEXIT: 156 ATF_REQUIRE_EQ(frobme[1], FROBVAL); 157 break; 158 case 1: 159 atf_tc_fail("child: argument does not contain parent's pid"); 160 /*NOTREACHED*/ 161 case 2: 162 atf_tc_fail("child: called in parent's pid"); 163 /*NOTREACHED*/ 164 case 3: 165 atf_tc_fail("child: called with bad stack"); 166 /*NOTREACHED*/ 167 default: 168 atf_tc_fail("child returned unknown code: %d", 169 WEXITSTATUS(stat)); 170 /*NOTREACHED*/ 171 } 172 173 putstack(stack); 174 } 175 176 ATF_TC(clone_null_stack); 177 ATF_TC_HEAD(clone_null_stack, tc) 178 { 179 180 atf_tc_set_md_var(tc, "descr", 181 "Checks that clone(2) fails when stack pointer is NULL"); 182 } 183 184 ATF_TC_BODY(clone_null_stack, tc) 185 { 186 int rv; 187 188 rv = __clone(dummy, NULL, 189 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); 190 191 ATF_REQUIRE_EQ(rv, -1); 192 ATF_REQUIRE_EQ(errno, EINVAL); 193 } 194 195 ATF_TC(clone_null_func); 196 ATF_TC_HEAD(clone_null_func, tc) 197 { 198 199 atf_tc_set_md_var(tc, "descr", 200 "Checks that clone(2) fails when function pointer is NULL"); 201 } 202 203 ATF_TC_BODY(clone_null_func, tc) 204 { 205 void *stack = getstack(); 206 int rv; 207 208 209 errno = 0; 210 rv = __clone(0, stack, 211 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); 212 213 ATF_REQUIRE_EQ(rv, -1); 214 ATF_REQUIRE_EQ(errno, EINVAL); 215 216 putstack(stack); 217 } 218 219 ATF_TC(clone_out_of_proc); 220 ATF_TC_HEAD(clone_out_of_proc, tc) 221 { 222 223 atf_tc_set_md_var(tc, "descr", 224 "Checks that clone(2) fails when running out of processes"); 225 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 226 } 227 228 ATF_TC_BODY(clone_out_of_proc, tc) 229 { 230 char *stack = getstack(); 231 struct rlimit rl; 232 int rv; 233 234 ATF_REQUIRE_ERRNO(errno, getrlimit(RLIMIT_NPROC, &rl) != -1); 235 236 rl.rlim_cur = 0; 237 rl.rlim_max = 0; 238 239 ATF_REQUIRE_ERRNO(errno, setrlimit(RLIMIT_NPROC, &rl) != -1); 240 241 errno = 0; 242 rv = __clone(dummy, stack, 243 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, (void *)&rl); 244 245 ATF_REQUIRE_EQ(rv, -1); 246 ATF_REQUIRE_EQ(errno, EAGAIN); 247 putstack(stack); 248 } 249 250 ATF_TP_ADD_TCS(tp) 251 { 252 253 ATF_TP_ADD_TC(tp, clone_basic); 254 ATF_TP_ADD_TC(tp, clone_null_stack); 255 ATF_TP_ADD_TC(tp, clone_null_func); 256 ATF_TP_ADD_TC(tp, clone_out_of_proc); 257 258 return atf_no_error(); 259 } 260