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