Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1535122 > unrolled thread

Unkillable processes due to PTRACE_TRACEME again

Started byDmitry Vyukov <dvyukov@google.com>
First post2016-12-02 19:50 +0100
Last post2016-12-05 18:10 +0100
Articles 8 — 3 participants

Back to article view | Back to linux.kernel


Contents

  Unkillable processes due to PTRACE_TRACEME again Dmitry Vyukov <dvyukov@google.com> - 2016-12-02 19:50 +0100
    Re: Unkillable processes due to PTRACE_TRACEME again Pavel Machek <pavel@ucw.cz> - 2016-12-02 22:10 +0100
      Re: Unkillable processes due to PTRACE_TRACEME again Dmitry Vyukov <dvyukov@google.com> - 2016-12-03 17:00 +0100
        Re: Unkillable processes due to PTRACE_TRACEME again Pavel Machek <pavel@ucw.cz> - 2016-12-03 20:20 +0100
    Re: Unkillable processes due to PTRACE_TRACEME again Oleg Nesterov <oleg@redhat.com> - 2016-12-05 11:50 +0100
      Re: Unkillable processes due to PTRACE_TRACEME again Oleg Nesterov <oleg@redhat.com> - 2016-12-05 12:10 +0100
        Re: Unkillable processes due to PTRACE_TRACEME again Dmitry Vyukov <dvyukov@google.com> - 2016-12-05 15:10 +0100
          Re: Unkillable processes due to PTRACE_TRACEME again Oleg Nesterov <oleg@redhat.com> - 2016-12-05 18:10 +0100

#1535122 — Unkillable processes due to PTRACE_TRACEME again

FromDmitry Vyukov <dvyukov@google.com>
Date2016-12-02 19:50 +0100
SubjectUnkillable processes due to PTRACE_TRACEME again
Message-ID<sK14e-7tU-15@gated-at.bofh.it>
Hello,

There was an issue discussed a year ago which leads to
unkillalble/unwaitable zombie processes due to PTRACE_TRACEME:
https://groups.google.com/d/msg/syzkaller/uGzwvhlCXAw/E-cfY2ejAgAJ
and I though it has been fixed by "wait/ptrace: assume __WALL if the
child is traced":
https://groups.google.com/d/msg/syzkaller/caeB1ebZWAs/gcbvcM2HDAAJ

I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
the same unwaitable zombie processes.

Reproducer is:

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <signal.h>

void *thr(void *arg)
{
  ptrace(PTRACE_TRACEME, 0, 0, 0);
}

int main()
{
  int pid = fork();
  if (pid == 0) {
    pthread_t th;
    pthread_create(&th, 0, thr, 0);
    usleep(100000);
    exit(0);
  }
  usleep(200000);
  kill(pid, SIGKILL);
  int status = 0;
  waitpid(pid, &status, __WALL);
  return 0;
}

It creates the following process tree:

root     15730  0.0  0.0   1156     4 pts/0    S+   18:33   0:00  |
   \_ ./a.out
root     15731  0.0  0.0      0     0 pts/0    Zl+  18:33   0:00  |
       \_ [a.out] <defunct>

Both threads of the child processes terminated:

# ls -l /proc/15731/task/
total 0
dr-xr-xr-x 7 root root 0 Dec  2 18:33 15731
dr-xr-xr-x 7 root root 0 Dec  2 18:33 15732
root@dvyukov-z840:~# cat /proc/15731/status
Name: a.out
State: Z (zombie)
Tgid: 15731
Ngid: 0
Pid: 15731
PPid: 15730
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 0
Groups: 0
NStgid: 15731
NSpid: 15731
NSpgid: 15730
NSsid: 6670
Threads: 2
SigQ: 1/3098
SigPnd: 0000000000000000
ShdPnd: 0000000000000100
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000

