1#!/bin/sh 2 3# 4# Copyright (c) 2016 EMC Corp. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# It seems to be possible for ptrace(PT_ATTACH) to race with the delivery 30# of a signal to the same process. 31 32# $ while ./pt.sh; do date; done 33# 15. juli 2016 kl. 05.59.05 CEST 34# 15. juli 2016 kl. 06.03.07 CEST 35# UID PID PPID CPU PRI NI VSZ RSS MWCHAN STAT TT TIME COMMAND 36# 1001 863 862 0 44 0 13880 5268 wait Is 0 0:00,13 -bash (bash) 37# 1001 21053 863 0 52 0 13188 3088 wait I+ 0 0:00,01 /bin/sh ./pt.sh 38# 1001 21096 21053 0 52 0 10544 2308 wait I+ 0 0:00,00 /tmp/pt 39# 1001 21103 21096 0 20 0 12852 2456 wait S+ 0 0:00,00 pt: main (pt) 40# 1001 21103 21096 0 35 0 12852 2456 wait I+ 0 0:55,30 pt: main (pt) 41# 1001 21104 21096 0 72 0 0 0 - Z+ 0 0:00,00 <defunct> 42# 1001 21105 21096 0 72 0 0 0 - Z+ 0 0:00,00 <defunct> 43# 1001 21116 21103 0 103 0 10544 2336 - RX+ 0 4:22,41 pt: spinner (pt) 44# 1001 37711 21103 0 20 0 21200 2960 - R+ 0 0:00,00 ps -Hl 45# 1001 890 879 0 20 0 22184 6196 select Ss+ 1 1:21,86 top -s 1 46# 1001 85222 85221 0 21 0 13880 5276 ttyin Is+ 2 0:00,23 -bash (bash) 47# SIGALRM state 2, pid 21116 48# $ 49 50# Fixed by r303423. 51 52. ../default.cfg 53 54dir=/tmp 55odir=`pwd` 56cd $dir 57sed '1,/^EOF/d' < $odir/$0 > $dir/ptrace7.c 58mycc -o ptrace7 -Wall -Wextra -O0 -g ptrace7.c -pthread || exit 1 59rm -f ptrace7.c 60cd $odir 61 62/tmp/ptrace7 63s=$? 64 65while pgrep -q swap; do 66 pkill -9 swap 67done 68rm -rf /tmp/ptrace7 69exit $s 70 71EOF 72#include <sys/param.h> 73#include <sys/ptrace.h> 74#include <sys/stat.h> 75#include <sys/wait.h> 76 77#include <err.h> 78#include <errno.h> 79#include <fcntl.h> 80#include <pthread.h> 81#ifdef __FreeBSD__ 82#include <pthread_np.h> 83#define __NP__ 84#endif 85#include <signal.h> 86#include <stdio.h> 87#include <stdlib.h> 88#include <time.h> 89#include <unistd.h> 90 91static pid_t pid; 92static pthread_barrier_t barr; 93static int cont; 94static int state; 95 96#define PARALLEL 8 97#define RUNTIME (4 * 60) 98 99static void 100ahandler(int i __unused) 101{ 102 system("ps -Hl"); 103 fprintf(stderr, "SIGALRM state %d, pid %d\n", state, pid); 104 exit(1); 105} 106 107static void 108handler(int i __unused) 109{ 110} 111 112static void * 113t1(void *data __unused) 114{ 115 int status; 116 117#ifdef __NP__ 118 pthread_set_name_np(pthread_self(), __func__); 119#endif 120 while (cont == 1) { 121 state = 1; 122 if (ptrace(PT_ATTACH, pid, 0, 0) == -1) 123 err(1, "ptrace(%d)", pid); 124 125 state = 2; 126 if (waitpid(pid, &status, 0) == -1) 127 err(1, "waitpid"); 128 else if (!WIFSTOPPED(status)) 129 errx(1, "failed to stop child"); 130 state = 3; 131 if (ptrace(PT_DETACH, pid, 0, 0) == -1) 132 err(1, "ptrace"); 133 state = 4; 134 usleep(arc4random() % 100 + 50); 135 } 136 137 return (NULL); 138} 139 140static void * 141t2(void *data __unused) 142{ 143#ifdef __NP__ 144 pthread_set_name_np(pthread_self(), __func__); 145#endif 146 while (cont == 1) { 147 if (kill(pid, SIGHUP) == -1) 148 err(1, "kill"); 149 usleep(arc4random() % 100 + 50); 150 } 151 152 return (NULL); 153} 154 155static void 156test(void) 157{ 158 pthread_t tid[2]; 159 struct sigaction sa; 160 int r, status; 161 162 r = pthread_barrier_wait(&barr); 163 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) 164 errc(1, r, "pthread_barrier_wait"); 165 166 sa.sa_handler = ahandler; 167 sigemptyset(&sa.sa_mask); 168 sa.sa_flags = 0; 169 if (sigaction(SIGALRM, &sa, NULL) == -1) 170 err(1, "sigaction"); 171 alarm(RUNTIME + 60); 172 173 sa.sa_handler = handler; 174 sigemptyset(&sa.sa_mask); 175 sa.sa_flags = 0; 176 if (sigaction(SIGHUP, &sa, NULL) == -1) 177 err(1, "sigaction"); 178 179 setproctitle("%s", "spinner"); 180 if ((pid = fork()) == 0) { 181 for(;;) 182 getuid(); 183 184 _exit(0); 185 } 186 187 cont = 1; 188 if ((r = pthread_create(&tid[0], NULL, t1, NULL)) == -1) 189 errc(1, r, "pthread_create"); 190 if ((r = pthread_create(&tid[1], NULL, t2, NULL)) == -1) 191 errc(1, r, "pthread_create"); 192 193 setproctitle("%s", "main"); 194 sleep(RUNTIME); 195 196 cont = 0; 197 if ((r = pthread_join(tid[0], NULL)) == -1) 198 errc(1, r, "pthread_join"); 199 if ((r = pthread_join(tid[1], NULL)) == -1) 200 errc(1, r, "pthread_join"); 201 if (kill(pid, SIGKILL) != 0) 202 err(1, "kill(%d)", pid); 203 if (waitpid(pid, &status, 0) == -1) 204 err(1, "waitpid(%d)", pid); 205 206 exit(0); 207} 208 209int 210main(void) 211{ 212 pthread_barrierattr_t attr; 213 int e, i, pids[PARALLEL], r, status; 214 215 if ((r = pthread_barrierattr_init(&attr)) != 0) 216 errc(1, r, "pthread_barrierattr_init"); 217 if ((r = pthread_barrierattr_setpshared(&attr, 218 PTHREAD_PROCESS_SHARED)) != 0) 219 errc(1, r, "pthread_barrierattr_setpshared"); 220 if ((r = pthread_barrier_init(&barr, &attr, PARALLEL)) != 0) 221 errc(1, r, "pthread_barrier_init"); 222 223 e = 0; 224 for (i = 0; i < PARALLEL; i++) { 225 if ((pids[i] = fork()) == 0) 226 test(); 227 } 228 for (i = 0; i < PARALLEL; i++) { 229 if (waitpid(pids[i], &status, 0) == -1) 230 err(1, "waitpid%d)", pids[i]); 231 e += status == 0 ? 0 : 1; 232 } 233 234 if ((r = pthread_barrier_destroy(&barr)) > 0) 235 errc(1, r, "pthread_barrier_destroy"); 236 237 return (e); 238} 239