Ptrace segfault
Gunnar Hinriksson
tomtinn at gmail.com
Thu Apr 29 23:49:34 UTC 2010
2010/4/29 Gunnar Hinriksson <tomtinn at gmail.com>:
> 2010/4/29 Gunnar Hinriksson <tomtinn at gmail.com>:
>> 2010/4/29 Bob Bishop <rb at gid.co.uk>:
>>> Hi,
>>>
>>> On 29 Apr 2010, at 22:37, Garrett Cooper wrote:
>>>
>>>> On Thu, Apr 29, 2010 at 12:06 PM, Gunnar Hinriksson <tomtinn at gmail.com> wrote:
>>>>> Hello
>>>>>
>>>>> Im having a little problem using ptrace on my system.
>>>>> If I use ptrace to attach to another process the child process
>>>>> segfaults once I detach.
>>>>> For example using this simple program.
>>>>>
>>>>> #include <stdio.h>
>>>>> #include <stdlib.h>
>>>>> #include <sys/types.h>
>>>>> #include <sys/ptrace.h>
>>>>> #include <sys/wait.h>
>>>>>
>>>>> int main(int argc, char *argv[])
>>>>> {
>>>>> int pid = atoi(argv[1]);
>>>>> ptrace(PT_ATTACH, pid, 0, 0);
>>>>> wait(NULL);
>>>>> ptrace(PT_DETACH, pid, 0, 0);
>>>>> return 0;
>>>>> }
>>>>>
>>>>> Am I using ptrace incorrectly or is there perhaps a bug in ptrace that
>>>>> causes the child to always segfault ?
>>>>
>>>> Nope -- it's a bug in your code. From ptrace(2):
>>>>
>>>> PT_CONTINUE The traced process continues execution. The addr argument
>>>> is an address specifying the place where execution is to be
>>>> resumed (a new value for the program counter), or
>>>> (caddr_t)1 to indicate that execution is to pick up where
>>>> it left off. The data argument provides a signal number to
>>>> be delivered to the traced process as it resumes execution,
>>>> or 0 if no signal is to be sent.
>>>>
>>>> [...]
>>>>
>>>> PT_DETACH This request is like PT_CONTINUE, except that it does not
>>> ^^^^^^^^^^^
>>>> allow specifying an alternate place to continue execution,
>>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>> and after it succeeds, the traced process is no longer
>>>> traced and continues execution normally.
>>>>
>>>> Note very carefully the fact that PT_DETACH is like PT_CONTINUE,
>>>> and that PT_CONTINUE says that addr references the memory where the
>>>> execution is going to be resumed.
>>>
>>> Looks to me like a bug in ptrace(PT_DETACH,...) which to agree with ptrace(2) ought either to
>>> (a) fail (EINVAL?) if addr != (caddr_t)1, or
>>> (b) ignore addr entirely; it's not clear which.
>>>
>>> OP inferred (b) which is reasonable.
>>>
>>>> HTH,
>>>> -Garrett
>>>> _______________________________________________
>>>> freebsd-hackers at freebsd.org mailing list
>>>> http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
>>>> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"
>>>>
>>>>
>>>
>>>
>>> --
>>> Bob Bishop +44 (0)118 940 1243
>>> rb at gid.co.uk fax +44 (0)118 940 1295
>>> mobile +44 (0)783 626 4518
>>>
>>>
>>>
>>>
>>>
>>>
>>
>> Hello
>>
>> I didn't want to make the code to big so I omitted any tests.
>> About wait(), you are supposed to use wait to check if the child
>> process has stopped successfully.
>> I guess the correct usage would be something like this if im
>> understanding the documentation correctly.
>> if ( wait(WIFSTOPPED(SIGSTOP)) == pid )
>> Im not sure if there is any posix way of describing how ptrace should
>> be implemented but I know linux ptrace ignores the addr on DETACH.
>> So my vote would be that ptrace ignores addr on detach to make it
>> compatible with code for linux.
>>
>> With Regards
>>
>> Gunnar
>>
>
> Hello
>
> I started looking around in the kernel sources and I think i've found
> out how it is implemented.
> in /usr/src/sys/kern/sys_process.c line 744 the following code is found.
>
> if (addr != (void *)1) {
> error = ptrace_set_pc(td2, (u_long)(uintfptr_t)addr);
> if (error)
> break;
> }
>
> So it is changing the address if the addr is anything but 1.
> I tested my program by passing 1 as an argument in the addr field and
> the segfaults stopped.
>
> So the question is if this code should be removed so that PT_DETACH
> ignores addr or leave it be and perhaps update the documentation to
> reflect that it allows the addr to the changed.
>
> With Regards
>
> Gunnar
>
After reading the code more carefully the correct way would be to
modify it like this.
---
case PT_CONTINUE:
{
if (addr != (void *)1) {
error = ptrace_set_pc(td2, (u_long)(uintfptr_t)addr);
}
}
if (error)
break;
---
Note that im just learning programming so this might not be the
correct way to do it.
With Regards
Gunnar
More information about the freebsd-hackers
mailing list