Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/kern/pdrfork.c
96290 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2026 ConnectWise
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/types.h>
29
#include <sys/user.h>
30
#include <sys/procdesc.h>
31
#include <sys/wait.h>
32
33
#include <atf-c.h>
34
#include <stdio.h>
35
#include <string.h>
36
#include <unistd.h>
37
38
static void basic_usage(int rfflags) {
39
int pd = -1;
40
pid_t pid, pd_pid, waited_pid;
41
int r, status;
42
43
pid = pdrfork(&pd, 0, rfflags);
44
ATF_REQUIRE_MSG(pid >= 0, "rfork failed with %s", strerror(errno));
45
if (pid == 0) {
46
/* In child */
47
_exit(0);
48
}
49
ATF_REQUIRE_MSG(pd >= 0, "rfork did not return a process descriptor");
50
r = pdgetpid(pd, &pd_pid);
51
ATF_CHECK_EQ_MSG(r, 0, "pdgetpid failed: %s", strerror(errno));
52
53
/* We should be able to collect the child's status */
54
waited_pid = waitpid(pid, &status, WEXITED | WNOWAIT);
55
ATF_CHECK_EQ(waited_pid, pid);
56
57
/* But after closing the process descriptor, we won't */
58
close(pd);
59
waited_pid = waitpid(pid, &status, WEXITED | WNOHANG);
60
ATF_CHECK_EQ(-1, waited_pid);
61
ATF_CHECK_EQ(ECHILD, errno);
62
}
63
64
/* pdrfork does not return a process descriptor to the child */
65
ATF_TC_WITHOUT_HEAD(child_gets_no_pidfd);
66
ATF_TC_BODY(child_gets_no_pidfd, tc)
67
{
68
int pd = -1;
69
pid_t pid, pd_pid, waited_pid;
70
int r, status;
71
72
pid = pdrfork(&pd, 0, RFPROC | RFPROCDESC);
73
ATF_REQUIRE_MSG(pid >= 0, "rfork failed with %s", strerror(errno));
74
if (pid == 0) {
75
/*
76
* In child. We can't do very much here before we exec, so
77
* just use our exit status to report success.
78
*/
79
_exit(pd == -1);
80
}
81
ATF_REQUIRE_MSG(pd >= 0, "rfork did not return a process descriptor");
82
r = pdgetpid(pd, &pd_pid);
83
ATF_CHECK_EQ_MSG(r, 0, "pdgetpid failed: %s", strerror(errno));
84
85
waited_pid = waitpid(pid, &status, WEXITED | WNOWAIT);
86
ATF_CHECK_EQ(waited_pid, pid);
87
ATF_REQUIRE(WIFEXITED(status) && (WEXITSTATUS(status) == true));
88
89
close(pd);
90
}
91
92
/* If the pidfd argument is invalid, the error should be handled gracefully */
93
ATF_TC_WITHOUT_HEAD(efault);
94
ATF_TC_BODY(efault, tc)
95
{
96
ATF_REQUIRE_ERRNO(EFAULT, pdrfork((int*)-1, 0, RFPROC | RFPROCDESC) < 0);
97
}
98
99
/* Invalid combinations of flags should return EINVAL */
100
ATF_TC_WITHOUT_HEAD(einval);
101
ATF_TC_BODY(einval, tc)
102
{
103
int pd = -1;
104
105
ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, -1, RFSPAWN) < 0);
106
ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, -1) < 0);
107
ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFSPAWN | RFNOWAIT) < 0);
108
ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFPROC | RFFDG| RFCFDG) < 0);
109
ATF_CHECK_ERRNO(EINVAL, pdrfork(&pd, 0, RFPROCDESC) < 0);
110
}
111
112
/*
113
* Without RFSPAWN, RFPROC, or RFPROCDESC, an existing process may be modified
114
*/
115
ATF_TC_WITHOUT_HEAD(modify_child);
116
ATF_TC_BODY(modify_child, tc)
117
{
118
int fdp = -1;
119
pid_t pid1, pid2;
120
121
pid1 = pdfork(&fdp, 0);
122
if (pid1 == 0)
123
_exit(0);
124
ATF_REQUIRE_MSG(pid1 >= 0, "pdfork failed: %s", strerror(errno));
125
ATF_REQUIRE_MSG(fdp >= 0, "pdfork didn't return a process descriptor");
126
127
pid2 = pdrfork(&fdp, 0, RFNOWAIT);
128
ATF_REQUIRE_MSG(pid2 >= 0, "pdrfork failed: %s", strerror(errno));
129
ATF_CHECK_EQ_MSG(pid2, 0,
130
"pdrfork created a process even though we told it not to");
131
132
close(fdp);
133
}
134
135
/*
136
* Basic usage with RFPROC. No process descriptor will be created.
137
* I'm not sure why you would use pdrfork in this case instead of plain rfork
138
*/
139
ATF_TC_WITHOUT_HEAD(rfproc);
140
ATF_TC_BODY(rfproc, tc)
141
{
142
int pd = -1;
143
pid_t pid;
144
145
pid = pdrfork(&pd, 0, RFPROC);
146
ATF_REQUIRE_MSG(pid > 0, "rfork failed with %s", strerror(errno));
147
if (pid == 0)
148
_exit(0);
149
150
ATF_REQUIRE_EQ_MSG(pd, -1,
151
"rfork(RFPROC) returned a process descriptor");
152
}
153
154
/* basic usage with RFPROCDESC */
155
ATF_TC_WITHOUT_HEAD(rfprocdesc);
156
ATF_TC_BODY(rfprocdesc, tc)
157
{
158
basic_usage(RFPROC | RFPROCDESC);
159
}
160
161
/* basic usage with RFSPAWN */
162
/*
163
* Skip on i386 and x86_64 because RFSPAWN cannot be used from C code on those
164
* architectures. See lib/libc/gen/posix_spawn.c for details.
165
*/
166
#if !(defined(__i386__)) && !(defined(__amd64__))
167
ATF_TC_WITHOUT_HEAD(rfspawn);
168
ATF_TC_BODY(rfspawn, tc)
169
{
170
basic_usage(RFSPAWN);
171
}
172
#endif
173
174
ATF_TP_ADD_TCS(tp)
175
{
176
ATF_TP_ADD_TC(tp, child_gets_no_pidfd);
177
ATF_TP_ADD_TC(tp, efault);
178
ATF_TP_ADD_TC(tp, einval);
179
ATF_TP_ADD_TC(tp, modify_child);
180
ATF_TP_ADD_TC(tp, rfproc);
181
ATF_TP_ADD_TC(tp, rfprocdesc);
182
#if !(defined(__i386__)) && !(defined(__amd64__))
183
ATF_TP_ADD_TC(tp, rfspawn);
184
#endif
185
186
return (atf_no_error());
187
}
188
189