]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/kext_net.c
xnu-1228.3.13.tar.gz
[apple/xnu.git] / bsd / net / kext_net.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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
9bccf70c
A
50static int sockfilter_fix_symantec_bug(struct NFDescriptor* theirDesc);
51
1c79356b
A
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
9bccf70c
A
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
1c79356b
A
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
91447636
A
105int
106unregister_sockfilter(struct NFDescriptor *nfp, struct protosw *pr, __unused int flags)
1c79356b
A
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)
91447636 139{
1c79356b
A
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}
9bccf70c
A
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}