1 /* $OpenBSD: unfdpass.c,v 1.4 2023/03/08 04:43:06 guenther Exp $ */
2 /* $NetBSD: unfdpass.c,v 1.3 1998/06/24 23:51:30 thorpej Exp $ */
3
4 /*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Test passing of a /dev/pf file descriptors over socketpair,
36 * and of passing a fd opened before the first pledge call that
37 * is then used for ioctl()
38 */
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <sys/time.h>
44 #include <sys/wait.h>
45 #include <sys/un.h>
46 #include <net/if.h>
47 #include <net/pfvar.h>
48
49 #include <err.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <signal.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #define SOCK_NAME "test-sock"
59
60 int main(int, char *[]);
61 void child(int, int);
62 void catch_sigchld(int);
63
64 int
main(int argc,char * argv[])65 main(int argc, char *argv[])
66 {
67 struct msghdr msg;
68 int sock, pfd[2], i;
69 struct cmsghdr *cmp;
70 int *files = NULL;
71 int fdpf_prepledge, fdpf_postpledge;
72 pid_t pid;
73 union {
74 struct cmsghdr hdr;
75 char buf[CMSG_SPACE(sizeof(int))];
76 } cmsgbuf;
77 int type = SOCK_STREAM;
78 int fail = 0;
79 struct pf_status status;
80 extern char *__progname;
81
82 if ((fdpf_prepledge = open("/dev/pf", O_RDWR)) == -1) {
83 err(1, "%s: cannot open pf socket", __func__);
84 }
85
86 if (pledge("stdio rpath wpath sendfd recvfd proc pf", NULL)
87 == -1)
88 err(1, "pledge");
89
90 if ((fdpf_postpledge = open("/dev/pf", O_RDWR)) == -1) {
91 err(1, "%s: cannot open pf socket", __func__);
92 }
93
94 while ((i = getopt(argc, argv, "f")) != -1) {
95 switch (i) {
96 case 'f':
97 fail = 1;
98 break;
99 default:
100 fprintf(stderr, "usage: %s [-f]\n", __progname);
101 exit(1);
102 }
103 }
104
105 if (socketpair(PF_LOCAL, type, 0, pfd) == -1)
106 err(1, "socketpair");
107
108 /*
109 * Create the sender.
110 */
111 (void) signal(SIGCHLD, catch_sigchld);
112 pid = fork();
113 switch (pid) {
114 case -1:
115 err(1, "fork");
116 /* NOTREACHED */
117
118 case 0:
119 if (pfd[0] != -1)
120 close(pfd[0]);
121 child(pfd[1], (fail ? fdpf_postpledge : fdpf_prepledge));
122 /* NOTREACHED */
123 }
124
125 if (pfd[0] != -1) {
126 close(pfd[1]);
127 sock = pfd[0];
128 } else {
129 err(1, "should not happen");
130 }
131
132 if (pledge("stdio recvfd pf", NULL) == -1)
133 err(1, "pledge");
134
135 /*
136 * Give sender a chance to run. We will get going again
137 * once the SIGCHLD arrives.
138 */
139 (void) sleep(10);
140
141 /*
142 * Grab the descriptors passed to us.
143 */
144 (void) memset(&msg, 0, sizeof(msg));
145 msg.msg_control = &cmsgbuf.buf;
146 msg.msg_controllen = sizeof(cmsgbuf.buf);
147
148 if (recvmsg(sock, &msg, 0) < 0)
149 err(1, "recvmsg");
150
151 (void) close(sock);
152
153 if (msg.msg_controllen == 0)
154 errx(1, "no control messages received");
155
156 if (msg.msg_flags & MSG_CTRUNC)
157 errx(1, "lost control message data");
158
159 for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL;
160 cmp = CMSG_NXTHDR(&msg, cmp)) {
161 if (cmp->cmsg_level != SOL_SOCKET)
162 errx(1, "bad control message level %d",
163 cmp->cmsg_level);
164
165 switch (cmp->cmsg_type) {
166 case SCM_RIGHTS:
167 if (cmp->cmsg_len != CMSG_LEN(sizeof(int)))
168 errx(1, "bad fd control message length %d",
169 cmp->cmsg_len);
170
171 files = (int *)CMSG_DATA(cmp);
172 break;
173
174 default:
175 errx(1, "unexpected control message");
176 /* NOTREACHED */
177 }
178 }
179
180 /*
181 * Read the files and print their contents.
182 */
183 if (files == NULL)
184 errx(1, "didn't get fd control message");
185
186 if (ioctl(files[0], DIOCGETSTATUS, &status) == -1)
187 err(1, "%s: DIOCGETSTATUS", __func__);
188 if (!status.running)
189 warnx("%s: pf is disabled", __func__);
190
191 /*
192 * All done!
193 */
194 return 0;
195 }
196
197 void
catch_sigchld(sig)198 catch_sigchld(sig)
199 int sig;
200 {
201 int save_errno = errno;
202 int status;
203
204 (void) wait(&status);
205 errno = save_errno;
206 }
207
208 void
child(int sock,int fdpf)209 child(int sock, int fdpf)
210 {
211 struct msghdr msg;
212 struct cmsghdr *cmp;
213 union {
214 struct cmsghdr hdr;
215 char buf[CMSG_SPACE(sizeof(int))];
216 } cmsgbuf;
217 int *files;
218
219 (void) memset(&msg, 0, sizeof(msg));
220 msg.msg_control = &cmsgbuf.buf;
221 msg.msg_controllen = sizeof(cmsgbuf.buf);
222
223 cmp = CMSG_FIRSTHDR(&msg);
224 cmp->cmsg_len = CMSG_LEN(sizeof(int));
225 cmp->cmsg_level = SOL_SOCKET;
226 cmp->cmsg_type = SCM_RIGHTS;
227
228 files = (int *)CMSG_DATA(cmp);
229 files[0] = fdpf;
230
231 if (pledge("stdio sendfd", NULL) == -1)
232 errx(1, "pledge");
233
234 if (sendmsg(sock, &msg, 0))
235 err(1, "child sendmsg");
236
237 /*
238 * All done!
239 */
240 _exit(0);
241 }
242