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