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