# cat /proc/15732/status
Name: a.out
State: Z (zombie)
Tgid: 15731
Ngid: 0
Pid: 15732
PPid: 15730
TracerPid: 15730
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 0
Groups: 0
NStgid: 15731
NSpid: 15732
NSpgid: 15730
NSsid: 6670
Threads: 2
SigQ: 1/3098
SigPnd: 0000000000000000
ShdPnd: 0000000000000100
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000


The parent process is blocked in waitpid(__WALL):

# cat /proc/15730/stack
[<ffffffff8140fbbb>] do_wait+0x34b/0xb30 kernel/exit.c:1574
[<     inline     >] SYSC_wait4 kernel/exit.c:1684
[<ffffffff814143bd>] SyS_wait4+0x20d/0x340 kernel/exit.c:1653
[<ffffffff81009a24>] do_syscall_64+0x2f4/0x940 arch/x86/entry/common.c:280
[<ffffffff881a3dcd>] entry_SYSCALL64_slow_path+0x25/0x25
arch/x86/entry/entry_64.S:251


Shouldn't __WALL cause the wait to return?

Again, it's easy to change the repro so that the process first
reparents to init, and then does PTRACE_TRACEME. Which will cause a
forever hanged processes.

Thanks

[toc] | [next] | [standalone]


#1535215

FromPavel Machek <pavel@ucw.cz>
Date2016-12-02 22:10 +0100
Message-ID<sK3fI-zX-45@gated-at.bofh.it>
In reply to#1535122

[Multipart message — attachments visible in raw view] — view raw

On Fri 2016-12-02 19:48:40, Dmitry Vyukov wrote:
> Hello,
> 
> There was an issue discussed a year ago which leads to
> unkillalble/unwaitable zombie processes due to PTRACE_TRACEME:
> https://groups.google.com/d/msg/syzkaller/uGzwvhlCXAw/E-cfY2ejAgAJ
> and I though it has been fixed by "wait/ptrace: assume __WALL if the
> child is traced":
> https://groups.google.com/d/msg/syzkaller/caeB1ebZWAs/gcbvcM2HDAAJ
> 
> I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see

"Now on"?

> the same unwaitable zombie processes.

Well.. I guess git bisect is one option...?

Best regards,
								Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[toc] | [prev] | [next] | [standalone]


#1535447

FromDmitry Vyukov <dvyukov@google.com>
Date2016-12-03 17:00 +0100
Message-ID<sKkTg-3cV-17@gated-at.bofh.it>
In reply to#1535215
On Fri, Dec 2, 2016 at 10:02 PM, Pavel Machek <pavel@ucw.cz> wrote:
> On Fri 2016-12-02 19:48:40, Dmitry Vyukov wrote:
>> Hello,
>>
>> There was an issue discussed a year ago which leads to
>> unkillalble/unwaitable zombie processes due to PTRACE_TRACEME:
>> https://groups.google.com/d/msg/syzkaller/uGzwvhlCXAw/E-cfY2ejAgAJ
>> and I though it has been fixed by "wait/ptrace: assume __WALL if the
>> child is traced":
>> https://groups.google.com/d/msg/syzkaller/caeB1ebZWAs/gcbvcM2HDAAJ
>>
>> I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
>
> "Now on"?

Yes.

>> the same unwaitable zombie processes.
>
> Well.. I guess git bisect is one option...?

I've checked on:

commit 91c4e8ea8f05916df0c8a6f383508ac7c9e10dba
Author: Oleg Nesterov <oleg@redhat.com>
Date:   Mon May 23 16:23:53 2016 -0700
    wait: allow sys_waitid() to accept __WNOTHREAD/__WCLONE/__WALL

and the program hangs the same way. So it seems that it was just never fixed.

[toc] | [prev] | [next] | [standalone]


#1535511

FromPavel Machek <pavel@ucw.cz>
Date2016-12-03 20:20 +0100
Message-ID<sKo0N-5jN-11@gated-at.bofh.it>
In reply to#1535447

[Multipart message — attachments visible in raw view] — view raw

Hi!

You cc-ed me on initial mail, I replied, and you removed me from cc. Ouch.

