]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kpi_socketfilter.c
60c35f52ad7b4fed59f568ac36e728ff5d4e33dc
[apple/xnu.git] / bsd / kern / kpi_socketfilter.c
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include <sys/kpi_socketfilter.h>
32
33 #include <sys/socket.h>
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/malloc.h>
37 #include <sys/protosw.h>
38 #include <kern/locks.h>
39 #include <net/kext_net.h>
40
41 static struct socket_filter_list sock_filter_head;
42 static lck_mtx_t *sock_filter_lock = 0;
43
44 static void sflt_detach_private(struct socket_filter_entry *entry, int unregistering);
45
46 __private_extern__ void
47 sflt_init(void)
48 {
49 lck_grp_attr_t *grp_attrib = 0;
50 lck_attr_t *lck_attrib = 0;
51 lck_grp_t *lck_group = 0;
52
53 TAILQ_INIT(&sock_filter_head);
54
55 /* Allocate a spin lock */
56 grp_attrib = lck_grp_attr_alloc_init();
57 lck_grp_attr_setdefault(grp_attrib);
58 lck_group = lck_grp_alloc_init("socket filter lock", grp_attrib);
59 lck_grp_attr_free(grp_attrib);
60 lck_attrib = lck_attr_alloc_init();
61 lck_attr_setdefault(lck_attrib);
62 lck_attr_setdebug(lck_attrib);
63 sock_filter_lock = lck_mtx_alloc_init(lck_group, lck_attrib);
64 lck_grp_free(lck_group);
65 lck_attr_free(lck_attrib);
66 }
67
68 __private_extern__ void
69 sflt_initsock(
70 struct socket *so)
71 {
72 struct protosw *proto = so->so_proto;
73 struct socket_filter *filter;
74
75 if (TAILQ_FIRST(&proto->pr_filter_head) != NULL) {
76 lck_mtx_lock(sock_filter_lock);
77 TAILQ_FOREACH(filter, &proto->pr_filter_head, sf_protosw_next) {
78 sflt_attach_private(so, filter, 0, 0);
79 }
80 lck_mtx_unlock(sock_filter_lock);
81 }
82 }
83
84 __private_extern__ void
85 sflt_termsock(
86 struct socket *so)
87 {
88 struct socket_filter_entry *filter;
89 struct socket_filter_entry *filter_next;
90
91 for (filter = so->so_filt; filter; filter = filter_next) {
92 filter_next = filter->sfe_next_onsocket;
93 sflt_detach_private(filter, 0);
94 }
95 so->so_filt = NULL;
96 }
97
98 __private_extern__ void
99 sflt_use(
100 struct socket *so)
101 {
102 so->so_filteruse++;
103 }
104
105 __private_extern__ void
106 sflt_unuse(
107 struct socket *so)
108 {
109 so->so_filteruse--;
110 if (so->so_filteruse == 0) {
111 struct socket_filter_entry *filter;
112 struct socket_filter_entry *next_filter;
113 // search for detaching filters
114 for (filter = so->so_filt; filter; filter = next_filter) {
115 next_filter = filter->sfe_next_onsocket;
116
117 if (filter->sfe_flags & SFEF_DETACHUSEZERO) {
118 sflt_detach_private(filter, 0);
119 }
120 }
121 }
122 }
123
124 __private_extern__ void
125 sflt_notify(
126 struct socket *so,
127 sflt_event_t event,
128 void *param)
129 {
130 struct socket_filter_entry *filter;
131 int filtered = 0;
132
133 for (filter = so->so_filt; filter;
134 filter = filter->sfe_next_onsocket) {
135 if (filter->sfe_filter->sf_filter.sf_notify) {
136 if (filtered == 0) {
137 filtered = 1;
138 sflt_use(so);
139 socket_unlock(so, 0);
140 }
141 filter->sfe_filter->sf_filter.sf_notify(
142 filter->sfe_cookie, so, event, param);
143 }
144 }
145
146 if (filtered != 0) {
147 socket_lock(so, 0);
148 sflt_unuse(so);
149 }
150 }
151
152 __private_extern__ int
153 sflt_data_in(
154 struct socket *so,
155 const struct sockaddr *from,
156 mbuf_t *data,
157 mbuf_t *control,
158 sflt_data_flag_t flags,
159 int *filtered)
160 {
161 struct socket_filter_entry *filter;
162 int error = 0;
163 int filtered_storage;
164
165 if (filtered == NULL)
166 filtered = &filtered_storage;
167 *filtered = 0;
168
169 for (filter = so->so_filt; filter && (error == 0);
170 filter = filter->sfe_next_onsocket) {
171 if (filter->sfe_filter->sf_filter.sf_data_in) {
172 if (*filtered == 0) {
173 *filtered = 1;
174 sflt_use(so);
175 socket_unlock(so, 0);
176 }
177 error = filter->sfe_filter->sf_filter.sf_data_in(
178 filter->sfe_cookie, so, from, data, control, flags);
179 }
180 }
181
182 if (*filtered != 0) {
183 socket_lock(so, 0);
184 sflt_unuse(so);
185 }
186
187 return error;
188 }
189
190 /* sflt_attach_private
191 *
192 * Assumptions: If filter is not NULL, socket_filter_lock is held.
193 */
194
195 __private_extern__ int
196 sflt_attach_private(
197 struct socket *so,
198 struct socket_filter *filter,
199 sflt_handle handle,
200 int sock_locked)
201 {
202 struct socket_filter_entry *entry = NULL;
203 int didlock = 0;
204 int error = 0;
205
206 if (filter == NULL) {
207 /* Find the filter by the handle */
208 lck_mtx_lock(sock_filter_lock);
209 didlock = 1;
210
211 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
212 if (filter->sf_filter.sf_handle == handle)
213 break;
214 }
215 }
216
217 if (filter == NULL)
218 error = ENOENT;
219
220 if (error == 0) {
221 /* allocate the socket filter entry */
222 MALLOC(entry, struct socket_filter_entry *, sizeof(*entry), M_IFADDR, M_WAITOK);
223 if (entry == NULL) {
224 error = ENOMEM;
225 }
226 }
227
228 if (error == 0) {
229 /* Initialize the socket filter entry and call the attach function */
230 entry->sfe_filter = filter;
231 entry->sfe_socket = so;
232 entry->sfe_cookie = NULL;
233 entry->sfe_flags = 0;
234 if (entry->sfe_filter->sf_filter.sf_attach) {
235 filter->sf_usecount++;
236
237 if (sock_locked)
238 socket_unlock(so, 0);
239 error = entry->sfe_filter->sf_filter.sf_attach(&entry->sfe_cookie, so);
240 if (sock_locked)
241 socket_lock(so, 0);
242
243 filter->sf_usecount--;
244
245 /* If the attach function returns an error, this filter is not attached */
246 if (error) {
247 FREE(entry, M_IFADDR);
248 entry = NULL;
249 }
250 }
251 }
252
253 if (error == 0) {
254 /* Put the entry in the socket list */
255 entry->sfe_next_onsocket = so->so_filt;
256 so->so_filt = entry;
257
258 /* Put the entry in the filter list */
259 entry->sfe_next_onfilter = filter->sf_entry_head;
260 filter->sf_entry_head = entry;
261
262 /* Incremenet the parent filter's usecount */
263 filter->sf_usecount++;
264 }
265
266 if (didlock) {
267 lck_mtx_unlock(sock_filter_lock);
268 }
269
270 return error;
271 }
272
273
274 /* sflt_detach_private
275 *
276 * Assumptions: if you pass 0 in for the second parameter, you are holding the
277 * socket lock for the socket the entry is attached to. If you pass 1 in for
278 * the second parameter, it is assumed that the entry is not on the filter's
279 * list and the socket lock is not held.
280 */
281
282 static void
283 sflt_detach_private(
284 struct socket_filter_entry *entry,
285 int unregistering)
286 {
287 struct socket *so = entry->sfe_socket;
288 struct socket_filter_entry **next_ptr;
289 int detached = 0;
290 int found = 0;
291
292 if (unregistering) {
293 socket_lock(entry->sfe_socket, 0);
294 }
295
296 /*
297 * Attempt to find the entry on the filter's list and
298 * remove it. This prevents a filter detaching at the
299 * same time from attempting to remove the same entry.
300 */
301 lck_mtx_lock(sock_filter_lock);
302 if (!unregistering) {
303 if ((entry->sfe_flags & SFEF_UNREGISTERING) != 0) {
304 /*
305 * Another thread is unregistering the filter, we need to
306 * avoid detaching the filter here so the socket won't go
307 * away.
308 */
309 lck_mtx_unlock(sock_filter_lock);
310 return;
311 }
312 for (next_ptr = &entry->sfe_filter->sf_entry_head; *next_ptr;
313 next_ptr = &((*next_ptr)->sfe_next_onfilter)) {
314 if (*next_ptr == entry) {
315 found = 1;
316 *next_ptr = entry->sfe_next_onfilter;
317 break;
318 }
319 }
320
321 if (!found && (entry->sfe_flags & SFEF_DETACHUSEZERO) == 0) {
322 lck_mtx_unlock(sock_filter_lock);
323 return;
324 }
325 }
326 else {
327 /*
328 * Clear the removing flag. We will perform the detach here or
329 * request a delayed deatch.
330 */
331 entry->sfe_flags &= ~SFEF_UNREGISTERING;
332 }
333
334 if (entry->sfe_socket->so_filteruse != 0) {
335 entry->sfe_flags |= SFEF_DETACHUSEZERO;
336 lck_mtx_unlock(sock_filter_lock);
337 return;
338 }
339 else {
340 /*
341 * Check if we are removing the last attached filter and
342 * the parent filter is being unregistered.
343 */
344 entry->sfe_filter->sf_usecount--;
345 if ((entry->sfe_filter->sf_usecount == 0) &&
346 (entry->sfe_filter->sf_flags & SFF_DETACHING) != 0)
347 detached = 1;
348 }
349 lck_mtx_unlock(sock_filter_lock);
350
351 /* Remove from the socket list */
352 for (next_ptr = &entry->sfe_socket->so_filt; *next_ptr;
353 next_ptr = &((*next_ptr)->sfe_next_onsocket)) {
354 if (*next_ptr == entry) {
355 *next_ptr = entry->sfe_next_onsocket;
356 break;
357 }
358 }
359
360 if (entry->sfe_filter->sf_filter.sf_detach)
361 entry->sfe_filter->sf_filter.sf_detach(entry->sfe_cookie, entry->sfe_socket);
362
363 if (detached && entry->sfe_filter->sf_filter.sf_unregistered) {
364 entry->sfe_filter->sf_filter.sf_unregistered(entry->sfe_filter->sf_filter.sf_handle);
365 FREE(entry->sfe_filter, M_IFADDR);
366 }
367
368 if (unregistering)
369 socket_unlock(entry->sfe_socket, 1);
370
371 FREE(entry, M_IFADDR);
372 }
373
374 errno_t
375 sflt_attach(
376 socket_t socket,
377 sflt_handle handle)
378 {
379 if (socket == NULL || handle == 0)
380 return EINVAL;
381
382 return sflt_attach_private(socket, NULL, handle, 0);
383 }
384
385 errno_t
386 sflt_detach(
387 socket_t socket,
388 sflt_handle handle)
389 {
390 struct socket_filter_entry *filter;
391 errno_t result = 0;
392
393 if (socket == NULL || handle == 0)
394 return EINVAL;
395
396 socket_lock(socket, 1);
397
398 for (filter = socket->so_filt; filter;
399 filter = filter->sfe_next_onsocket) {
400 if (filter->sfe_filter->sf_filter.sf_handle == handle)
401 break;
402 }
403
404 if (filter != NULL) {
405 sflt_detach_private(filter, 0);
406 }
407 else {
408 socket->so_filt = NULL;
409 result = ENOENT;
410 }
411
412 socket_unlock(socket, 1);
413
414 return result;
415 }
416
417
418 errno_t
419 sflt_register(
420 const struct sflt_filter *filter,
421 int domain,
422 int type,
423 int protocol)
424 {
425 struct socket_filter *sock_filt = NULL;
426 struct socket_filter *match = NULL;
427 int error = 0;
428 struct protosw *pr = pffindproto(domain, protocol, type);
429
430 if (pr == NULL) return ENOENT;
431
432 if (filter->sf_attach == NULL || filter->sf_detach == NULL) return EINVAL;
433 if (filter->sf_handle == 0) return EINVAL;
434 if (filter->sf_name == NULL) return EINVAL;
435
436 /* Allocate the socket filter */
437 MALLOC(sock_filt, struct socket_filter*, sizeof(*sock_filt), M_IFADDR, M_WAITOK);
438 if (sock_filt == NULL) {
439 return ENOBUFS;
440 }
441
442 bzero(sock_filt, sizeof(*sock_filt));
443 sock_filt->sf_filter = *filter;
444
445 lck_mtx_lock(sock_filter_lock);
446 /* Look for an existing entry */
447 TAILQ_FOREACH(match, &sock_filter_head, sf_global_next) {
448 if (match->sf_filter.sf_handle == sock_filt->sf_filter.sf_handle) {
449 break;
450 }
451 }
452
453 /* Add the entry only if there was no existing entry */
454 if (match == NULL) {
455 TAILQ_INSERT_TAIL(&sock_filter_head, sock_filt, sf_global_next);
456 if ((sock_filt->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
457 TAILQ_INSERT_TAIL(&pr->pr_filter_head, sock_filt, sf_protosw_next);
458 sock_filt->sf_proto = pr;
459 }
460 }
461 lck_mtx_unlock(sock_filter_lock);
462
463 if (match != NULL) {
464 FREE(sock_filt, M_IFADDR);
465 return EEXIST;
466 }
467
468 return error;
469 }
470
471 errno_t
472 sflt_unregister(
473 sflt_handle handle)
474 {
475 struct socket_filter *filter;
476 struct socket_filter_entry *entry_head = NULL;
477 struct socket_filter_entry *next_entry = NULL;
478
479 /* Find the entry and remove it from the global and protosw lists */
480 lck_mtx_lock(sock_filter_lock);
481 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
482 if (filter->sf_filter.sf_handle == handle)
483 break;
484 }
485
486 if (filter) {
487 TAILQ_REMOVE(&sock_filter_head, filter, sf_global_next);
488 if ((filter->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
489 TAILQ_REMOVE(&filter->sf_proto->pr_filter_head, filter, sf_protosw_next);
490 }
491 entry_head = filter->sf_entry_head;
492 filter->sf_entry_head = NULL;
493 filter->sf_flags |= SFF_DETACHING;
494
495 for (next_entry = entry_head; next_entry;
496 next_entry = next_entry->sfe_next_onfilter) {
497 socket_lock(next_entry->sfe_socket, 1);
498 next_entry->sfe_flags |= SFEF_UNREGISTERING;
499 socket_unlock(next_entry->sfe_socket, 0); /* Radar 4201550: prevents the socket from being deleted while being unregistered */
500 }
501 }
502
503 lck_mtx_unlock(sock_filter_lock);
504
505 if (filter == NULL)
506 return ENOENT;
507
508 /* We need to detach the filter from any sockets it's attached to */
509 if (entry_head == 0) {
510 if (filter->sf_filter.sf_unregistered)
511 filter->sf_filter.sf_unregistered(filter->sf_filter.sf_handle);
512 } else {
513 while (entry_head) {
514 next_entry = entry_head->sfe_next_onfilter;
515 sflt_detach_private(entry_head, 1);
516 entry_head = next_entry;
517 }
518 }
519
520 return 0;
521 }
522
523 errno_t
524 sock_inject_data_in(
525 socket_t so,
526 const struct sockaddr* from,
527 mbuf_t data,
528 mbuf_t control,
529 sflt_data_flag_t flags)
530 {
531 int error = 0;
532 if (so == NULL || data == NULL) return EINVAL;
533
534 if (flags & sock_data_filt_flag_oob) {
535 return ENOTSUP;
536 }
537
538 socket_lock(so, 1);
539
540 if (from) {
541 if (sbappendaddr(&so->so_rcv, (struct sockaddr*)from, data,
542 control, NULL))
543 sorwakeup(so);
544 goto done;
545 }
546
547 if (control) {
548 if (sbappendcontrol(&so->so_rcv, data, control, NULL))
549 sorwakeup(so);
550 goto done;
551 }
552
553 if (flags & sock_data_filt_flag_record) {
554 if (control || from) {
555 error = EINVAL;
556 goto done;
557 }
558 if (sbappendrecord(&so->so_rcv, (struct mbuf*)data))
559 sorwakeup(so);
560 goto done;
561 }
562
563 if (sbappend(&so->so_rcv, data))
564 sorwakeup(so);
565 done:
566 socket_unlock(so, 1);
567 return error;
568 }
569
570 errno_t
571 sock_inject_data_out(
572 socket_t so,
573 const struct sockaddr* to,
574 mbuf_t data,
575 mbuf_t control,
576 sflt_data_flag_t flags)
577 {
578 int sosendflags = 0;
579 if (flags & sock_data_filt_flag_oob) sosendflags = MSG_OOB;
580 return sosend(so, (const struct sockaddr*)to, NULL,
581 data, control, sosendflags);
582 }
583
584 sockopt_dir
585 sockopt_direction(
586 sockopt_t sopt)
587 {
588 return (sopt->sopt_dir == SOPT_GET) ? sockopt_get : sockopt_set;
589 }
590
591 int
592 sockopt_level(
593 sockopt_t sopt)
594 {
595 return sopt->sopt_level;
596 }
597
598 int
599 sockopt_name(
600 sockopt_t sopt)
601 {
602 return sopt->sopt_name;
603 }
604
605 size_t
606 sockopt_valsize(
607 sockopt_t sopt)
608 {
609 return sopt->sopt_valsize;
610 }
611
612 errno_t
613 sockopt_copyin(
614 sockopt_t sopt,
615 void *data,
616 size_t len)
617 {
618 return sooptcopyin(sopt, data, len, len);
619 }
620
621 errno_t
622 sockopt_copyout(
623 sockopt_t sopt,
624 void *data,
625 size_t len)
626 {
627 return sooptcopyout(sopt, data, len);
628 }