]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/kext_net.c
xnu-1228.9.59.tar.gz
[apple/xnu.git] / bsd / net / kext_net.c
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 */
48 struct nf_list nf_list;
49
50 static 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 */
57 int
58 register_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
105 int
106 unregister_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
118 struct NFDescriptor *
119 find_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 */
137 int
138 nke_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
223 static struct sockif* g_symantec_if_funcs = NULL;
224 static struct sockutil* g_symantec_util_funcs = NULL;
225 static int sym_fix_sbflush(struct sockbuf *, struct kextcb *);
226 static int sym_fix_sbappend(struct sockbuf *, struct mbuf *, struct kextcb *);
227 static int sym_fix_soclose(struct socket *, struct kextcb *);
228 static int sym_fix_sofree(struct socket *, struct kextcb *);
229 static int sym_fix_soconnect(struct socket *, struct sockaddr *, struct kextcb *);
230 static int sym_fix_soisconnected(struct socket *, struct kextcb *);
231 static int sym_fix_sosend(struct socket *, struct sockaddr **, struct uio **, struct mbuf **,
232 struct mbuf **, int *, struct kextcb *);
233 static int sym_fix_socantrcvmore(struct socket *, struct kextcb *);
234 static int sym_fix_socontrol(struct socket *, struct sockopt *, struct kextcb *);
235
236 static 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
278 static 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
286 static 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
294 static 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
302 static 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
310 static 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
318 static 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
326 static 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
335 static 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
343 static 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 }