NetBSD Problem Report #51596

From www@NetBSD.org  Thu Nov  3 17:53:36 2016
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
	(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 6D58F7A210
	for <gnats-bugs@gnats.NetBSD.org>; Thu,  3 Nov 2016 17:53:36 +0000 (UTC)
Message-Id: <20161103175335.0FFB97A2AD@mollari.NetBSD.org>
Date: Thu,  3 Nov 2016 17:53:35 +0000 (UTC)
From: n54@gmx.com
Reply-To: n54@gmx.com
To: gnats-bugs@NetBSD.org
Subject: ptrace(2): raising SIGCONT in a child results with WIFCONTINUED and WIFSTOPPED true in the parent
X-Send-Pr-Version: www-1.0

>Number:         51596
>Category:       kern
>Synopsis:       ptrace(2): raising SIGCONT in a child results with WIFCONTINUED and WIFSTOPPED true in the parent
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Nov 03 17:55:00 +0000 2016
>Closed-Date:    Fri Nov 04 09:10:18 +0000 2016
>Last-Modified:  Fri Nov 04 09:20:00 +0000 2016
>Originator:     Kamil Rytarowski
>Release:        NetBSD 7.99.39 amd64
>Organization:
TNF
>Environment:
NetBSD chieftec 7.99.39 NetBSD 7.99.39 (GENERIC) #0: Tue Oct  4 15:59:50 CEST 2016  kamil@chieftec:/tmp/netbsd-tmp/sys/arch/amd64/compile/GENERIC amd64
>Description:
In the ptrace(2) context raising SIGCONT in a child results status with WIFCONTINUED and WIFSTOPPED true returned from waitpid(2) in the parent.

Linux and FreeBSD return there status with WIFSTOPPED true and WIFCONTINUED false.

The ptrace(2) interface is not a part of POSIX and it is implementation specific behavior, however WIFCONTINUED and WIFSTOPPED both set to true is suspicious.

This use-case is tested as ptraceme4 in the ATF test called t_ptrace.

http://mail-index.netbsd.org/source-changes/2016/11/03/msg078847.html

Discussion:

http://mail-index.netbsd.org/source-changes-d/2016/11/03/msg008823.html

As proposed by Robert Elz, I'm assuming the Linux behavior as correct.
>How-To-Repeat:
This code triggers the issue:

#include <sys/param.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define ATF_REQUIRE(a) assert(a)

#if defined(linux)
#define WALLSIG __WALL
#define sys_signame sys_siglist
#endif

int main(int argc, char **argv)
{
        int status;
        const int exitval = 5;
        const int sigval = SIGSTOP, sigsent = SIGCONT;
        pid_t child, wpid;

        printf("1: Before forking process PID=%d\n", getpid());
        ATF_REQUIRE((child = fork()) != -1);
        if (child == 0) {
                /* printf(3) messages from a child aren't intercepted by ATF */
                /* "2: Child process PID=%d\n", getpid() */

                /* "2: Before calling ptrace(PT_TRACE_ME, ...)\n" */
                if (ptrace(PT_TRACE_ME, 0, NULL, 0) == -1) {
                        /* XXX: Is it safe to use ATF functions in a child? */
                        err(EXIT_FAILURE, "2: ptrace(2) call failed with "
                            "status %s", sys_errlist[errno]);
                }

                /* "2: Before raising SIGSTOP\n" */
                raise(sigval);

                /* "2: Before raising SIGCONT\n" */
                raise(sigsent);

                /* "2: Before calling _exit(%d)\n", exitval */
                _exit(exitval);
        } else {
                printf("1: Parent process PID=%d, child's PID=%d\n", getpid(),
                    child);

                printf("1: Before calling waitpid() for the child\n");
                wpid = waitpid(child, &status, 0);

                printf("1: Validating child's PID (expected %d, got %d)\n",
                    child, wpid);
                ATF_REQUIRE(child == wpid);

                printf("1: Ensuring that the child has not been exited\n");
                ATF_REQUIRE(!WIFEXITED(status));

                printf("1: Ensuring that the child has not been continued\n");
                ATF_REQUIRE(!WIFCONTINUED(status));

                printf("1: Ensuring that the child has not been terminated "
                    "with a signal\n");
                ATF_REQUIRE(!WIFSIGNALED(status));

                printf("1: Ensuring that the child has been stopped\n");
                ATF_REQUIRE(WIFSTOPPED(status));
                printf("1: Verifying that he child has been stopped with the"
                    " %s signal (received %s)\n", sys_signame[sigval],
                    sys_signame[WSTOPSIG(status)]);
                ATF_REQUIRE(WSTOPSIG(status) == sigval);

                printf("1: Before resuming the child process where it left "
                    "off and without signal to be sent\n");
                ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
                    != -1);

                printf("1: Before calling waitpid() for the child\n");
                wpid = waitpid(child, &status, WALLSIG);

                printf("1: Validating that child's PID is still there\n");
                ATF_REQUIRE(wpid == child);

                printf("1: Ensuring that the child has not been exited\n");
                ATF_REQUIRE(!WIFEXITED(status));

                printf("1: Ensuring that the child has been continued\n");
                ATF_REQUIRE(WIFCONTINUED(status));

                printf("1: Ensuring that the child has not been terminated "
                    "with a signal\n");
                ATF_REQUIRE(!WIFSIGNALED(status));

                printf("1: Ensuring that the child has not been stopped\n");
                ATF_REQUIRE(WIFSTOPPED(status));

                printf("1: Before resuming the child process where it left "
                    "off and without signal to be sent\n");
                ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
                printf("1: Before calling waitpid() for the child\n");
                wpid = waitpid(child, &status, 0);

                printf("1: Validating that child's PID is still there\n");
                ATF_REQUIRE(wpid == child);

                printf("1: Ensuring that the child has been exited\n");
                ATF_REQUIRE(WIFEXITED(status));

                printf("1: Ensuring that the child has not been continued\n");
                ATF_REQUIRE(!WIFCONTINUED(status));

                printf("1: Ensuring that the child has not been terminated "
                    "with a signal\n");
                ATF_REQUIRE(!WIFSIGNALED(status));

                printf("1: Ensuring that the child has not been stopped\n");
                ATF_REQUIRE(!WIFSTOPPED(status));

                printf("1: Verifying that he child has exited with the "
                    "%d status (received %d)\n", exitval, WEXITSTATUS(status));
                ATF_REQUIRE(WEXITSTATUS(status) == exitval);

                printf("1: Before calling waitpid() for the exited child\n");
                wpid = waitpid(child, &status, 0);

                printf("1: Validating that child's PID no longer exists\n");
                ATF_REQUIRE(wpid == -1);

                printf("1: Validating that errno is set to %s (got %s)\n",
                    sys_errlist[ECHILD], sys_errlist[errno]);
                ATF_REQUIRE(errno == ECHILD);
	}
}
>Fix:
N/A

