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 56static int 57dummy(void *arg) 58{ 59 60 return 0; 61} 62 63static int 64clone_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 87ATF_TC(clone_basic); 88ATF_TC_HEAD(clone_basic, tc) 89{ 90 91 atf_tc_set_md_var(tc, "descr", "Checks clone(2)"); 92} 93 94ATF_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 164ATF_TC(clone_null_stack); 165ATF_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 172ATF_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 183ATF_TC(clone_null_func); 184ATF_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 191ATF_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 214ATF_TC(clone_out_of_proc); 215ATF_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 223ATF_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 243ATF_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