lkml.org 
[lkml]   [2010]   [Feb]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: Race in ptrace.
From
On Thu, Feb 11, 2010 at 4:56 AM, Oleg Nesterov <oleg@redhat.com> wrote:
> On 02/10, Salman Qazi wrote:
>>
>> I have
>> made a simpler version of tavis's test case:
>
> Thanks, now I see what you mean.
>
> But this all is correct, you can't expect PTRACE_SYSCALL can succeed
> is the tracee is running, it must be stopped or traced.
>
> The tracee is running because it was TASK_STOPPED and antagonist()
> sends SIGCONT.
>
> The tracee was TASK_STOPPED because the tracer passes sig = SIGSTOP
> via ptrace(PTRACE_SYSCALL, WSTOPSIG(status).
>
> Where do you see the bug?

Shouldn't ptrace(PTRACE_SYSCALL, WSTOPSIG(status)...), cause any
future signals to the child be intercepted by the parent?

>
> OK, let me simplify the test-case even more:
>
>        int main(void)
>        {
>                int stat, ret;
>                int pid = fork();
>
>                if (!pid) {
>                        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
>                        for (;;)
>                                ;
>                }
>
>                sleep(1);       // wait for PTRACE_TRACEME
>                kill(pid, SIGSTOP);
>
>                // the child reports SIGSTOP, it is TASK_TRACED
>                assert(pid == wait(&stat) && WIFSTOPPED(stat));
>
>                // the tracee should stop, we pass sig = SIGSTOP
>                assert(ptrace(PTRACE_SYSCALL, pid, 0, WSTOPSIG(stat)) == 0);
>
>                // the child reports the group stop, it is TASK_STOPPED
>                assert(pid == wait(&stat) && WIFSTOPPED(stat));
>
>                // the tracee is STOPPED as requested, not TRACED,
>                // SIGCONT wakes it up
>                kill(pid, SIGCONT);

According to the man page, any signals to the
process are supposed to be intercepted by the parent and that is how
one is supposed to be able to control which signals make it to the
child. I am not sure if it makes any difference if the signal
originates at the parent. But in our test case, it doesn't. So, why
doesn't the parent get a notification first?

>
>                // now the tracee is _running_, and PTRACE_SYSCALL must fail
>                ret = ptrace(PTRACE_SYSCALL, pid, 0, WSTOPSIG(stat));
>                printf("should fail: ret=%d %m\n", ret);
>
>                return 0;
>        }
>
> PTRACE_SYSCALL fails, and this is absolutely correct.
>
> Now, let's look at your test-case
>
>> int main(int argc, char **argv)
>> {
>>         int status;
>>         assert((child_pid = do_fork(child)) > 0);
>>         assert((ant_pid = do_fork(antagonist)) > 0);
>>         waitpid(child_pid, &status, 0);
>>         ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL);
>>         while(1) {
>>                 if (waitpid(child_pid, &status, 0) <= 0) {
>>                         printf("Errno %d\n", errno);
>>                         exit(EXIT_FAILURE);
>>                 }
>>                 if (WIFSTOPPED(status)) {
>
> WSTOPSIG() should be either SIGCONT or SIGSTOP
>
>>                         printf("stopped: %d\n", WSTOPSIG(status));
>>
>>                         /* This should work, but sometimes it doesn't */
>>                         if (ptrace(PTRACE_SYSCALL, child_pid,
>>                                                 NULL, WSTOPSIG(status)) < 0) {
>
> This should not work if the tracee reported the group stop (not the
> fact it dequeued SIGSTOP) and antagonist() sends SIGCONT in between.
>
>>                                 /* Oddly it works the second time! */
>>                                 assert (ptrace(PTRACE_SYSCALL,
>>                                         child_pid, NULL, WSTOPSIG(status)) < 0);
>
> Of couse, it _can_ work the second time, antagonist() sends a signal
> (SIGCONT or SIGSTOP), the tracee dequeues the signal, and stops to
> report this signal.
>
> See?
>
> Oleg.
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2010-02-11 17:35    [W:0.078 / U:0.248 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site