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