[PATCH] USE_SEIZE: fix detaching from stopped processes

Denys Vlasenko dvlasenk at redhat.com
Wed Jun 19 10:32:37 UTC 2013


On 06/18/2013 10:36 PM, Dmitry V. Levin wrote:
> On Tue, Jun 18, 2013 at 06:18:14PM +0200, Denys Vlasenko wrote:
>> * strace.c (detach) [USE_SEIZE]: If PTRACE_SEIZE API is in use, stop
>> the tracee using PTRACE_INTERRUPT instead of sending it a SIGSTOP.
>> In a subsequent waitpid loop, wait for either SIGSTOP or SIGTRAP.
>>
>> Signed-off-by: Denys Vlasenko <dvlasenk at redhat.com>
>> ---
>>  strace.c | 33 ++++++++++++++++++++++-----------
>>  1 file changed, 22 insertions(+), 11 deletions(-)
>>
>> diff --git a/strace.c b/strace.c
>> index 87aad48..af8156d 100644
>> --- a/strace.c
>> +++ b/strace.c
>> @@ -733,7 +733,7 @@ static int
>>  detach(struct tcb *tcp)
>>  {
>>  	int error;
>> -	int status, sigstop_expected;
>> +	int status, stop_expected;
>>  
>>  	if (tcp->flags & TCB_BPTSET)
>>  		clearbpt(tcp);
>> @@ -749,15 +749,15 @@ detach(struct tcb *tcp)
>>  #endif
>>  
>>  	error = 0;
>> -	sigstop_expected = 0;
>> +	stop_expected = 0;
>>  	if (tcp->flags & TCB_ATTACHED) {
>>  		/*
>>  		 * We attached but possibly didn't see the expected SIGSTOP.
>>  		 * We must catch exactly one as otherwise the detached process
>>  		 * would be left stopped (process state T).
>>  		 */
>> -		sigstop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
>> -		error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0);
>> +		stop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
>> +		error = ptrace(PTRACE_DETACH, tcp->pid, 0, 0);
>>  		if (error == 0) {
>>  			/* On a clear day, you can see forever. */
>>  		}
>> @@ -769,15 +769,24 @@ detach(struct tcb *tcp)
>>  			if (errno != ESRCH)
>>  				perror_msg("detach: checking sanity");
>>  		}
>> -		else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) {
>> -			if (errno != ESRCH)
>> -				perror_msg("detach: stopping child");
>> +		else if (!stop_expected) {
>> +			/* Process is running, need to stop it first */
>> +			if (use_seize)
>> +				error = ptrace(PTRACE_INTERRUPT, tcp->pid, 0, 0);
>> +			else
>> +				error = my_tkill(tcp->pid, SIGSTOP);
>> +			if (!error)
>> +				stop_expected = 1;
>> +			else if (errno != ESRCH) {
>> +				if (use_seize)
>> +					perror_msg("detach: ptrace(PTRACE_INTERRUPT, ...)");
>> +				else
>> +					perror_msg("detach: stopping child");
>> +			}
>>  		}
>> -		else
>> -			sigstop_expected = 1;
>>  	}
>>  
>> -	if (sigstop_expected) {
>> +	if (stop_expected) {
>>  		for (;;) {
>>  #ifdef __WALL
>>  			if (waitpid(tcp->pid, &status, __WALL) < 0) {
>> @@ -810,7 +819,9 @@ detach(struct tcb *tcp)
>>  				/* Au revoir, mon ami. */
>>  				break;
>>  			}
>> -			if (WSTOPSIG(status) == SIGSTOP) {
>> +			if (WSTOPSIG(status) == SIGSTOP
>> +			 || WSTOPSIG(status) == SIGTRAP /* may be generated by PTRACE_INTERRUPT stop */
>> +			) {
> 
> In case of PTRACE_INTERRUPT this WSTOPSIG(status) is not plain SIGTRAP
> but (SIGTRAP | 0x80), which also may happen in other !use_seize cases.

Right, I forgot about that!
It's because of TRACESYSGOOD, not SEIZE.
The check should be:

WSTOPSIG(status) == syscall_trap_sig

I'll test and resend the patch.




More information about the Strace-devel mailing list