>Release-Note:

>Audit-Trail:
From: "Kamil Rytarowski" <kamil@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/51596 CVS commit: src/tests/kernel
Date: Thu, 3 Nov 2016 18:25:54 +0000

 Module Name:	src
 Committed By:	kamil
 Date:		Thu Nov  3 18:25:54 UTC 2016

 Modified Files:
 	src/tests/kernel: t_ptrace.c

 Log Message:
 Mark ptraceme4 as expected failure, assume that Linux&FreeBSD are correct

 Raising SIGCONT from a ptrace(2)d child should be catched with waidpid(2)
 as WIFCONTINUED() false and WIFSTOPPED() true; not both true as it does not
 make much sense.

 PR kern/51596

 Change requested by <kre>
 Checked by <christos>

 Sponsored by <The NetBSD Foundation>


 To generate a diff of this commit:
 cvs rdiff -u -r1.4 -r1.5 src/tests/kernel/t_ptrace.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->closed
State-Changed-By: kamil@NetBSD.org
State-Changed-When: Fri, 04 Nov 2016 10:10:18 +0100
State-Changed-Why:
Fixed by Christos Zoulas
http://mail-index.netbsd.org/source-changes/2016/11/03/msg078852.html


From: "Kamil Rytarowski" <kamil@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc: 
Subject: PR/51596 CVS commit: src/tests/kernel
Date: Fri, 4 Nov 2016 09:08:12 +0000

 Module Name:	src
 Committed By:	kamil
 Date:		Fri Nov  4 09:08:12 UTC 2016

 Modified Files:
 	src/tests/kernel: t_ptrace.c

 Log Message:
 The problem with WIFCONTINUED() and WIFSTOPPED() in traceme4 is resolved

 Fixed by Christos Zoulas in:
 cvs rdiff -u -r1.260 -r1.261 src/sys/kern/kern_exit.c
 http://mail-index.netbsd.org/source-changes/2016/11/03/msg078852.html

 This has been verified to work on NetBSD releng machines.

 Closes PR kern/51596

 Sponsored by <The NetBSD Foundation>.


 To generate a diff of this commit:
 cvs rdiff -u -r1.7 -r1.8 src/tests/kernel/t_ptrace.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.