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