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