On Sat 2016-12-03 16:55:49, Dmitry Vyukov wrote:
> On Fri, Dec 2, 2016 at 10:02 PM, Pavel Machek <pavel@ucw.cz> wrote:
> > On Fri 2016-12-02 19:48:40, Dmitry Vyukov wrote:
> >> Hello,
> >>
> >> There was an issue discussed a year ago which leads to
> >> unkillalble/unwaitable zombie processes due to PTRACE_TRACEME:
> >> https://groups.google.com/d/msg/syzkaller/uGzwvhlCXAw/E-cfY2ejAgAJ
> >> and I though it has been fixed by "wait/ptrace: assume __WALL if the
> >> child is traced":
> >> https://groups.google.com/d/msg/syzkaller/caeB1ebZWAs/gcbvcM2HDAAJ
> >>
> >> I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
> >
> > "Now on"?
> 
> Yes.
> 
> >> the same unwaitable zombie processes.
> >
> > Well.. I guess git bisect is one option...?
> 
> I've checked on:
> 
> commit 91c4e8ea8f05916df0c8a6f383508ac7c9e10dba
> Author: Oleg Nesterov <oleg@redhat.com>
> Date:   Mon May 23 16:23:53 2016 -0700
>     wait: allow sys_waitid() to accept __WNOTHREAD/__WCLONE/__WALL
> 
> and the program hangs the same way. So it seems that it was just never fixed.

Ouch #2. Oleg, any ideas?

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[toc] | [prev] | [next] | [standalone]


#1535992

FromOleg Nesterov <oleg@redhat.com>
Date2016-12-05 11:50 +0100
Message-ID<sKZ0l-3qn-1@gated-at.bofh.it>
In reply to#1535122
On 12/02, Dmitry Vyukov wrote:
>
> I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
> the same unwaitable zombie processes.

This is another thing, and notabug. This is how ptrace works,

