1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Privilege Separation for dhcpcd, BSD driver 4 * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> 5 * All rights reserved 6 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/ioctl.h> 30 31 /* Need these for filtering the ioctls */ 32 #include <net/if.h> 33 #include <netinet/in.h> 34 #include <netinet6/in6_var.h> 35 #include <netinet6/nd6.h> 36 #ifdef __DragonFly__ 37 # include <netproto/802_11/ieee80211_ioctl.h> 38 #else 39 # include <net80211/ieee80211.h> 40 # include <net80211/ieee80211_ioctl.h> 41 #endif 42 43 #include <errno.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "dhcpcd.h" 48 #include "logerr.h" 49 #include "privsep.h" 50 51 static ssize_t 52 ps_root_doioctldom(int domain, unsigned long req, void *data, size_t len) 53 { 54 int s, err; 55 56 /* Only allow these ioctls */ 57 switch(req) { 58 #ifdef SIOCG80211NWID 59 case SIOCG80211NWID: /* FALLTHROUGH */ 60 #endif 61 #ifdef SIOCGETVLAN 62 case SIOCGETVLAN: /* FALLTHROUGH */ 63 #endif 64 #ifdef SIOCIFAFATTACH 65 case SIOCIFAFATTACH: /* FALLTHROUGH */ 66 #endif 67 #ifdef SIOCSIFXFLAGS 68 case SIOCSIFXFLAGS: /* FALLTHROUGH */ 69 #endif 70 #ifdef SIOCSIFINFO_FLAGS 71 case SIOCSIFINFO_FLAGS: /* FALLTHROUGH */ 72 #endif 73 #ifdef SIOCSRTRFLUSH_IN6 74 case SIOCSRTRFLUSH_IN6: /* FALLTHROUGH */ 75 case SIOCSPFXFLUSH_IN6: /* FALLTHROUGH */ 76 #endif 77 #if defined(SIOCALIFADDR) && defined(IFLR_ACTIVE) 78 case SIOCALIFADDR: /* FALLTHROUGH */ 79 case SIOCDLIFADDR: /* FALLTHROUGH */ 80 #else 81 case SIOCSIFLLADDR: /* FALLTHROUGH */ 82 #endif 83 #ifdef SIOCSIFINFO_IN6 84 case SIOCSIFINFO_IN6: /* FALLTHROUGH */ 85 #endif 86 case SIOCAIFADDR_IN6: /* FALLTHROUGH */ 87 case SIOCDIFADDR_IN6: 88 break; 89 default: 90 errno = EPERM; 91 return -1; 92 } 93 94 s = socket(domain, SOCK_DGRAM, 0); 95 if (s == -1) 96 return -1; 97 err = ioctl(s, req, data, len); 98 close(s); 99 return err; 100 } 101 102 static ssize_t 103 ps_root_doroute(void *data, size_t len) 104 { 105 int s; 106 ssize_t err; 107 108 s = socket(PF_ROUTE, SOCK_RAW, 0); 109 if (s != -1) 110 err = write(s, data, len); 111 else 112 err = -1; 113 if (s != -1) 114 close(s); 115 return err; 116 } 117 118 #ifdef HAVE_PLEDGE 119 static ssize_t 120 ps_root_doindirectioctl(unsigned long req, void *data, size_t len) 121 { 122 char *p = data; 123 struct ifreq ifr = { .ifr_flags = 0 }; 124 125 /* ioctl filtering is done in ps_root_doioctldom */ 126 127 if (len < IFNAMSIZ + 1) { 128 errno = EINVAL; 129 return -1; 130 } 131 132 strlcpy(ifr.ifr_name, p, IFNAMSIZ); 133 len -= IFNAMSIZ; 134 memmove(data, p + IFNAMSIZ, len); 135 ifr.ifr_data = data; 136 137 return ps_root_doioctldom(PF_INET, req, &ifr, sizeof(ifr)); 138 } 139 #endif 140 141 ssize_t 142 ps_root_os(struct ps_msghdr *psm, struct msghdr *msg, 143 void **rdata, size_t *rlen) 144 { 145 struct iovec *iov = msg->msg_iov; 146 void *data = iov->iov_base; 147 size_t len = iov->iov_len; 148 ssize_t err; 149 150 switch (psm->ps_cmd) { 151 case PS_IOCTLLINK: 152 err = ps_root_doioctldom(PF_LINK, psm->ps_flags, data, len); 153 break; 154 case PS_IOCTL6: 155 err = ps_root_doioctldom(PF_INET6, psm->ps_flags, data, len); 156 break; 157 case PS_ROUTE: 158 return ps_root_doroute(data, len); 159 #ifdef HAVE_PLEDGE 160 case PS_IOCTLINDIRECT: 161 err = ps_root_doindirectioctl(psm->ps_flags, data, len); 162 break; 163 #endif 164 default: 165 errno = ENOTSUP; 166 return -1; 167 } 168 169 if (err != -1) { 170 *rdata = data; 171 *rlen = len; 172 } 173 return err; 174 } 175 176 static ssize_t 177 ps_root_ioctldom(struct dhcpcd_ctx *ctx, uint16_t domain, unsigned long request, 178 void *data, size_t len) 179 { 180 181 if (ps_sendcmd(ctx, ctx->ps_root_fd, domain, 182 request, data, len) == -1) 183 return -1; 184 return ps_root_readerror(ctx, data, len); 185 } 186 187 ssize_t 188 ps_root_ioctllink(struct dhcpcd_ctx *ctx, unsigned long request, 189 void *data, size_t len) 190 { 191 192 return ps_root_ioctldom(ctx, PS_IOCTLLINK, request, data, len); 193 } 194 195 ssize_t 196 ps_root_ioctl6(struct dhcpcd_ctx *ctx, unsigned long request, 197 void *data, size_t len) 198 { 199 200 return ps_root_ioctldom(ctx, PS_IOCTL6, request, data, len); 201 } 202 203 ssize_t 204 ps_root_route(struct dhcpcd_ctx *ctx, void *data, size_t len) 205 { 206 207 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_ROUTE, 0, data, len) == -1) 208 return -1; 209 return ps_root_readerror(ctx, data, len); 210 } 211 212 #ifdef HAVE_PLEDGE 213 ssize_t 214 ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request, 215 const char *ifname, void *data, size_t len) 216 { 217 char buf[PS_BUFLEN]; 218 219 if (IFNAMSIZ + len > sizeof(buf)) { 220 errno = ENOBUFS; 221 return -1; 222 } 223 224 strlcpy(buf, ifname, IFNAMSIZ); 225 memcpy(buf + IFNAMSIZ, data, len); 226 if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_IOCTLINDIRECT, 227 request, buf, IFNAMSIZ + len) == -1) 228 return -1; 229 return ps_root_readerror(ctx, data, len); 230 } 231 #endif 232