xref: /openbsd/regress/sys/kern/pledge/ioctl/unfdpass.c (revision 09467b48)
1 /*	$OpenBSD: unfdpass.c,v 1.1 2017/01/26 04:58:08 benno 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/param.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 /* ARGSUSED */
65 int
66 main(int argc, char *argv[])
67 {
68 	struct msghdr msg;
69 	int sock, pfd[2], i;
70 	struct cmsghdr *cmp;
71 	int *files = NULL;
72 	int fdpf_prepledge, fdpf_postpledge;
73 	pid_t pid;
74 	union {
75 		struct cmsghdr hdr;
76 		char buf[CMSG_SPACE(sizeof(int))];
77 	} cmsgbuf;
78 	int type = SOCK_STREAM;
79 	int fail = 0;
80 	struct pf_status status;
81 	extern char *__progname;
82 
83 	if ((fdpf_prepledge = open("/dev/pf", O_RDWR)) == -1) {
84 		err(1, "%s: cannot open pf socket", __func__);
85 	}
86 
87 	if (pledge("stdio rpath wpath sendfd recvfd proc pf", NULL)
88 	    == -1)
89 		errx(1, "pledge");
90 
91 	if ((fdpf_postpledge = open("/dev/pf", O_RDWR)) == -1) {
92 		err(1, "%s: cannot open pf socket", __func__);
93 	}
94 
95 	while ((i = getopt(argc, argv, "f")) != -1) {
96 		switch (i) {
97 		case 'f':
98 			fail = 1;
99 			break;
100 		default:
101 			fprintf(stderr, "usage: %s [-f]\n", __progname);
102 			exit(1);
103 		}
104 	}
105 
106 	if (socketpair(PF_LOCAL, type, 0, pfd) == -1)
107 		err(1, "socketpair");
108 
109 	/*
110 	 * Create the sender.
111 	 */
112 	(void) signal(SIGCHLD, catch_sigchld);
113 	pid = fork();
114 	switch (pid) {
115 	case -1:
116 		err(1, "fork");
117 		/* NOTREACHED */
118 
119 	case 0:
120 		if (pfd[0] != -1)
121 			close(pfd[0]);
122 		child(pfd[1], (fail ? fdpf_postpledge : fdpf_prepledge));
123 		/* NOTREACHED */
124 	}
125 
126 	if (pfd[0] != -1) {
127 		close(pfd[1]);
128 		sock = pfd[0];
129 	} else {
130 		err(1, "should not happen");
131 	}
132 
133 	if (pledge("stdio recvfd pf", NULL) == -1)
134 		errx(1, "pledge");
135 
136 	/*
137 	 * Give sender a chance to run.  We will get going again
138 	 * once the SIGCHLD arrives.
139 	 */
140 	(void) sleep(10);
141 
142 	/*
143 	 * Grab the descriptors passed to us.
144 	 */
145 	(void) memset(&msg, 0, sizeof(msg));
146 	msg.msg_control = &cmsgbuf.buf;
147 	msg.msg_controllen = sizeof(cmsgbuf.buf);
148 
149 	if (recvmsg(sock, &msg, 0) < 0)
150 		err(1, "recvmsg");
151 
152 	(void) close(sock);
153 
154 	if (msg.msg_controllen == 0)
155 		errx(1, "no control messages received");
156 
157 	if (msg.msg_flags & MSG_CTRUNC)
158 		errx(1, "lost control message data");
159 
160 	for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL;
161 	    cmp = CMSG_NXTHDR(&msg, cmp)) {
162 		if (cmp->cmsg_level != SOL_SOCKET)
163 			errx(1, "bad control message level %d",
164 			    cmp->cmsg_level);
165 
166 		switch (cmp->cmsg_type) {
167 		case SCM_RIGHTS:
168 			if (cmp->cmsg_len != CMSG_LEN(sizeof(int)))
169 				errx(1, "bad fd control message length %d",
170 				    cmp->cmsg_len);
171 
172 			files = (int *)CMSG_DATA(cmp);
173 			break;
174 
175 		default:
176 			errx(1, "unexpected control message");
177 			/* NOTREACHED */
178 		}
179 	}
180 
181 	/*
182 	 * Read the files and print their contents.
183 	 */
184 	if (files == NULL)
185 		warnx("didn't get fd control message");
186 	else {
187 		if (ioctl(files[0], DIOCGETSTATUS, &status) == -1)
188 			err(1, "%s: DIOCGETSTATUS", __func__);
189 		if (!status.running)
190 			errx(1, "%s: pf is disabled", __func__);
191 		else
192 			printf("pf is running\n");
193 	}
194 
195 	/*
196 	 * All done!
197 	 */
198 	exit(0);
199 }
200 
201 void
202 catch_sigchld(sig)
203 	int sig;
204 {
205 	int save_errno = errno;
206 	int status;
207 
208 	(void) wait(&status);
209 	errno = save_errno;
210 }
211 
212 void
213 child(int sock, int fdpf)
214 {
215 	struct msghdr msg;
216 	struct cmsghdr *cmp;
217 	union {
218 		struct cmsghdr hdr;
219 		char buf[CMSG_SPACE(sizeof(int))];
220 	} cmsgbuf;
221 	int *files;
222 
223 	(void) memset(&msg, 0, sizeof(msg));
224 	msg.msg_control = &cmsgbuf.buf;
225 	msg.msg_controllen = sizeof(cmsgbuf.buf);
226 
227 	cmp = CMSG_FIRSTHDR(&msg);
228 	cmp->cmsg_len = CMSG_LEN(sizeof(int));
229 	cmp->cmsg_level = SOL_SOCKET;
230 	cmp->cmsg_type = SCM_RIGHTS;
231 
232 	files = (int *)CMSG_DATA(cmp);
233 	files[0] = fdpf;
234 
235 	if (pledge("stdio sendfd", NULL) == -1)
236 		errx(1, "pledge");
237 
238 	if (sendmsg(sock, &msg, 0))
239 		err(1, "child sendmsg");
240 
241 	/*
242 	 * All done!
243 	 */
244 	exit(0);
245 }
246