1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* Copyright (C) 1999 Apple Computer, Inc. */ 29 30/* 31 * Support for Network Kernel Extensions: Socket Filters 32 * 33 * Justin C. Walker, 990319 34 */ 35 36#include <sys/types.h> 37#include <sys/queue.h> 38#include <sys/malloc.h> 39#include <sys/param.h> 40#include <sys/mbuf.h> 41#include <sys/domain.h> 42#include <sys/protosw.h> 43#include <sys/socket.h> 44#include <machine/spl.h> 45#include "kext_net.h" 46 47/* List of kernel extensions (networking) known to kernel */ 48struct nf_list nf_list; 49 50static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc); 51 52/* 53 * Register a global filter for the specified protocol 54 * Make a few checks and then insert the new descriptor in the 55 * filter list and, if global, in its protosw's chain. 56 */ 57int 58register_sockfilter(struct NFDescriptor *nfp, struct NFDescriptor *nfp1, 59 struct protosw *pr, int flags) 60{ int s; 61 static int NF_initted = 0; 62 63 if (nfp == NULL) 64 return(EINVAL); 65 66 /* Fix Symantec's broken NPC kext */ 67 if (nfp->nf_handle == 0xf1ab02de) { 68 int err = sockfilter_fix_symantec_bug(nfp); 69 if (err != 0) 70 return err; 71 } 72 73 s = splhigh(); 74 if (!NF_initted) 75 { NF_initted = 1; 76 TAILQ_INIT(&nf_list); 77 } 78 79 /* 80 * Install the extension: 81 * First, put it in the global list of all filters 82 * Then, if global, install in the protosw's list 83 */ 84 TAILQ_INSERT_TAIL(&nf_list, nfp, nf_list); 85 if (nfp->nf_flags & NFD_GLOBAL) 86 { if (flags & NFF_BEFORE) 87 { if (nfp1 == NULL) 88 { TAILQ_INSERT_HEAD(&pr->pr_sfilter, 89 nfp, nf_next); 90 } else 91 TAILQ_INSERT_BEFORE(nfp1, nfp, nf_next); 92 } else /* Default: AFTER */ 93 { if (nfp1 == NULL) 94 { TAILQ_INSERT_TAIL(&pr->pr_sfilter, 95 nfp, nf_next); 96 } else 97 TAILQ_INSERT_AFTER(&pr->pr_sfilter, nfp1, 98 nfp, nf_next); 99 } 100 } 101 splx(s); 102 return(0); 103} 104 105int 106unregister_sockfilter(struct NFDescriptor *nfp, struct protosw *pr, __unused int flags) 107{ int s; 108 109 s = splhigh(); 110 TAILQ_REMOVE(&nf_list, nfp, nf_list); 111 /* Only globals are attached to the protosw entry */ 112 if (nfp->nf_flags & NFD_GLOBAL) 113 TAILQ_REMOVE(&pr->pr_sfilter, nfp, nf_next); 114 splx(s); 115 return(0); 116} 117 118struct NFDescriptor * 119find_nke(unsigned int handle) 120{ struct NFDescriptor *nfp; 121 122 nfp = nf_list.tqh_first; 123 while (nfp) 124 { if (nfp->nf_handle == handle) 125 return(nfp); 126 nfp = nfp->nf_list.tqe_next; 127 } 128 return(NULL); 129} 130 131/* 132 * Insert a previously registered, non-global, NKE into the list of 133 * active NKEs for this socket. Then invoke its "attach/create" entry. 134 * Assumed called with protection in place (spl/mutex/whatever) 135 * XXX: How to which extension is not found, on error. 136 */ 137int 138nke_insert(struct socket *so, struct so_nke *np) 139{ 140 struct kextcb *kp, *kp1; 141 struct NFDescriptor *nf1, *nf2 = NULL; 142 143 if (np->nke_where != NULL) 144 { if ((nf2 = find_nke(np->nke_where)) == NULL) 145 { /* ??? */ 146 return(ENXIO);/* XXX */ 147 } 148 } 149 150 if ((nf1 = find_nke(np->nke_handle)) == NULL) 151 { /* ??? */ 152 return(ENXIO);/* XXX */ 153 } 154 155 kp = so->so_ext; 156 kp1 = NULL; 157 if (np->nke_flags & NFF_BEFORE) 158 { if (nf2) 159 { while (kp) 160 { if (kp->e_nfd == nf2) 161 break; 162 kp1 = kp; 163 kp = kp->e_next; 164 } 165 if (kp == NULL) 166 return(ENXIO);/* XXX */ 167 } 168 } else 169 { if (nf2) 170 { while (kp) 171 { if (kp->e_nfd == nf2) 172 break; 173 kp1 = kp; 174 kp = kp->e_next; 175 } 176 if (kp == NULL) 177 return(ENXIO);/* XXX */ 178 } 179 kp1 = kp; 180 } 181 /* 182 * Here with kp1 pointing to the insertion point. 183 * If null, this is first entry. 184 * Now, create and insert the descriptor. 185 */ 186 187 MALLOC(kp, struct kextcb *, sizeof(*kp), M_TEMP, M_WAITOK); 188 if (kp == NULL) 189 return(ENOBUFS); /* so_free will clean up */ 190 bzero(kp, sizeof (*kp)); 191 if (kp1 == NULL) 192 { kp->e_next = so->so_ext; 193 so->so_ext = kp; 194 } else 195 { kp->e_next = kp1->e_next; 196 kp1->e_next = kp; 197 } 198 kp->e_fcb = NULL; 199 kp->e_nfd = nf1; 200 kp->e_soif = nf1->nf_soif; 201 kp->e_sout = nf1->nf_soutil; 202 /* 203 * Ignore return value for create 204 * Everyone gets a chance at startup 205 */ 206 if (kp->e_soif && kp->e_soif->sf_socreate) 207 (*kp->e_soif->sf_socreate)(so, so->so_proto, kp); 208 return(0); 209} 210 211/* 212 * The following gunk is a fix for Symantec's broken NPC kext 213 * Symantec's NPC kext does not check that the kextcb->e_fcb 214 * is not NULL before derefing it. The result is a panic in 215 * the very few cases where the e_fcb is actually NULL. 216 * 217 * This gross chunk of code copies the old function ptrs 218 * supplied by the kext and wraps a few select ones in 219 * our own functions that just check for NULL before 220 * calling in to the kext. 221 */ 222 223static struct sockif* g_symantec_if_funcs = NULL; 224static struct sockutil* g_symantec_util_funcs = NULL; 225static int sym_fix_sbflush(struct sockbuf *, struct kextcb *); 226static int sym_fix_sbappend(struct sockbuf *, struct mbuf *, struct kextcb *); 227static int sym_fix_soclose(struct socket *, struct kextcb *); 228static int sym_fix_sofree(struct socket *, struct kextcb *); 229static int sym_fix_soconnect(struct socket *, struct sockaddr *, struct kextcb *); 230static int sym_fix_soisconnected(struct socket *, struct kextcb *); 231static int sym_fix_sosend(struct socket *, struct sockaddr **, struct uio **, struct mbuf **, 232 struct mbuf **, int *, struct kextcb *); 233static int sym_fix_socantrcvmore(struct socket *, struct kextcb *); 234static int sym_fix_socontrol(struct socket *, struct sockopt *, struct kextcb *); 235 236static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc) 237{ 238 if (!g_symantec_if_funcs ) { 239 MALLOC(g_symantec_if_funcs, struct sockif*, sizeof(*g_symantec_if_funcs), M_TEMP, M_WAITOK); 240 241 if (!g_symantec_if_funcs) 242 return ENOMEM; 243 244 *g_symantec_if_funcs = *theirDesc->nf_soif; 245 } 246 247 if (!g_symantec_util_funcs) { 248 MALLOC(g_symantec_util_funcs, struct sockutil*, sizeof(*g_symantec_util_funcs), M_TEMP, M_WAITOK); 249 250 if (!g_symantec_util_funcs) 251 return ENOMEM; 252 253 *g_symantec_util_funcs = *theirDesc->nf_soutil; 254 } 255 256 if (theirDesc->nf_soutil->su_sbflush) 257 theirDesc->nf_soutil->su_sbflush = sym_fix_sbflush; 258 if (theirDesc->nf_soutil->su_sbappend) 259 theirDesc->nf_soutil->su_sbappend = sym_fix_sbappend; 260 if (theirDesc->nf_soif->sf_soclose) 261 theirDesc->nf_soif->sf_soclose = sym_fix_soclose; 262 if (theirDesc->nf_soif->sf_sofree) 263 theirDesc->nf_soif->sf_sofree = sym_fix_sofree; 264 if (theirDesc->nf_soif->sf_soconnect) 265 theirDesc->nf_soif->sf_soconnect = sym_fix_soconnect; 266 if (theirDesc->nf_soif->sf_soisconnected) 267 theirDesc->nf_soif->sf_soisconnected = sym_fix_soisconnected; 268 if (theirDesc->nf_soif->sf_sosend) 269 theirDesc->nf_soif->sf_sosend = sym_fix_sosend; 270 if (theirDesc->nf_soif->sf_socantrcvmore) 271 theirDesc->nf_soif->sf_socantrcvmore = sym_fix_socantrcvmore; 272 if (theirDesc->nf_soif->sf_socontrol) 273 theirDesc->nf_soif->sf_socontrol = sym_fix_socontrol; 274 275 return 0; 276} 277 278static int sym_fix_sbflush(struct sockbuf *p1, struct kextcb *p2) 279{ 280 if (p2->e_fcb != NULL && g_symantec_util_funcs) 281 return g_symantec_util_funcs->su_sbflush(p1, p2); 282 else 283 return 0; 284} 285 286static int sym_fix_sbappend(struct sockbuf *p1, struct mbuf *p2, struct kextcb *p3) 287{ 288 if (p3->e_fcb != NULL && g_symantec_util_funcs) 289 return g_symantec_util_funcs->su_sbappend(p1, p2, p3); 290 else 291 return 0; 292} 293 294static int sym_fix_soclose(struct socket *p1, struct kextcb *p2) 295{ 296 if (p2->e_fcb != NULL && g_symantec_if_funcs) 297 return g_symantec_if_funcs->sf_soclose(p1, p2); 298 else 299 return 0; 300} 301 302static int sym_fix_sofree(struct socket *p1, struct kextcb *p2) 303{ 304 if (p2->e_fcb != NULL && g_symantec_if_funcs) 305 return g_symantec_if_funcs->sf_sofree(p1, p2); 306 else 307 return 0; 308} 309 310static int sym_fix_soconnect(struct socket *p1, struct sockaddr *p2, struct kextcb *p3) 311{ 312 if (p3->e_fcb != NULL && g_symantec_if_funcs) 313 return g_symantec_if_funcs->sf_soconnect(p1, p2, p3); 314 else 315 return 0; 316} 317 318static int sym_fix_soisconnected(struct socket *p1, struct kextcb *p2) 319{ 320 if (p2->e_fcb != NULL && g_symantec_if_funcs) 321 return g_symantec_if_funcs->sf_soisconnected(p1, p2); 322 else 323 return 0; 324} 325 326static int sym_fix_sosend(struct socket *p1, struct sockaddr **p2, struct uio **p3, struct mbuf **p4, 327 struct mbuf **p5, int *p6, struct kextcb *p7) 328{ 329 if (p7->e_fcb != NULL && g_symantec_if_funcs) 330 return g_symantec_if_funcs->sf_sosend(p1, p2, p3, p4, p5, p6, p7); 331 else 332 return 0; 333} 334 335static int sym_fix_socantrcvmore(struct socket *p1, struct kextcb *p2) 336{ 337 if (p2->e_fcb != NULL && g_symantec_if_funcs) 338 return g_symantec_if_funcs->sf_socantrcvmore(p1, p2); 339 else 340 return 0; 341} 342 343static int sym_fix_socontrol(struct socket *p1, struct sockopt *p2, struct kextcb *p3) 344{ 345 if (p3->e_fcb != NULL && g_symantec_if_funcs) 346 return g_symantec_if_funcs->sf_socontrol(p1, p2, p3); 347 else 348 return 0; 349} 350