xref: /openbsd-src/regress/sys/kern/pledge/ioctl/unfdpass.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: unfdpass.c,v 1.4 2023/03/08 04:43:06 guenther Exp $	*/
20ed871a7Sbenno /*	$NetBSD: unfdpass.c,v 1.3 1998/06/24 23:51:30 thorpej Exp $	*/
30ed871a7Sbenno 
40ed871a7Sbenno /*-
50ed871a7Sbenno  * Copyright (c) 1998 The NetBSD Foundation, Inc.
60ed871a7Sbenno  * All rights reserved.
70ed871a7Sbenno  *
80ed871a7Sbenno  * This code is derived from software contributed to The NetBSD Foundation
90ed871a7Sbenno  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
100ed871a7Sbenno  * NASA Ames Research Center.
110ed871a7Sbenno  *
120ed871a7Sbenno  * Redistribution and use in source and binary forms, with or without
130ed871a7Sbenno  * modification, are permitted provided that the following conditions
140ed871a7Sbenno  * are met:
150ed871a7Sbenno  * 1. Redistributions of source code must retain the above copyright
160ed871a7Sbenno  *    notice, this list of conditions and the following disclaimer.
170ed871a7Sbenno  * 2. Redistributions in binary form must reproduce the above copyright
180ed871a7Sbenno  *    notice, this list of conditions and the following disclaimer in the
190ed871a7Sbenno  *    documentation and/or other materials provided with the distribution.
200ed871a7Sbenno  *
210ed871a7Sbenno  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
220ed871a7Sbenno  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230ed871a7Sbenno  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240ed871a7Sbenno  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
250ed871a7Sbenno  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
260ed871a7Sbenno  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
270ed871a7Sbenno  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
280ed871a7Sbenno  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
290ed871a7Sbenno  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300ed871a7Sbenno  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310ed871a7Sbenno  * POSSIBILITY OF SUCH DAMAGE.
320ed871a7Sbenno  */
330ed871a7Sbenno 
340ed871a7Sbenno /*
350ed871a7Sbenno  * Test passing of a /dev/pf file descriptors over socketpair,
360ed871a7Sbenno  * and of passing a fd opened before the first pledge call that
370ed871a7Sbenno  * is then used for ioctl()
380ed871a7Sbenno  */
390ed871a7Sbenno 
4049a6e16fSderaadt #include <sys/types.h>
410ed871a7Sbenno #include <sys/socket.h>
420ed871a7Sbenno #include <sys/ioctl.h>
430ed871a7Sbenno #include <sys/time.h>
440ed871a7Sbenno #include <sys/wait.h>
450ed871a7Sbenno #include <sys/un.h>
460ed871a7Sbenno #include <net/if.h>
470ed871a7Sbenno #include <net/pfvar.h>
480ed871a7Sbenno 
490ed871a7Sbenno #include <err.h>
500ed871a7Sbenno #include <errno.h>
510ed871a7Sbenno #include <fcntl.h>
520ed871a7Sbenno #include <signal.h>
530ed871a7Sbenno #include <stdio.h>
540ed871a7Sbenno #include <stdlib.h>
550ed871a7Sbenno #include <string.h>
560ed871a7Sbenno #include <unistd.h>
570ed871a7Sbenno 
580ed871a7Sbenno #define	SOCK_NAME	"test-sock"
590ed871a7Sbenno 
600ed871a7Sbenno int	main(int, char *[]);
610ed871a7Sbenno void	child(int, int);
620ed871a7Sbenno void	catch_sigchld(int);
630ed871a7Sbenno 
640ed871a7Sbenno int
main(int argc,char * argv[])650ed871a7Sbenno main(int argc, char *argv[])
660ed871a7Sbenno {
670ed871a7Sbenno 	struct msghdr msg;
680ed871a7Sbenno 	int sock, pfd[2], i;
690ed871a7Sbenno 	struct cmsghdr *cmp;
700ed871a7Sbenno 	int *files = NULL;
710ed871a7Sbenno 	int fdpf_prepledge, fdpf_postpledge;
720ed871a7Sbenno 	pid_t pid;
730ed871a7Sbenno 	union {
740ed871a7Sbenno 		struct cmsghdr hdr;
750ed871a7Sbenno 		char buf[CMSG_SPACE(sizeof(int))];
760ed871a7Sbenno 	} cmsgbuf;
770ed871a7Sbenno 	int type = SOCK_STREAM;
780ed871a7Sbenno 	int fail = 0;
790ed871a7Sbenno 	struct pf_status status;
800ed871a7Sbenno 	extern char *__progname;
810ed871a7Sbenno 
820ed871a7Sbenno 	if ((fdpf_prepledge = open("/dev/pf", O_RDWR)) == -1) {
830ed871a7Sbenno 		err(1, "%s: cannot open pf socket", __func__);
840ed871a7Sbenno 	}
850ed871a7Sbenno 
860ed871a7Sbenno 	if (pledge("stdio rpath wpath sendfd recvfd proc pf", NULL)
870ed871a7Sbenno 	    == -1)
880e59fe4aSbluhm 		err(1, "pledge");
890ed871a7Sbenno 
900ed871a7Sbenno 	if ((fdpf_postpledge = open("/dev/pf", O_RDWR)) == -1) {
910ed871a7Sbenno 		err(1, "%s: cannot open pf socket", __func__);
920ed871a7Sbenno 	}
930ed871a7Sbenno 
940ed871a7Sbenno 	while ((i = getopt(argc, argv, "f")) != -1) {
950ed871a7Sbenno 		switch (i) {
960ed871a7Sbenno 		case 'f':
970ed871a7Sbenno 			fail = 1;
980ed871a7Sbenno 			break;
990ed871a7Sbenno 		default:
1000ed871a7Sbenno 			fprintf(stderr, "usage: %s [-f]\n", __progname);
1010ed871a7Sbenno 			exit(1);
1020ed871a7Sbenno 		}
1030ed871a7Sbenno 	}
1040ed871a7Sbenno 
1050ed871a7Sbenno 	if (socketpair(PF_LOCAL, type, 0, pfd) == -1)
1060ed871a7Sbenno 		err(1, "socketpair");
1070ed871a7Sbenno 
1080ed871a7Sbenno 	/*
1090ed871a7Sbenno 	 * Create the sender.
1100ed871a7Sbenno 	 */
1110ed871a7Sbenno 	(void) signal(SIGCHLD, catch_sigchld);
1120ed871a7Sbenno 	pid = fork();
1130ed871a7Sbenno 	switch (pid) {
1140ed871a7Sbenno 	case -1:
1150ed871a7Sbenno 		err(1, "fork");
1160ed871a7Sbenno 		/* NOTREACHED */
1170ed871a7Sbenno 
1180ed871a7Sbenno 	case 0:
1190ed871a7Sbenno 		if (pfd[0] != -1)
1200ed871a7Sbenno 			close(pfd[0]);
1210ed871a7Sbenno 		child(pfd[1], (fail ? fdpf_postpledge : fdpf_prepledge));
1220ed871a7Sbenno 		/* NOTREACHED */
1230ed871a7Sbenno 	}
1240ed871a7Sbenno 
1250ed871a7Sbenno 	if (pfd[0] != -1) {
1260ed871a7Sbenno 		close(pfd[1]);
1270ed871a7Sbenno 		sock = pfd[0];
1280ed871a7Sbenno 	} else {
1290ed871a7Sbenno 		err(1, "should not happen");
1300ed871a7Sbenno 	}
1310ed871a7Sbenno 
1320ed871a7Sbenno 	if (pledge("stdio recvfd pf", NULL) == -1)
1330e59fe4aSbluhm 		err(1, "pledge");
1340ed871a7Sbenno 
1350ed871a7Sbenno 	/*
1360ed871a7Sbenno 	 * Give sender a chance to run.  We will get going again
1370ed871a7Sbenno 	 * once the SIGCHLD arrives.
1380ed871a7Sbenno 	 */
1390ed871a7Sbenno 	(void) sleep(10);
1400ed871a7Sbenno 
1410ed871a7Sbenno 	/*
1420ed871a7Sbenno 	 * Grab the descriptors passed to us.
1430ed871a7Sbenno 	 */
1440ed871a7Sbenno 	(void) memset(&msg, 0, sizeof(msg));
1450ed871a7Sbenno 	msg.msg_control = &cmsgbuf.buf;
1460ed871a7Sbenno 	msg.msg_controllen = sizeof(cmsgbuf.buf);
1470ed871a7Sbenno 
1480ed871a7Sbenno 	if (recvmsg(sock, &msg, 0) < 0)
1490ed871a7Sbenno 		err(1, "recvmsg");
1500ed871a7Sbenno 
1510ed871a7Sbenno 	(void) close(sock);
1520ed871a7Sbenno 
1530ed871a7Sbenno 	if (msg.msg_controllen == 0)
1540ed871a7Sbenno 		errx(1, "no control messages received");
1550ed871a7Sbenno 
1560ed871a7Sbenno 	if (msg.msg_flags & MSG_CTRUNC)
1570ed871a7Sbenno 		errx(1, "lost control message data");
1580ed871a7Sbenno 
1590ed871a7Sbenno 	for (cmp = CMSG_FIRSTHDR(&msg); cmp != NULL;
1600ed871a7Sbenno 	    cmp = CMSG_NXTHDR(&msg, cmp)) {
1610ed871a7Sbenno 		if (cmp->cmsg_level != SOL_SOCKET)
1620ed871a7Sbenno 			errx(1, "bad control message level %d",
1630ed871a7Sbenno 			    cmp->cmsg_level);
1640ed871a7Sbenno 
1650ed871a7Sbenno 		switch (cmp->cmsg_type) {
1660ed871a7Sbenno 		case SCM_RIGHTS:
1670ed871a7Sbenno 			if (cmp->cmsg_len != CMSG_LEN(sizeof(int)))
1680ed871a7Sbenno 				errx(1, "bad fd control message length %d",
1690ed871a7Sbenno 				    cmp->cmsg_len);
1700ed871a7Sbenno 
1710ed871a7Sbenno 			files = (int *)CMSG_DATA(cmp);
1720ed871a7Sbenno 			break;
1730ed871a7Sbenno 
1740ed871a7Sbenno 		default:
1750ed871a7Sbenno 			errx(1, "unexpected control message");
1760ed871a7Sbenno 			/* NOTREACHED */
1770ed871a7Sbenno 		}
1780ed871a7Sbenno 	}
1790ed871a7Sbenno 
1800ed871a7Sbenno 	/*
1810ed871a7Sbenno 	 * Read the files and print their contents.
1820ed871a7Sbenno 	 */
1830ed871a7Sbenno 	if (files == NULL)
1840e59fe4aSbluhm 		errx(1, "didn't get fd control message");
1850e59fe4aSbluhm 
1860ed871a7Sbenno 	if (ioctl(files[0], DIOCGETSTATUS, &status) == -1)
1870ed871a7Sbenno 		err(1, "%s: DIOCGETSTATUS", __func__);
1880ed871a7Sbenno 	if (!status.running)
1890e59fe4aSbluhm 		warnx("%s: pf is disabled", __func__);
1900ed871a7Sbenno 
1910ed871a7Sbenno 	/*
1920ed871a7Sbenno 	 * All done!
1930ed871a7Sbenno 	 */
1940e59fe4aSbluhm 	return 0;
1950ed871a7Sbenno }
1960ed871a7Sbenno 
1970ed871a7Sbenno void
catch_sigchld(sig)1980ed871a7Sbenno catch_sigchld(sig)
1990ed871a7Sbenno 	int sig;
2000ed871a7Sbenno {
2010ed871a7Sbenno 	int save_errno = errno;
2020ed871a7Sbenno 	int status;
2030ed871a7Sbenno 
2040ed871a7Sbenno 	(void) wait(&status);
2050ed871a7Sbenno 	errno = save_errno;
2060ed871a7Sbenno }
2070ed871a7Sbenno 
2080ed871a7Sbenno void
child(int sock,int fdpf)2090ed871a7Sbenno child(int sock, int fdpf)
2100ed871a7Sbenno {
2110ed871a7Sbenno 	struct msghdr msg;
2120ed871a7Sbenno 	struct cmsghdr *cmp;
2130ed871a7Sbenno 	union {
2140ed871a7Sbenno 		struct cmsghdr hdr;
2150ed871a7Sbenno 		char buf[CMSG_SPACE(sizeof(int))];
2160ed871a7Sbenno 	} cmsgbuf;
2170ed871a7Sbenno 	int *files;
2180ed871a7Sbenno 
2190ed871a7Sbenno 	(void) memset(&msg, 0, sizeof(msg));
2200ed871a7Sbenno 	msg.msg_control = &cmsgbuf.buf;
2210ed871a7Sbenno 	msg.msg_controllen = sizeof(cmsgbuf.buf);
2220ed871a7Sbenno 
2230ed871a7Sbenno 	cmp = CMSG_FIRSTHDR(&msg);
2240ed871a7Sbenno 	cmp->cmsg_len = CMSG_LEN(sizeof(int));
2250ed871a7Sbenno 	cmp->cmsg_level = SOL_SOCKET;
2260ed871a7Sbenno 	cmp->cmsg_type = SCM_RIGHTS;
2270ed871a7Sbenno 
2280ed871a7Sbenno 	files = (int *)CMSG_DATA(cmp);
2290ed871a7Sbenno 	files[0] = fdpf;
2300ed871a7Sbenno 
2310ed871a7Sbenno 	if (pledge("stdio sendfd", NULL) == -1)
2320ed871a7Sbenno 		errx(1, "pledge");
2330ed871a7Sbenno 
2340ed871a7Sbenno 	if (sendmsg(sock, &msg, 0))
2350ed871a7Sbenno 		err(1, "child sendmsg");
2360ed871a7Sbenno 
2370ed871a7Sbenno 	/*
2380ed871a7Sbenno 	 * All done!
2390ed871a7Sbenno 	 */
2400e59fe4aSbluhm 	_exit(0);
2410ed871a7Sbenno }
242