]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socketfilter.c
xnu-1228.12.14.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socketfilter.c
CommitLineData
91447636 1/*
2d21ac55 2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 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@
91447636
A
27 */
28
29#include <sys/kpi_socketfilter.h>
30
31#include <sys/socket.h>
32#include <sys/param.h>
33#include <sys/errno.h>
34#include <sys/malloc.h>
35#include <sys/protosw.h>
36#include <kern/locks.h>
37#include <net/kext_net.h>
38
c910b4d9
A
39#include <libkern/libkern.h>
40
2d21ac55
A
41#include <string.h>
42
91447636
A
43static struct socket_filter_list sock_filter_head;
44static lck_mtx_t *sock_filter_lock = 0;
45
3a60a9f5
A
46static void sflt_detach_private(struct socket_filter_entry *entry, int unregistering);
47
91447636
A
48__private_extern__ void
49sflt_init(void)
50{
51 lck_grp_attr_t *grp_attrib = 0;
52 lck_attr_t *lck_attrib = 0;
53 lck_grp_t *lck_group = 0;
54
55 TAILQ_INIT(&sock_filter_head);
56
57 /* Allocate a spin lock */
58 grp_attrib = lck_grp_attr_alloc_init();
91447636
A
59 lck_group = lck_grp_alloc_init("socket filter lock", grp_attrib);
60 lck_grp_attr_free(grp_attrib);
61 lck_attrib = lck_attr_alloc_init();
91447636
A
62 sock_filter_lock = lck_mtx_alloc_init(lck_group, lck_attrib);
63 lck_grp_free(lck_group);
64 lck_attr_free(lck_attrib);
65}
66
67__private_extern__ void
68sflt_initsock(
69 struct socket *so)
70{
71 struct protosw *proto = so->so_proto;
72 struct socket_filter *filter;
73
74 if (TAILQ_FIRST(&proto->pr_filter_head) != NULL) {
75 lck_mtx_lock(sock_filter_lock);
76 TAILQ_FOREACH(filter, &proto->pr_filter_head, sf_protosw_next) {
77 sflt_attach_private(so, filter, 0, 0);
78 }
79 lck_mtx_unlock(sock_filter_lock);
80 }
81}
82
83__private_extern__ void
84sflt_termsock(
85 struct socket *so)
86{
87 struct socket_filter_entry *filter;
88 struct socket_filter_entry *filter_next;
89
90 for (filter = so->so_filt; filter; filter = filter_next) {
91 filter_next = filter->sfe_next_onsocket;
92 sflt_detach_private(filter, 0);
93 }
3a60a9f5 94 so->so_filt = NULL;
91447636
A
95}
96
97__private_extern__ void
98sflt_use(
99 struct socket *so)
100{
101 so->so_filteruse++;
102}
103
104__private_extern__ void
105sflt_unuse(
106 struct socket *so)
107{
108 so->so_filteruse--;
109 if (so->so_filteruse == 0) {
110 struct socket_filter_entry *filter;
111 struct socket_filter_entry *next_filter;
112 // search for detaching filters
113 for (filter = so->so_filt; filter; filter = next_filter) {
114 next_filter = filter->sfe_next_onsocket;
115
3a60a9f5 116 if (filter->sfe_flags & SFEF_DETACHUSEZERO) {
91447636
A
117 sflt_detach_private(filter, 0);
118 }
119 }
120 }
121}
122
123__private_extern__ void
124sflt_notify(
125 struct socket *so,
126 sflt_event_t event,
127 void *param)
128{
129 struct socket_filter_entry *filter;
130 int filtered = 0;
131
132 for (filter = so->so_filt; filter;
133 filter = filter->sfe_next_onsocket) {
134 if (filter->sfe_filter->sf_filter.sf_notify) {
135 if (filtered == 0) {
136 filtered = 1;
137 sflt_use(so);
138 socket_unlock(so, 0);
139 }
140 filter->sfe_filter->sf_filter.sf_notify(
141 filter->sfe_cookie, so, event, param);
142 }
143 }
144
145 if (filtered != 0) {
146 socket_lock(so, 0);
147 sflt_unuse(so);
148 }
149}
150
151__private_extern__ int
152sflt_data_in(
153 struct socket *so,
154 const struct sockaddr *from,
155 mbuf_t *data,
156 mbuf_t *control,
cc9f6e38
A
157 sflt_data_flag_t flags,
158 int *filtered)
91447636
A
159{
160 struct socket_filter_entry *filter;
91447636 161 int error = 0;
cc9f6e38
A
162 int filtered_storage;
163
164 if (filtered == NULL)
165 filtered = &filtered_storage;
166 *filtered = 0;
91447636 167
b36670ce 168 for (filter = so->so_filt; filter && (error == 0);
91447636
A
169 filter = filter->sfe_next_onsocket) {
170 if (filter->sfe_filter->sf_filter.sf_data_in) {
cc9f6e38
A
171 if (*filtered == 0) {
172 *filtered = 1;
91447636
A
173 sflt_use(so);
174 socket_unlock(so, 0);
175 }
176 error = filter->sfe_filter->sf_filter.sf_data_in(
177 filter->sfe_cookie, so, from, data, control, flags);
178 }
179 }
180
cc9f6e38 181 if (*filtered != 0) {
91447636
A
182 socket_lock(so, 0);
183 sflt_unuse(so);
184 }
185
186 return error;
187}
188
189/* sflt_attach_private
190 *
191 * Assumptions: If filter is not NULL, socket_filter_lock is held.
192 */
193
194__private_extern__ int
195sflt_attach_private(
196 struct socket *so,
197 struct socket_filter *filter,
198 sflt_handle handle,
199 int sock_locked)
200{
201 struct socket_filter_entry *entry = NULL;
202 int didlock = 0;
203 int error = 0;
204
205 if (filter == NULL) {
206 /* Find the filter by the handle */
207 lck_mtx_lock(sock_filter_lock);
208 didlock = 1;
209
210 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
211 if (filter->sf_filter.sf_handle == handle)
212 break;
213 }
214 }
215
216 if (filter == NULL)
217 error = ENOENT;
218
219 if (error == 0) {
220 /* allocate the socket filter entry */
221 MALLOC(entry, struct socket_filter_entry *, sizeof(*entry), M_IFADDR, M_WAITOK);
222 if (entry == NULL) {
223 error = ENOMEM;
224 }
225 }
226
227 if (error == 0) {
228 /* Initialize the socket filter entry and call the attach function */
229 entry->sfe_filter = filter;
230 entry->sfe_socket = so;
231 entry->sfe_cookie = NULL;
3a60a9f5 232 entry->sfe_flags = 0;
91447636
A
233 if (entry->sfe_filter->sf_filter.sf_attach) {
234 filter->sf_usecount++;
235
236 if (sock_locked)
237 socket_unlock(so, 0);
238 error = entry->sfe_filter->sf_filter.sf_attach(&entry->sfe_cookie, so);
239 if (sock_locked)
240 socket_lock(so, 0);
241
242 filter->sf_usecount--;
243
244 /* If the attach function returns an error, this filter is not attached */
245 if (error) {
246 FREE(entry, M_IFADDR);
247 entry = NULL;
248 }
249 }
250 }
251
252 if (error == 0) {
253 /* Put the entry in the socket list */
254 entry->sfe_next_onsocket = so->so_filt;
255 so->so_filt = entry;
256
257 /* Put the entry in the filter list */
258 entry->sfe_next_onfilter = filter->sf_entry_head;
259 filter->sf_entry_head = entry;
260
91447636
A
261 /* Incremenet the parent filter's usecount */
262 filter->sf_usecount++;
263 }
264
265 if (didlock) {
266 lck_mtx_unlock(sock_filter_lock);
267 }
268
269 return error;
270}
271
272
273/* sflt_detach_private
274 *
275 * Assumptions: if you pass 0 in for the second parameter, you are holding the
276 * socket lock for the socket the entry is attached to. If you pass 1 in for
277 * the second parameter, it is assumed that the entry is not on the filter's
278 * list and the socket lock is not held.
279 */
280
3a60a9f5 281static void
91447636
A
282sflt_detach_private(
283 struct socket_filter_entry *entry,
3a60a9f5 284 int unregistering)
91447636 285{
91447636
A
286 struct socket_filter_entry **next_ptr;
287 int detached = 0;
288 int found = 0;
289
3a60a9f5 290 if (unregistering) {
91447636
A
291 socket_lock(entry->sfe_socket, 0);
292 }
293
294 /*
295 * Attempt to find the entry on the filter's list and
296 * remove it. This prevents a filter detaching at the
297 * same time from attempting to remove the same entry.
298 */
299 lck_mtx_lock(sock_filter_lock);
3a60a9f5
A
300 if (!unregistering) {
301 if ((entry->sfe_flags & SFEF_UNREGISTERING) != 0) {
302 /*
4a3eedf9
A
303 * Another thread is unregistering the filter, we
304 * need to avoid detaching the filter here so the
305 * socket won't go away. Bump up the socket's
306 * usecount so that it won't be freed until after
307 * the filter unregistration has been completed;
308 * at this point the caller has already held the
309 * socket's lock, so we can directly modify the
310 * usecount.
3a60a9f5 311 */
4a3eedf9
A
312 if (!(entry->sfe_flags & SFEF_DETACHXREF)) {
313 entry->sfe_socket->so_usecount++;
314 entry->sfe_flags |= SFEF_DETACHXREF;
315 }
3a60a9f5
A
316 lck_mtx_unlock(sock_filter_lock);
317 return;
318 }
91447636
A
319 for (next_ptr = &entry->sfe_filter->sf_entry_head; *next_ptr;
320 next_ptr = &((*next_ptr)->sfe_next_onfilter)) {
321 if (*next_ptr == entry) {
322 found = 1;
323 *next_ptr = entry->sfe_next_onfilter;
324 break;
325 }
326 }
3a60a9f5
A
327
328 if (!found && (entry->sfe_flags & SFEF_DETACHUSEZERO) == 0) {
329 lck_mtx_unlock(sock_filter_lock);
330 return;
331 }
c910b4d9 332 } else {
3a60a9f5
A
333 /*
334 * Clear the removing flag. We will perform the detach here or
4a3eedf9
A
335 * request a delayed detach. Since we do an extra ref release
336 * below, bump up the usecount if we haven't done so.
3a60a9f5
A
337 */
338 entry->sfe_flags &= ~SFEF_UNREGISTERING;
4a3eedf9
A
339 if (!(entry->sfe_flags & SFEF_DETACHXREF)) {
340 entry->sfe_socket->so_usecount++;
341 entry->sfe_flags |= SFEF_DETACHXREF;
342 }
91447636
A
343 }
344
345 if (entry->sfe_socket->so_filteruse != 0) {
3a60a9f5 346 entry->sfe_flags |= SFEF_DETACHUSEZERO;
91447636 347 lck_mtx_unlock(sock_filter_lock);
c910b4d9
A
348
349 if (unregistering) {
350#if DEBUG
351 printf("sflt_detach_private unregistering SFEF_DETACHUSEZERO "
352 "so%p so_filteruse %u so_usecount %d\n",
353 entry->sfe_socket, entry->sfe_socket->so_filteruse,
354 entry->sfe_socket->so_usecount);
355#endif
356 socket_unlock(entry->sfe_socket, 0);
357 }
358
91447636 359 return;
c910b4d9 360 } else {
3a60a9f5
A
361 /*
362 * Check if we are removing the last attached filter and
363 * the parent filter is being unregistered.
364 */
91447636
A
365 entry->sfe_filter->sf_usecount--;
366 if ((entry->sfe_filter->sf_usecount == 0) &&
367 (entry->sfe_filter->sf_flags & SFF_DETACHING) != 0)
368 detached = 1;
369 }
370 lck_mtx_unlock(sock_filter_lock);
371
372 /* Remove from the socket list */
373 for (next_ptr = &entry->sfe_socket->so_filt; *next_ptr;
374 next_ptr = &((*next_ptr)->sfe_next_onsocket)) {
375 if (*next_ptr == entry) {
376 *next_ptr = entry->sfe_next_onsocket;
377 break;
378 }
379 }
380
381 if (entry->sfe_filter->sf_filter.sf_detach)
382 entry->sfe_filter->sf_filter.sf_detach(entry->sfe_cookie, entry->sfe_socket);
383
384 if (detached && entry->sfe_filter->sf_filter.sf_unregistered) {
385 entry->sfe_filter->sf_filter.sf_unregistered(entry->sfe_filter->sf_filter.sf_handle);
386 FREE(entry->sfe_filter, M_IFADDR);
387 }
3a60a9f5
A
388
389 if (unregistering)
91447636 390 socket_unlock(entry->sfe_socket, 1);
3a60a9f5 391
91447636
A
392 FREE(entry, M_IFADDR);
393}
394
395errno_t
396sflt_attach(
397 socket_t socket,
398 sflt_handle handle)
399{
400 if (socket == NULL || handle == 0)
401 return EINVAL;
402
403 return sflt_attach_private(socket, NULL, handle, 0);
404}
405
406errno_t
407sflt_detach(
408 socket_t socket,
409 sflt_handle handle)
410{
411 struct socket_filter_entry *filter;
412 errno_t result = 0;
413
414 if (socket == NULL || handle == 0)
415 return EINVAL;
416
417 socket_lock(socket, 1);
418
419 for (filter = socket->so_filt; filter;
420 filter = filter->sfe_next_onsocket) {
421 if (filter->sfe_filter->sf_filter.sf_handle == handle)
422 break;
423 }
424
425 if (filter != NULL) {
426 sflt_detach_private(filter, 0);
427 }
428 else {
3a60a9f5 429 socket->so_filt = NULL;
91447636
A
430 result = ENOENT;
431 }
432
433 socket_unlock(socket, 1);
434
435 return result;
436}
437
438
439errno_t
440sflt_register(
441 const struct sflt_filter *filter,
2d21ac55
A
442 int domain,
443 int type,
444 int protocol)
91447636
A
445{
446 struct socket_filter *sock_filt = NULL;
447 struct socket_filter *match = NULL;
448 int error = 0;
449 struct protosw *pr = pffindproto(domain, protocol, type);
2d21ac55
A
450 unsigned int len;
451
452 if (pr == NULL)
453 return ENOENT;
454
455 if (filter->sf_attach == NULL || filter->sf_detach == NULL ||
456 filter->sf_handle == 0 || filter->sf_name == NULL)
457 return EINVAL;
91447636
A
458
459 /* Allocate the socket filter */
2d21ac55
A
460 MALLOC(sock_filt, struct socket_filter *, sizeof (*sock_filt),
461 M_IFADDR, M_WAITOK);
91447636
A
462 if (sock_filt == NULL) {
463 return ENOBUFS;
464 }
2d21ac55
A
465
466 bzero(sock_filt, sizeof (*sock_filt));
467
468 /* Legacy sflt_filter length; current structure minus extended */
469 len = sizeof (*filter) - sizeof (struct sflt_filter_ext);
470 /*
471 * Include extended fields if filter defines SFLT_EXTENDED.
472 * We've zeroed out our internal sflt_filter placeholder,
473 * so any unused portion would have been taken care of.
474 */
475 if (filter->sf_flags & SFLT_EXTENDED) {
476 unsigned int ext_len = filter->sf_len;
477
478 if (ext_len > sizeof (struct sflt_filter_ext))
479 ext_len = sizeof (struct sflt_filter_ext);
480
481 len += ext_len;
482 }
483 bcopy(filter, &sock_filt->sf_filter, len);
484
91447636
A
485 lck_mtx_lock(sock_filter_lock);
486 /* Look for an existing entry */
487 TAILQ_FOREACH(match, &sock_filter_head, sf_global_next) {
2d21ac55
A
488 if (match->sf_filter.sf_handle ==
489 sock_filt->sf_filter.sf_handle) {
91447636
A
490 break;
491 }
492 }
2d21ac55 493
91447636
A
494 /* Add the entry only if there was no existing entry */
495 if (match == NULL) {
496 TAILQ_INSERT_TAIL(&sock_filter_head, sock_filt, sf_global_next);
497 if ((sock_filt->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
2d21ac55
A
498 TAILQ_INSERT_TAIL(&pr->pr_filter_head, sock_filt,
499 sf_protosw_next);
91447636
A
500 sock_filt->sf_proto = pr;
501 }
502 }
503 lck_mtx_unlock(sock_filter_lock);
2d21ac55 504
91447636
A
505 if (match != NULL) {
506 FREE(sock_filt, M_IFADDR);
507 return EEXIST;
508 }
2d21ac55 509
91447636
A
510 return error;
511}
512
513errno_t
514sflt_unregister(
515 sflt_handle handle)
516{
517 struct socket_filter *filter;
518 struct socket_filter_entry *entry_head = NULL;
3a60a9f5 519 struct socket_filter_entry *next_entry = NULL;
91447636
A
520
521 /* Find the entry and remove it from the global and protosw lists */
522 lck_mtx_lock(sock_filter_lock);
523 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
524 if (filter->sf_filter.sf_handle == handle)
525 break;
526 }
527
528 if (filter) {
529 TAILQ_REMOVE(&sock_filter_head, filter, sf_global_next);
530 if ((filter->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
531 TAILQ_REMOVE(&filter->sf_proto->pr_filter_head, filter, sf_protosw_next);
532 }
533 entry_head = filter->sf_entry_head;
534 filter->sf_entry_head = NULL;
535 filter->sf_flags |= SFF_DETACHING;
3a60a9f5
A
536
537 for (next_entry = entry_head; next_entry;
4a3eedf9
A
538 next_entry = next_entry->sfe_next_onfilter) {
539 /*
540 * Mark this as "unregistering"; upon dropping the
541 * lock, another thread may win the race and attempt
542 * to detach a socket from it (e.g. as part of close)
543 * before we get a chance to detach. Setting this
544 * flag practically tells the other thread to go away.
545 * If the other thread wins, this causes an extra
546 * reference hold on the socket so that it won't be
547 * deallocated until after we finish with the detach
548 * for it below. If we win the race, the extra
549 * reference hold is also taken to compensate for the
550 * extra reference release when detach is called
551 * with a "1" for its second parameter.
552 */
3a60a9f5 553 next_entry->sfe_flags |= SFEF_UNREGISTERING;
3a60a9f5 554 }
91447636
A
555 }
556
557 lck_mtx_unlock(sock_filter_lock);
558
559 if (filter == NULL)
560 return ENOENT;
561
562 /* We need to detach the filter from any sockets it's attached to */
563 if (entry_head == 0) {
564 if (filter->sf_filter.sf_unregistered)
565 filter->sf_filter.sf_unregistered(filter->sf_filter.sf_handle);
566 } else {
567 while (entry_head) {
91447636
A
568 next_entry = entry_head->sfe_next_onfilter;
569 sflt_detach_private(entry_head, 1);
570 entry_head = next_entry;
571 }
572 }
573
574 return 0;
575}
576
577errno_t
578sock_inject_data_in(
579 socket_t so,
580 const struct sockaddr* from,
581 mbuf_t data,
582 mbuf_t control,
583 sflt_data_flag_t flags)
584{
585 int error = 0;
586 if (so == NULL || data == NULL) return EINVAL;
587
588 if (flags & sock_data_filt_flag_oob) {
589 return ENOTSUP;
590 }
591
592 socket_lock(so, 1);
593
594 if (from) {
595 if (sbappendaddr(&so->so_rcv, (struct sockaddr*)from, data,
596 control, NULL))
597 sorwakeup(so);
598 goto done;
599 }
600
601 if (control) {
602 if (sbappendcontrol(&so->so_rcv, data, control, NULL))
603 sorwakeup(so);
604 goto done;
605 }
606
607 if (flags & sock_data_filt_flag_record) {
608 if (control || from) {
609 error = EINVAL;
610 goto done;
611 }
612 if (sbappendrecord(&so->so_rcv, (struct mbuf*)data))
613 sorwakeup(so);
614 goto done;
615 }
616
617 if (sbappend(&so->so_rcv, data))
618 sorwakeup(so);
619done:
620 socket_unlock(so, 1);
621 return error;
622}
623
624errno_t
625sock_inject_data_out(
626 socket_t so,
627 const struct sockaddr* to,
628 mbuf_t data,
629 mbuf_t control,
630 sflt_data_flag_t flags)
631{
632 int sosendflags = 0;
633 if (flags & sock_data_filt_flag_oob) sosendflags = MSG_OOB;
2d21ac55 634 return sosend(so, (struct sockaddr*)to, NULL,
91447636
A
635 data, control, sosendflags);
636}
637
638sockopt_dir
639sockopt_direction(
640 sockopt_t sopt)
641{
642 return (sopt->sopt_dir == SOPT_GET) ? sockopt_get : sockopt_set;
643}
644
645int
646sockopt_level(
647 sockopt_t sopt)
648{
649 return sopt->sopt_level;
650}
651
652int
653sockopt_name(
654 sockopt_t sopt)
655{
656 return sopt->sopt_name;
657}
658
659size_t
660sockopt_valsize(
661 sockopt_t sopt)
662{
663 return sopt->sopt_valsize;
664}
665
666errno_t
667sockopt_copyin(
668 sockopt_t sopt,
669 void *data,
670 size_t len)
671{
672 return sooptcopyin(sopt, data, len, len);
673}
674
675errno_t
676sockopt_copyout(
677 sockopt_t sopt,
678 void *data,
679 size_t len)
680{
681 return sooptcopyout(sopt, data, len);
682}