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