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 */
48struct nf_list nf_list;
49
50static 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 */
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
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
105int
106unregister_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
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)
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
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}
350