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