> void *thr(void *arg)
> {
>   ptrace(PTRACE_TRACEME, 0, 0, 0);
> }
>
> int main()
> {
>   int pid = fork();
>   if (pid == 0) {
>     pthread_t th;
>     pthread_create(&th, 0, thr, 0);
>     usleep(100000);
>     exit(0);
>   }
>   usleep(200000);
>   kill(pid, SIGKILL);
>   int status = 0;
>   waitpid(pid, &status, __WALL);

waitpid(pid) hangs because you need to reap the sub-thread first.

Oleg.

[toc] | [prev] | [next] | [standalone]


#1536001

FromOleg Nesterov <oleg@redhat.com>
Date2016-12-05 12:10 +0100
Message-ID<sKZjH-3M4-11@gated-at.bofh.it>
In reply to#1535992
On 12/05, Oleg Nesterov wrote:
>
> On 12/02, Dmitry Vyukov wrote:
> >
> > I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
> > the same unwaitable zombie processes.
>
> This is another thing, and notabug. This is how ptrace works,
>
> > void *thr(void *arg)
> > {
> >   ptrace(PTRACE_TRACEME, 0, 0, 0);
> > }
> >
> > int main()
> > {
> >   int pid = fork();
> >   if (pid == 0) {
> >     pthread_t th;
> >     pthread_create(&th, 0, thr, 0);
> >     usleep(100000);
> >     exit(0);
> >   }
> >   usleep(200000);
> >   kill(pid, SIGKILL);
> >   int status = 0;
> >   waitpid(pid, &status, __WALL);
>
> waitpid(pid) hangs because you need to reap the sub-thread first.

I'm afraid I wasn't clear...

So the child process has 2 threads, the leader thread L and the sub-thread T.
waitpid(pid == L->pid) will block until all the threads go away, but since T is
traced it won't autoreap, the tracer should do waitpid(T->pid) first to reap
this zombie. waitpid(-1) should work too.

Oleg.

[toc] | [prev] | [next] | [standalone]


#1536117

FromDmitry Vyukov <dvyukov@google.com>
Date2016-12-05 15:10 +0100
Message-ID<sL27U-5yr-33@gated-at.bofh.it>
In reply to#1536001
On Mon, Dec 5, 2016 at 12:00 PM, Oleg Nesterov <oleg@redhat.com> wrote:
> On 12/05, Oleg Nesterov wrote:
>>
>> On 12/02, Dmitry Vyukov wrote:
>> >
>> > I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
>> > the same unwaitable zombie processes.
>>
>> This is another thing, and notabug. This is how ptrace works,
>>
>> > void *thr(void *arg)
>> > {
>> >   ptrace(PTRACE_TRACEME, 0, 0, 0);
>> > }
>> >
>> > int main()
>> > {
>> >   int pid = fork();
>> >   if (pid == 0) {
>> >     pthread_t th;
>> >     pthread_create(&th, 0, thr, 0);
>> >     usleep(100000);
>> >     exit(0);
>> >   }
>> >   usleep(200000);
>> >   kill(pid, SIGKILL);
>> >   int status = 0;
>> >   waitpid(pid, &status, __WALL);
>>
>> waitpid(pid) hangs because you need to reap the sub-thread first.
>
> I'm afraid I wasn't clear...
>
> So the child process has 2 threads, the leader thread L and the sub-thread T.
> waitpid(pid == L->pid) will block until all the threads go away, but since T is
> traced it won't autoreap, the tracer should do waitpid(T->pid) first to reap
> this zombie. waitpid(-1) should work too.

Do you mean that I need to replace:
 waitpid(pid, &status, __WALL);
with:
 while (waitpid(-1, &status, __WALL) != pid) {}
?
It seems to work. But want to make sure.

[toc] | [prev] | [next] | [standalone]


#1536242

FromOleg Nesterov <oleg@redhat.com>
Date2016-12-05 18:10 +0100
Message-ID<sL4W5-7kh-1@gated-at.bofh.it>
In reply to#1536117
On 12/05, Dmitry Vyukov wrote:
>
> On Mon, Dec 5, 2016 at 12:00 PM, Oleg Nesterov <oleg@redhat.com> wrote:
> > On 12/05, Oleg Nesterov wrote:
> >>
> >> On 12/02, Dmitry Vyukov wrote:
> >> >
> >> > I am not on 2caceb3294a78c389b462e7e236a4e744a53a474 (Dec 1). And see
> >> > the same unwaitable zombie processes.
> >>
> >> This is another thing, and notabug. This is how ptrace works,
> >>
> >> > void *thr(void *arg)
> >> > {
> >> >   ptrace(PTRACE_TRACEME, 0, 0, 0);
> >> > }
> >> >
> >> > int main()
> >> > {
> >> >   int pid = fork();
> >> >   if (pid == 0) {
> >> >     pthread_t th;
> >> >     pthread_create(&th, 0, thr, 0);
> >> >     usleep(100000);
> >> >     exit(0);
> >> >   }
> >> >   usleep(200000);
> >> >   kill(pid, SIGKILL);
> >> >   int status = 0;
> >> >   waitpid(pid, &status, __WALL);
> >>
> >> waitpid(pid) hangs because you need to reap the sub-thread first.
> >
> > I'm afraid I wasn't clear...
> >
> > So the child process has 2 threads, the leader thread L and the sub-thread T.
> > waitpid(pid == L->pid) will block until all the threads go away, but since T is
> > traced it won't autoreap, the tracer should do waitpid(T->pid) first to reap
> > this zombie. waitpid(-1) should work too.
> 
> Do you mean that I need to replace:
>  waitpid(pid, &status, __WALL);
> with:
>  while (waitpid(-1, &status, __WALL) != pid) {}
> ?

Yes. Or, if you knew the pid of the traced thread you could do

	// need to do this first, the traced sub-thread won't autoreap,
	// and the leader which represents the whole process is not reapable
	// until all other threads go away
	waitpid(tracee_pid, &status, __WALL);

	waitpid(pid, &status, __WALL);

Oleg.

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web