job control: Don't set group_stop exit_code if re-entering job control stop
authorTejun Heo <tj@kernel.org>
Wed, 23 Mar 2011 09:37:01 +0000 (10:37 +0100)
committerTejun Heo <tj@kernel.org>
Wed, 23 Mar 2011 09:37:01 +0000 (10:37 +0100)
commit408a37de6c95832a4880a88a742f89f0cc554d06
tree14e89583cd01a91a75e93b262e162e623847d2ef
parent0e9f0a4abfd80f8adca624538d479d95159b16d8
job control: Don't set group_stop exit_code if re-entering job control stop

While ptraced, a task may be resumed while the containing process is
still job control stopped.  If the task receives another stop signal
in this state, it will still initiate group stop, which generates
group_exit_code, which the real parent would be able to see once the
ptracer detaches.

In this scenario, the real parent may see two consecutive CLD_STOPPED
events from two stop signals without intervening SIGCONT, which
normally is impossible.

Test case follows.

  #include <stdio.h>
  #include <unistd.h>
  #include <sys/ptrace.h>
  #include <sys/wait.h>

  int main(void)
  {
  pid_t tracee;
  siginfo_t si;

  tracee = fork();
  if (!tracee)
  while (1)
  pause();

  kill(tracee, SIGSTOP);
  waitid(P_PID, tracee, &si, WSTOPPED);

  if (!fork()) {
  ptrace(PTRACE_ATTACH, tracee, NULL, NULL);
  waitid(P_PID, tracee, &si, WSTOPPED);
  ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status);
  waitid(P_PID, tracee, &si, WSTOPPED);
  ptrace(PTRACE_CONT, tracee, NULL, (void *)(long)si.si_status);
  waitid(P_PID, tracee, &si, WSTOPPED);
  ptrace(PTRACE_DETACH, tracee, NULL, NULL);
  return 0;
  }

  while (1) {
  si.si_pid = 0;
  waitid(P_PID, tracee, &si, WSTOPPED | WNOHANG);
  if (si.si_pid)
  printf("st=%02d c=%02d\n", si.si_status, si.si_code);
  }
  return 0;
  }

Before the patch, the latter waitid() in polling mode reports the
second stopped event generated by the implied SIGSTOP of
PTRACE_ATTACH.

  st=19 c=05
  ^C

After the patch, the second event is not reported.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Oleg Nesterov <oleg@redhat.com>
kernel/signal.c