@@ -40,7 +40,28 @@ static int required_exit_status(void) {
4040
4141static void kill_and_reap (pid_t pid ) {
4242 kill (pid , SIGKILL );
43- while (waitpid (pid , NULL , 0 ) < 0 && errno == EINTR ) {}
43+ for (;;) {
44+ int status ;
45+ pid_t waited ;
46+ do {
47+ waited = waitpid (pid , & status , __WALL );
48+ } while (waited < 0 && errno == EINTR );
49+ if (waited < 0 || WIFEXITED (status ) || WIFSIGNALED (status )) return ;
50+ if (WIFSTOPPED (status )) ptrace (PTRACE_CONT , pid , 0 , (void * )(uintptr_t )SIGKILL );
51+ }
52+ }
53+
54+ static int interrupt_and_detach (pid_t pid ) {
55+ if (ptrace (PTRACE_INTERRUPT , pid , 0 , 0 ) < 0 ) return errno ;
56+ int status = 0 ;
57+ pid_t waited ;
58+ do {
59+ waited = waitpid (pid , & status , __WALL );
60+ } while (waited < 0 && errno == EINTR );
61+ if (waited < 0 ) return errno ;
62+ if (waited != pid || !WIFSTOPPED (status )) return EPROTO ;
63+ if (ptrace (PTRACE_DETACH , pid , 0 , 0 ) < 0 ) return errno ;
64+ return 0 ;
4465}
4566
4667static pid_t paused_child (int * ready_fd , volatile uint64_t * * remote_word ) {
@@ -153,15 +174,39 @@ static void test_seize_and_vm_io(void) {
153174 report ("process-vm-read" , read_ok , read_error , "direct child" );
154175
155176 if (seize_ok ) {
156- if (ptrace (PTRACE_INTERRUPT , pid , 0 , 0 ) < 0 ) abort ();
157- int status ;
158- while (waitpid (pid , & status , 0 ) < 0 && errno == EINTR ) {}
159- if (!WIFSTOPPED (status )) abort ();
160-
177+ int word_error = 0 ;
178+ bool word_ok = true;
179+ bool stopped = false;
161180 errno = 0 ;
162- long peeked = ptrace (PTRACE_PEEKDATA , pid , (void * )remote_word , 0 );
163- int word_error = errno ;
164- bool word_ok = !(peeked == -1 && word_error != 0 );
181+ if (ptrace (PTRACE_INTERRUPT , pid , 0 , 0 ) < 0 ) {
182+ word_error = errno ;
183+ word_ok = false;
184+ }
185+
186+ if (word_ok ) {
187+ int status = 0 ;
188+ pid_t waited ;
189+ do {
190+ waited = waitpid (pid , & status , 0 );
191+ } while (waited < 0 && errno == EINTR );
192+ if (waited < 0 ) {
193+ word_error = errno ;
194+ word_ok = false;
195+ } else if (waited != pid || !WIFSTOPPED (status )) {
196+ word_error = EPROTO ;
197+ word_ok = false;
198+ } else {
199+ stopped = true;
200+ }
201+ }
202+
203+ long peeked = 0 ;
204+ if (word_ok ) {
205+ errno = 0 ;
206+ peeked = ptrace (PTRACE_PEEKDATA , pid , (void * )remote_word , 0 );
207+ word_error = errno ;
208+ word_ok = !(peeked == -1 && word_error != 0 );
209+ }
165210 const uint64_t ptrace_replacement = UINT64_C (0x8877665544332211 );
166211 if (word_ok &&
167212 ptrace (PTRACE_POKEDATA , pid , (void * )remote_word ,
@@ -176,9 +221,12 @@ static void test_seize_and_vm_io(void) {
176221 word_ok = !(peeked == -1 && word_error != 0 ) &&
177222 (uint64_t )(unsigned long )peeked == ptrace_replacement ;
178223 }
224+ if (stopped && ptrace (PTRACE_DETACH , pid , 0 , 0 ) < 0 ) {
225+ if (word_ok ) word_error = errno ;
226+ word_ok = false;
227+ }
179228 report_required ("ptrace-word-io" , word_ok , word_error ,
180- "stopped direct child" );
181- if (ptrace (PTRACE_DETACH , pid , 0 , 0 ) < 0 ) abort ();
229+ "interrupt, stop, word I/O, and detach" );
182230 } else {
183231 report_required ("ptrace-word-io" , false, error ,
184232 "seize failed before word I/O" );
@@ -189,14 +237,7 @@ static void test_seize_and_vm_io(void) {
189237static int seize_from_child (pid_t target ) {
190238 errno = 0 ;
191239 if (ptrace (PTRACE_SEIZE , target , 0 , 0 ) < 0 ) return errno ;
192- if (ptrace (PTRACE_INTERRUPT , target , 0 , 0 ) < 0 ) return errno ;
193- int status ;
194- while (waitpid (target , & status , __WALL ) < 0 ) {
195- if (errno != EINTR ) return errno ;
196- }
197- if (!WIFSTOPPED (status )) return EPROTO ;
198- if (ptrace (PTRACE_DETACH , target , 0 , 0 ) < 0 ) return errno ;
199- return 0 ;
240+ return interrupt_and_detach (target );
200241}
201242
202243static void test_sibling (bool allow_with_prctl ) {
@@ -238,9 +279,13 @@ static void test_sibling(bool allow_with_prctl) {
238279 }
239280 if (write (tracer_pipe [1 ], & target , sizeof (target )) != sizeof (target )) abort ();
240281 close (tracer_pipe [1 ]);
241- int status ;
242- while (waitpid (tracer , & status , 0 ) < 0 && errno == EINTR ) {}
243- int result = WIFEXITED (status ) ? WEXITSTATUS (status ) : 255 ;
282+ int status = 0 ;
283+ pid_t waited ;
284+ do {
285+ waited = waitpid (tracer , & status , 0 );
286+ } while (waited < 0 && errno == EINTR );
287+ int result = waited == tracer && WIFEXITED (status ) ? WEXITSTATUS (status ) : 255 ;
288+ if (waited < 0 ) result = errno ;
244289 report (name , result == 0 , result , allow_with_prctl ? "target opted in" : "same UID" );
245290 kill_and_reap (target );
246291}
@@ -263,8 +308,9 @@ static void test_dumpable_zero(void) {
263308 errno = 0 ;
264309 int rc = ptrace (PTRACE_SEIZE , pid , 0 , 0 );
265310 int error = errno ;
266- report ("seize-dumpable-zero-child" , rc == 0 , error , "" );
267- if (rc == 0 ) ptrace (PTRACE_DETACH , pid , 0 , 0 );
311+ bool ok = rc == 0 ;
312+ if (ok && (error = interrupt_and_detach (pid )) != 0 ) ok = false;
313+ report ("seize-dumpable-zero-child" , ok , error , "" );
268314 kill_and_reap (pid );
269315}
270316
@@ -286,9 +332,10 @@ static void test_grandchild(void) {
286332 errno = 0 ;
287333 int rc = ptrace (PTRACE_SEIZE , target , 0 , 0 );
288334 int error = errno ;
289- report_required ("seize-live-grandchild" , rc == 0 , error ,
335+ bool ok = rc == 0 ;
336+ if (ok && (error = interrupt_and_detach (target )) != 0 ) ok = false;
337+ report_required ("seize-live-grandchild" , ok , error ,
290338 "ancestor, not direct parent" );
291- if (rc == 0 ) ptrace (PTRACE_DETACH , target , 0 , 0 );
292339 kill_and_reap (target );
293340 kill_and_reap (middle );
294341}
@@ -314,9 +361,10 @@ static void test_orphan(bool subreaper) {
314361 errno = 0 ;
315362 int rc = ptrace (PTRACE_SEIZE , target , 0 , 0 );
316363 int error = errno ;
364+ bool ok = rc == 0 ;
365+ if (ok && (error = interrupt_and_detach (target )) != 0 ) ok = false;
317366 report (subreaper ? "seize-orphan-subreaper" : "seize-orphan-no-subreaper" ,
318- rc == 0 , error , subreaper ? "reparented to supervisor" : "reparented away" );
319- if (rc == 0 ) ptrace (PTRACE_DETACH , target , 0 , 0 );
367+ ok , error , subreaper ? "reparented to supervisor" : "reparented away" );
320368 kill (target , SIGKILL );
321369 waitpid (target , NULL , 0 );
322370 prctl (PR_SET_CHILD_SUBREAPER , 0 , 0 , 0 , 0 );
@@ -338,16 +386,40 @@ static void test_suid_exec(bool traced) {
338386 execl (suid_target , suid_target , "suid-target" , NULL );
339387 _exit (121 );
340388 }
341- int status ;
342- waitpid (pid , & status , 0 );
389+ int status = 0 ;
390+ pid_t waited ;
391+ do {
392+ waited = waitpid (pid , & status , 0 );
393+ } while (waited < 0 && errno == EINTR );
394+ if (waited < 0 ) {
395+ int error = errno ;
396+ report_required (traced ? "setuid-exec-traced" : "setuid-exec-untraced" ,
397+ false, error , "waitpid failed" );
398+ kill_and_reap (pid );
399+ return ;
400+ }
343401 if (traced && WIFSTOPPED (status ) && WSTOPSIG (status ) == SIGTRAP ) {
344- ptrace (PTRACE_CONT , pid , 0 , 0 );
345- waitpid (pid , & status , 0 );
402+ if (ptrace (PTRACE_CONT , pid , 0 , 0 ) < 0 ) {
403+ int error = errno ;
404+ report_required ("setuid-exec-traced" , false, error , "PTRACE_CONT failed" );
405+ kill_and_reap (pid );
406+ return ;
407+ }
408+ do {
409+ waited = waitpid (pid , & status , 0 );
410+ } while (waited < 0 && errno == EINTR );
411+ if (waited < 0 ) {
412+ int error = errno ;
413+ report_required ("setuid-exec-traced" , false, error , "waitpid failed" );
414+ kill_and_reap (pid );
415+ return ;
416+ }
346417 }
347418 int code = WIFEXITED (status ) ? WEXITSTATUS (status ) : 255 ;
348419 bool ok = traced ? code == 42 : code == 0 ;
349420 report_required (traced ? "setuid-exec-traced" : "setuid-exec-untraced" , ok , 0 ,
350421 traced ? "expected euid unchanged" : "expected euid root" );
422+ if (!WIFEXITED (status ) && !WIFSIGNALED (status )) kill_and_reap (pid );
351423}
352424
353425static void print_proc_field (const char * prefix ) {
0 commit comments