1 /* $NetBSD: t_clone.c,v 1.3 2011/12/12 20:55:44 joerg 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.3 2011/12/12 20:55:44 joerg Exp $"); 36 37 #include <sys/mman.h> 38 #include <sys/resource.h> 39 #include <sys/types.h> 40 #include <sys/wait.h> 41 42 #include <errno.h> 43 #include <sched.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include <atf-c.h> 51 52 #define STACKSIZE (8 * 1024) 53 #define FROBVAL 41973 54 #define CHILDEXIT 0xa5 55 56 static int 57 dummy(void *arg) 58 { 59 60 return 0; 61 } 62 63 static int 64 clone_func(void *arg) 65 { 66 long *frobp = arg, diff; 67 68 printf("child: stack ~= %p, frobme = %p\n", &frobp, frobp); 69 fflush(stdout); 70 71 if (frobp[0] != getppid()) 72 return 1; 73 74 if (frobp[0] == getpid()) 75 return 2; 76 77 diff = labs(frobp[1] - (long) &frobp); 78 79 if (diff > 1024) 80 return 3; 81 82 frobp[1] = FROBVAL; 83 84 return (CHILDEXIT); 85 } 86 87 ATF_TC(clone_basic); 88 ATF_TC_HEAD(clone_basic, tc) 89 { 90 91 atf_tc_set_md_var(tc, "descr", "Checks clone(2)"); 92 } 93 94 ATF_TC_BODY(clone_basic, tc) 95 { 96 sigset_t mask; 97 void *allocstack, *stack; 98 pid_t pid; 99 volatile long frobme[2]; 100 int stat; 101 102 allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, 103 MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); 104 105 ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED); 106 107 stack = allocstack; 108 #ifndef __MACHINE_STACK_GROWS_UP 109 stack = (char *)stack + STACKSIZE; 110 #endif 111 112 printf("parent: stack = %p, frobme = %p\n", stack, frobme); 113 fflush(stdout); 114 115 frobme[0] = (long)getpid(); 116 frobme[1] = (long)stack; 117 118 sigemptyset(&mask); 119 sigaddset(&mask, SIGUSR1); 120 121 ATF_REQUIRE_ERRNO(errno, sigprocmask(SIG_BLOCK, &mask, NULL) != -1); 122 123 switch (pid = __clone(clone_func, stack, 124 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGUSR1, 125 __UNVOLATILE(frobme))) { 126 case 0: 127 atf_tc_fail("clone() returned 0"); 128 /*NOTREACHED*/ 129 case -1: 130 atf_tc_fail("clone() failed: %s", strerror(errno)); 131 /*NOTREACHED*/ 132 default: 133 while (waitpid(pid, &stat, __WCLONE) != pid) 134 continue; 135 } 136 137 ATF_REQUIRE_MSG(WIFEXITED(stat) != 0, "child didn't exit"); 138 139 printf("parent: childexit = 0x%x, frobme = %ld\n", 140 WEXITSTATUS(stat), frobme[1]); 141 142 switch (WEXITSTATUS(stat)) { 143 case CHILDEXIT: 144 ATF_REQUIRE_EQ(frobme[1], FROBVAL); 145 break; 146 case 1: 147 atf_tc_fail("child: argument does not contain parent's pid"); 148 /*NOTREACHED*/ 149 case 2: 150 atf_tc_fail("child: called in parent's pid"); 151 /*NOTREACHED*/ 152 case 3: 153 atf_tc_fail("child: called with bad stack"); 154 /*NOTREACHED*/ 155 default: 156 atf_tc_fail("child returned unknown code: %d", 157 WEXITSTATUS(stat)); 158 /*NOTREACHED*/ 159 } 160 161 ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1); 162 } 163 164 ATF_TC(clone_null_stack); 165 ATF_TC_HEAD(clone_null_stack, tc) 166 { 167 168 atf_tc_set_md_var(tc, "descr", 169 "Checks that clone(2) fails when stack pointer is NULL"); 170 } 171 172 ATF_TC_BODY(clone_null_stack, tc) 173 { 174 int rv; 175 176 rv = __clone(dummy, NULL, 177 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); 178 179 ATF_REQUIRE_EQ(rv, -1); 180 ATF_REQUIRE_EQ(errno, EINVAL); 181 } 182 183 ATF_TC(clone_null_func); 184 ATF_TC_HEAD(clone_null_func, tc) 185 { 186 187 atf_tc_set_md_var(tc, "descr", 188 "Checks that clone(2) fails when function pointer is NULL"); 189 } 190 191 ATF_TC_BODY(clone_null_func, tc) 192 { 193 void *allocstack, *stack; 194 int rv; 195 196 allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, 197 MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); 198 ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED); 199 stack = allocstack; 200 #ifndef __MACHINE_STACK_GROWS_UP 201 stack = (char *)stack + STACKSIZE; 202 #endif 203 204 errno = 0; 205 rv = __clone(0, stack, 206 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); 207 208 ATF_REQUIRE_EQ(rv, -1); 209 ATF_REQUIRE_EQ(errno, EINVAL); 210 211 ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1); 212 } 213 214 ATF_TC(clone_out_of_proc); 215 ATF_TC_HEAD(clone_out_of_proc, tc) 216 { 217 218 atf_tc_set_md_var(tc, "descr", 219 "Checks that clone(2) fails when running out of processes"); 220 atf_tc_set_md_var(tc, "require.user", "unprivileged"); 221 } 222 223 ATF_TC_BODY(clone_out_of_proc, tc) 224 { 225 struct rlimit rl; 226 int rv; 227 228 ATF_REQUIRE_ERRNO(errno, getrlimit(RLIMIT_NPROC, &rl) != -1); 229 230 rl.rlim_cur = 0; 231 rl.rlim_max = 0; 232 233 ATF_REQUIRE_ERRNO(errno, setrlimit(RLIMIT_NPROC, &rl) != -1); 234 235 errno = 0; 236 rv = __clone(dummy, malloc(10240), 237 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, (void *)&rl); 238 239 ATF_REQUIRE_EQ(rv, -1); 240 ATF_REQUIRE_EQ(errno, EAGAIN); 241 } 242 243 ATF_TP_ADD_TCS(tp) 244 { 245 246 ATF_TP_ADD_TC(tp, clone_basic); 247 ATF_TP_ADD_TC(tp, clone_null_stack); 248 ATF_TP_ADD_TC(tp, clone_null_func); 249 ATF_TP_ADD_TC(tp, clone_out_of_proc); 250 251 return atf_no_error(); 252 } 253