]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/kern/ptrace_test.c
Only reparent a traced process to its old parent if the tracing process is
[FreeBSD/FreeBSD.git] / tests / sys / kern / ptrace_test.c
1 /*-
2  * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/types.h>
31 #include <sys/ptrace.h>
32 #include <sys/wait.h>
33 #include <errno.h>
34 #include <signal.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <atf-c.h>
38
39 /*
40  * Verify that a parent debugger process "sees" the exit of a debugged
41  * process exactly once when attached via PT_TRACE_ME.
42  */
43 ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me);
44 ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
45 {
46         pid_t child, wpid;
47         int status;
48
49         ATF_REQUIRE((child = fork()) != -1);
50         if (child == 0) {
51                 /* Child process. */
52                 ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
53
54                 /* Trigger a stop. */
55                 raise(SIGSTOP);
56
57                 exit(1);
58         }
59
60         /* Parent process. */
61
62         /* The first wait() should report the stop from SIGSTOP. */
63         wpid = waitpid(child, &status, 0);
64         ATF_REQUIRE(wpid == child);
65         ATF_REQUIRE(WIFSTOPPED(status));
66         ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
67
68         /* Continue the child ignoring the SIGSTOP. */
69         ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
70
71         /* The second wait() should report the exit status. */
72         wpid = waitpid(child, &status, 0);
73         ATF_REQUIRE(wpid == child);
74         ATF_REQUIRE(WIFEXITED(status));
75         ATF_REQUIRE(WEXITSTATUS(status) == 1);
76
77         /* The child should no longer exist. */
78         wpid = waitpid(child, &status, 0);
79         ATF_REQUIRE(wpid == -1);
80         ATF_REQUIRE(errno == ECHILD);
81 }
82
83 /*
84  * Verify that a parent debugger process "sees" the exit of a debugged
85  * process exactly once when attached via PT_ATTACH.
86  */
87 ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach);
88 ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
89 {
90         pid_t child, wpid;
91         int cpipe[2], status;
92         char c;
93
94         ATF_REQUIRE(pipe(cpipe) == 0);
95         ATF_REQUIRE((child = fork()) != -1);
96         if (child == 0) {
97                 /* Child process. */
98                 close(cpipe[0]);
99
100                 /* Wait for the parent to attach. */
101                 ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0);
102
103                 exit(1);
104         }
105         close(cpipe[1]);
106
107         /* Parent process. */
108
109         /* Attach to the child process. */
110         ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0);
111
112         /* The first wait() should report the SIGSTOP from PT_ATTACH. */
113         wpid = waitpid(child, &status, 0);
114         ATF_REQUIRE(wpid == child);
115         ATF_REQUIRE(WIFSTOPPED(status));
116         ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
117
118         /* Continue the child ignoring the SIGSTOP. */
119         ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
120
121         /* Signal the child to exit. */
122         close(cpipe[0]);
123
124         /* The second wait() should report the exit status. */
125         wpid = waitpid(child, &status, 0);
126         ATF_REQUIRE(wpid == child);
127         ATF_REQUIRE(WIFEXITED(status));
128         ATF_REQUIRE(WEXITSTATUS(status) == 1);
129
130         /* The child should no longer exist. */
131         wpid = waitpid(child, &status, 0);
132         ATF_REQUIRE(wpid == -1);
133         ATF_REQUIRE(errno == ECHILD);
134 }
135
136 ATF_TP_ADD_TCS(tp)
137 {
138
139         ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
140         ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
141
142         return (atf_no_error());
143 }