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 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 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 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