2 * Copyright (c) 2013-2019 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 * The socket content filter subsystem provides a way for user space agents to
28 * make filtering decisions based on the content of the data being sent and
29 * received by TCP/IP sockets.
31 * A content filter user space agents gets a copy of the data and the data is
32 * also kept in kernel buffer until the user space agents makes a pass or drop
33 * decision. This unidirectional flow of content avoids unnecessary data copies
36 * A user space filter agent opens a kernel control socket with the name
37 * CONTENT_FILTER_CONTROL_NAME to attach to the socket content filter subsystem.
38 * When connected, a "struct content_filter" is created and set as the
39 * "unitinfo" of the corresponding kernel control socket instance.
41 * The socket content filter subsystem exchanges messages with the user space
42 * filter agent until an ultimate pass or drop decision is made by the
43 * user space filter agent.
45 * It should be noted that messages about many TCP/IP sockets can be multiplexed
46 * over a single kernel control socket.
49 * - The current implementation is limited to TCP sockets.
50 * - The current implementation supports up to two simultaneous content filters
51 * for the sake of simplicity of the implementation.
54 * NECP FILTER CONTROL UNIT
56 * A user space filter agent uses the Network Extension Control Policy (NECP)
57 * database to specify which TCP/IP sockets need to be filtered. The NECP
58 * criteria may be based on a variety of properties like user ID or proc UUID.
60 * The NECP "filter control unit" is used by the socket content filter subsystem
61 * to deliver the relevant TCP/IP content information to the appropriate
62 * user space filter agent via its kernel control socket instance.
63 * This works as follows:
65 * 1) The user space filter agent specifies an NECP filter control unit when
66 * in adds its filtering rules to the NECP database.
68 * 2) The user space filter agent also sets its NECP filter control unit on the
69 * content filter kernel control socket via the socket option
70 * CFIL_OPT_NECP_CONTROL_UNIT.
72 * 3) The NECP database is consulted to find out if a given TCP/IP socket
73 * needs to be subjected to content filtering and returns the corresponding
74 * NECP filter control unit -- the NECP filter control unit is actually
75 * stored in the TCP/IP socket structure so the NECP lookup is really simple.
77 * 4) The NECP filter control unit is then used to find the corresponding
78 * kernel control socket instance.
80 * Note: NECP currently supports a single filter control unit per TCP/IP socket
81 * but this restriction may be soon lifted.
84 * THE MESSAGING PROTOCOL
86 * The socket content filter subsystem and a user space filter agent
87 * communicate over the kernel control socket via an asynchronous
88 * messaging protocol (this is not a request-response protocol).
89 * The socket content filter subsystem sends event messages to the user
90 * space filter agent about the TCP/IP sockets it is interested to filter.
91 * The user space filter agent sends action messages to either allow
92 * data to pass or to disallow the data flow (and drop the connection).
94 * All messages over a content filter kernel control socket share the same
95 * common header of type "struct cfil_msg_hdr". The message type tells if
96 * it's a event message "CFM_TYPE_EVENT" or a action message "CFM_TYPE_ACTION".
97 * The message header field "cfm_sock_id" identifies a given TCP/IP socket.
98 * Note the message header length field may be padded for alignment and can
99 * be larger than the actual content of the message.
100 * The field "cfm_op" describe the kind of event or action.
102 * Here are the kinds of content filter events:
103 * - CFM_OP_SOCKET_ATTACHED: a new TCP/IP socket is being filtered
104 * - CFM_OP_SOCKET_CLOSED: A TCP/IP socket is closed
105 * - CFM_OP_DATA_OUT: A span of data is being sent on a TCP/IP socket
106 * - CFM_OP_DATA_IN: A span of data is being or received on a TCP/IP socket
111 * The CFM_OP_DATA_OUT and CFM_OP_DATA_IN event messages contains a span of
112 * data that is being sent or received. The position of this span of data
113 * in the data flow is described by a set of start and end offsets. These
114 * are absolute 64 bits offsets. The first byte sent (or received) starts
115 * at offset 0 and ends at offset 1. The length of the content data
116 * is given by the difference between the end offset and the start offset.
118 * After a CFM_OP_SOCKET_ATTACHED is delivered, CFM_OP_DATA_OUT and
119 * CFM_OP_DATA_OUT events are not delivered until a CFM_OP_DATA_UPDATE
120 * action message is sent by the user space filter agent.
122 * Note: absolute 64 bits offsets should be large enough for the foreseeable
123 * future. A 64-bits counter will wrap after 468 years at 10 Gbit/sec:
124 * 2E64 / ((10E9 / 8) * 60 * 60 * 24 * 365.25) = 467.63
126 * They are two kinds of primary content filter actions:
127 * - CFM_OP_DATA_UPDATE: to update pass or peek offsets for each direction.
128 * - CFM_OP_DROP: to shutdown socket and disallow further data flow
130 * There is also an action to mark a given client flow as already filtered
131 * at a higher level, CFM_OP_BLESS_CLIENT.
136 * The CFM_OP_DATA_UPDATE action messages let the user space filter
137 * agent allow data to flow up to the specified pass offset -- there
138 * is a pass offset for outgoing data and a pass offset for incoming data.
139 * When a new TCP/IP socket is attached to the content filter, each pass offset
140 * is initially set to 0 so not data is allowed to pass by default.
141 * When the pass offset is set to CFM_MAX_OFFSET via a CFM_OP_DATA_UPDATE
142 * then the data flow becomes unrestricted.
144 * Note that pass offsets can only be incremented. A CFM_OP_DATA_UPDATE message
145 * with a pass offset smaller than the pass offset of a previous
146 * CFM_OP_DATA_UPDATE message is silently ignored.
148 * A user space filter agent also uses CFM_OP_DATA_UPDATE action messages
149 * to tell the kernel how much data it wants to see by using the peek offsets.
150 * Just like pass offsets, there is a peek offset for each direction.
151 * When a new TCP/IP socket is attached to the content filter, each peek offset
152 * is initially set to 0 so no CFM_OP_DATA_OUT and CFM_OP_DATA_IN event
153 * messages are dispatched by default until a CFM_OP_DATA_UPDATE action message
154 * with a greater than 0 peek offset is sent by the user space filter agent.
155 * When the peek offset is set to CFM_MAX_OFFSET via a CFM_OP_DATA_UPDATE
156 * then the flow of update data events becomes unrestricted.
158 * Note that peek offsets cannot be smaller than the corresponding pass offset.
159 * Also a peek offsets cannot be smaller than the corresponding end offset
160 * of the last CFM_OP_DATA_OUT/CFM_OP_DATA_IN message dispatched. Trying
161 * to set a too small peek value is silently ignored.
164 * PER SOCKET "struct cfil_info"
166 * As soon as a TCP/IP socket gets attached to a content filter, a
167 * "struct cfil_info" is created to hold the content filtering state for this
170 * The content filtering state is made of the following information
171 * for each direction:
172 * - The current pass offset;
173 * - The first and last offsets of the data pending, waiting for a filtering
175 * - The inject queue for data that passed the filters and that needs
177 * - A content filter specific state in a set of "struct cfil_entry"
180 * CONTENT FILTER STATE "struct cfil_entry"
182 * The "struct cfil_entry" maintains the information most relevant to the
183 * message handling over a kernel control socket with a user space filter agent.
185 * The "struct cfil_entry" holds the NECP filter control unit that corresponds
186 * to the kernel control socket unit it corresponds to and also has a pointer
187 * to the corresponding "struct content_filter".
189 * For each direction, "struct cfil_entry" maintains the following information:
192 * - The offset of the last data peeked at by the filter
193 * - A queue of data that's waiting to be delivered to the user space filter
194 * agent on the kernel control socket
195 * - A queue of data for which event messages have been sent on the kernel
196 * control socket and are pending for a filtering decision.
199 * CONTENT FILTER QUEUES
201 * Data that is being filtered is steered away from the TCP/IP socket buffer
202 * and instead will sit in one of three content filter queues until the data
203 * can be re-injected into the TCP/IP socket buffer.
205 * A content filter queue is represented by "struct cfil_queue" that contains
206 * a list of mbufs and the start and end offset of the data span of
209 * The data moves into the three content filter queues according to this
211 * a) The "cfe_ctl_q" of "struct cfil_entry"
212 * b) The "cfe_pending_q" of "struct cfil_entry"
213 * c) The "cfi_inject_q" of "struct cfil_info"
215 * Note: The sequence (a),(b) may be repeated several times if there is more
216 * than one content filter attached to the TCP/IP socket.
218 * The "cfe_ctl_q" queue holds data than cannot be delivered to the
219 * kernel conntrol socket for two reasons:
220 * - The peek offset is less that the end offset of the mbuf data
221 * - The kernel control socket is flow controlled
223 * The "cfe_pending_q" queue holds data for which CFM_OP_DATA_OUT or
224 * CFM_OP_DATA_IN have been successfully dispatched to the kernel control
225 * socket and are waiting for a pass action message fromn the user space
226 * filter agent. An mbuf length must be fully allowed to pass to be removed
227 * from the cfe_pending_q.
229 * The "cfi_inject_q" queue holds data that has been fully allowed to pass
230 * by the user space filter agent and that needs to be re-injected into the
234 * IMPACT ON FLOW CONTROL
236 * An essential aspect of the content filer subsystem is to minimize the
237 * impact on flow control of the TCP/IP sockets being filtered.
239 * The processing overhead of the content filtering may have an effect on
240 * flow control by adding noticeable delays and cannot be eliminated --
241 * care must be taken by the user space filter agent to minimize the
244 * The amount of data being filtered is kept in buffers while waiting for
245 * a decision by the user space filter agent. This amount of data pending
246 * needs to be subtracted from the amount of data available in the
247 * corresponding TCP/IP socket buffer. This is done by modifying
248 * sbspace() and tcp_sbspace() to account for amount of data pending
249 * in the content filter.
254 * The global state of content filter subsystem is protected by a single
255 * read-write lock "cfil_lck_rw". The data flow can be done with the
256 * cfil read-write lock held as shared so it can be re-entered from multiple
259 * The per TCP/IP socket content filterstate -- "struct cfil_info" -- is
260 * protected by the socket lock.
262 * A TCP/IP socket lock cannot be taken while the cfil read-write lock
263 * is held. That's why we have some sequences where we drop the cfil read-write
264 * lock before taking the TCP/IP lock.
266 * It is also important to lock the TCP/IP socket buffer while the content
267 * filter is modifying the amount of pending data. Otherwise the calculations
268 * in sbspace() and tcp_sbspace() could be wrong.
270 * The "cfil_lck_rw" protects "struct content_filter" and also the fields
271 * "cfe_link" and "cfe_filter" of "struct cfil_entry".
273 * Actually "cfe_link" and "cfe_filter" are protected by both by
274 * "cfil_lck_rw" and the socket lock: they may be modified only when
275 * "cfil_lck_rw" is exclusive and the socket is locked.
277 * To read the other fields of "struct content_filter" we have to take
278 * "cfil_lck_rw" in shared mode.
283 * - For TCP sockets only
285 * - Does not support TCP unordered messages
297 * If support datagram, enqueue control and address mbufs as well
300 #include <sys/types.h>
301 #include <sys/kern_control.h>
302 #include <sys/queue.h>
303 #include <sys/domain.h>
304 #include <sys/protosw.h>
305 #include <sys/syslog.h>
306 #include <sys/systm.h>
307 #include <sys/param.h>
308 #include <sys/mbuf.h>
310 #include <kern/locks.h>
311 #include <kern/zalloc.h>
312 #include <kern/debug.h>
314 #include <net/content_filter.h>
315 #include <net/content_filter_crypto.h>
317 #include <netinet/in_pcb.h>
318 #include <netinet/tcp.h>
319 #include <netinet/tcp_var.h>
320 #include <netinet/udp.h>
321 #include <netinet/udp_var.h>
324 #include <libkern/libkern.h>
325 #include <kern/sched_prim.h>
326 #include <kern/task.h>
327 #include <mach/task_info.h>
329 #if !TARGET_OS_OSX && !defined(XNU_TARGET_OS_OSX)
330 #define MAX_CONTENT_FILTER 2
332 #define MAX_CONTENT_FILTER 8
338 * The structure content_filter represents a user space content filter
339 * It's created and associated with a kernel control socket instance
341 struct content_filter
{
342 kern_ctl_ref cf_kcref
;
346 uint32_t cf_necp_control_unit
;
348 uint32_t cf_sock_count
;
349 TAILQ_HEAD(, cfil_entry
) cf_sock_entries
;
351 cfil_crypto_state_t cf_crypto_state
;
354 #define CFF_ACTIVE 0x01
355 #define CFF_DETACHING 0x02
356 #define CFF_FLOW_CONTROLLED 0x04
358 struct content_filter
**content_filters
= NULL
;
359 uint32_t cfil_active_count
= 0; /* Number of active content filters */
360 uint32_t cfil_sock_attached_count
= 0; /* Number of sockets attachements */
361 uint32_t cfil_sock_udp_attached_count
= 0; /* Number of UDP sockets attachements */
362 uint32_t cfil_close_wait_timeout
= 1000; /* in milliseconds */
364 static kern_ctl_ref cfil_kctlref
= NULL
;
366 static lck_grp_attr_t
*cfil_lck_grp_attr
= NULL
;
367 static lck_attr_t
*cfil_lck_attr
= NULL
;
368 static lck_grp_t
*cfil_lck_grp
= NULL
;
369 decl_lck_rw_data(static, cfil_lck_rw
);
371 #define CFIL_RW_LCK_MAX 8
373 int cfil_rw_nxt_lck
= 0;
374 void* cfil_rw_lock_history
[CFIL_RW_LCK_MAX
];
376 int cfil_rw_nxt_unlck
= 0;
377 void* cfil_rw_unlock_history
[CFIL_RW_LCK_MAX
];
379 #define CONTENT_FILTER_ZONE_NAME "content_filter"
380 #define CONTENT_FILTER_ZONE_MAX 10
381 static struct zone
*content_filter_zone
= NULL
; /* zone for content_filter */
384 #define CFIL_INFO_ZONE_NAME "cfil_info"
385 #define CFIL_INFO_ZONE_MAX 1024
386 static struct zone
*cfil_info_zone
= NULL
; /* zone for cfil_info */
388 MBUFQ_HEAD(cfil_mqhead
);
391 uint64_t q_start
; /* offset of first byte in queue */
392 uint64_t q_end
; /* offset of last byte in queue */
393 struct cfil_mqhead q_mq
;
399 * The is one entry per content filter
402 TAILQ_ENTRY(cfil_entry
) cfe_link
;
403 SLIST_ENTRY(cfil_entry
) cfe_order_link
;
404 struct content_filter
*cfe_filter
;
406 struct cfil_info
*cfe_cfil_info
;
408 uint32_t cfe_necp_control_unit
;
409 struct timeval cfe_last_event
; /* To user space */
410 struct timeval cfe_last_action
; /* From user space */
414 * cfe_pending_q holds data that has been delivered to
415 * the filter and for which we are waiting for an action
417 struct cfil_queue cfe_pending_q
;
419 * This queue is for data that has not be delivered to
420 * the content filter (new data, pass peek or flow control)
422 struct cfil_queue cfe_ctl_q
;
424 uint64_t cfe_pass_offset
;
425 uint64_t cfe_peek_offset
;
430 #define CFEF_CFIL_ATTACHED 0x0001 /* was attached to filter */
431 #define CFEF_SENT_SOCK_ATTACHED 0x0002 /* sock attach event was sent */
432 #define CFEF_DATA_START 0x0004 /* can send data event */
433 #define CFEF_FLOW_CONTROLLED 0x0008 /* wait for flow control lift */
434 #define CFEF_SENT_DISCONNECT_IN 0x0010 /* event was sent */
435 #define CFEF_SENT_DISCONNECT_OUT 0x0020 /* event was sent */
436 #define CFEF_SENT_SOCK_CLOSED 0x0040 /* closed event was sent */
437 #define CFEF_CFIL_DETACHED 0x0080 /* filter was detached */
440 #define CFI_ADD_TIME_LOG(cfil, t1, t0, op) \
441 struct timeval _tdiff; \
442 if ((cfil)->cfi_op_list_ctr < CFI_MAX_TIME_LOG_ENTRY) { \
443 timersub(t1, t0, &_tdiff); \
444 (cfil)->cfi_op_time[(cfil)->cfi_op_list_ctr] = (uint32_t)(_tdiff.tv_sec * 1000 + _tdiff.tv_usec / 1000);\
445 (cfil)->cfi_op_list[(cfil)->cfi_op_list_ctr] = (unsigned char)op; \
446 (cfil)->cfi_op_list_ctr ++; \
449 struct cfil_hash_entry
;
454 * There is a struct cfil_info per socket
457 TAILQ_ENTRY(cfil_info
) cfi_link
;
458 struct socket
*cfi_so
;
460 uint64_t cfi_sock_id
;
461 struct timeval64 cfi_first_event
;
462 uint32_t cfi_op_list_ctr
;
463 uint32_t cfi_op_time
[CFI_MAX_TIME_LOG_ENTRY
]; /* time interval in microseconds since first event */
464 unsigned char cfi_op_list
[CFI_MAX_TIME_LOG_ENTRY
];
465 union sockaddr_in_4_6 cfi_so_attach_faddr
; /* faddr at the time of attach */
466 union sockaddr_in_4_6 cfi_so_attach_laddr
; /* laddr at the time of attach */
469 uint64_t cfi_byte_inbound_count
;
470 uint64_t cfi_byte_outbound_count
;
472 boolean_t cfi_isSignatureLatest
; /* Indicates if signature covers latest flow attributes */
475 * cfi_pending_first and cfi_pending_last describe the total
476 * amount of data outstanding for all the filters on
477 * this socket and data in the flow queue
478 * cfi_pending_mbcnt counts in sballoc() "chars of mbufs used"
480 uint64_t cfi_pending_first
;
481 uint64_t cfi_pending_last
;
482 uint32_t cfi_pending_mbcnt
;
483 uint32_t cfi_pending_mbnum
;
484 uint32_t cfi_tail_drop_cnt
;
486 * cfi_pass_offset is the minimum of all the filters
488 uint64_t cfi_pass_offset
;
490 * cfi_inject_q holds data that needs to be re-injected
491 * into the socket after filtering and that can
492 * be queued because of flow control
494 struct cfil_queue cfi_inject_q
;
497 struct cfil_entry cfi_entries
[MAX_CONTENT_FILTER
];
498 struct cfil_hash_entry
*cfi_hash_entry
;
499 SLIST_HEAD(, cfil_entry
) cfi_ordered_entries
;
500 } __attribute__((aligned(8)));
502 #define CFIF_DROP 0x0001 /* drop action applied */
503 #define CFIF_CLOSE_WAIT 0x0002 /* waiting for filter to close */
504 #define CFIF_SOCK_CLOSED 0x0004 /* socket is closed */
505 #define CFIF_RETRY_INJECT_IN 0x0010 /* inject in failed */
506 #define CFIF_RETRY_INJECT_OUT 0x0020 /* inject out failed */
507 #define CFIF_SHUT_WR 0x0040 /* shutdown write */
508 #define CFIF_SHUT_RD 0x0080 /* shutdown read */
509 #define CFIF_SOCKET_CONNECTED 0x0100 /* socket is connected */
510 #define CFIF_INITIAL_VERDICT 0x0200 /* received initial verdict */
512 #define CFI_MASK_GENCNT 0xFFFFFFFF00000000 /* upper 32 bits */
513 #define CFI_SHIFT_GENCNT 32
514 #define CFI_MASK_FLOWHASH 0x00000000FFFFFFFF /* lower 32 bits */
515 #define CFI_SHIFT_FLOWHASH 0
517 #define CFI_ENTRY_KCUNIT(i, e) (((e) - &((i)->cfi_entries[0])) + 1)
519 TAILQ_HEAD(cfil_sock_head
, cfil_info
) cfil_sock_head
;
521 #define CFIL_QUEUE_VERIFY(x) if (cfil_debug) cfil_queue_verify(x)
522 #define CFIL_INFO_VERIFY(x) if (cfil_debug) cfil_info_verify(x)
527 LIST_HEAD(cfilhashhead
, cfil_hash_entry
);
528 #define CFILHASHSIZE 16
529 #define CFIL_HASH(laddr, faddr, lport, fport) ((faddr) ^ ((laddr) >> 16) ^ (fport) ^ (lport))
530 #define IS_UDP(so) (so && so->so_proto && so->so_proto->pr_type == SOCK_DGRAM && so->so_proto->pr_protocol == IPPROTO_UDP)
531 #define UNCONNECTED(inp) (inp && (((inp->inp_vflag & INP_IPV4) && (inp->inp_faddr.s_addr == INADDR_ANY)) || \
532 ((inp->inp_vflag & INP_IPV6) && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))))
533 #define IS_ENTRY_ATTACHED(cfil_info, kcunit) (cfil_info != NULL && (kcunit <= MAX_CONTENT_FILTER) && \
534 cfil_info->cfi_entries[kcunit - 1].cfe_filter != NULL)
535 #define IS_DNS(local, remote) (check_port(local, 53) || check_port(remote, 53) || check_port(local, 5353) || check_port(remote, 5353))
536 #define IS_INITIAL_TFO_DATA(so) (so && (so->so_flags1 & SOF1_PRECONNECT_DATA) && (so->so_state & SS_ISCONNECTING))
537 #define NULLADDRESS(addr) ((addr.sa.sa_len == 0) || \
538 (addr.sa.sa_family == AF_INET && addr.sin.sin_addr.s_addr == 0) || \
539 (addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&addr.sin6.sin6_addr)))
542 * UDP Garbage Collection:
544 static struct thread
*cfil_udp_gc_thread
;
545 #define UDP_FLOW_GC_IDLE_TO 30 // Flow Idle Timeout in seconds
546 #define UDP_FLOW_GC_ACTION_TO 10 // Flow Action Timeout (no action from user space) in seconds
547 #define UDP_FLOW_GC_MAX_COUNT 100 // Max UDP flows to be handled per run
548 #define UDP_FLOW_GC_RUN_INTERVAL_NSEC (10 * NSEC_PER_SEC) // GC wakes up every 10 seconds
551 * UDP flow queue thresholds
553 #define UDP_FLOW_GC_MBUF_CNT_MAX (2 << MBSHIFT) // Max mbuf byte count in flow queue (2MB)
554 #define UDP_FLOW_GC_MBUF_NUM_MAX (UDP_FLOW_GC_MBUF_CNT_MAX >> MCLSHIFT) // Max mbuf count in flow queue (1K)
555 #define UDP_FLOW_GC_MBUF_SHIFT 5 // Shift to get 1/32 of platform limits
557 * UDP flow queue threshold globals:
559 static unsigned int cfil_udp_gc_mbuf_num_max
= UDP_FLOW_GC_MBUF_NUM_MAX
;
560 static unsigned int cfil_udp_gc_mbuf_cnt_max
= UDP_FLOW_GC_MBUF_CNT_MAX
;
563 * struct cfil_hash_entry
565 * Hash entry for cfil_info
567 struct cfil_hash_entry
{
568 LIST_ENTRY(cfil_hash_entry
) cfentry_link
;
569 struct cfil_info
*cfentry_cfil
;
570 u_short cfentry_fport
;
571 u_short cfentry_lport
;
572 sa_family_t cfentry_family
;
573 u_int32_t cfentry_flowhash
;
574 u_int32_t cfentry_lastused
;
576 /* foreign host table entry */
577 struct in_addr_4in6 addr46
;
578 struct in6_addr addr6
;
581 /* local host table entry */
582 struct in_addr_4in6 addr46
;
583 struct in6_addr addr6
;
590 * For each UDP socket, this is a hash table maintaining all cfil_info structs
591 * keyed by the flow 4-tuples <lport,fport,laddr,faddr>.
594 struct socket
*cfdb_so
;
595 uint32_t cfdb_count
; /* Number of total content filters */
596 struct cfilhashhead
*cfdb_hashbase
;
597 u_long cfdb_hashmask
;
598 struct cfil_hash_entry
*cfdb_only_entry
; /* Optimization for connected UDP */
602 * CFIL specific mbuf tag:
603 * Save state of socket at the point of data entry into cfil.
604 * Use saved state for reinjection at protocol layer.
607 union sockaddr_in_4_6 cfil_faddr
;
608 uint32_t cfil_so_state_change_cnt
;
609 short cfil_so_options
;
612 #define CFIL_HASH_ENTRY_ZONE_NAME "cfil_entry_hash"
613 #define CFIL_HASH_ENTRY_ZONE_MAX 1024
614 static struct zone
*cfil_hash_entry_zone
= NULL
;
616 #define CFIL_DB_ZONE_NAME "cfil_db"
617 #define CFIL_DB_ZONE_MAX 1024
618 static struct zone
*cfil_db_zone
= NULL
;
624 struct cfil_stats cfil_stats
;
627 * For troubleshooting
629 int cfil_log_level
= LOG_ERR
;
632 // Debug controls added for selective debugging.
633 // Disabled for production. If enabled,
634 // these will have performance impact
635 #define LIFECYCLE_DEBUG 0
636 #define VERDICT_DEBUG 0
642 * Sysctls for logs and statistics
644 static int sysctl_cfil_filter_list(struct sysctl_oid
*, void *, int,
645 struct sysctl_req
*);
646 static int sysctl_cfil_sock_list(struct sysctl_oid
*, void *, int,
647 struct sysctl_req
*);
649 SYSCTL_NODE(_net
, OID_AUTO
, cfil
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "cfil");
651 SYSCTL_INT(_net_cfil
, OID_AUTO
, log
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
652 &cfil_log_level
, 0, "");
654 SYSCTL_INT(_net_cfil
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
657 SYSCTL_UINT(_net_cfil
, OID_AUTO
, sock_attached_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
658 &cfil_sock_attached_count
, 0, "");
660 SYSCTL_UINT(_net_cfil
, OID_AUTO
, active_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
661 &cfil_active_count
, 0, "");
663 SYSCTL_UINT(_net_cfil
, OID_AUTO
, close_wait_timeout
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
664 &cfil_close_wait_timeout
, 0, "");
666 static int cfil_sbtrim
= 1;
667 SYSCTL_UINT(_net_cfil
, OID_AUTO
, sbtrim
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
668 &cfil_sbtrim
, 0, "");
670 SYSCTL_PROC(_net_cfil
, OID_AUTO
, filter_list
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
671 0, 0, sysctl_cfil_filter_list
, "S,cfil_filter_stat", "");
673 SYSCTL_PROC(_net_cfil
, OID_AUTO
, sock_list
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
674 0, 0, sysctl_cfil_sock_list
, "S,cfil_sock_stat", "");
676 SYSCTL_STRUCT(_net_cfil
, OID_AUTO
, stats
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
677 &cfil_stats
, cfil_stats
, "");
680 * Forward declaration to appease the compiler
682 static int cfil_action_data_pass(struct socket
*, struct cfil_info
*, uint32_t, int,
684 static int cfil_action_drop(struct socket
*, struct cfil_info
*, uint32_t);
685 static int cfil_action_bless_client(uint32_t, struct cfil_msg_hdr
*);
686 static int cfil_action_set_crypto_key(uint32_t, struct cfil_msg_hdr
*);
687 static int cfil_dispatch_closed_event(struct socket
*, struct cfil_info
*, int);
688 static int cfil_data_common(struct socket
*, struct cfil_info
*, int, struct sockaddr
*,
689 struct mbuf
*, struct mbuf
*, uint32_t);
690 static int cfil_data_filter(struct socket
*, struct cfil_info
*, uint32_t, int,
691 struct mbuf
*, uint64_t);
692 static void fill_ip_sockaddr_4_6(union sockaddr_in_4_6
*,
693 struct in_addr
, u_int16_t
);
694 static void fill_ip6_sockaddr_4_6(union sockaddr_in_4_6
*,
695 struct in6_addr
*, u_int16_t
);
697 static int cfil_dispatch_attach_event(struct socket
*, struct cfil_info
*, uint32_t, int);
698 static void cfil_info_free(struct cfil_info
*);
699 static struct cfil_info
* cfil_info_alloc(struct socket
*, struct cfil_hash_entry
*);
700 static int cfil_info_attach_unit(struct socket
*, uint32_t, struct cfil_info
*);
701 static struct socket
* cfil_socket_from_sock_id(cfil_sock_id_t
, bool);
702 static struct socket
* cfil_socket_from_client_uuid(uuid_t
, bool *);
703 static int cfil_service_pending_queue(struct socket
*, struct cfil_info
*, uint32_t, int);
704 static int cfil_data_service_ctl_q(struct socket
*, struct cfil_info
*, uint32_t, int);
705 static void cfil_info_verify(struct cfil_info
*);
706 static int cfil_update_data_offsets(struct socket
*, struct cfil_info
*, uint32_t, int,
708 static int cfil_acquire_sockbuf(struct socket
*, struct cfil_info
*, int);
709 static void cfil_release_sockbuf(struct socket
*, int);
710 static int cfil_filters_attached(struct socket
*);
712 static void cfil_rw_lock_exclusive(lck_rw_t
*);
713 static void cfil_rw_unlock_exclusive(lck_rw_t
*);
714 static void cfil_rw_lock_shared(lck_rw_t
*);
715 static void cfil_rw_unlock_shared(lck_rw_t
*);
716 static boolean_t
cfil_rw_lock_shared_to_exclusive(lck_rw_t
*);
717 static void cfil_rw_lock_exclusive_to_shared(lck_rw_t
*);
719 static unsigned int cfil_data_length(struct mbuf
*, int *, int *);
720 static errno_t
cfil_db_init(struct socket
*);
721 static void cfil_db_free(struct socket
*so
);
722 struct cfil_hash_entry
*cfil_db_lookup_entry(struct cfil_db
*, struct sockaddr
*, struct sockaddr
*);
723 struct cfil_hash_entry
*cfil_db_lookup_entry_with_sockid(struct cfil_db
*, u_int64_t
);
724 struct cfil_hash_entry
*cfil_db_add_entry(struct cfil_db
*, struct sockaddr
*, struct sockaddr
*);
725 void cfil_db_delete_entry(struct cfil_db
*, struct cfil_hash_entry
*);
726 struct cfil_hash_entry
*cfil_sock_udp_get_flow(struct socket
*, uint32_t, bool, struct sockaddr
*, struct sockaddr
*);
727 struct cfil_info
*cfil_db_get_cfil_info(struct cfil_db
*, cfil_sock_id_t
);
728 static errno_t
cfil_sock_udp_handle_data(bool, struct socket
*, struct sockaddr
*, struct sockaddr
*,
729 struct mbuf
*, struct mbuf
*, uint32_t);
730 static int32_t cfil_sock_udp_data_pending(struct sockbuf
*, bool);
731 static void cfil_sock_udp_is_closed(struct socket
*);
732 static int cfil_sock_udp_notify_shutdown(struct socket
*, int, int, int);
733 static int cfil_sock_udp_shutdown(struct socket
*, int *);
734 static void cfil_sock_udp_close_wait(struct socket
*);
735 static void cfil_sock_udp_buf_update(struct sockbuf
*);
736 static int cfil_filters_udp_attached(struct socket
*, bool);
737 static void cfil_get_flow_address_v6(struct cfil_hash_entry
*, struct inpcb
*,
738 struct in6_addr
**, struct in6_addr
**,
739 u_int16_t
*, u_int16_t
*);
740 static void cfil_get_flow_address(struct cfil_hash_entry
*, struct inpcb
*,
741 struct in_addr
*, struct in_addr
*,
742 u_int16_t
*, u_int16_t
*);
743 static void cfil_info_log(int, struct cfil_info
*, const char *);
744 void cfil_filter_show(u_int32_t
);
745 void cfil_info_show(void);
746 bool cfil_info_idle_timed_out(struct cfil_info
*, int, u_int32_t
);
747 bool cfil_info_action_timed_out(struct cfil_info
*, int);
748 bool cfil_info_buffer_threshold_exceeded(struct cfil_info
*);
749 struct m_tag
*cfil_udp_save_socket_state(struct cfil_info
*, struct mbuf
*);
750 static void cfil_udp_gc_thread_func(void *, wait_result_t
);
751 static void cfil_info_udp_expire(void *, wait_result_t
);
752 static bool fill_cfil_hash_entry_from_address(struct cfil_hash_entry
*, bool, struct sockaddr
*);
753 static void cfil_sock_received_verdict(struct socket
*so
);
754 static void cfil_fill_event_msg_addresses(struct cfil_hash_entry
*, struct inpcb
*,
755 union sockaddr_in_4_6
*, union sockaddr_in_4_6
*,
756 boolean_t
, boolean_t
);
758 bool check_port(struct sockaddr
*, u_short
);
761 * Content filter global read write lock
765 cfil_rw_lock_exclusive(lck_rw_t
*lck
)
769 lr_saved
= __builtin_return_address(0);
771 lck_rw_lock_exclusive(lck
);
773 cfil_rw_lock_history
[cfil_rw_nxt_lck
] = lr_saved
;
774 cfil_rw_nxt_lck
= (cfil_rw_nxt_lck
+ 1) % CFIL_RW_LCK_MAX
;
778 cfil_rw_unlock_exclusive(lck_rw_t
*lck
)
782 lr_saved
= __builtin_return_address(0);
784 lck_rw_unlock_exclusive(lck
);
786 cfil_rw_unlock_history
[cfil_rw_nxt_unlck
] = lr_saved
;
787 cfil_rw_nxt_unlck
= (cfil_rw_nxt_unlck
+ 1) % CFIL_RW_LCK_MAX
;
791 cfil_rw_lock_shared(lck_rw_t
*lck
)
795 lr_saved
= __builtin_return_address(0);
797 lck_rw_lock_shared(lck
);
799 cfil_rw_lock_history
[cfil_rw_nxt_lck
] = lr_saved
;
800 cfil_rw_nxt_lck
= (cfil_rw_nxt_lck
+ 1) % CFIL_RW_LCK_MAX
;
804 cfil_rw_unlock_shared(lck_rw_t
*lck
)
808 lr_saved
= __builtin_return_address(0);
810 lck_rw_unlock_shared(lck
);
812 cfil_rw_unlock_history
[cfil_rw_nxt_unlck
] = lr_saved
;
813 cfil_rw_nxt_unlck
= (cfil_rw_nxt_unlck
+ 1) % CFIL_RW_LCK_MAX
;
817 cfil_rw_lock_shared_to_exclusive(lck_rw_t
*lck
)
822 lr_saved
= __builtin_return_address(0);
824 upgraded
= lck_rw_lock_shared_to_exclusive(lck
);
826 cfil_rw_unlock_history
[cfil_rw_nxt_unlck
] = lr_saved
;
827 cfil_rw_nxt_unlck
= (cfil_rw_nxt_unlck
+ 1) % CFIL_RW_LCK_MAX
;
833 cfil_rw_lock_exclusive_to_shared(lck_rw_t
*lck
)
837 lr_saved
= __builtin_return_address(0);
839 lck_rw_lock_exclusive_to_shared(lck
);
841 cfil_rw_lock_history
[cfil_rw_nxt_lck
] = lr_saved
;
842 cfil_rw_nxt_lck
= (cfil_rw_nxt_lck
+ 1) % CFIL_RW_LCK_MAX
;
846 cfil_rw_lock_assert_held(lck_rw_t
*lck
, int exclusive
)
849 #pragma unused(lck, exclusive)
852 exclusive
? LCK_RW_ASSERT_EXCLUSIVE
: LCK_RW_ASSERT_HELD
);
856 * Return the number of bytes in the mbuf chain using the same
857 * method as m_length() or sballoc()
859 * Returns data len - starting from PKT start
860 * - retmbcnt - optional param to get total mbuf bytes in chain
861 * - retmbnum - optional param to get number of mbufs in chain
864 cfil_data_length(struct mbuf
*m
, int *retmbcnt
, int *retmbnum
)
867 unsigned int pktlen
= 0;
871 // Locate the start of data
872 for (m0
= m
; m0
!= NULL
; m0
= m0
->m_next
) {
873 if (m0
->m_flags
& M_PKTHDR
) {
878 CFIL_LOG(LOG_ERR
, "cfil_data_length: no M_PKTHDR");
883 if (retmbcnt
== NULL
&& retmbnum
== NULL
) {
890 for (m0
= m
; m0
!= NULL
; m0
= m0
->m_next
) {
894 if (m0
->m_flags
& M_EXT
) {
895 mbcnt
+= m0
->m_ext
.ext_size
;
908 cfil_data_start(struct mbuf
*m
)
912 // Locate the start of data
913 for (m0
= m
; m0
!= NULL
; m0
= m0
->m_next
) {
914 if (m0
->m_flags
& M_PKTHDR
) {
922 * Common mbuf queue utilities
926 cfil_queue_init(struct cfil_queue
*cfq
)
930 MBUFQ_INIT(&cfq
->q_mq
);
933 static inline uint64_t
934 cfil_queue_drain(struct cfil_queue
*cfq
)
936 uint64_t drained
= cfq
->q_start
- cfq
->q_end
;
939 MBUFQ_DRAIN(&cfq
->q_mq
);
944 /* Return 1 when empty, 0 otherwise */
946 cfil_queue_empty(struct cfil_queue
*cfq
)
948 return MBUFQ_EMPTY(&cfq
->q_mq
);
951 static inline uint64_t
952 cfil_queue_offset_first(struct cfil_queue
*cfq
)
957 static inline uint64_t
958 cfil_queue_offset_last(struct cfil_queue
*cfq
)
963 static inline uint64_t
964 cfil_queue_len(struct cfil_queue
*cfq
)
966 return cfq
->q_end
- cfq
->q_start
;
970 * Routines to verify some fundamental assumptions
974 cfil_queue_verify(struct cfil_queue
*cfq
)
979 uint64_t queuesize
= 0;
981 /* Verify offset are ordered */
982 VERIFY(cfq
->q_start
<= cfq
->q_end
);
985 * When queue is empty, the offsets are equal otherwise the offsets
988 VERIFY((MBUFQ_EMPTY(&cfq
->q_mq
) && cfq
->q_start
== cfq
->q_end
) ||
989 (!MBUFQ_EMPTY(&cfq
->q_mq
) &&
990 cfq
->q_start
!= cfq
->q_end
));
992 MBUFQ_FOREACH(chain
, &cfq
->q_mq
) {
993 size_t chainsize
= 0;
995 unsigned int mlen
= cfil_data_length(m
, NULL
, NULL
);
996 // skip the addr and control stuff if present
997 m
= cfil_data_start(m
);
1000 m
== (void *)M_TAG_FREE_PATTERN
||
1001 m
->m_next
== (void *)M_TAG_FREE_PATTERN
||
1002 m
->m_nextpkt
== (void *)M_TAG_FREE_PATTERN
) {
1003 panic("%s - mq %p is free at %p", __func__
,
1006 for (n
= m
; n
!= NULL
; n
= n
->m_next
) {
1007 if (n
->m_type
!= MT_DATA
&&
1008 n
->m_type
!= MT_HEADER
&&
1009 n
->m_type
!= MT_OOBDATA
) {
1010 panic("%s - %p unsupported type %u", __func__
,
1013 chainsize
+= n
->m_len
;
1015 if (mlen
!= chainsize
) {
1016 panic("%s - %p m_length() %u != chainsize %lu",
1017 __func__
, m
, mlen
, chainsize
);
1019 queuesize
+= chainsize
;
1021 if (queuesize
!= cfq
->q_end
- cfq
->q_start
) {
1022 panic("%s - %p queuesize %llu != offsetdiffs %llu", __func__
,
1023 m
, queuesize
, cfq
->q_end
- cfq
->q_start
);
1028 cfil_queue_enqueue(struct cfil_queue
*cfq
, mbuf_t m
, size_t len
)
1030 CFIL_QUEUE_VERIFY(cfq
);
1032 MBUFQ_ENQUEUE(&cfq
->q_mq
, m
);
1035 CFIL_QUEUE_VERIFY(cfq
);
1039 cfil_queue_remove(struct cfil_queue
*cfq
, mbuf_t m
, size_t len
)
1041 CFIL_QUEUE_VERIFY(cfq
);
1043 VERIFY(cfil_data_length(m
, NULL
, NULL
) == len
);
1045 MBUFQ_REMOVE(&cfq
->q_mq
, m
);
1046 MBUFQ_NEXT(m
) = NULL
;
1047 cfq
->q_start
+= len
;
1049 CFIL_QUEUE_VERIFY(cfq
);
1053 cfil_queue_first(struct cfil_queue
*cfq
)
1055 return MBUFQ_FIRST(&cfq
->q_mq
);
1059 cfil_queue_next(struct cfil_queue
*cfq
, mbuf_t m
)
1062 return MBUFQ_NEXT(m
);
1066 cfil_entry_buf_verify(struct cfe_buf
*cfe_buf
)
1068 CFIL_QUEUE_VERIFY(&cfe_buf
->cfe_ctl_q
);
1069 CFIL_QUEUE_VERIFY(&cfe_buf
->cfe_pending_q
);
1071 /* Verify the queues are ordered so that pending is before ctl */
1072 VERIFY(cfe_buf
->cfe_ctl_q
.q_start
>= cfe_buf
->cfe_pending_q
.q_end
);
1074 /* The peek offset cannot be less than the pass offset */
1075 VERIFY(cfe_buf
->cfe_peek_offset
>= cfe_buf
->cfe_pass_offset
);
1077 /* Make sure we've updated the offset we peeked at */
1078 VERIFY(cfe_buf
->cfe_ctl_q
.q_start
<= cfe_buf
->cfe_peeked
);
1082 cfil_entry_verify(struct cfil_entry
*entry
)
1084 cfil_entry_buf_verify(&entry
->cfe_snd
);
1085 cfil_entry_buf_verify(&entry
->cfe_rcv
);
1089 cfil_info_buf_verify(struct cfi_buf
*cfi_buf
)
1091 CFIL_QUEUE_VERIFY(&cfi_buf
->cfi_inject_q
);
1093 VERIFY(cfi_buf
->cfi_pending_first
<= cfi_buf
->cfi_pending_last
);
1097 cfil_info_verify(struct cfil_info
*cfil_info
)
1101 if (cfil_info
== NULL
) {
1105 cfil_info_buf_verify(&cfil_info
->cfi_snd
);
1106 cfil_info_buf_verify(&cfil_info
->cfi_rcv
);
1108 for (i
= 0; i
< MAX_CONTENT_FILTER
; i
++) {
1109 cfil_entry_verify(&cfil_info
->cfi_entries
[i
]);
1114 verify_content_filter(struct content_filter
*cfc
)
1116 struct cfil_entry
*entry
;
1119 VERIFY(cfc
->cf_sock_count
>= 0);
1121 TAILQ_FOREACH(entry
, &cfc
->cf_sock_entries
, cfe_link
) {
1123 VERIFY(cfc
== entry
->cfe_filter
);
1125 VERIFY(count
== cfc
->cf_sock_count
);
1129 * Kernel control socket callbacks
1132 cfil_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
,
1136 struct content_filter
*cfc
= NULL
;
1138 CFIL_LOG(LOG_NOTICE
, "");
1140 cfc
= zalloc(content_filter_zone
);
1142 CFIL_LOG(LOG_ERR
, "zalloc failed");
1146 bzero(cfc
, sizeof(struct content_filter
));
1148 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1149 if (content_filters
== NULL
) {
1150 struct content_filter
**tmp
;
1152 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1155 struct content_filter
**,
1156 MAX_CONTENT_FILTER
* sizeof(struct content_filter
*),
1160 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1162 if (tmp
== NULL
&& content_filters
== NULL
) {
1164 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1167 /* Another thread may have won the race */
1168 if (content_filters
!= NULL
) {
1171 content_filters
= tmp
;
1175 if (sac
->sc_unit
== 0 || sac
->sc_unit
> MAX_CONTENT_FILTER
) {
1176 CFIL_LOG(LOG_ERR
, "bad sc_unit %u", sac
->sc_unit
);
1178 } else if (content_filters
[sac
->sc_unit
- 1] != NULL
) {
1179 CFIL_LOG(LOG_ERR
, "sc_unit %u in use", sac
->sc_unit
);
1183 * kernel control socket kcunit numbers start at 1
1185 content_filters
[sac
->sc_unit
- 1] = cfc
;
1187 cfc
->cf_kcref
= kctlref
;
1188 cfc
->cf_kcunit
= sac
->sc_unit
;
1189 TAILQ_INIT(&cfc
->cf_sock_entries
);
1192 cfil_active_count
++;
1194 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1196 if (error
!= 0 && cfc
!= NULL
) {
1197 zfree(content_filter_zone
, cfc
);
1201 OSIncrementAtomic(&cfil_stats
.cfs_ctl_connect_ok
);
1203 OSIncrementAtomic(&cfil_stats
.cfs_ctl_connect_fail
);
1206 CFIL_LOG(LOG_INFO
, "return %d cfil_active_count %u kcunit %u",
1207 error
, cfil_active_count
, sac
->sc_unit
);
1213 cfil_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
)
1215 #pragma unused(kctlref)
1217 struct content_filter
*cfc
;
1218 struct cfil_entry
*entry
;
1219 uint64_t sock_flow_id
= 0;
1221 CFIL_LOG(LOG_NOTICE
, "");
1223 if (content_filters
== NULL
) {
1224 CFIL_LOG(LOG_ERR
, "no content filter");
1228 if (kcunit
> MAX_CONTENT_FILTER
) {
1229 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1230 kcunit
, MAX_CONTENT_FILTER
);
1235 cfc
= (struct content_filter
*)unitinfo
;
1240 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1241 if (content_filters
[kcunit
- 1] != cfc
|| cfc
->cf_kcunit
!= kcunit
) {
1242 CFIL_LOG(LOG_ERR
, "bad unit info %u)",
1244 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1247 cfc
->cf_flags
|= CFF_DETACHING
;
1249 * Remove all sockets from the filter
1251 while ((entry
= TAILQ_FIRST(&cfc
->cf_sock_entries
)) != NULL
) {
1252 cfil_rw_lock_assert_held(&cfil_lck_rw
, 1);
1254 verify_content_filter(cfc
);
1256 * Accept all outstanding data by pushing to next filter
1259 * TBD: Actually we should make sure all data has been pushed
1262 if (entry
->cfe_cfil_info
&& entry
->cfe_cfil_info
->cfi_so
) {
1263 struct cfil_info
*cfil_info
= entry
->cfe_cfil_info
;
1264 struct socket
*so
= cfil_info
->cfi_so
;
1265 sock_flow_id
= cfil_info
->cfi_sock_id
;
1267 /* Need to let data flow immediately */
1268 entry
->cfe_flags
|= CFEF_SENT_SOCK_ATTACHED
|
1272 * Respect locking hierarchy
1274 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1279 * When cfe_filter is NULL the filter is detached
1280 * and the entry has been removed from cf_sock_entries
1282 if ((so
->so_cfil
== NULL
&& so
->so_cfil_db
== NULL
) || entry
->cfe_filter
== NULL
) {
1283 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1287 (void) cfil_action_data_pass(so
, cfil_info
, kcunit
, 1,
1291 (void) cfil_action_data_pass(so
, cfil_info
, kcunit
, 0,
1295 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1298 * Check again to make sure if the cfil_info is still valid
1299 * as the socket may have been unlocked when when calling
1300 * cfil_acquire_sockbuf()
1302 if (entry
->cfe_filter
== NULL
||
1303 (so
->so_cfil
== NULL
&& cfil_db_get_cfil_info(so
->so_cfil_db
, sock_flow_id
) == NULL
)) {
1307 /* The filter is now detached */
1308 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
1310 cfil_info_log(LOG_DEBUG
, cfil_info
, "CFIL: LIFECYCLE: - FILTER DISCONNECTED");
1312 CFIL_LOG(LOG_NOTICE
, "so %llx detached %u",
1313 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
1314 if ((cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) &&
1315 cfil_filters_attached(so
) == 0) {
1316 CFIL_LOG(LOG_NOTICE
, "so %llx waking",
1317 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1318 wakeup((caddr_t
)cfil_info
);
1322 * Remove the filter entry from the content filter
1323 * but leave the rest of the state intact as the queues
1324 * may not be empty yet
1326 entry
->cfe_filter
= NULL
;
1327 entry
->cfe_necp_control_unit
= 0;
1329 TAILQ_REMOVE(&cfc
->cf_sock_entries
, entry
, cfe_link
);
1330 cfc
->cf_sock_count
--;
1332 socket_unlock(so
, 1);
1335 verify_content_filter(cfc
);
1337 VERIFY(cfc
->cf_sock_count
== 0);
1340 * Make filter inactive
1342 content_filters
[kcunit
- 1] = NULL
;
1343 cfil_active_count
--;
1344 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1346 if (cfc
->cf_crypto_state
!= NULL
) {
1347 cfil_crypto_cleanup_state(cfc
->cf_crypto_state
);
1348 cfc
->cf_crypto_state
= NULL
;
1351 zfree(content_filter_zone
, cfc
);
1354 OSIncrementAtomic(&cfil_stats
.cfs_ctl_disconnect_ok
);
1356 OSIncrementAtomic(&cfil_stats
.cfs_ctl_disconnect_fail
);
1359 CFIL_LOG(LOG_INFO
, "return %d cfil_active_count %u kcunit %u",
1360 error
, cfil_active_count
, kcunit
);
1366 * cfil_acquire_sockbuf()
1368 * Prevent any other thread from acquiring the sockbuf
1369 * We use sb_cfil_thread as a semaphore to prevent other threads from
1370 * messing with the sockbuf -- see sblock()
1371 * Note: We do not set SB_LOCK here because the thread may check or modify
1372 * SB_LOCK several times until it calls cfil_release_sockbuf() -- currently
1373 * sblock(), sbunlock() or sodefunct()
1376 cfil_acquire_sockbuf(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
)
1378 thread_t tp
= current_thread();
1379 struct sockbuf
*sb
= outgoing
? &so
->so_snd
: &so
->so_rcv
;
1380 lck_mtx_t
*mutex_held
;
1384 * Wait until no thread is holding the sockbuf and other content
1385 * filter threads have released the sockbuf
1387 while ((sb
->sb_flags
& SB_LOCK
) ||
1388 (sb
->sb_cfil_thread
!= NULL
&& sb
->sb_cfil_thread
!= tp
)) {
1389 if (so
->so_proto
->pr_getlock
!= NULL
) {
1390 mutex_held
= (*so
->so_proto
->pr_getlock
)(so
, PR_F_WILLUNLOCK
);
1392 mutex_held
= so
->so_proto
->pr_domain
->dom_mtx
;
1395 LCK_MTX_ASSERT(mutex_held
, LCK_MTX_ASSERT_OWNED
);
1398 VERIFY(sb
->sb_wantlock
!= 0);
1400 msleep(&sb
->sb_flags
, mutex_held
, PSOCK
, "cfil_acquire_sockbuf",
1403 VERIFY(sb
->sb_wantlock
!= 0);
1407 * Use reference count for repetitive calls on same thread
1409 if (sb
->sb_cfil_refs
== 0) {
1410 VERIFY(sb
->sb_cfil_thread
== NULL
);
1411 VERIFY((sb
->sb_flags
& SB_LOCK
) == 0);
1413 sb
->sb_cfil_thread
= tp
;
1414 sb
->sb_flags
|= SB_LOCK
;
1418 /* We acquire the socket buffer when we need to cleanup */
1419 if (cfil_info
== NULL
) {
1420 CFIL_LOG(LOG_ERR
, "so %llx cfil detached",
1421 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1423 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
1424 CFIL_LOG(LOG_ERR
, "so %llx drop set",
1425 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1433 cfil_release_sockbuf(struct socket
*so
, int outgoing
)
1435 struct sockbuf
*sb
= outgoing
? &so
->so_snd
: &so
->so_rcv
;
1436 thread_t tp
= current_thread();
1438 socket_lock_assert_owned(so
);
1440 if (sb
->sb_cfil_thread
!= NULL
&& sb
->sb_cfil_thread
!= tp
) {
1441 panic("%s sb_cfil_thread %p not current %p", __func__
,
1442 sb
->sb_cfil_thread
, tp
);
1445 * Don't panic if we are defunct because SB_LOCK has
1446 * been cleared by sodefunct()
1448 if (!(so
->so_flags
& SOF_DEFUNCT
) && !(sb
->sb_flags
& SB_LOCK
)) {
1449 panic("%s SB_LOCK not set on %p", __func__
,
1453 * We can unlock when the thread unwinds to the last reference
1456 if (sb
->sb_cfil_refs
== 0) {
1457 sb
->sb_cfil_thread
= NULL
;
1458 sb
->sb_flags
&= ~SB_LOCK
;
1460 if (sb
->sb_wantlock
> 0) {
1461 wakeup(&sb
->sb_flags
);
1467 cfil_sock_id_from_socket(struct socket
*so
)
1469 if ((so
->so_flags
& SOF_CONTENT_FILTER
) && so
->so_cfil
) {
1470 return so
->so_cfil
->cfi_sock_id
;
1472 return CFIL_SOCK_ID_NONE
;
1477 cfil_socket_safe_lock(struct inpcb
*inp
)
1479 if (in_pcb_checkstate(inp
, WNT_ACQUIRE
, 0) != WNT_STOPUSING
) {
1480 socket_lock(inp
->inp_socket
, 1);
1481 if (in_pcb_checkstate(inp
, WNT_RELEASE
, 1) != WNT_STOPUSING
) {
1484 socket_unlock(inp
->inp_socket
, 1);
1489 static struct socket
*
1490 cfil_socket_from_sock_id(cfil_sock_id_t cfil_sock_id
, bool udp_only
)
1492 struct socket
*so
= NULL
;
1493 u_int64_t gencnt
= cfil_sock_id
>> 32;
1494 u_int32_t flowhash
= (u_int32_t
)(cfil_sock_id
& 0x0ffffffff);
1495 struct inpcb
*inp
= NULL
;
1496 struct inpcbinfo
*pcbinfo
= NULL
;
1499 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT: search for socket: id %llu gencnt %llx flowhash %x", cfil_sock_id
, gencnt
, flowhash
);
1507 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1508 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1509 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1510 inp
->inp_socket
!= NULL
&&
1511 inp
->inp_flowhash
== flowhash
&&
1512 (inp
->inp_socket
->so_gencnt
& 0x0ffffffff) == gencnt
&&
1513 inp
->inp_socket
->so_cfil
!= NULL
) {
1514 if (cfil_socket_safe_lock(inp
)) {
1515 so
= inp
->inp_socket
;
1520 lck_rw_done(pcbinfo
->ipi_lock
);
1528 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1529 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1530 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1531 inp
->inp_socket
!= NULL
&&
1532 inp
->inp_socket
->so_cfil_db
!= NULL
&&
1533 (inp
->inp_socket
->so_gencnt
& 0x0ffffffff) == gencnt
) {
1534 if (cfil_socket_safe_lock(inp
)) {
1535 so
= inp
->inp_socket
;
1540 lck_rw_done(pcbinfo
->ipi_lock
);
1544 OSIncrementAtomic(&cfil_stats
.cfs_sock_id_not_found
);
1546 "no socket for sock_id %llx gencnt %llx flowhash %x",
1547 cfil_sock_id
, gencnt
, flowhash
);
1553 static struct socket
*
1554 cfil_socket_from_client_uuid(uuid_t necp_client_uuid
, bool *cfil_attached
)
1556 struct socket
*so
= NULL
;
1557 struct inpcb
*inp
= NULL
;
1558 struct inpcbinfo
*pcbinfo
= &tcbinfo
;
1560 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1561 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1562 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1563 inp
->inp_socket
!= NULL
&&
1564 uuid_compare(inp
->necp_client_uuid
, necp_client_uuid
) == 0) {
1565 *cfil_attached
= (inp
->inp_socket
->so_cfil
!= NULL
);
1566 if (cfil_socket_safe_lock(inp
)) {
1567 so
= inp
->inp_socket
;
1572 lck_rw_done(pcbinfo
->ipi_lock
);
1578 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1579 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1580 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1581 inp
->inp_socket
!= NULL
&&
1582 uuid_compare(inp
->necp_client_uuid
, necp_client_uuid
) == 0) {
1583 *cfil_attached
= (inp
->inp_socket
->so_cfil_db
!= NULL
);
1584 if (cfil_socket_safe_lock(inp
)) {
1585 so
= inp
->inp_socket
;
1590 lck_rw_done(pcbinfo
->ipi_lock
);
1597 cfil_ctl_send(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
, mbuf_t m
,
1600 #pragma unused(kctlref, flags)
1602 struct cfil_msg_hdr
*msghdr
;
1603 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
1605 struct cfil_msg_action
*action_msg
;
1606 struct cfil_entry
*entry
;
1607 struct cfil_info
*cfil_info
= NULL
;
1608 unsigned int data_len
= 0;
1610 CFIL_LOG(LOG_INFO
, "");
1612 if (content_filters
== NULL
) {
1613 CFIL_LOG(LOG_ERR
, "no content filter");
1617 if (kcunit
> MAX_CONTENT_FILTER
) {
1618 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1619 kcunit
, MAX_CONTENT_FILTER
);
1624 CFIL_LOG(LOG_ERR
, "null mbuf");
1628 data_len
= m_length(m
);
1630 if (data_len
< sizeof(struct cfil_msg_hdr
)) {
1631 CFIL_LOG(LOG_ERR
, "too short %u", data_len
);
1635 msghdr
= (struct cfil_msg_hdr
*)mbuf_data(m
);
1636 if (msghdr
->cfm_version
!= CFM_VERSION_CURRENT
) {
1637 CFIL_LOG(LOG_ERR
, "bad version %u", msghdr
->cfm_version
);
1641 if (msghdr
->cfm_type
!= CFM_TYPE_ACTION
) {
1642 CFIL_LOG(LOG_ERR
, "bad type %u", msghdr
->cfm_type
);
1646 if (msghdr
->cfm_len
> data_len
) {
1647 CFIL_LOG(LOG_ERR
, "bad length %u", msghdr
->cfm_len
);
1652 /* Validate action operation */
1653 switch (msghdr
->cfm_op
) {
1654 case CFM_OP_DATA_UPDATE
:
1656 &cfil_stats
.cfs_ctl_action_data_update
);
1659 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_drop
);
1661 case CFM_OP_BLESS_CLIENT
:
1662 if (msghdr
->cfm_len
!= sizeof(struct cfil_msg_bless_client
)) {
1663 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_len
);
1665 CFIL_LOG(LOG_ERR
, "bad len: %u for op %u",
1670 error
= cfil_action_bless_client(kcunit
, msghdr
);
1672 case CFM_OP_SET_CRYPTO_KEY
:
1673 if (msghdr
->cfm_len
!= sizeof(struct cfil_msg_set_crypto_key
)) {
1674 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_len
);
1676 CFIL_LOG(LOG_ERR
, "bad len: %u for op %u",
1681 error
= cfil_action_set_crypto_key(kcunit
, msghdr
);
1684 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_op
);
1685 CFIL_LOG(LOG_ERR
, "bad op %u", msghdr
->cfm_op
);
1689 if (msghdr
->cfm_len
!= sizeof(struct cfil_msg_action
)) {
1690 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_len
);
1692 CFIL_LOG(LOG_ERR
, "bad len: %u for op %u",
1697 cfil_rw_lock_shared(&cfil_lck_rw
);
1698 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
1699 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
1702 cfil_rw_unlock_shared(&cfil_lck_rw
);
1705 cfil_rw_unlock_shared(&cfil_lck_rw
);
1707 // Search for socket (TCP+UDP and lock so)
1708 so
= cfil_socket_from_sock_id(msghdr
->cfm_sock_id
, false);
1710 CFIL_LOG(LOG_NOTICE
, "bad sock_id %llx",
1711 msghdr
->cfm_sock_id
);
1716 cfil_info
= so
->so_cfil_db
!= NULL
?
1717 cfil_db_get_cfil_info(so
->so_cfil_db
, msghdr
->cfm_sock_id
) : so
->so_cfil
;
1719 if (cfil_info
== NULL
) {
1720 CFIL_LOG(LOG_NOTICE
, "so %llx <id %llu> not attached",
1721 (uint64_t)VM_KERNEL_ADDRPERM(so
), msghdr
->cfm_sock_id
);
1724 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
1725 CFIL_LOG(LOG_NOTICE
, "so %llx drop set",
1726 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1730 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
1731 if (entry
->cfe_filter
== NULL
) {
1732 CFIL_LOG(LOG_NOTICE
, "so %llx no filter",
1733 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1738 if (entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) {
1739 entry
->cfe_flags
|= CFEF_DATA_START
;
1742 "so %llx attached not sent for %u",
1743 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
1748 microuptime(&entry
->cfe_last_action
);
1749 CFI_ADD_TIME_LOG(cfil_info
, &entry
->cfe_last_action
, &cfil_info
->cfi_first_event
, msghdr
->cfm_op
);
1751 action_msg
= (struct cfil_msg_action
*)msghdr
;
1753 switch (msghdr
->cfm_op
) {
1754 case CFM_OP_DATA_UPDATE
:
1756 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT RECEIVED: <so %llx sockID %llu> <IN peek:%llu pass:%llu, OUT peek:%llu pass:%llu>",
1757 (uint64_t)VM_KERNEL_ADDRPERM(so
),
1758 cfil_info
->cfi_sock_id
,
1759 action_msg
->cfa_in_peek_offset
, action_msg
->cfa_in_pass_offset
,
1760 action_msg
->cfa_out_peek_offset
, action_msg
->cfa_out_pass_offset
);
1763 * Received verdict, at this point we know this
1764 * socket connection is allowed. Unblock thread
1765 * immediately before proceeding to process the verdict.
1767 cfil_sock_received_verdict(so
);
1769 if (action_msg
->cfa_out_peek_offset
!= 0 ||
1770 action_msg
->cfa_out_pass_offset
!= 0) {
1771 error
= cfil_action_data_pass(so
, cfil_info
, kcunit
, 1,
1772 action_msg
->cfa_out_pass_offset
,
1773 action_msg
->cfa_out_peek_offset
);
1775 if (error
== EJUSTRETURN
) {
1781 if (action_msg
->cfa_in_peek_offset
!= 0 ||
1782 action_msg
->cfa_in_pass_offset
!= 0) {
1783 error
= cfil_action_data_pass(so
, cfil_info
, kcunit
, 0,
1784 action_msg
->cfa_in_pass_offset
,
1785 action_msg
->cfa_in_peek_offset
);
1787 if (error
== EJUSTRETURN
) {
1794 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT DROP RECEIVED: <so %llx sockID %llu> <IN peek:%llu pass:%llu, OUT peek:%llu pass:%llu>",
1795 (uint64_t)VM_KERNEL_ADDRPERM(so
),
1796 cfil_info
->cfi_sock_id
,
1797 action_msg
->cfa_in_peek_offset
, action_msg
->cfa_in_pass_offset
,
1798 action_msg
->cfa_out_peek_offset
, action_msg
->cfa_out_pass_offset
);
1800 error
= cfil_action_drop(so
, cfil_info
, kcunit
);
1801 cfil_sock_received_verdict(so
);
1809 socket_unlock(so
, 1);
1814 OSIncrementAtomic(&cfil_stats
.cfs_ctl_send_ok
);
1816 OSIncrementAtomic(&cfil_stats
.cfs_ctl_send_bad
);
1823 cfil_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
,
1824 int opt
, void *data
, size_t *len
)
1826 #pragma unused(kctlref, opt)
1827 struct cfil_info
*cfil_info
= NULL
;
1829 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
1831 CFIL_LOG(LOG_NOTICE
, "");
1833 cfil_rw_lock_shared(&cfil_lck_rw
);
1835 if (content_filters
== NULL
) {
1836 CFIL_LOG(LOG_ERR
, "no content filter");
1840 if (kcunit
> MAX_CONTENT_FILTER
) {
1841 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1842 kcunit
, MAX_CONTENT_FILTER
);
1846 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
1847 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
1853 case CFIL_OPT_NECP_CONTROL_UNIT
:
1854 if (*len
< sizeof(uint32_t)) {
1855 CFIL_LOG(LOG_ERR
, "len too small %lu", *len
);
1860 *(uint32_t *)data
= cfc
->cf_necp_control_unit
;
1863 case CFIL_OPT_GET_SOCKET_INFO
:
1864 if (*len
!= sizeof(struct cfil_opt_sock_info
)) {
1865 CFIL_LOG(LOG_ERR
, "len does not match %lu", *len
);
1870 CFIL_LOG(LOG_ERR
, "data not passed");
1875 struct cfil_opt_sock_info
*sock_info
=
1876 (struct cfil_opt_sock_info
*) data
;
1878 // Unlock here so that we never hold both cfil_lck_rw and the
1879 // socket_lock at the same time. Otherwise, this can deadlock
1880 // because soclose() takes the socket_lock and then exclusive
1881 // cfil_lck_rw and we require the opposite order.
1883 // WARNING: Be sure to never use anything protected
1884 // by cfil_lck_rw beyond this point.
1885 // WARNING: Be sure to avoid fallthrough and
1886 // goto return_already_unlocked from this branch.
1887 cfil_rw_unlock_shared(&cfil_lck_rw
);
1889 // Search (TCP+UDP) and lock socket
1890 struct socket
*sock
=
1891 cfil_socket_from_sock_id(sock_info
->cfs_sock_id
, false);
1894 CFIL_LOG(LOG_ERR
, "CFIL: GET_SOCKET_INFO failed: bad sock_id %llu",
1895 sock_info
->cfs_sock_id
);
1898 goto return_already_unlocked
;
1901 cfil_info
= (sock
->so_cfil_db
!= NULL
) ?
1902 cfil_db_get_cfil_info(sock
->so_cfil_db
, sock_info
->cfs_sock_id
) : sock
->so_cfil
;
1904 if (cfil_info
== NULL
) {
1906 CFIL_LOG(LOG_ERR
, "CFIL: GET_SOCKET_INFO failed: so %llx not attached, cannot fetch info",
1907 (uint64_t)VM_KERNEL_ADDRPERM(sock
));
1910 socket_unlock(sock
, 1);
1911 goto return_already_unlocked
;
1914 // Fill out family, type, and protocol
1915 sock_info
->cfs_sock_family
= sock
->so_proto
->pr_domain
->dom_family
;
1916 sock_info
->cfs_sock_type
= sock
->so_proto
->pr_type
;
1917 sock_info
->cfs_sock_protocol
= sock
->so_proto
->pr_protocol
;
1919 // Source and destination addresses
1920 struct inpcb
*inp
= sotoinpcb(sock
);
1921 if (inp
->inp_vflag
& INP_IPV6
) {
1922 struct in6_addr
*laddr
= NULL
, *faddr
= NULL
;
1923 u_int16_t lport
= 0, fport
= 0;
1925 cfil_get_flow_address_v6(cfil_info
->cfi_hash_entry
, inp
,
1926 &laddr
, &faddr
, &lport
, &fport
);
1927 fill_ip6_sockaddr_4_6(&sock_info
->cfs_local
, laddr
, lport
);
1928 fill_ip6_sockaddr_4_6(&sock_info
->cfs_remote
, faddr
, fport
);
1929 } else if (inp
->inp_vflag
& INP_IPV4
) {
1930 struct in_addr laddr
= {.s_addr
= 0}, faddr
= {.s_addr
= 0};
1931 u_int16_t lport
= 0, fport
= 0;
1933 cfil_get_flow_address(cfil_info
->cfi_hash_entry
, inp
,
1934 &laddr
, &faddr
, &lport
, &fport
);
1935 fill_ip_sockaddr_4_6(&sock_info
->cfs_local
, laddr
, lport
);
1936 fill_ip_sockaddr_4_6(&sock_info
->cfs_remote
, faddr
, fport
);
1940 sock_info
->cfs_pid
= sock
->last_pid
;
1941 memcpy(sock_info
->cfs_uuid
, sock
->last_uuid
, sizeof(uuid_t
));
1943 if (sock
->so_flags
& SOF_DELEGATED
) {
1944 sock_info
->cfs_e_pid
= sock
->e_pid
;
1945 memcpy(sock_info
->cfs_e_uuid
, sock
->e_uuid
, sizeof(uuid_t
));
1947 sock_info
->cfs_e_pid
= sock
->last_pid
;
1948 memcpy(sock_info
->cfs_e_uuid
, sock
->last_uuid
, sizeof(uuid_t
));
1951 socket_unlock(sock
, 1);
1953 goto return_already_unlocked
;
1955 error
= ENOPROTOOPT
;
1959 cfil_rw_unlock_shared(&cfil_lck_rw
);
1963 return_already_unlocked
:
1969 cfil_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
,
1970 int opt
, void *data
, size_t len
)
1972 #pragma unused(kctlref, opt)
1974 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
1976 CFIL_LOG(LOG_NOTICE
, "");
1978 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1980 if (content_filters
== NULL
) {
1981 CFIL_LOG(LOG_ERR
, "no content filter");
1985 if (kcunit
> MAX_CONTENT_FILTER
) {
1986 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1987 kcunit
, MAX_CONTENT_FILTER
);
1991 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
1992 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
1998 case CFIL_OPT_NECP_CONTROL_UNIT
:
1999 if (len
< sizeof(uint32_t)) {
2000 CFIL_LOG(LOG_ERR
, "CFIL_OPT_NECP_CONTROL_UNIT "
2001 "len too small %lu", len
);
2005 if (cfc
->cf_necp_control_unit
!= 0) {
2006 CFIL_LOG(LOG_ERR
, "CFIL_OPT_NECP_CONTROL_UNIT "
2008 cfc
->cf_necp_control_unit
);
2012 cfc
->cf_necp_control_unit
= *(uint32_t *)data
;
2015 error
= ENOPROTOOPT
;
2019 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2026 cfil_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
, int flags
)
2028 #pragma unused(kctlref, flags)
2029 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
2030 struct socket
*so
= NULL
;
2032 struct cfil_entry
*entry
;
2033 struct cfil_info
*cfil_info
= NULL
;
2035 CFIL_LOG(LOG_INFO
, "");
2037 if (content_filters
== NULL
) {
2038 CFIL_LOG(LOG_ERR
, "no content filter");
2039 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_bad
);
2042 if (kcunit
> MAX_CONTENT_FILTER
) {
2043 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
2044 kcunit
, MAX_CONTENT_FILTER
);
2045 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_bad
);
2048 cfil_rw_lock_shared(&cfil_lck_rw
);
2049 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
2050 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
2052 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_bad
);
2055 /* Let's assume the flow control is lifted */
2056 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
2057 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
2058 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2061 cfc
->cf_flags
&= ~CFF_FLOW_CONTROLLED
;
2063 cfil_rw_lock_exclusive_to_shared(&cfil_lck_rw
);
2064 LCK_RW_ASSERT(&cfil_lck_rw
, LCK_RW_ASSERT_SHARED
);
2067 * Flow control will be raised again as soon as an entry cannot enqueue
2068 * to the kernel control socket
2070 while ((cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) == 0) {
2071 verify_content_filter(cfc
);
2073 cfil_rw_lock_assert_held(&cfil_lck_rw
, 0);
2075 /* Find an entry that is flow controlled */
2076 TAILQ_FOREACH(entry
, &cfc
->cf_sock_entries
, cfe_link
) {
2077 if (entry
->cfe_cfil_info
== NULL
||
2078 entry
->cfe_cfil_info
->cfi_so
== NULL
) {
2081 if ((entry
->cfe_flags
& CFEF_FLOW_CONTROLLED
) == 0) {
2085 if (entry
== NULL
) {
2089 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_flow_lift
);
2091 cfil_info
= entry
->cfe_cfil_info
;
2092 so
= cfil_info
->cfi_so
;
2094 cfil_rw_unlock_shared(&cfil_lck_rw
);
2098 error
= cfil_acquire_sockbuf(so
, cfil_info
, 1);
2100 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, 1);
2102 cfil_release_sockbuf(so
, 1);
2107 error
= cfil_acquire_sockbuf(so
, cfil_info
, 0);
2109 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, 0);
2111 cfil_release_sockbuf(so
, 0);
2114 socket_lock_assert_owned(so
);
2115 socket_unlock(so
, 1);
2117 cfil_rw_lock_shared(&cfil_lck_rw
);
2120 cfil_rw_unlock_shared(&cfil_lck_rw
);
2126 struct kern_ctl_reg kern_ctl
;
2128 vm_size_t content_filter_size
= 0; /* size of content_filter */
2129 vm_size_t cfil_info_size
= 0; /* size of cfil_info */
2130 vm_size_t cfil_hash_entry_size
= 0; /* size of cfil_hash_entry */
2131 vm_size_t cfil_db_size
= 0; /* size of cfil_db */
2132 unsigned int mbuf_limit
= 0;
2134 CFIL_LOG(LOG_NOTICE
, "");
2137 * Compile time verifications
2139 _CASSERT(CFIL_MAX_FILTER_COUNT
== MAX_CONTENT_FILTER
);
2140 _CASSERT(sizeof(struct cfil_filter_stat
) % sizeof(uint32_t) == 0);
2141 _CASSERT(sizeof(struct cfil_entry_stat
) % sizeof(uint32_t) == 0);
2142 _CASSERT(sizeof(struct cfil_sock_stat
) % sizeof(uint32_t) == 0);
2145 * Runtime time verifications
2147 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_in_enqueued
,
2149 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_out_enqueued
,
2151 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_in_peeked
,
2153 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_out_peeked
,
2156 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_pending_q_in_enqueued
,
2158 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_pending_q_out_enqueued
,
2161 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_in_enqueued
,
2163 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_out_enqueued
,
2165 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_in_passed
,
2167 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_out_passed
,
2171 * Zone for content filters kernel control sockets
2173 content_filter_size
= sizeof(struct content_filter
);
2174 content_filter_zone
= zinit(content_filter_size
,
2175 CONTENT_FILTER_ZONE_MAX
* content_filter_size
,
2177 CONTENT_FILTER_ZONE_NAME
);
2178 if (content_filter_zone
== NULL
) {
2179 panic("%s: zinit(%s) failed", __func__
,
2180 CONTENT_FILTER_ZONE_NAME
);
2183 zone_change(content_filter_zone
, Z_CALLERACCT
, FALSE
);
2184 zone_change(content_filter_zone
, Z_EXPAND
, TRUE
);
2187 * Zone for per socket content filters
2189 cfil_info_size
= sizeof(struct cfil_info
);
2190 cfil_info_zone
= zinit(cfil_info_size
,
2191 CFIL_INFO_ZONE_MAX
* cfil_info_size
,
2193 CFIL_INFO_ZONE_NAME
);
2194 if (cfil_info_zone
== NULL
) {
2195 panic("%s: zinit(%s) failed", __func__
, CFIL_INFO_ZONE_NAME
);
2198 zone_change(cfil_info_zone
, Z_CALLERACCT
, FALSE
);
2199 zone_change(cfil_info_zone
, Z_EXPAND
, TRUE
);
2202 * Zone for content filters cfil hash entries and db
2204 cfil_hash_entry_size
= sizeof(struct cfil_hash_entry
);
2205 cfil_hash_entry_zone
= zinit(cfil_hash_entry_size
,
2206 CFIL_HASH_ENTRY_ZONE_MAX
* cfil_hash_entry_size
,
2208 CFIL_HASH_ENTRY_ZONE_NAME
);
2209 if (cfil_hash_entry_zone
== NULL
) {
2210 panic("%s: zinit(%s) failed", __func__
, CFIL_HASH_ENTRY_ZONE_NAME
);
2213 zone_change(cfil_hash_entry_zone
, Z_CALLERACCT
, FALSE
);
2214 zone_change(cfil_hash_entry_zone
, Z_EXPAND
, TRUE
);
2216 cfil_db_size
= sizeof(struct cfil_db
);
2217 cfil_db_zone
= zinit(cfil_db_size
,
2218 CFIL_DB_ZONE_MAX
* cfil_db_size
,
2221 if (cfil_db_zone
== NULL
) {
2222 panic("%s: zinit(%s) failed", __func__
, CFIL_DB_ZONE_NAME
);
2225 zone_change(cfil_db_zone
, Z_CALLERACCT
, FALSE
);
2226 zone_change(cfil_db_zone
, Z_EXPAND
, TRUE
);
2231 cfil_lck_grp_attr
= lck_grp_attr_alloc_init();
2232 if (cfil_lck_grp_attr
== NULL
) {
2233 panic("%s: lck_grp_attr_alloc_init failed", __func__
);
2236 cfil_lck_grp
= lck_grp_alloc_init("content filter",
2238 if (cfil_lck_grp
== NULL
) {
2239 panic("%s: lck_grp_alloc_init failed", __func__
);
2242 cfil_lck_attr
= lck_attr_alloc_init();
2243 if (cfil_lck_attr
== NULL
) {
2244 panic("%s: lck_attr_alloc_init failed", __func__
);
2247 lck_rw_init(&cfil_lck_rw
, cfil_lck_grp
, cfil_lck_attr
);
2249 TAILQ_INIT(&cfil_sock_head
);
2252 * Register kernel control
2254 bzero(&kern_ctl
, sizeof(kern_ctl
));
2255 strlcpy(kern_ctl
.ctl_name
, CONTENT_FILTER_CONTROL_NAME
,
2256 sizeof(kern_ctl
.ctl_name
));
2257 kern_ctl
.ctl_flags
= CTL_FLAG_PRIVILEGED
| CTL_FLAG_REG_EXTENDED
;
2258 kern_ctl
.ctl_sendsize
= 512 * 1024; /* enough? */
2259 kern_ctl
.ctl_recvsize
= 512 * 1024; /* enough? */
2260 kern_ctl
.ctl_connect
= cfil_ctl_connect
;
2261 kern_ctl
.ctl_disconnect
= cfil_ctl_disconnect
;
2262 kern_ctl
.ctl_send
= cfil_ctl_send
;
2263 kern_ctl
.ctl_getopt
= cfil_ctl_getopt
;
2264 kern_ctl
.ctl_setopt
= cfil_ctl_setopt
;
2265 kern_ctl
.ctl_rcvd
= cfil_ctl_rcvd
;
2266 error
= ctl_register(&kern_ctl
, &cfil_kctlref
);
2268 CFIL_LOG(LOG_ERR
, "ctl_register failed: %d", error
);
2272 // Spawn thread for gargage collection
2273 if (kernel_thread_start(cfil_udp_gc_thread_func
, NULL
,
2274 &cfil_udp_gc_thread
) != KERN_SUCCESS
) {
2275 panic_plain("%s: Can't create UDP GC thread", __func__
);
2278 /* this must not fail */
2279 VERIFY(cfil_udp_gc_thread
!= NULL
);
2281 // Set UDP per-flow mbuf thresholds to 1/32 of platform max
2282 mbuf_limit
= MAX(UDP_FLOW_GC_MBUF_CNT_MAX
, (nmbclusters
<< MCLSHIFT
) >> UDP_FLOW_GC_MBUF_SHIFT
);
2283 cfil_udp_gc_mbuf_num_max
= (mbuf_limit
>> MCLSHIFT
);
2284 cfil_udp_gc_mbuf_cnt_max
= mbuf_limit
;
2288 cfil_info_alloc(struct socket
*so
, struct cfil_hash_entry
*hash_entry
)
2291 struct cfil_info
*cfil_info
= NULL
;
2292 struct inpcb
*inp
= sotoinpcb(so
);
2294 CFIL_LOG(LOG_INFO
, "");
2296 socket_lock_assert_owned(so
);
2298 cfil_info
= zalloc(cfil_info_zone
);
2299 if (cfil_info
== NULL
) {
2302 bzero(cfil_info
, sizeof(struct cfil_info
));
2304 cfil_queue_init(&cfil_info
->cfi_snd
.cfi_inject_q
);
2305 cfil_queue_init(&cfil_info
->cfi_rcv
.cfi_inject_q
);
2307 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
2308 struct cfil_entry
*entry
;
2310 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2311 entry
->cfe_cfil_info
= cfil_info
;
2313 /* Initialize the filter entry */
2314 entry
->cfe_filter
= NULL
;
2315 entry
->cfe_flags
= 0;
2316 entry
->cfe_necp_control_unit
= 0;
2317 entry
->cfe_snd
.cfe_pass_offset
= 0;
2318 entry
->cfe_snd
.cfe_peek_offset
= 0;
2319 entry
->cfe_snd
.cfe_peeked
= 0;
2320 entry
->cfe_rcv
.cfe_pass_offset
= 0;
2321 entry
->cfe_rcv
.cfe_peek_offset
= 0;
2322 entry
->cfe_rcv
.cfe_peeked
= 0;
2324 * Timestamp the last action to avoid pre-maturely
2325 * triggering garbage collection
2327 microuptime(&entry
->cfe_last_action
);
2329 cfil_queue_init(&entry
->cfe_snd
.cfe_pending_q
);
2330 cfil_queue_init(&entry
->cfe_rcv
.cfe_pending_q
);
2331 cfil_queue_init(&entry
->cfe_snd
.cfe_ctl_q
);
2332 cfil_queue_init(&entry
->cfe_rcv
.cfe_ctl_q
);
2335 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2338 * Create a cfi_sock_id that's not the socket pointer!
2341 if (hash_entry
== NULL
) {
2342 // This is the TCP case, cfil_info is tracked per socket
2343 if (inp
->inp_flowhash
== 0) {
2344 inp
->inp_flowhash
= inp_calc_flowhash(inp
);
2347 so
->so_cfil
= cfil_info
;
2348 cfil_info
->cfi_so
= so
;
2349 cfil_info
->cfi_sock_id
=
2350 ((so
->so_gencnt
<< 32) | inp
->inp_flowhash
);
2352 // This is the UDP case, cfil_info is tracked in per-socket hash
2353 cfil_info
->cfi_so
= so
;
2354 hash_entry
->cfentry_cfil
= cfil_info
;
2355 cfil_info
->cfi_hash_entry
= hash_entry
;
2356 cfil_info
->cfi_sock_id
= ((so
->so_gencnt
<< 32) | (hash_entry
->cfentry_flowhash
& 0xffffffff));
2357 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP inp_flowhash %x so_gencnt %llx entry flowhash %x sockID %llx",
2358 inp
->inp_flowhash
, so
->so_gencnt
, hash_entry
->cfentry_flowhash
, cfil_info
->cfi_sock_id
);
2360 // Wake up gc thread if this is first flow added
2361 if (cfil_sock_udp_attached_count
== 0) {
2362 thread_wakeup((caddr_t
)&cfil_sock_udp_attached_count
);
2365 cfil_sock_udp_attached_count
++;
2368 TAILQ_INSERT_TAIL(&cfil_sock_head
, cfil_info
, cfi_link
);
2369 SLIST_INIT(&cfil_info
->cfi_ordered_entries
);
2371 cfil_sock_attached_count
++;
2373 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2376 if (cfil_info
!= NULL
) {
2377 OSIncrementAtomic(&cfil_stats
.cfs_cfi_alloc_ok
);
2379 OSIncrementAtomic(&cfil_stats
.cfs_cfi_alloc_fail
);
2386 cfil_info_attach_unit(struct socket
*so
, uint32_t filter_control_unit
, struct cfil_info
*cfil_info
)
2391 CFIL_LOG(LOG_INFO
, "");
2393 socket_lock_assert_owned(so
);
2395 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2398 content_filters
!= NULL
&& kcunit
<= MAX_CONTENT_FILTER
;
2400 struct content_filter
*cfc
= content_filters
[kcunit
- 1];
2401 struct cfil_entry
*entry
;
2402 struct cfil_entry
*iter_entry
;
2403 struct cfil_entry
*iter_prev
;
2408 if (!(cfc
->cf_necp_control_unit
& filter_control_unit
)) {
2412 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2414 entry
->cfe_filter
= cfc
;
2415 entry
->cfe_necp_control_unit
= cfc
->cf_necp_control_unit
;
2416 TAILQ_INSERT_TAIL(&cfc
->cf_sock_entries
, entry
, cfe_link
);
2417 cfc
->cf_sock_count
++;
2419 /* Insert the entry into the list ordered by control unit */
2421 SLIST_FOREACH(iter_entry
, &cfil_info
->cfi_ordered_entries
, cfe_order_link
) {
2422 if (entry
->cfe_necp_control_unit
< iter_entry
->cfe_necp_control_unit
) {
2425 iter_prev
= iter_entry
;
2428 if (iter_prev
== NULL
) {
2429 SLIST_INSERT_HEAD(&cfil_info
->cfi_ordered_entries
, entry
, cfe_order_link
);
2431 SLIST_INSERT_AFTER(iter_prev
, entry
, cfe_order_link
);
2434 verify_content_filter(cfc
);
2436 entry
->cfe_flags
|= CFEF_CFIL_ATTACHED
;
2439 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2445 cfil_info_free(struct cfil_info
*cfil_info
)
2448 uint64_t in_drain
= 0;
2449 uint64_t out_drained
= 0;
2451 if (cfil_info
== NULL
) {
2455 CFIL_LOG(LOG_INFO
, "");
2457 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2460 content_filters
!= NULL
&& kcunit
<= MAX_CONTENT_FILTER
;
2462 struct cfil_entry
*entry
;
2463 struct content_filter
*cfc
;
2465 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2467 /* Don't be silly and try to detach twice */
2468 if (entry
->cfe_filter
== NULL
) {
2472 cfc
= content_filters
[kcunit
- 1];
2474 VERIFY(cfc
== entry
->cfe_filter
);
2476 entry
->cfe_filter
= NULL
;
2477 entry
->cfe_necp_control_unit
= 0;
2478 TAILQ_REMOVE(&cfc
->cf_sock_entries
, entry
, cfe_link
);
2479 cfc
->cf_sock_count
--;
2481 verify_content_filter(cfc
);
2483 if (cfil_info
->cfi_hash_entry
!= NULL
) {
2484 cfil_sock_udp_attached_count
--;
2486 cfil_sock_attached_count
--;
2487 TAILQ_REMOVE(&cfil_sock_head
, cfil_info
, cfi_link
);
2489 out_drained
+= cfil_queue_drain(&cfil_info
->cfi_snd
.cfi_inject_q
);
2490 in_drain
+= cfil_queue_drain(&cfil_info
->cfi_rcv
.cfi_inject_q
);
2492 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
2493 struct cfil_entry
*entry
;
2495 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2496 out_drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_pending_q
);
2497 in_drain
+= cfil_queue_drain(&entry
->cfe_rcv
.cfe_pending_q
);
2498 out_drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_ctl_q
);
2499 in_drain
+= cfil_queue_drain(&entry
->cfe_rcv
.cfe_ctl_q
);
2501 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2504 OSIncrementAtomic(&cfil_stats
.cfs_flush_out_free
);
2507 OSIncrementAtomic(&cfil_stats
.cfs_flush_in_free
);
2510 zfree(cfil_info_zone
, cfil_info
);
2514 * Received a verdict from userspace for a socket.
2515 * Perform any delayed operation if needed.
2518 cfil_sock_received_verdict(struct socket
*so
)
2520 if (so
== NULL
|| so
->so_cfil
== NULL
) {
2524 so
->so_cfil
->cfi_flags
|= CFIF_INITIAL_VERDICT
;
2527 * If socket has already been connected, trigger
2528 * soisconnected now.
2530 if (so
->so_cfil
->cfi_flags
& CFIF_SOCKET_CONNECTED
) {
2531 so
->so_cfil
->cfi_flags
&= ~CFIF_SOCKET_CONNECTED
;
2538 * Entry point from Sockets layer
2539 * The socket is locked.
2541 * Checks if a connected socket is subject to filter and
2542 * pending the initial verdict.
2545 cfil_sock_connected_pending_verdict(struct socket
*so
)
2547 if (so
== NULL
|| so
->so_cfil
== NULL
) {
2551 if (so
->so_cfil
->cfi_flags
& CFIF_INITIAL_VERDICT
) {
2555 * Remember that this protocol is already connected, so
2556 * we will trigger soisconnected() upon receipt of
2557 * initial verdict later.
2559 so
->so_cfil
->cfi_flags
|= CFIF_SOCKET_CONNECTED
;
2565 cfil_filter_present(void)
2567 return cfil_active_count
> 0;
2571 * Entry point from Sockets layer
2572 * The socket is locked.
2575 cfil_sock_attach(struct socket
*so
, struct sockaddr
*local
, struct sockaddr
*remote
, int dir
)
2578 uint32_t filter_control_unit
;
2580 socket_lock_assert_owned(so
);
2582 /* Limit ourselves to TCP that are not MPTCP subflows */
2583 if ((so
->so_proto
->pr_domain
->dom_family
!= PF_INET
&&
2584 so
->so_proto
->pr_domain
->dom_family
!= PF_INET6
) ||
2585 so
->so_proto
->pr_type
!= SOCK_STREAM
||
2586 so
->so_proto
->pr_protocol
!= IPPROTO_TCP
||
2587 (so
->so_flags
& SOF_MP_SUBFLOW
) != 0 ||
2588 (so
->so_flags1
& SOF1_CONTENT_FILTER_SKIP
) != 0) {
2592 filter_control_unit
= necp_socket_get_content_filter_control_unit(so
);
2593 if (filter_control_unit
== 0) {
2597 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
2600 if ((filter_control_unit
& NECP_MASK_USERSPACE_ONLY
) != 0) {
2601 OSIncrementAtomic(&cfil_stats
.cfs_sock_userspace_only
);
2604 if (cfil_active_count
== 0) {
2605 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_in_vain
);
2608 if (so
->so_cfil
!= NULL
) {
2609 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_already
);
2610 CFIL_LOG(LOG_ERR
, "already attached");
2612 cfil_info_alloc(so
, NULL
);
2613 if (so
->so_cfil
== NULL
) {
2615 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_no_mem
);
2618 so
->so_cfil
->cfi_dir
= dir
;
2620 if (cfil_info_attach_unit(so
, filter_control_unit
, so
->so_cfil
) == 0) {
2621 CFIL_LOG(LOG_ERR
, "cfil_info_attach_unit(%u) failed",
2622 filter_control_unit
);
2623 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_failed
);
2626 CFIL_LOG(LOG_INFO
, "so %llx filter_control_unit %u sockID %llx",
2627 (uint64_t)VM_KERNEL_ADDRPERM(so
),
2628 filter_control_unit
, so
->so_cfil
->cfi_sock_id
);
2630 so
->so_flags
|= SOF_CONTENT_FILTER
;
2631 OSIncrementAtomic(&cfil_stats
.cfs_sock_attached
);
2633 /* Hold a reference on the socket */
2637 * Save passed addresses for attach event msg (in case resend
2640 if (remote
!= NULL
) {
2641 memcpy(&so
->so_cfil
->cfi_so_attach_faddr
, remote
, remote
->sa_len
);
2643 if (local
!= NULL
) {
2644 memcpy(&so
->so_cfil
->cfi_so_attach_laddr
, local
, local
->sa_len
);
2647 error
= cfil_dispatch_attach_event(so
, so
->so_cfil
, 0, dir
);
2648 /* We can recover from flow control or out of memory errors */
2649 if (error
== ENOBUFS
|| error
== ENOMEM
) {
2651 } else if (error
!= 0) {
2655 CFIL_INFO_VERIFY(so
->so_cfil
);
2661 * Entry point from Sockets layer
2662 * The socket is locked.
2665 cfil_sock_detach(struct socket
*so
)
2673 if (so
->so_flags
& SOF_CONTENT_FILTER
) {
2674 so
->so_flags
&= ~SOF_CONTENT_FILTER
;
2675 VERIFY(so
->so_usecount
> 0);
2678 cfil_info_free(so
->so_cfil
);
2680 OSIncrementAtomic(&cfil_stats
.cfs_sock_detached
);
2686 * Fill in the address info of an event message from either
2687 * the socket or passed in address info.
2690 cfil_fill_event_msg_addresses(struct cfil_hash_entry
*entry
, struct inpcb
*inp
,
2691 union sockaddr_in_4_6
*sin_src
, union sockaddr_in_4_6
*sin_dst
,
2692 boolean_t isIPv4
, boolean_t outgoing
)
2695 struct in_addr laddr
= {0}, faddr
= {0};
2696 u_int16_t lport
= 0, fport
= 0;
2698 cfil_get_flow_address(entry
, inp
, &laddr
, &faddr
, &lport
, &fport
);
2701 fill_ip_sockaddr_4_6(sin_src
, laddr
, lport
);
2702 fill_ip_sockaddr_4_6(sin_dst
, faddr
, fport
);
2704 fill_ip_sockaddr_4_6(sin_src
, faddr
, fport
);
2705 fill_ip_sockaddr_4_6(sin_dst
, laddr
, lport
);
2708 struct in6_addr
*laddr
= NULL
, *faddr
= NULL
;
2709 u_int16_t lport
= 0, fport
= 0;
2711 cfil_get_flow_address_v6(entry
, inp
, &laddr
, &faddr
, &lport
, &fport
);
2713 fill_ip6_sockaddr_4_6(sin_src
, laddr
, lport
);
2714 fill_ip6_sockaddr_4_6(sin_dst
, faddr
, fport
);
2716 fill_ip6_sockaddr_4_6(sin_src
, faddr
, fport
);
2717 fill_ip6_sockaddr_4_6(sin_dst
, laddr
, lport
);
2723 cfil_dispatch_attach_event_sign(cfil_crypto_state_t crypto_state
,
2724 struct cfil_info
*cfil_info
,
2725 struct cfil_msg_sock_attached
*msg
)
2727 struct cfil_crypto_data data
= {};
2729 if (crypto_state
== NULL
|| msg
== NULL
|| cfil_info
== NULL
) {
2733 data
.sock_id
= msg
->cfs_msghdr
.cfm_sock_id
;
2734 data
.direction
= msg
->cfs_conn_dir
;
2736 data
.pid
= msg
->cfs_pid
;
2737 data
.effective_pid
= msg
->cfs_e_pid
;
2738 uuid_copy(data
.uuid
, msg
->cfs_uuid
);
2739 uuid_copy(data
.effective_uuid
, msg
->cfs_e_uuid
);
2740 data
.socketProtocol
= msg
->cfs_sock_protocol
;
2741 if (data
.direction
== CFS_CONNECTION_DIR_OUT
) {
2742 data
.remote
.sin6
= msg
->cfs_dst
.sin6
;
2743 data
.local
.sin6
= msg
->cfs_src
.sin6
;
2745 data
.remote
.sin6
= msg
->cfs_src
.sin6
;
2746 data
.local
.sin6
= msg
->cfs_dst
.sin6
;
2749 // At attach, if local address is already present, no need to re-sign subsequent data messages.
2750 if (!NULLADDRESS(data
.local
)) {
2751 cfil_info
->cfi_isSignatureLatest
= true;
2754 msg
->cfs_signature_length
= sizeof(cfil_crypto_signature
);
2755 if (cfil_crypto_sign_data(crypto_state
, &data
, msg
->cfs_signature
, &msg
->cfs_signature_length
) != 0) {
2756 msg
->cfs_signature_length
= 0;
2757 CFIL_LOG(LOG_ERR
, "CFIL: Failed to sign attached msg <sockID %llu>",
2758 msg
->cfs_msghdr
.cfm_sock_id
);
2766 cfil_dispatch_data_event_sign(cfil_crypto_state_t crypto_state
,
2767 struct socket
*so
, struct cfil_info
*cfil_info
,
2768 struct cfil_msg_data_event
*msg
)
2770 struct cfil_crypto_data data
= {};
2772 if (crypto_state
== NULL
|| msg
== NULL
||
2773 so
== NULL
|| cfil_info
== NULL
) {
2777 data
.sock_id
= cfil_info
->cfi_sock_id
;
2778 data
.direction
= cfil_info
->cfi_dir
;
2779 data
.pid
= so
->last_pid
;
2780 memcpy(data
.uuid
, so
->last_uuid
, sizeof(uuid_t
));
2781 if (so
->so_flags
& SOF_DELEGATED
) {
2782 data
.effective_pid
= so
->e_pid
;
2783 memcpy(data
.effective_uuid
, so
->e_uuid
, sizeof(uuid_t
));
2785 data
.effective_pid
= so
->last_pid
;
2786 memcpy(data
.effective_uuid
, so
->last_uuid
, sizeof(uuid_t
));
2788 data
.socketProtocol
= so
->so_proto
->pr_protocol
;
2790 if (data
.direction
== CFS_CONNECTION_DIR_OUT
) {
2791 data
.remote
.sin6
= msg
->cfc_dst
.sin6
;
2792 data
.local
.sin6
= msg
->cfc_src
.sin6
;
2794 data
.remote
.sin6
= msg
->cfc_src
.sin6
;
2795 data
.local
.sin6
= msg
->cfc_dst
.sin6
;
2798 // At first data, local address may show up for the first time, update address cache and
2799 // no need to re-sign subsequent data messages anymore.
2800 if (!NULLADDRESS(data
.local
)) {
2801 memcpy(&cfil_info
->cfi_so_attach_laddr
, &data
.local
, data
.local
.sa
.sa_len
);
2802 cfil_info
->cfi_isSignatureLatest
= true;
2805 msg
->cfd_signature_length
= sizeof(cfil_crypto_signature
);
2806 if (cfil_crypto_sign_data(crypto_state
, &data
, msg
->cfd_signature
, &msg
->cfd_signature_length
) != 0) {
2807 msg
->cfd_signature_length
= 0;
2808 CFIL_LOG(LOG_ERR
, "CFIL: Failed to sign data msg <sockID %llu>",
2809 msg
->cfd_msghdr
.cfm_sock_id
);
2817 cfil_dispatch_closed_event_sign(cfil_crypto_state_t crypto_state
,
2818 struct socket
*so
, struct cfil_info
*cfil_info
,
2819 struct cfil_msg_sock_closed
*msg
)
2821 struct cfil_crypto_data data
= {};
2822 struct cfil_hash_entry hash_entry
= {};
2823 struct cfil_hash_entry
*hash_entry_ptr
= NULL
;
2824 struct inpcb
*inp
= (struct inpcb
*)so
->so_pcb
;
2826 if (crypto_state
== NULL
|| msg
== NULL
||
2827 so
== NULL
|| inp
== NULL
|| cfil_info
== NULL
) {
2831 data
.sock_id
= cfil_info
->cfi_sock_id
;
2832 data
.direction
= cfil_info
->cfi_dir
;
2834 data
.pid
= so
->last_pid
;
2835 memcpy(data
.uuid
, so
->last_uuid
, sizeof(uuid_t
));
2836 if (so
->so_flags
& SOF_DELEGATED
) {
2837 data
.effective_pid
= so
->e_pid
;
2838 memcpy(data
.effective_uuid
, so
->e_uuid
, sizeof(uuid_t
));
2840 data
.effective_pid
= so
->last_pid
;
2841 memcpy(data
.effective_uuid
, so
->last_uuid
, sizeof(uuid_t
));
2843 data
.socketProtocol
= so
->so_proto
->pr_protocol
;
2846 * Fill in address info:
2847 * For UDP, use the cfil_info hash entry directly.
2848 * For TCP, compose an hash entry with the saved addresses.
2850 if (cfil_info
->cfi_hash_entry
!= NULL
) {
2851 hash_entry_ptr
= cfil_info
->cfi_hash_entry
;
2852 } else if (cfil_info
->cfi_so_attach_faddr
.sa
.sa_len
> 0 ||
2853 cfil_info
->cfi_so_attach_laddr
.sa
.sa_len
> 0) {
2854 fill_cfil_hash_entry_from_address(&hash_entry
, TRUE
, &cfil_info
->cfi_so_attach_laddr
.sa
);
2855 fill_cfil_hash_entry_from_address(&hash_entry
, FALSE
, &cfil_info
->cfi_so_attach_faddr
.sa
);
2856 hash_entry_ptr
= &hash_entry
;
2858 if (hash_entry_ptr
!= NULL
) {
2859 boolean_t outgoing
= (cfil_info
->cfi_dir
== CFS_CONNECTION_DIR_OUT
);
2860 union sockaddr_in_4_6
*src
= outgoing
? &data
.local
: &data
.remote
;
2861 union sockaddr_in_4_6
*dst
= outgoing
? &data
.remote
: &data
.local
;
2862 cfil_fill_event_msg_addresses(hash_entry_ptr
, inp
, src
, dst
, inp
->inp_vflag
& INP_IPV4
, outgoing
);
2865 data
.byte_count_in
= cfil_info
->cfi_byte_inbound_count
;
2866 data
.byte_count_out
= cfil_info
->cfi_byte_outbound_count
;
2868 msg
->cfc_signature_length
= sizeof(cfil_crypto_signature
);
2869 if (cfil_crypto_sign_data(crypto_state
, &data
, msg
->cfc_signature
, &msg
->cfc_signature_length
) != 0) {
2870 msg
->cfc_signature_length
= 0;
2871 CFIL_LOG(LOG_ERR
, "CFIL: Failed to sign closed msg <sockID %llu>",
2872 msg
->cfc_msghdr
.cfm_sock_id
);
2880 cfil_dispatch_attach_event(struct socket
*so
, struct cfil_info
*cfil_info
,
2881 uint32_t kcunit
, int conn_dir
)
2884 struct cfil_entry
*entry
= NULL
;
2885 struct cfil_msg_sock_attached msg_attached
;
2886 struct content_filter
*cfc
= NULL
;
2887 struct inpcb
*inp
= (struct inpcb
*)so
->so_pcb
;
2888 struct cfil_hash_entry
*hash_entry_ptr
= NULL
;
2889 struct cfil_hash_entry hash_entry
;
2891 memset(&hash_entry
, 0, sizeof(struct cfil_hash_entry
));
2892 proc_t p
= PROC_NULL
;
2893 task_t t
= TASK_NULL
;
2895 socket_lock_assert_owned(so
);
2897 cfil_rw_lock_shared(&cfil_lck_rw
);
2899 if (so
->so_proto
== NULL
|| so
->so_proto
->pr_domain
== NULL
) {
2905 entry
= SLIST_FIRST(&cfil_info
->cfi_ordered_entries
);
2907 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2910 if (entry
== NULL
) {
2914 cfc
= entry
->cfe_filter
;
2919 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
)) {
2924 kcunit
= CFI_ENTRY_KCUNIT(cfil_info
, entry
);
2927 CFIL_LOG(LOG_INFO
, "so %llx filter_control_unit %u kcunit %u",
2928 (uint64_t)VM_KERNEL_ADDRPERM(so
), entry
->cfe_necp_control_unit
, kcunit
);
2930 /* Would be wasteful to try when flow controlled */
2931 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
2936 bzero(&msg_attached
, sizeof(struct cfil_msg_sock_attached
));
2937 msg_attached
.cfs_msghdr
.cfm_len
= sizeof(struct cfil_msg_sock_attached
);
2938 msg_attached
.cfs_msghdr
.cfm_version
= CFM_VERSION_CURRENT
;
2939 msg_attached
.cfs_msghdr
.cfm_type
= CFM_TYPE_EVENT
;
2940 msg_attached
.cfs_msghdr
.cfm_op
= CFM_OP_SOCKET_ATTACHED
;
2941 msg_attached
.cfs_msghdr
.cfm_sock_id
= entry
->cfe_cfil_info
->cfi_sock_id
;
2943 msg_attached
.cfs_sock_family
= so
->so_proto
->pr_domain
->dom_family
;
2944 msg_attached
.cfs_sock_type
= so
->so_proto
->pr_type
;
2945 msg_attached
.cfs_sock_protocol
= so
->so_proto
->pr_protocol
;
2946 msg_attached
.cfs_pid
= so
->last_pid
;
2947 memcpy(msg_attached
.cfs_uuid
, so
->last_uuid
, sizeof(uuid_t
));
2948 if (so
->so_flags
& SOF_DELEGATED
) {
2949 msg_attached
.cfs_e_pid
= so
->e_pid
;
2950 memcpy(msg_attached
.cfs_e_uuid
, so
->e_uuid
, sizeof(uuid_t
));
2952 msg_attached
.cfs_e_pid
= so
->last_pid
;
2953 memcpy(msg_attached
.cfs_e_uuid
, so
->last_uuid
, sizeof(uuid_t
));
2957 * Fill in address info:
2958 * For UDP, use the cfil_info hash entry directly.
2959 * For TCP, compose an hash entry with the saved addresses.
2961 if (cfil_info
->cfi_hash_entry
!= NULL
) {
2962 hash_entry_ptr
= cfil_info
->cfi_hash_entry
;
2963 } else if (cfil_info
->cfi_so_attach_faddr
.sa
.sa_len
> 0 ||
2964 cfil_info
->cfi_so_attach_laddr
.sa
.sa_len
> 0) {
2965 fill_cfil_hash_entry_from_address(&hash_entry
, TRUE
, &cfil_info
->cfi_so_attach_laddr
.sa
);
2966 fill_cfil_hash_entry_from_address(&hash_entry
, FALSE
, &cfil_info
->cfi_so_attach_faddr
.sa
);
2967 hash_entry_ptr
= &hash_entry
;
2969 if (hash_entry_ptr
!= NULL
) {
2970 cfil_fill_event_msg_addresses(hash_entry_ptr
, inp
,
2971 &msg_attached
.cfs_src
, &msg_attached
.cfs_dst
,
2972 inp
->inp_vflag
& INP_IPV4
, conn_dir
== CFS_CONNECTION_DIR_OUT
);
2974 msg_attached
.cfs_conn_dir
= conn_dir
;
2976 if (msg_attached
.cfs_e_pid
!= 0) {
2977 p
= proc_find(msg_attached
.cfs_e_pid
);
2978 if (p
!= PROC_NULL
) {
2980 if (t
!= TASK_NULL
) {
2981 audit_token_t audit_token
;
2982 mach_msg_type_number_t count
= TASK_AUDIT_TOKEN_COUNT
;
2983 if (task_info(t
, TASK_AUDIT_TOKEN
, (task_info_t
)&audit_token
, &count
) == KERN_SUCCESS
) {
2984 memcpy(&msg_attached
.cfs_audit_token
, &audit_token
, sizeof(msg_attached
.cfs_audit_token
));
2986 CFIL_LOG(LOG_ERR
, "CFIL: Failed to get process audit token <sockID %llu> ",
2987 entry
->cfe_cfil_info
->cfi_sock_id
);
2994 cfil_dispatch_attach_event_sign(entry
->cfe_filter
->cf_crypto_state
, cfil_info
, &msg_attached
);
2997 CFIL_LOG(LOG_DEBUG
, "CFIL: LIFECYCLE: SENDING ATTACH UP <sockID %llu> ",
2998 entry
->cfe_cfil_info
->cfi_sock_id
);
3001 error
= ctl_enqueuedata(entry
->cfe_filter
->cf_kcref
,
3002 entry
->cfe_filter
->cf_kcunit
,
3004 sizeof(struct cfil_msg_sock_attached
),
3007 CFIL_LOG(LOG_ERR
, "ctl_enqueuedata() failed: %d", error
);
3010 microuptime(&entry
->cfe_last_event
);
3011 cfil_info
->cfi_first_event
.tv_sec
= entry
->cfe_last_event
.tv_sec
;
3012 cfil_info
->cfi_first_event
.tv_usec
= entry
->cfe_last_event
.tv_usec
;
3014 entry
->cfe_flags
|= CFEF_SENT_SOCK_ATTACHED
;
3015 OSIncrementAtomic(&cfil_stats
.cfs_attach_event_ok
);
3018 /* We can recover from flow control */
3019 if (error
== ENOBUFS
) {
3020 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3021 OSIncrementAtomic(&cfil_stats
.cfs_attach_event_flow_control
);
3023 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3024 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3027 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3029 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3032 OSIncrementAtomic(&cfil_stats
.cfs_attach_event_fail
);
3035 cfil_rw_unlock_shared(&cfil_lck_rw
);
3041 cfil_dispatch_disconnect_event(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
)
3044 struct mbuf
*msg
= NULL
;
3045 struct cfil_entry
*entry
;
3046 struct cfe_buf
*entrybuf
;
3047 struct cfil_msg_hdr msg_disconnected
;
3048 struct content_filter
*cfc
;
3050 socket_lock_assert_owned(so
);
3052 cfil_rw_lock_shared(&cfil_lck_rw
);
3054 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3056 entrybuf
= &entry
->cfe_snd
;
3058 entrybuf
= &entry
->cfe_rcv
;
3061 cfc
= entry
->cfe_filter
;
3066 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3067 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3070 * Send the disconnection event once
3072 if ((outgoing
&& (entry
->cfe_flags
& CFEF_SENT_DISCONNECT_OUT
)) ||
3073 (!outgoing
&& (entry
->cfe_flags
& CFEF_SENT_DISCONNECT_IN
))) {
3074 CFIL_LOG(LOG_INFO
, "so %llx disconnect already sent",
3075 (uint64_t)VM_KERNEL_ADDRPERM(so
));
3080 * We're not disconnected as long as some data is waiting
3081 * to be delivered to the filter
3083 if (outgoing
&& cfil_queue_empty(&entrybuf
->cfe_ctl_q
) == 0) {
3084 CFIL_LOG(LOG_INFO
, "so %llx control queue not empty",
3085 (uint64_t)VM_KERNEL_ADDRPERM(so
));
3089 /* Would be wasteful to try when flow controlled */
3090 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3096 cfil_info_log(LOG_ERR
, cfil_info
, outgoing
?
3097 "CFIL: LIFECYCLE: OUT - SENDING DISCONNECT UP":
3098 "CFIL: LIFECYCLE: IN - SENDING DISCONNECT UP");
3101 bzero(&msg_disconnected
, sizeof(struct cfil_msg_hdr
));
3102 msg_disconnected
.cfm_len
= sizeof(struct cfil_msg_hdr
);
3103 msg_disconnected
.cfm_version
= CFM_VERSION_CURRENT
;
3104 msg_disconnected
.cfm_type
= CFM_TYPE_EVENT
;
3105 msg_disconnected
.cfm_op
= outgoing
? CFM_OP_DISCONNECT_OUT
:
3106 CFM_OP_DISCONNECT_IN
;
3107 msg_disconnected
.cfm_sock_id
= entry
->cfe_cfil_info
->cfi_sock_id
;
3108 error
= ctl_enqueuedata(entry
->cfe_filter
->cf_kcref
,
3109 entry
->cfe_filter
->cf_kcunit
,
3111 sizeof(struct cfil_msg_hdr
),
3114 CFIL_LOG(LOG_ERR
, "ctl_enqueuembuf() failed: %d", error
);
3118 microuptime(&entry
->cfe_last_event
);
3119 CFI_ADD_TIME_LOG(cfil_info
, &entry
->cfe_last_event
, &cfil_info
->cfi_first_event
, msg_disconnected
.cfm_op
);
3121 /* Remember we have sent the disconnection message */
3123 entry
->cfe_flags
|= CFEF_SENT_DISCONNECT_OUT
;
3124 OSIncrementAtomic(&cfil_stats
.cfs_disconnect_out_event_ok
);
3126 entry
->cfe_flags
|= CFEF_SENT_DISCONNECT_IN
;
3127 OSIncrementAtomic(&cfil_stats
.cfs_disconnect_in_event_ok
);
3130 if (error
== ENOBUFS
) {
3131 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3133 &cfil_stats
.cfs_disconnect_event_flow_control
);
3135 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3136 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3139 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3141 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3145 &cfil_stats
.cfs_disconnect_event_fail
);
3148 cfil_rw_unlock_shared(&cfil_lck_rw
);
3154 cfil_dispatch_closed_event(struct socket
*so
, struct cfil_info
*cfil_info
, int kcunit
)
3156 struct cfil_entry
*entry
;
3157 struct cfil_msg_sock_closed msg_closed
;
3159 struct content_filter
*cfc
;
3161 socket_lock_assert_owned(so
);
3163 cfil_rw_lock_shared(&cfil_lck_rw
);
3165 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3166 cfc
= entry
->cfe_filter
;
3171 CFIL_LOG(LOG_INFO
, "so %llx kcunit %d",
3172 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
3174 /* Would be wasteful to try when flow controlled */
3175 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3180 * Send a single closed message per filter
3182 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_CLOSED
) != 0) {
3185 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
3189 microuptime(&entry
->cfe_last_event
);
3190 CFI_ADD_TIME_LOG(cfil_info
, &entry
->cfe_last_event
, &cfil_info
->cfi_first_event
, CFM_OP_SOCKET_CLOSED
);
3192 bzero(&msg_closed
, sizeof(struct cfil_msg_sock_closed
));
3193 msg_closed
.cfc_msghdr
.cfm_len
= sizeof(struct cfil_msg_sock_closed
);
3194 msg_closed
.cfc_msghdr
.cfm_version
= CFM_VERSION_CURRENT
;
3195 msg_closed
.cfc_msghdr
.cfm_type
= CFM_TYPE_EVENT
;
3196 msg_closed
.cfc_msghdr
.cfm_op
= CFM_OP_SOCKET_CLOSED
;
3197 msg_closed
.cfc_msghdr
.cfm_sock_id
= entry
->cfe_cfil_info
->cfi_sock_id
;
3198 msg_closed
.cfc_first_event
.tv_sec
= cfil_info
->cfi_first_event
.tv_sec
;
3199 msg_closed
.cfc_first_event
.tv_usec
= cfil_info
->cfi_first_event
.tv_usec
;
3200 memcpy(msg_closed
.cfc_op_time
, cfil_info
->cfi_op_time
, sizeof(uint32_t) * CFI_MAX_TIME_LOG_ENTRY
);
3201 memcpy(msg_closed
.cfc_op_list
, cfil_info
->cfi_op_list
, sizeof(unsigned char) * CFI_MAX_TIME_LOG_ENTRY
);
3202 msg_closed
.cfc_op_list_ctr
= cfil_info
->cfi_op_list_ctr
;
3203 msg_closed
.cfc_byte_inbound_count
= cfil_info
->cfi_byte_inbound_count
;
3204 msg_closed
.cfc_byte_outbound_count
= cfil_info
->cfi_byte_outbound_count
;
3206 cfil_dispatch_closed_event_sign(entry
->cfe_filter
->cf_crypto_state
, so
, cfil_info
, &msg_closed
);
3209 CFIL_LOG(LOG_ERR
, "CFIL: LIFECYCLE: SENDING CLOSED UP: <sock id %llu> op ctr %d, start time %llu.%llu", msg_closed
.cfc_msghdr
.cfm_sock_id
, cfil_info
->cfi_op_list_ctr
, cfil_info
->cfi_first_event
.tv_sec
, cfil_info
->cfi_first_event
.tv_usec
);
3212 * if (msg_closed.cfc_op_list_ctr > CFI_MAX_TIME_LOG_ENTRY) {
3213 * msg_closed.cfc_op_list_ctr = CFI_MAX_TIME_LOG_ENTRY; // just in case
3215 * for (unsigned int i = 0; i < msg_closed.cfc_op_list_ctr ; i++) {
3216 * CFIL_LOG(LOG_ERR, "MD: socket %llu event %2u, time + %u msec", msg_closed.cfc_msghdr.cfm_sock_id, (unsigned short)msg_closed.cfc_op_list[i], msg_closed.cfc_op_time[i]);
3220 error
= ctl_enqueuedata(entry
->cfe_filter
->cf_kcref
,
3221 entry
->cfe_filter
->cf_kcunit
,
3223 sizeof(struct cfil_msg_sock_closed
),
3226 CFIL_LOG(LOG_ERR
, "ctl_enqueuedata() failed: %d",
3231 entry
->cfe_flags
|= CFEF_SENT_SOCK_CLOSED
;
3232 OSIncrementAtomic(&cfil_stats
.cfs_closed_event_ok
);
3234 /* We can recover from flow control */
3235 if (error
== ENOBUFS
) {
3236 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3237 OSIncrementAtomic(&cfil_stats
.cfs_closed_event_flow_control
);
3239 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3240 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3243 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3245 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3248 OSIncrementAtomic(&cfil_stats
.cfs_closed_event_fail
);
3251 cfil_rw_unlock_shared(&cfil_lck_rw
);
3258 fill_ip6_sockaddr_4_6(union sockaddr_in_4_6
*sin46
,
3259 struct in6_addr
*ip6
, u_int16_t port
)
3261 struct sockaddr_in6
*sin6
= &sin46
->sin6
;
3263 sin6
->sin6_family
= AF_INET6
;
3264 sin6
->sin6_len
= sizeof(*sin6
);
3265 sin6
->sin6_port
= port
;
3266 sin6
->sin6_addr
= *ip6
;
3267 if (IN6_IS_SCOPE_EMBED(&sin6
->sin6_addr
)) {
3268 sin6
->sin6_scope_id
= ntohs(sin6
->sin6_addr
.s6_addr16
[1]);
3269 sin6
->sin6_addr
.s6_addr16
[1] = 0;
3274 fill_ip_sockaddr_4_6(union sockaddr_in_4_6
*sin46
,
3275 struct in_addr ip
, u_int16_t port
)
3277 struct sockaddr_in
*sin
= &sin46
->sin
;
3279 sin
->sin_family
= AF_INET
;
3280 sin
->sin_len
= sizeof(*sin
);
3281 sin
->sin_port
= port
;
3282 sin
->sin_addr
.s_addr
= ip
.s_addr
;
3286 cfil_get_flow_address_v6(struct cfil_hash_entry
*entry
, struct inpcb
*inp
,
3287 struct in6_addr
**laddr
, struct in6_addr
**faddr
,
3288 u_int16_t
*lport
, u_int16_t
*fport
)
3290 if (entry
!= NULL
) {
3291 *laddr
= &entry
->cfentry_laddr
.addr6
;
3292 *faddr
= &entry
->cfentry_faddr
.addr6
;
3293 *lport
= entry
->cfentry_lport
;
3294 *fport
= entry
->cfentry_fport
;
3296 *laddr
= &inp
->in6p_laddr
;
3297 *faddr
= &inp
->in6p_faddr
;
3298 *lport
= inp
->inp_lport
;
3299 *fport
= inp
->inp_fport
;
3304 cfil_get_flow_address(struct cfil_hash_entry
*entry
, struct inpcb
*inp
,
3305 struct in_addr
*laddr
, struct in_addr
*faddr
,
3306 u_int16_t
*lport
, u_int16_t
*fport
)
3308 if (entry
!= NULL
) {
3309 *laddr
= entry
->cfentry_laddr
.addr46
.ia46_addr4
;
3310 *faddr
= entry
->cfentry_faddr
.addr46
.ia46_addr4
;
3311 *lport
= entry
->cfentry_lport
;
3312 *fport
= entry
->cfentry_fport
;
3314 *laddr
= inp
->inp_laddr
;
3315 *faddr
= inp
->inp_faddr
;
3316 *lport
= inp
->inp_lport
;
3317 *fport
= inp
->inp_fport
;
3322 cfil_dispatch_data_event(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
3323 struct mbuf
*data
, unsigned int copyoffset
, unsigned int copylen
)
3326 struct mbuf
*copy
= NULL
;
3327 struct mbuf
*msg
= NULL
;
3328 unsigned int one
= 1;
3329 struct cfil_msg_data_event
*data_req
;
3331 struct inpcb
*inp
= (struct inpcb
*)so
->so_pcb
;
3332 struct cfil_entry
*entry
;
3333 struct cfe_buf
*entrybuf
;
3334 struct content_filter
*cfc
;
3337 cfil_rw_lock_shared(&cfil_lck_rw
);
3339 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3341 entrybuf
= &entry
->cfe_snd
;
3343 entrybuf
= &entry
->cfe_rcv
;
3346 cfc
= entry
->cfe_filter
;
3351 data
= cfil_data_start(data
);
3352 if (data
== NULL
|| (data
->m_flags
& M_PKTHDR
) == 0) {
3353 CFIL_LOG(LOG_ERR
, "NOT PKTHDR");
3357 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3358 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3360 socket_lock_assert_owned(so
);
3362 /* Would be wasteful to try */
3363 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3368 /* Make a copy of the data to pass to kernel control socket */
3369 copy
= m_copym_mode(data
, copyoffset
, copylen
, M_DONTWAIT
,
3372 CFIL_LOG(LOG_ERR
, "m_copym_mode() failed");
3377 /* We need an mbuf packet for the message header */
3378 hdrsize
= sizeof(struct cfil_msg_data_event
);
3379 error
= mbuf_allocpacket(MBUF_DONTWAIT
, hdrsize
, &one
, &msg
);
3381 CFIL_LOG(LOG_ERR
, "mbuf_allocpacket() failed");
3384 * ENOBUFS is to indicate flow control
3389 mbuf_setlen(msg
, hdrsize
);
3390 mbuf_pkthdr_setlen(msg
, hdrsize
+ copylen
);
3392 data_req
= (struct cfil_msg_data_event
*)mbuf_data(msg
);
3393 bzero(data_req
, hdrsize
);
3394 data_req
->cfd_msghdr
.cfm_len
= hdrsize
+ copylen
;
3395 data_req
->cfd_msghdr
.cfm_version
= 1;
3396 data_req
->cfd_msghdr
.cfm_type
= CFM_TYPE_EVENT
;
3397 data_req
->cfd_msghdr
.cfm_op
=
3398 outgoing
? CFM_OP_DATA_OUT
: CFM_OP_DATA_IN
;
3399 data_req
->cfd_msghdr
.cfm_sock_id
=
3400 entry
->cfe_cfil_info
->cfi_sock_id
;
3401 data_req
->cfd_start_offset
= entrybuf
->cfe_peeked
;
3402 data_req
->cfd_end_offset
= entrybuf
->cfe_peeked
+ copylen
;
3405 * Copy address/port into event msg.
3406 * For non connected sockets need to copy addresses from passed
3409 cfil_fill_event_msg_addresses(cfil_info
->cfi_hash_entry
, inp
,
3410 &data_req
->cfc_src
, &data_req
->cfc_dst
,
3411 inp
->inp_vflag
& INP_IPV4
, outgoing
);
3413 if (cfil_info
->cfi_isSignatureLatest
== false) {
3414 cfil_dispatch_data_event_sign(entry
->cfe_filter
->cf_crypto_state
, so
, cfil_info
, data_req
);
3418 CFI_ADD_TIME_LOG(cfil_info
, &tv
, &cfil_info
->cfi_first_event
, data_req
->cfd_msghdr
.cfm_op
);
3420 /* Pass the message to the content filter */
3421 error
= ctl_enqueuembuf(entry
->cfe_filter
->cf_kcref
,
3422 entry
->cfe_filter
->cf_kcunit
,
3425 CFIL_LOG(LOG_ERR
, "ctl_enqueuembuf() failed: %d", error
);
3429 entry
->cfe_flags
&= ~CFEF_FLOW_CONTROLLED
;
3430 OSIncrementAtomic(&cfil_stats
.cfs_data_event_ok
);
3433 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT ACTION: so %llx sockID %llu outgoing %d: mbuf %llx copyoffset %u copylen %u",
3434 (uint64_t)VM_KERNEL_ADDRPERM(so
), cfil_info
->cfi_sock_id
, outgoing
, (uint64_t)VM_KERNEL_ADDRPERM(data
), copyoffset
, copylen
);
3438 if (error
== ENOBUFS
) {
3439 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3441 &cfil_stats
.cfs_data_event_flow_control
);
3443 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3444 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3447 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3449 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3452 OSIncrementAtomic(&cfil_stats
.cfs_data_event_fail
);
3455 cfil_rw_unlock_shared(&cfil_lck_rw
);
3461 * Process the queue of data waiting to be delivered to content filter
3464 cfil_data_service_ctl_q(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
)
3467 struct mbuf
*data
, *tmp
= NULL
;
3468 unsigned int datalen
= 0, copylen
= 0, copyoffset
= 0;
3469 struct cfil_entry
*entry
;
3470 struct cfe_buf
*entrybuf
;
3471 uint64_t currentoffset
= 0;
3473 if (cfil_info
== NULL
) {
3477 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3478 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3480 socket_lock_assert_owned(so
);
3482 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3484 entrybuf
= &entry
->cfe_snd
;
3486 entrybuf
= &entry
->cfe_rcv
;
3489 /* Send attached message if not yet done */
3490 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
3491 error
= cfil_dispatch_attach_event(so
, cfil_info
, CFI_ENTRY_KCUNIT(cfil_info
, entry
),
3492 outgoing
? CFS_CONNECTION_DIR_OUT
: CFS_CONNECTION_DIR_IN
);
3494 /* We can recover from flow control */
3495 if (error
== ENOBUFS
|| error
== ENOMEM
) {
3500 } else if ((entry
->cfe_flags
& CFEF_DATA_START
) == 0) {
3501 OSIncrementAtomic(&cfil_stats
.cfs_ctl_q_not_started
);
3506 CFIL_LOG(LOG_DEBUG
, "CFIL: SERVICE CTL-Q: pass_offset %llu peeked %llu peek_offset %llu",
3507 entrybuf
->cfe_pass_offset
,
3508 entrybuf
->cfe_peeked
,
3509 entrybuf
->cfe_peek_offset
);
3512 /* Move all data that can pass */
3513 while ((data
= cfil_queue_first(&entrybuf
->cfe_ctl_q
)) != NULL
&&
3514 entrybuf
->cfe_ctl_q
.q_start
< entrybuf
->cfe_pass_offset
) {
3515 datalen
= cfil_data_length(data
, NULL
, NULL
);
3518 if (entrybuf
->cfe_ctl_q
.q_start
+ datalen
<=
3519 entrybuf
->cfe_pass_offset
) {
3521 * The first mbuf can fully pass
3526 * The first mbuf can partially pass
3528 copylen
= entrybuf
->cfe_pass_offset
-
3529 entrybuf
->cfe_ctl_q
.q_start
;
3531 VERIFY(copylen
<= datalen
);
3535 "CFIL: SERVICE CTL-Q PASSING: %llx first %llu peeked %llu pass %llu peek %llu"
3536 "datalen %u copylen %u",
3537 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3538 entrybuf
->cfe_ctl_q
.q_start
,
3539 entrybuf
->cfe_peeked
,
3540 entrybuf
->cfe_pass_offset
,
3541 entrybuf
->cfe_peek_offset
,
3546 * Data that passes has been peeked at explicitly or
3549 if (entrybuf
->cfe_ctl_q
.q_start
+ copylen
>
3550 entrybuf
->cfe_peeked
) {
3551 entrybuf
->cfe_peeked
=
3552 entrybuf
->cfe_ctl_q
.q_start
+ copylen
;
3555 * Stop on partial pass
3557 if (copylen
< datalen
) {
3561 /* All good, move full data from ctl queue to pending queue */
3562 cfil_queue_remove(&entrybuf
->cfe_ctl_q
, data
, datalen
);
3564 cfil_queue_enqueue(&entrybuf
->cfe_pending_q
, data
, datalen
);
3566 OSAddAtomic64(datalen
,
3567 &cfil_stats
.cfs_pending_q_out_enqueued
);
3569 OSAddAtomic64(datalen
,
3570 &cfil_stats
.cfs_pending_q_in_enqueued
);
3573 CFIL_INFO_VERIFY(cfil_info
);
3576 "%llx first %llu peeked %llu pass %llu peek %llu"
3577 "datalen %u copylen %u",
3578 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3579 entrybuf
->cfe_ctl_q
.q_start
,
3580 entrybuf
->cfe_peeked
,
3581 entrybuf
->cfe_pass_offset
,
3582 entrybuf
->cfe_peek_offset
,
3587 /* Now deal with remaining data the filter wants to peek at */
3588 for (data
= cfil_queue_first(&entrybuf
->cfe_ctl_q
),
3589 currentoffset
= entrybuf
->cfe_ctl_q
.q_start
;
3590 data
!= NULL
&& currentoffset
< entrybuf
->cfe_peek_offset
;
3591 data
= cfil_queue_next(&entrybuf
->cfe_ctl_q
, data
),
3592 currentoffset
+= datalen
) {
3593 datalen
= cfil_data_length(data
, NULL
, NULL
);
3596 /* We've already peeked at this mbuf */
3597 if (currentoffset
+ datalen
<= entrybuf
->cfe_peeked
) {
3601 * The data in the first mbuf may have been
3602 * partially peeked at
3604 copyoffset
= entrybuf
->cfe_peeked
- currentoffset
;
3605 VERIFY(copyoffset
< datalen
);
3606 copylen
= datalen
- copyoffset
;
3607 VERIFY(copylen
<= datalen
);
3609 * Do not copy more than needed
3611 if (currentoffset
+ copyoffset
+ copylen
>
3612 entrybuf
->cfe_peek_offset
) {
3613 copylen
= entrybuf
->cfe_peek_offset
-
3614 (currentoffset
+ copyoffset
);
3619 "CFIL: SERVICE CTL-Q PEEKING: %llx current %llu peeked %llu pass %llu peek %llu "
3620 "datalen %u copylen %u copyoffset %u",
3621 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3623 entrybuf
->cfe_peeked
,
3624 entrybuf
->cfe_pass_offset
,
3625 entrybuf
->cfe_peek_offset
,
3626 datalen
, copylen
, copyoffset
);
3630 * Stop if there is nothing more to peek at
3636 * Let the filter get a peek at this span of data
3638 error
= cfil_dispatch_data_event(so
, cfil_info
, kcunit
,
3639 outgoing
, data
, copyoffset
, copylen
);
3641 /* On error, leave data in ctl_q */
3644 entrybuf
->cfe_peeked
+= copylen
;
3646 OSAddAtomic64(copylen
,
3647 &cfil_stats
.cfs_ctl_q_out_peeked
);
3649 OSAddAtomic64(copylen
,
3650 &cfil_stats
.cfs_ctl_q_in_peeked
);
3653 /* Stop when data could not be fully peeked at */
3654 if (copylen
+ copyoffset
< datalen
) {
3658 CFIL_INFO_VERIFY(cfil_info
);
3661 "%llx first %llu peeked %llu pass %llu peek %llu"
3662 "datalen %u copylen %u copyoffset %u",
3663 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3665 entrybuf
->cfe_peeked
,
3666 entrybuf
->cfe_pass_offset
,
3667 entrybuf
->cfe_peek_offset
,
3668 datalen
, copylen
, copyoffset
);
3672 * Process data that has passed the filter
3674 error
= cfil_service_pending_queue(so
, cfil_info
, kcunit
, outgoing
);
3676 CFIL_LOG(LOG_ERR
, "cfil_service_pending_queue() error %d",
3682 * Dispatch disconnect events that could not be sent
3684 if (cfil_info
== NULL
) {
3686 } else if (outgoing
) {
3687 if ((cfil_info
->cfi_flags
& CFIF_SHUT_WR
) &&
3688 !(entry
->cfe_flags
& CFEF_SENT_DISCONNECT_OUT
)) {
3689 cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 1);
3692 if ((cfil_info
->cfi_flags
& CFIF_SHUT_RD
) &&
3693 !(entry
->cfe_flags
& CFEF_SENT_DISCONNECT_IN
)) {
3694 cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 0);
3700 "first %llu peeked %llu pass %llu peek %llu",
3701 entrybuf
->cfe_ctl_q
.q_start
,
3702 entrybuf
->cfe_peeked
,
3703 entrybuf
->cfe_pass_offset
,
3704 entrybuf
->cfe_peek_offset
);
3706 CFIL_INFO_VERIFY(cfil_info
);
3711 * cfil_data_filter()
3713 * Process data for a content filter installed on a socket
3716 cfil_data_filter(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
3717 struct mbuf
*data
, uint64_t datalen
)
3720 struct cfil_entry
*entry
;
3721 struct cfe_buf
*entrybuf
;
3723 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3724 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3726 socket_lock_assert_owned(so
);
3728 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3730 entrybuf
= &entry
->cfe_snd
;
3732 entrybuf
= &entry
->cfe_rcv
;
3735 /* Are we attached to the filter? */
3736 if (entry
->cfe_filter
== NULL
) {
3741 /* Dispatch to filters */
3742 cfil_queue_enqueue(&entrybuf
->cfe_ctl_q
, data
, datalen
);
3744 OSAddAtomic64(datalen
,
3745 &cfil_stats
.cfs_ctl_q_out_enqueued
);
3747 OSAddAtomic64(datalen
,
3748 &cfil_stats
.cfs_ctl_q_in_enqueued
);
3751 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, outgoing
);
3753 CFIL_LOG(LOG_ERR
, "cfil_data_service_ctl_q() error %d",
3757 * We have to return EJUSTRETURN in all cases to avoid double free
3760 error
= EJUSTRETURN
;
3762 CFIL_INFO_VERIFY(cfil_info
);
3764 CFIL_LOG(LOG_INFO
, "return %d", error
);
3769 * cfil_service_inject_queue() re-inject data that passed the
3773 cfil_service_inject_queue(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
)
3776 unsigned int datalen
;
3780 struct cfi_buf
*cfi_buf
;
3781 struct cfil_queue
*inject_q
;
3782 int need_rwakeup
= 0;
3785 if (cfil_info
== NULL
) {
3789 socket_lock_assert_owned(so
);
3792 cfi_buf
= &cfil_info
->cfi_snd
;
3793 cfil_info
->cfi_flags
&= ~CFIF_RETRY_INJECT_OUT
;
3795 cfi_buf
= &cfil_info
->cfi_rcv
;
3796 cfil_info
->cfi_flags
&= ~CFIF_RETRY_INJECT_IN
;
3798 inject_q
= &cfi_buf
->cfi_inject_q
;
3800 if (cfil_queue_empty(inject_q
)) {
3804 #if DATA_DEBUG | VERDICT_DEBUG
3805 CFIL_LOG(LOG_ERR
, "CFIL: SERVICE INJECT-Q: <so %llx> outgoing %d queue len %llu",
3806 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
, cfil_queue_len(inject_q
));
3809 while ((data
= cfil_queue_first(inject_q
)) != NULL
) {
3810 datalen
= cfil_data_length(data
, &mbcnt
, &mbnum
);
3813 CFIL_LOG(LOG_DEBUG
, "CFIL: SERVICE INJECT-Q: <%s>: <so %llx> data %llx datalen %u (mbcnt %u)",
3814 remote_addr_ptr
? "UNCONNECTED" : "CONNECTED",
3815 (uint64_t)VM_KERNEL_ADDRPERM(so
), (uint64_t)VM_KERNEL_ADDRPERM(data
), datalen
, mbcnt
);
3818 /* Remove data from queue and adjust stats */
3819 cfil_queue_remove(inject_q
, data
, datalen
);
3820 cfi_buf
->cfi_pending_first
+= datalen
;
3821 cfi_buf
->cfi_pending_mbcnt
-= mbcnt
;
3822 cfi_buf
->cfi_pending_mbnum
-= mbnum
;
3823 cfil_info_buf_verify(cfi_buf
);
3826 error
= sosend_reinject(so
, NULL
, data
, NULL
, 0);
3829 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: Error: sosend_reinject() failed");
3830 CFIL_LOG(LOG_ERR
, "### sosend() failed %d", error
);
3834 // At least one injection succeeded, need to wake up pending threads.
3837 data
->m_flags
|= M_SKIPCFIL
;
3840 * NOTE: We currently only support TCP and UDP.
3841 * For RAWIP, MPTCP and message TCP we'll
3842 * need to call the appropriate sbappendxxx()
3843 * of fix sock_inject_data_in()
3845 if (IS_UDP(so
) == TRUE
) {
3846 if (sbappendchain(&so
->so_rcv
, data
, 0)) {
3850 if (sbappendstream(&so
->so_rcv
, data
)) {
3857 OSAddAtomic64(datalen
,
3858 &cfil_stats
.cfs_inject_q_out_passed
);
3860 OSAddAtomic64(datalen
,
3861 &cfil_stats
.cfs_inject_q_in_passed
);
3867 #if DATA_DEBUG | VERDICT_DEBUG
3868 CFIL_LOG(LOG_ERR
, "CFIL: SERVICE INJECT-Q: <so %llx> injected %d",
3869 (uint64_t)VM_KERNEL_ADDRPERM(so
), count
);
3872 /* A single wakeup is for several packets is more efficient */
3874 if (outgoing
== TRUE
) {
3881 if (error
!= 0 && cfil_info
) {
3882 if (error
== ENOBUFS
) {
3883 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_nobufs
);
3885 if (error
== ENOMEM
) {
3886 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_nomem
);
3890 cfil_info
->cfi_flags
|= CFIF_RETRY_INJECT_OUT
;
3891 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_out_fail
);
3893 cfil_info
->cfi_flags
|= CFIF_RETRY_INJECT_IN
;
3894 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_in_fail
);
3901 if (cfil_info
&& (cfil_info
->cfi_flags
& CFIF_SHUT_WR
)) {
3902 cfil_sock_notify_shutdown(so
, SHUT_WR
);
3903 if (cfil_sock_data_pending(&so
->so_snd
) == 0) {
3904 soshutdownlock_final(so
, SHUT_WR
);
3907 if (cfil_info
&& (cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
)) {
3908 if (cfil_filters_attached(so
) == 0) {
3909 CFIL_LOG(LOG_INFO
, "so %llx waking",
3910 (uint64_t)VM_KERNEL_ADDRPERM(so
));
3911 wakeup((caddr_t
)cfil_info
);
3915 CFIL_INFO_VERIFY(cfil_info
);
3921 cfil_service_pending_queue(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
)
3923 uint64_t passlen
, curlen
;
3925 unsigned int datalen
;
3927 struct cfil_entry
*entry
;
3928 struct cfe_buf
*entrybuf
;
3929 struct cfil_queue
*pending_q
;
3931 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3932 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3934 socket_lock_assert_owned(so
);
3936 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3938 entrybuf
= &entry
->cfe_snd
;
3940 entrybuf
= &entry
->cfe_rcv
;
3943 pending_q
= &entrybuf
->cfe_pending_q
;
3945 passlen
= entrybuf
->cfe_pass_offset
- pending_q
->q_start
;
3948 * Locate the chunks of data that we can pass to the next filter
3949 * A data chunk must be on mbuf boundaries
3952 while ((data
= cfil_queue_first(pending_q
)) != NULL
) {
3953 struct cfil_entry
*iter_entry
;
3954 datalen
= cfil_data_length(data
, NULL
, NULL
);
3958 "CFIL: SERVICE PENDING-Q: data %llx datalen %u passlen %llu curlen %llu",
3959 (uint64_t)VM_KERNEL_ADDRPERM(data
), datalen
,
3963 if (curlen
+ datalen
> passlen
) {
3967 cfil_queue_remove(pending_q
, data
, datalen
);
3971 for (iter_entry
= SLIST_NEXT(entry
, cfe_order_link
);
3973 iter_entry
= SLIST_NEXT(iter_entry
, cfe_order_link
)) {
3974 error
= cfil_data_filter(so
, cfil_info
, CFI_ENTRY_KCUNIT(cfil_info
, iter_entry
), outgoing
,
3976 /* 0 means passed so we can continue */
3981 /* When data has passed all filters, re-inject */
3985 &cfil_info
->cfi_snd
.cfi_inject_q
,
3987 OSAddAtomic64(datalen
,
3988 &cfil_stats
.cfs_inject_q_out_enqueued
);
3991 &cfil_info
->cfi_rcv
.cfi_inject_q
,
3993 OSAddAtomic64(datalen
,
3994 &cfil_stats
.cfs_inject_q_in_enqueued
);
3999 CFIL_INFO_VERIFY(cfil_info
);
4005 cfil_update_data_offsets(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
4006 uint64_t pass_offset
, uint64_t peek_offset
)
4009 struct cfil_entry
*entry
= NULL
;
4010 struct cfe_buf
*entrybuf
;
4013 CFIL_LOG(LOG_INFO
, "pass %llu peek %llu", pass_offset
, peek_offset
);
4015 socket_lock_assert_owned(so
);
4017 if (cfil_info
== NULL
) {
4018 CFIL_LOG(LOG_ERR
, "so %llx cfil detached",
4019 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4022 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4023 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4024 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4029 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4031 entrybuf
= &entry
->cfe_snd
;
4033 entrybuf
= &entry
->cfe_rcv
;
4036 /* Record updated offsets for this content filter */
4037 if (pass_offset
> entrybuf
->cfe_pass_offset
) {
4038 entrybuf
->cfe_pass_offset
= pass_offset
;
4040 if (entrybuf
->cfe_peek_offset
< entrybuf
->cfe_pass_offset
) {
4041 entrybuf
->cfe_peek_offset
= entrybuf
->cfe_pass_offset
;
4045 CFIL_LOG(LOG_INFO
, "pass_offset %llu <= cfe_pass_offset %llu",
4046 pass_offset
, entrybuf
->cfe_pass_offset
);
4048 /* Filter does not want or need to see data that's allowed to pass */
4049 if (peek_offset
> entrybuf
->cfe_pass_offset
&&
4050 peek_offset
> entrybuf
->cfe_peek_offset
) {
4051 entrybuf
->cfe_peek_offset
= peek_offset
;
4059 /* Move data held in control queue to pending queue if needed */
4060 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, outgoing
);
4062 CFIL_LOG(LOG_ERR
, "cfil_data_service_ctl_q() error %d",
4066 error
= EJUSTRETURN
;
4070 * The filter is effectively detached when pass all from both sides
4071 * or when the socket is closed and no more data is waiting
4072 * to be delivered to the filter
4074 if (entry
!= NULL
&&
4075 ((entry
->cfe_snd
.cfe_pass_offset
== CFM_MAX_OFFSET
&&
4076 entry
->cfe_rcv
.cfe_pass_offset
== CFM_MAX_OFFSET
) ||
4077 ((cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) &&
4078 cfil_queue_empty(&entry
->cfe_snd
.cfe_ctl_q
) &&
4079 cfil_queue_empty(&entry
->cfe_rcv
.cfe_ctl_q
)))) {
4080 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
4082 cfil_info_log(LOG_ERR
, cfil_info
, outgoing
?
4083 "CFIL: LIFECYCLE: OUT - PASSED ALL - DETACH":
4084 "CFIL: LIFECYCLE: IN - PASSED ALL - DETACH");
4086 CFIL_LOG(LOG_INFO
, "so %llx detached %u",
4087 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
4088 if ((cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) &&
4089 cfil_filters_attached(so
) == 0) {
4091 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAKING");
4093 CFIL_LOG(LOG_INFO
, "so %llx waking",
4094 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4095 wakeup((caddr_t
)cfil_info
);
4098 CFIL_INFO_VERIFY(cfil_info
);
4099 CFIL_LOG(LOG_INFO
, "return %d", error
);
4104 * Update pass offset for socket when no data is pending
4107 cfil_set_socket_pass_offset(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
)
4109 struct cfi_buf
*cfi_buf
;
4110 struct cfil_entry
*entry
;
4111 struct cfe_buf
*entrybuf
;
4113 uint64_t pass_offset
= 0;
4115 if (cfil_info
== NULL
) {
4119 CFIL_LOG(LOG_INFO
, "so %llx outgoing %d",
4120 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
);
4122 socket_lock_assert_owned(so
);
4125 cfi_buf
= &cfil_info
->cfi_snd
;
4127 cfi_buf
= &cfil_info
->cfi_rcv
;
4130 CFIL_LOG(LOG_DEBUG
, "CFIL: <so %llx, sockID %llu> outgoing %d cfi_pending_first %llu cfi_pending_last %llu",
4131 (uint64_t)VM_KERNEL_ADDRPERM(so
), cfil_info
->cfi_sock_id
, outgoing
,
4132 cfi_buf
->cfi_pending_first
, cfi_buf
->cfi_pending_last
);
4134 if (cfi_buf
->cfi_pending_last
- cfi_buf
->cfi_pending_first
== 0) {
4135 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4136 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4138 /* Are we attached to a filter? */
4139 if (entry
->cfe_filter
== NULL
) {
4144 entrybuf
= &entry
->cfe_snd
;
4146 entrybuf
= &entry
->cfe_rcv
;
4149 if (pass_offset
== 0 ||
4150 entrybuf
->cfe_pass_offset
< pass_offset
) {
4151 pass_offset
= entrybuf
->cfe_pass_offset
;
4154 cfi_buf
->cfi_pass_offset
= pass_offset
;
4157 CFIL_LOG(LOG_DEBUG
, "CFIL: <so %llx, sockID %llu>, cfi_pass_offset %llu",
4158 (uint64_t)VM_KERNEL_ADDRPERM(so
), cfil_info
->cfi_sock_id
, cfi_buf
->cfi_pass_offset
);
4164 cfil_action_data_pass(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
4165 uint64_t pass_offset
, uint64_t peek_offset
)
4169 CFIL_LOG(LOG_INFO
, "");
4171 socket_lock_assert_owned(so
);
4173 error
= cfil_acquire_sockbuf(so
, cfil_info
, outgoing
);
4175 CFIL_LOG(LOG_INFO
, "so %llx %s dropped",
4176 (uint64_t)VM_KERNEL_ADDRPERM(so
),
4177 outgoing
? "out" : "in");
4181 error
= cfil_update_data_offsets(so
, cfil_info
, kcunit
, outgoing
,
4182 pass_offset
, peek_offset
);
4184 cfil_service_inject_queue(so
, cfil_info
, outgoing
);
4186 cfil_set_socket_pass_offset(so
, cfil_info
, outgoing
);
4188 CFIL_INFO_VERIFY(cfil_info
);
4189 cfil_release_sockbuf(so
, outgoing
);
4196 cfil_flush_queues(struct socket
*so
, struct cfil_info
*cfil_info
)
4198 struct cfil_entry
*entry
;
4202 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || cfil_info
== NULL
) {
4206 socket_lock_assert_owned(so
);
4209 * Flush the output queues and ignore errors as long as
4212 (void) cfil_acquire_sockbuf(so
, cfil_info
, 1);
4213 if (cfil_info
!= NULL
) {
4215 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4216 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4218 drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_ctl_q
);
4219 drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_pending_q
);
4221 drained
+= cfil_queue_drain(&cfil_info
->cfi_snd
.cfi_inject_q
);
4224 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4226 &cfil_stats
.cfs_flush_out_drop
);
4229 &cfil_stats
.cfs_flush_out_close
);
4233 cfil_release_sockbuf(so
, 1);
4236 * Flush the input queues
4238 (void) cfil_acquire_sockbuf(so
, cfil_info
, 0);
4239 if (cfil_info
!= NULL
) {
4241 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4242 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4244 drained
+= cfil_queue_drain(
4245 &entry
->cfe_rcv
.cfe_ctl_q
);
4246 drained
+= cfil_queue_drain(
4247 &entry
->cfe_rcv
.cfe_pending_q
);
4249 drained
+= cfil_queue_drain(&cfil_info
->cfi_rcv
.cfi_inject_q
);
4252 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4254 &cfil_stats
.cfs_flush_in_drop
);
4257 &cfil_stats
.cfs_flush_in_close
);
4261 cfil_release_sockbuf(so
, 0);
4263 CFIL_INFO_VERIFY(cfil_info
);
4267 cfil_action_drop(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
)
4270 struct cfil_entry
*entry
;
4273 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || cfil_info
== NULL
) {
4277 socket_lock_assert_owned(so
);
4279 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4281 /* Are we attached to the filter? */
4282 if (entry
->cfe_filter
== NULL
) {
4286 cfil_info
->cfi_flags
|= CFIF_DROP
;
4291 * Force the socket to be marked defunct
4292 * (forcing fixed along with rdar://19391339)
4294 if (so
->so_cfil_db
== NULL
) {
4295 error
= sosetdefunct(p
, so
,
4296 SHUTDOWN_SOCKET_LEVEL_CONTENT_FILTER
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
,
4299 /* Flush the socket buffer and disconnect */
4301 error
= sodefunct(p
, so
,
4302 SHUTDOWN_SOCKET_LEVEL_CONTENT_FILTER
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
);
4306 /* The filter is done, mark as detached */
4307 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
4309 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: DROP - DETACH");
4311 CFIL_LOG(LOG_INFO
, "so %llx detached %u",
4312 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
4314 /* Pending data needs to go */
4315 cfil_flush_queues(so
, cfil_info
);
4317 if (cfil_info
&& (cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
)) {
4318 if (cfil_filters_attached(so
) == 0) {
4319 CFIL_LOG(LOG_INFO
, "so %llx waking",
4320 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4321 wakeup((caddr_t
)cfil_info
);
4329 cfil_action_bless_client(uint32_t kcunit
, struct cfil_msg_hdr
*msghdr
)
4332 struct cfil_info
*cfil_info
= NULL
;
4334 bool cfil_attached
= false;
4335 struct cfil_msg_bless_client
*blessmsg
= (struct cfil_msg_bless_client
*)msghdr
;
4337 // Search and lock socket
4338 struct socket
*so
= cfil_socket_from_client_uuid(blessmsg
->cfb_client_uuid
, &cfil_attached
);
4342 // The client gets a pass automatically
4343 cfil_info
= (so
->so_cfil_db
!= NULL
) ?
4344 cfil_db_get_cfil_info(so
->so_cfil_db
, msghdr
->cfm_sock_id
) : so
->so_cfil
;
4346 if (cfil_attached
) {
4348 if (cfil_info
!= NULL
) {
4349 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT RECEIVED: BLESS %s <so %llx sockID %llu>",
4350 cfil_info
->cfi_hash_entry
? "UDP" : "TCP",
4351 (uint64_t)VM_KERNEL_ADDRPERM(so
),
4352 cfil_info
->cfi_sock_id
);
4355 cfil_sock_received_verdict(so
);
4356 (void)cfil_action_data_pass(so
, cfil_info
, kcunit
, 1, CFM_MAX_OFFSET
, CFM_MAX_OFFSET
);
4357 (void)cfil_action_data_pass(so
, cfil_info
, kcunit
, 0, CFM_MAX_OFFSET
, CFM_MAX_OFFSET
);
4359 so
->so_flags1
|= SOF1_CONTENT_FILTER_SKIP
;
4361 socket_unlock(so
, 1);
4368 cfil_action_set_crypto_key(uint32_t kcunit
, struct cfil_msg_hdr
*msghdr
)
4370 struct content_filter
*cfc
= NULL
;
4371 cfil_crypto_state_t crypto_state
= NULL
;
4372 struct cfil_msg_set_crypto_key
*keymsg
= (struct cfil_msg_set_crypto_key
*)msghdr
;
4374 CFIL_LOG(LOG_NOTICE
, "");
4376 if (content_filters
== NULL
) {
4377 CFIL_LOG(LOG_ERR
, "no content filter");
4380 if (kcunit
> MAX_CONTENT_FILTER
) {
4381 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
4382 kcunit
, MAX_CONTENT_FILTER
);
4385 crypto_state
= cfil_crypto_init_client((uint8_t *)keymsg
->crypto_key
);
4386 if (crypto_state
== NULL
) {
4387 CFIL_LOG(LOG_ERR
, "failed to initialize crypto state for unit %u)",
4392 cfil_rw_lock_exclusive(&cfil_lck_rw
);
4394 cfc
= content_filters
[kcunit
- 1];
4395 if (cfc
->cf_kcunit
!= kcunit
) {
4396 CFIL_LOG(LOG_ERR
, "bad unit info %u)",
4398 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
4399 cfil_crypto_cleanup_state(crypto_state
);
4402 if (cfc
->cf_crypto_state
!= NULL
) {
4403 cfil_crypto_cleanup_state(cfc
->cf_crypto_state
);
4404 cfc
->cf_crypto_state
= NULL
;
4406 cfc
->cf_crypto_state
= crypto_state
;
4408 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
4413 cfil_update_entry_offsets(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
, unsigned int datalen
)
4415 struct cfil_entry
*entry
;
4416 struct cfe_buf
*entrybuf
;
4419 CFIL_LOG(LOG_INFO
, "so %llx outgoing %d datalen %u",
4420 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
, datalen
);
4422 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4423 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4425 /* Are we attached to the filter? */
4426 if (entry
->cfe_filter
== NULL
) {
4431 entrybuf
= &entry
->cfe_snd
;
4433 entrybuf
= &entry
->cfe_rcv
;
4436 entrybuf
->cfe_ctl_q
.q_start
+= datalen
;
4437 entrybuf
->cfe_pass_offset
= entrybuf
->cfe_ctl_q
.q_start
;
4438 entrybuf
->cfe_peeked
= entrybuf
->cfe_ctl_q
.q_start
;
4439 if (entrybuf
->cfe_peek_offset
< entrybuf
->cfe_pass_offset
) {
4440 entrybuf
->cfe_peek_offset
= entrybuf
->cfe_pass_offset
;
4443 entrybuf
->cfe_ctl_q
.q_end
+= datalen
;
4445 entrybuf
->cfe_pending_q
.q_start
+= datalen
;
4446 entrybuf
->cfe_pending_q
.q_end
+= datalen
;
4448 CFIL_INFO_VERIFY(cfil_info
);
4453 cfil_data_common(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
, struct sockaddr
*to
,
4454 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
4456 #pragma unused(to, control, flags)
4458 unsigned int datalen
;
4462 struct cfi_buf
*cfi_buf
;
4463 struct mbuf
*chain
= NULL
;
4465 if (cfil_info
== NULL
) {
4466 CFIL_LOG(LOG_ERR
, "so %llx cfil detached",
4467 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4470 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4471 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4472 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4477 datalen
= cfil_data_length(data
, &mbcnt
, &mbnum
);
4480 cfi_buf
= &cfil_info
->cfi_snd
;
4481 cfil_info
->cfi_byte_outbound_count
+= datalen
;
4483 cfi_buf
= &cfil_info
->cfi_rcv
;
4484 cfil_info
->cfi_byte_inbound_count
+= datalen
;
4487 cfi_buf
->cfi_pending_last
+= datalen
;
4488 cfi_buf
->cfi_pending_mbcnt
+= mbcnt
;
4489 cfi_buf
->cfi_pending_mbnum
+= mbnum
;
4492 if (cfi_buf
->cfi_pending_mbnum
> cfil_udp_gc_mbuf_num_max
||
4493 cfi_buf
->cfi_pending_mbcnt
> cfil_udp_gc_mbuf_cnt_max
) {
4494 cfi_buf
->cfi_tail_drop_cnt
++;
4495 cfi_buf
->cfi_pending_mbcnt
-= mbcnt
;
4496 cfi_buf
->cfi_pending_mbnum
-= mbnum
;
4501 cfil_info_buf_verify(cfi_buf
);
4504 CFIL_LOG(LOG_DEBUG
, "CFIL: QUEUEING DATA: <so %llx> %s: data %llx len %u flags 0x%x nextpkt %llx - cfi_pending_last %llu cfi_pending_mbcnt %u cfi_pass_offset %llu",
4505 (uint64_t)VM_KERNEL_ADDRPERM(so
),
4506 outgoing
? "OUT" : "IN",
4507 (uint64_t)VM_KERNEL_ADDRPERM(data
), datalen
, data
->m_flags
,
4508 (uint64_t)VM_KERNEL_ADDRPERM(data
->m_nextpkt
),
4509 cfi_buf
->cfi_pending_last
,
4510 cfi_buf
->cfi_pending_mbcnt
,
4511 cfi_buf
->cfi_pass_offset
);
4514 /* Fast path when below pass offset */
4515 if (cfi_buf
->cfi_pending_last
<= cfi_buf
->cfi_pass_offset
) {
4516 cfil_update_entry_offsets(so
, cfil_info
, outgoing
, datalen
);
4518 CFIL_LOG(LOG_DEBUG
, "CFIL: QUEUEING DATA: FAST PATH");
4521 struct cfil_entry
*iter_entry
;
4522 SLIST_FOREACH(iter_entry
, &cfil_info
->cfi_ordered_entries
, cfe_order_link
) {
4523 // Is cfil attached to this filter?
4524 kcunit
= CFI_ENTRY_KCUNIT(cfil_info
, iter_entry
);
4525 if (IS_ENTRY_ATTACHED(cfil_info
, kcunit
)) {
4526 if (IS_UDP(so
) && chain
== NULL
) {
4528 * Chain addr (incoming only TDB), control (optional) and data into one chain.
4529 * This full chain will be reinjected into socket after recieving verdict.
4531 (void) cfil_udp_save_socket_state(cfil_info
, data
);
4532 chain
= sbconcat_mbufs(NULL
, outgoing
? NULL
: to
, data
, control
);
4533 if (chain
== NULL
) {
4538 error
= cfil_data_filter(so
, cfil_info
, kcunit
, outgoing
, data
,
4541 /* 0 means passed so continue with next filter */
4548 /* Move cursor if no filter claimed the data */
4550 cfi_buf
->cfi_pending_first
+= datalen
;
4551 cfi_buf
->cfi_pending_mbcnt
-= mbcnt
;
4552 cfi_buf
->cfi_pending_mbnum
-= mbnum
;
4553 cfil_info_buf_verify(cfi_buf
);
4556 CFIL_INFO_VERIFY(cfil_info
);
4562 * Callback from socket layer sosendxxx()
4565 cfil_sock_data_out(struct socket
*so
, struct sockaddr
*to
,
4566 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
4571 return cfil_sock_udp_handle_data(TRUE
, so
, NULL
, to
, data
, control
, flags
);
4574 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4579 * Pass initial data for TFO.
4581 if (IS_INITIAL_TFO_DATA(so
)) {
4585 socket_lock_assert_owned(so
);
4587 if (so
->so_cfil
->cfi_flags
& CFIF_DROP
) {
4588 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4589 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4592 if (control
!= NULL
) {
4593 CFIL_LOG(LOG_ERR
, "so %llx control",
4594 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4595 OSIncrementAtomic(&cfil_stats
.cfs_data_out_control
);
4597 if ((flags
& MSG_OOB
)) {
4598 CFIL_LOG(LOG_ERR
, "so %llx MSG_OOB",
4599 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4600 OSIncrementAtomic(&cfil_stats
.cfs_data_out_oob
);
4602 if ((so
->so_snd
.sb_flags
& SB_LOCK
) == 0) {
4603 panic("so %p SB_LOCK not set", so
);
4606 if (so
->so_snd
.sb_cfil_thread
!= NULL
) {
4607 panic("%s sb_cfil_thread %p not NULL", __func__
,
4608 so
->so_snd
.sb_cfil_thread
);
4611 error
= cfil_data_common(so
, so
->so_cfil
, 1, to
, data
, control
, flags
);
4617 * Callback from socket layer sbappendxxx()
4620 cfil_sock_data_in(struct socket
*so
, struct sockaddr
*from
,
4621 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
4626 return cfil_sock_udp_handle_data(FALSE
, so
, NULL
, from
, data
, control
, flags
);
4629 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4634 * Pass initial data for TFO.
4636 if (IS_INITIAL_TFO_DATA(so
)) {
4640 socket_lock_assert_owned(so
);
4642 if (so
->so_cfil
->cfi_flags
& CFIF_DROP
) {
4643 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4644 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4647 if (control
!= NULL
) {
4648 CFIL_LOG(LOG_ERR
, "so %llx control",
4649 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4650 OSIncrementAtomic(&cfil_stats
.cfs_data_in_control
);
4652 if (data
->m_type
== MT_OOBDATA
) {
4653 CFIL_LOG(LOG_ERR
, "so %llx MSG_OOB",
4654 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4655 OSIncrementAtomic(&cfil_stats
.cfs_data_in_oob
);
4657 error
= cfil_data_common(so
, so
->so_cfil
, 0, from
, data
, control
, flags
);
4663 * Callback from socket layer soshutdownxxx()
4665 * We may delay the shutdown write if there's outgoing data in process.
4667 * There is no point in delaying the shutdown read because the process
4668 * indicated that it does not want to read anymore data.
4671 cfil_sock_shutdown(struct socket
*so
, int *how
)
4676 return cfil_sock_udp_shutdown(so
, how
);
4679 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4683 socket_lock_assert_owned(so
);
4685 CFIL_LOG(LOG_INFO
, "so %llx how %d",
4686 (uint64_t)VM_KERNEL_ADDRPERM(so
), *how
);
4689 * Check the state of the socket before the content filter
4691 if (*how
!= SHUT_WR
&& (so
->so_state
& SS_CANTRCVMORE
) != 0) {
4692 /* read already shut down */
4696 if (*how
!= SHUT_RD
&& (so
->so_state
& SS_CANTSENDMORE
) != 0) {
4697 /* write already shut down */
4702 if ((so
->so_cfil
->cfi_flags
& CFIF_DROP
) != 0) {
4703 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4704 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4709 * shutdown read: SHUT_RD or SHUT_RDWR
4711 if (*how
!= SHUT_WR
) {
4712 if (so
->so_cfil
->cfi_flags
& CFIF_SHUT_RD
) {
4716 so
->so_cfil
->cfi_flags
|= CFIF_SHUT_RD
;
4717 cfil_sock_notify_shutdown(so
, SHUT_RD
);
4720 * shutdown write: SHUT_WR or SHUT_RDWR
4722 if (*how
!= SHUT_RD
) {
4723 if (so
->so_cfil
->cfi_flags
& CFIF_SHUT_WR
) {
4727 so
->so_cfil
->cfi_flags
|= CFIF_SHUT_WR
;
4728 cfil_sock_notify_shutdown(so
, SHUT_WR
);
4730 * When outgoing data is pending, we delay the shutdown at the
4731 * protocol level until the content filters give the final
4732 * verdict on the pending data.
4734 if (cfil_sock_data_pending(&so
->so_snd
) != 0) {
4736 * When shutting down the read and write sides at once
4737 * we can proceed to the final shutdown of the read
4738 * side. Otherwise, we just return.
4740 if (*how
== SHUT_WR
) {
4741 error
= EJUSTRETURN
;
4742 } else if (*how
== SHUT_RDWR
) {
4752 * This is called when the socket is closed and there is no more
4753 * opportunity for filtering
4756 cfil_sock_is_closed(struct socket
*so
)
4762 cfil_sock_udp_is_closed(so
);
4766 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4770 CFIL_LOG(LOG_INFO
, "so %llx", (uint64_t)VM_KERNEL_ADDRPERM(so
));
4772 socket_lock_assert_owned(so
);
4774 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4775 /* Let the filters know of the closing */
4776 error
= cfil_dispatch_closed_event(so
, so
->so_cfil
, kcunit
);
4779 /* Last chance to push passed data out */
4780 error
= cfil_acquire_sockbuf(so
, so
->so_cfil
, 1);
4782 cfil_service_inject_queue(so
, so
->so_cfil
, 1);
4784 cfil_release_sockbuf(so
, 1);
4786 so
->so_cfil
->cfi_flags
|= CFIF_SOCK_CLOSED
;
4788 /* Pending data needs to go */
4789 cfil_flush_queues(so
, so
->so_cfil
);
4791 CFIL_INFO_VERIFY(so
->so_cfil
);
4795 * This is called when the socket is disconnected so let the filters
4796 * know about the disconnection and that no more data will come
4798 * The how parameter has the same values as soshutown()
4801 cfil_sock_notify_shutdown(struct socket
*so
, int how
)
4807 cfil_sock_udp_notify_shutdown(so
, how
, 0, 0);
4811 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4815 CFIL_LOG(LOG_INFO
, "so %llx how %d",
4816 (uint64_t)VM_KERNEL_ADDRPERM(so
), how
);
4818 socket_lock_assert_owned(so
);
4820 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4821 /* Disconnect incoming side */
4822 if (how
!= SHUT_WR
) {
4823 error
= cfil_dispatch_disconnect_event(so
, so
->so_cfil
, kcunit
, 0);
4825 /* Disconnect outgoing side */
4826 if (how
!= SHUT_RD
) {
4827 error
= cfil_dispatch_disconnect_event(so
, so
->so_cfil
, kcunit
, 1);
4833 cfil_filters_attached(struct socket
*so
)
4835 struct cfil_entry
*entry
;
4840 return cfil_filters_udp_attached(so
, FALSE
);
4843 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4847 socket_lock_assert_owned(so
);
4849 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4850 entry
= &so
->so_cfil
->cfi_entries
[kcunit
- 1];
4852 /* Are we attached to the filter? */
4853 if (entry
->cfe_filter
== NULL
) {
4856 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
4859 if ((entry
->cfe_flags
& CFEF_CFIL_DETACHED
) != 0) {
4870 * This is called when the socket is closed and we are waiting for
4871 * the filters to gives the final pass or drop
4874 cfil_sock_close_wait(struct socket
*so
)
4876 lck_mtx_t
*mutex_held
;
4881 cfil_sock_udp_close_wait(so
);
4885 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4889 CFIL_LOG(LOG_INFO
, "so %llx", (uint64_t)VM_KERNEL_ADDRPERM(so
));
4891 if (so
->so_proto
->pr_getlock
!= NULL
) {
4892 mutex_held
= (*so
->so_proto
->pr_getlock
)(so
, PR_F_WILLUNLOCK
);
4894 mutex_held
= so
->so_proto
->pr_domain
->dom_mtx
;
4896 LCK_MTX_ASSERT(mutex_held
, LCK_MTX_ASSERT_OWNED
);
4898 while (cfil_filters_attached(so
)) {
4900 * Notify the filters we are going away so they can detach
4902 cfil_sock_notify_shutdown(so
, SHUT_RDWR
);
4905 * Make sure we need to wait after the filter are notified
4906 * of the disconnection
4908 if (cfil_filters_attached(so
) == 0) {
4912 CFIL_LOG(LOG_INFO
, "so %llx waiting",
4913 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4915 ts
.tv_sec
= cfil_close_wait_timeout
/ 1000;
4916 ts
.tv_nsec
= (cfil_close_wait_timeout
% 1000) *
4917 NSEC_PER_USEC
* 1000;
4919 OSIncrementAtomic(&cfil_stats
.cfs_close_wait
);
4920 so
->so_cfil
->cfi_flags
|= CFIF_CLOSE_WAIT
;
4921 error
= msleep((caddr_t
)so
->so_cfil
, mutex_held
,
4922 PSOCK
| PCATCH
, "cfil_sock_close_wait", &ts
);
4923 so
->so_cfil
->cfi_flags
&= ~CFIF_CLOSE_WAIT
;
4925 CFIL_LOG(LOG_NOTICE
, "so %llx timed out %d",
4926 (uint64_t)VM_KERNEL_ADDRPERM(so
), (error
!= 0));
4929 * Force close in case of timeout
4932 OSIncrementAtomic(&cfil_stats
.cfs_close_wait_timeout
);
4939 * Returns the size of the data held by the content filter by using
4942 cfil_sock_data_pending(struct sockbuf
*sb
)
4944 struct socket
*so
= sb
->sb_so
;
4945 uint64_t pending
= 0;
4948 return cfil_sock_udp_data_pending(sb
, FALSE
);
4951 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil
!= NULL
) {
4952 struct cfi_buf
*cfi_buf
;
4954 socket_lock_assert_owned(so
);
4956 if ((sb
->sb_flags
& SB_RECV
) == 0) {
4957 cfi_buf
= &so
->so_cfil
->cfi_snd
;
4959 cfi_buf
= &so
->so_cfil
->cfi_rcv
;
4962 pending
= cfi_buf
->cfi_pending_last
-
4963 cfi_buf
->cfi_pending_first
;
4966 * If we are limited by the "chars of mbufs used" roughly
4967 * adjust so we won't overcommit
4969 if (pending
> (uint64_t)cfi_buf
->cfi_pending_mbcnt
) {
4970 pending
= cfi_buf
->cfi_pending_mbcnt
;
4974 VERIFY(pending
< INT32_MAX
);
4976 return (int32_t)(pending
);
4980 * Return the socket buffer space used by data being held by content filters
4981 * so processes won't clog the socket buffer
4984 cfil_sock_data_space(struct sockbuf
*sb
)
4986 struct socket
*so
= sb
->sb_so
;
4987 uint64_t pending
= 0;
4990 return cfil_sock_udp_data_pending(sb
, TRUE
);
4993 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil
!= NULL
&&
4994 so
->so_snd
.sb_cfil_thread
!= current_thread()) {
4995 struct cfi_buf
*cfi_buf
;
4997 socket_lock_assert_owned(so
);
4999 if ((sb
->sb_flags
& SB_RECV
) == 0) {
5000 cfi_buf
= &so
->so_cfil
->cfi_snd
;
5002 cfi_buf
= &so
->so_cfil
->cfi_rcv
;
5005 pending
= cfi_buf
->cfi_pending_last
-
5006 cfi_buf
->cfi_pending_first
;
5009 * If we are limited by the "chars of mbufs used" roughly
5010 * adjust so we won't overcommit
5012 if ((uint64_t)cfi_buf
->cfi_pending_mbcnt
> pending
) {
5013 pending
= cfi_buf
->cfi_pending_mbcnt
;
5017 VERIFY(pending
< INT32_MAX
);
5019 return (int32_t)(pending
);
5023 * A callback from the socket and protocol layer when data becomes
5024 * available in the socket buffer to give a chance for the content filter
5025 * to re-inject data that was held back
5028 cfil_sock_buf_update(struct sockbuf
*sb
)
5032 struct socket
*so
= sb
->sb_so
;
5035 cfil_sock_udp_buf_update(sb
);
5039 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
5047 socket_lock_assert_owned(so
);
5049 if ((sb
->sb_flags
& SB_RECV
) == 0) {
5050 if ((so
->so_cfil
->cfi_flags
& CFIF_RETRY_INJECT_OUT
) == 0) {
5054 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_out_retry
);
5056 if ((so
->so_cfil
->cfi_flags
& CFIF_RETRY_INJECT_IN
) == 0) {
5060 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_in_retry
);
5063 CFIL_LOG(LOG_NOTICE
, "so %llx outgoing %d",
5064 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
);
5066 error
= cfil_acquire_sockbuf(so
, so
->so_cfil
, outgoing
);
5068 cfil_service_inject_queue(so
, so
->so_cfil
, outgoing
);
5070 cfil_release_sockbuf(so
, outgoing
);
5074 sysctl_cfil_filter_list(struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
5075 struct sysctl_req
*req
)
5077 #pragma unused(oidp, arg1, arg2)
5083 if (req
->newptr
!= USER_ADDR_NULL
) {
5087 cfil_rw_lock_shared(&cfil_lck_rw
);
5089 for (i
= 0; content_filters
!= NULL
&& i
< MAX_CONTENT_FILTER
; i
++) {
5090 struct cfil_filter_stat filter_stat
;
5091 struct content_filter
*cfc
= content_filters
[i
];
5097 /* If just asking for the size */
5098 if (req
->oldptr
== USER_ADDR_NULL
) {
5099 len
+= sizeof(struct cfil_filter_stat
);
5103 bzero(&filter_stat
, sizeof(struct cfil_filter_stat
));
5104 filter_stat
.cfs_len
= sizeof(struct cfil_filter_stat
);
5105 filter_stat
.cfs_filter_id
= cfc
->cf_kcunit
;
5106 filter_stat
.cfs_flags
= cfc
->cf_flags
;
5107 filter_stat
.cfs_sock_count
= cfc
->cf_sock_count
;
5108 filter_stat
.cfs_necp_control_unit
= cfc
->cf_necp_control_unit
;
5110 error
= SYSCTL_OUT(req
, &filter_stat
,
5111 sizeof(struct cfil_filter_stat
));
5116 /* If just asking for the size */
5117 if (req
->oldptr
== USER_ADDR_NULL
) {
5121 cfil_rw_unlock_shared(&cfil_lck_rw
);
5124 if (req
->oldptr
!= USER_ADDR_NULL
) {
5125 for (i
= 1; content_filters
!= NULL
&& i
<= MAX_CONTENT_FILTER
; i
++) {
5126 cfil_filter_show(i
);
5135 sysctl_cfil_sock_list(struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
5136 struct sysctl_req
*req
)
5138 #pragma unused(oidp, arg1, arg2)
5141 struct cfil_info
*cfi
;
5144 if (req
->newptr
!= USER_ADDR_NULL
) {
5148 cfil_rw_lock_shared(&cfil_lck_rw
);
5151 * If just asking for the size,
5153 if (req
->oldptr
== USER_ADDR_NULL
) {
5154 req
->oldidx
= cfil_sock_attached_count
*
5155 sizeof(struct cfil_sock_stat
);
5156 /* Bump the length in case new sockets gets attached */
5157 req
->oldidx
+= req
->oldidx
>> 3;
5161 TAILQ_FOREACH(cfi
, &cfil_sock_head
, cfi_link
) {
5162 struct cfil_entry
*entry
;
5163 struct cfil_sock_stat stat
;
5164 struct socket
*so
= cfi
->cfi_so
;
5166 bzero(&stat
, sizeof(struct cfil_sock_stat
));
5167 stat
.cfs_len
= sizeof(struct cfil_sock_stat
);
5168 stat
.cfs_sock_id
= cfi
->cfi_sock_id
;
5169 stat
.cfs_flags
= cfi
->cfi_flags
;
5172 stat
.cfs_pid
= so
->last_pid
;
5173 memcpy(stat
.cfs_uuid
, so
->last_uuid
,
5175 if (so
->so_flags
& SOF_DELEGATED
) {
5176 stat
.cfs_e_pid
= so
->e_pid
;
5177 memcpy(stat
.cfs_e_uuid
, so
->e_uuid
,
5180 stat
.cfs_e_pid
= so
->last_pid
;
5181 memcpy(stat
.cfs_e_uuid
, so
->last_uuid
,
5185 stat
.cfs_sock_family
= so
->so_proto
->pr_domain
->dom_family
;
5186 stat
.cfs_sock_type
= so
->so_proto
->pr_type
;
5187 stat
.cfs_sock_protocol
= so
->so_proto
->pr_protocol
;
5190 stat
.cfs_snd
.cbs_pending_first
=
5191 cfi
->cfi_snd
.cfi_pending_first
;
5192 stat
.cfs_snd
.cbs_pending_last
=
5193 cfi
->cfi_snd
.cfi_pending_last
;
5194 stat
.cfs_snd
.cbs_inject_q_len
=
5195 cfil_queue_len(&cfi
->cfi_snd
.cfi_inject_q
);
5196 stat
.cfs_snd
.cbs_pass_offset
=
5197 cfi
->cfi_snd
.cfi_pass_offset
;
5199 stat
.cfs_rcv
.cbs_pending_first
=
5200 cfi
->cfi_rcv
.cfi_pending_first
;
5201 stat
.cfs_rcv
.cbs_pending_last
=
5202 cfi
->cfi_rcv
.cfi_pending_last
;
5203 stat
.cfs_rcv
.cbs_inject_q_len
=
5204 cfil_queue_len(&cfi
->cfi_rcv
.cfi_inject_q
);
5205 stat
.cfs_rcv
.cbs_pass_offset
=
5206 cfi
->cfi_rcv
.cfi_pass_offset
;
5208 for (i
= 0; i
< MAX_CONTENT_FILTER
; i
++) {
5209 struct cfil_entry_stat
*estat
;
5210 struct cfe_buf
*ebuf
;
5211 struct cfe_buf_stat
*sbuf
;
5213 entry
= &cfi
->cfi_entries
[i
];
5215 estat
= &stat
.ces_entries
[i
];
5217 estat
->ces_len
= sizeof(struct cfil_entry_stat
);
5218 estat
->ces_filter_id
= entry
->cfe_filter
?
5219 entry
->cfe_filter
->cf_kcunit
: 0;
5220 estat
->ces_flags
= entry
->cfe_flags
;
5221 estat
->ces_necp_control_unit
=
5222 entry
->cfe_necp_control_unit
;
5224 estat
->ces_last_event
.tv_sec
=
5225 (int64_t)entry
->cfe_last_event
.tv_sec
;
5226 estat
->ces_last_event
.tv_usec
=
5227 (int64_t)entry
->cfe_last_event
.tv_usec
;
5229 estat
->ces_last_action
.tv_sec
=
5230 (int64_t)entry
->cfe_last_action
.tv_sec
;
5231 estat
->ces_last_action
.tv_usec
=
5232 (int64_t)entry
->cfe_last_action
.tv_usec
;
5234 ebuf
= &entry
->cfe_snd
;
5235 sbuf
= &estat
->ces_snd
;
5236 sbuf
->cbs_pending_first
=
5237 cfil_queue_offset_first(&ebuf
->cfe_pending_q
);
5238 sbuf
->cbs_pending_last
=
5239 cfil_queue_offset_last(&ebuf
->cfe_pending_q
);
5240 sbuf
->cbs_ctl_first
=
5241 cfil_queue_offset_first(&ebuf
->cfe_ctl_q
);
5242 sbuf
->cbs_ctl_last
=
5243 cfil_queue_offset_last(&ebuf
->cfe_ctl_q
);
5244 sbuf
->cbs_pass_offset
= ebuf
->cfe_pass_offset
;
5245 sbuf
->cbs_peek_offset
= ebuf
->cfe_peek_offset
;
5246 sbuf
->cbs_peeked
= ebuf
->cfe_peeked
;
5248 ebuf
= &entry
->cfe_rcv
;
5249 sbuf
= &estat
->ces_rcv
;
5250 sbuf
->cbs_pending_first
=
5251 cfil_queue_offset_first(&ebuf
->cfe_pending_q
);
5252 sbuf
->cbs_pending_last
=
5253 cfil_queue_offset_last(&ebuf
->cfe_pending_q
);
5254 sbuf
->cbs_ctl_first
=
5255 cfil_queue_offset_first(&ebuf
->cfe_ctl_q
);
5256 sbuf
->cbs_ctl_last
=
5257 cfil_queue_offset_last(&ebuf
->cfe_ctl_q
);
5258 sbuf
->cbs_pass_offset
= ebuf
->cfe_pass_offset
;
5259 sbuf
->cbs_peek_offset
= ebuf
->cfe_peek_offset
;
5260 sbuf
->cbs_peeked
= ebuf
->cfe_peeked
;
5262 error
= SYSCTL_OUT(req
, &stat
,
5263 sizeof(struct cfil_sock_stat
));
5269 cfil_rw_unlock_shared(&cfil_lck_rw
);
5272 if (req
->oldptr
!= USER_ADDR_NULL
) {
5281 * UDP Socket Support
5284 cfil_hash_entry_log(int level
, struct socket
*so
, struct cfil_hash_entry
*entry
, uint64_t sockId
, const char* msg
)
5286 char local
[MAX_IPv6_STR_LEN
+ 6];
5287 char remote
[MAX_IPv6_STR_LEN
+ 6];
5290 // No sock or not UDP, no-op
5291 if (so
== NULL
|| entry
== NULL
) {
5295 local
[0] = remote
[0] = 0x0;
5297 switch (entry
->cfentry_family
) {
5299 addr
= &entry
->cfentry_laddr
.addr6
;
5300 inet_ntop(AF_INET6
, addr
, local
, sizeof(local
));
5301 addr
= &entry
->cfentry_faddr
.addr6
;
5302 inet_ntop(AF_INET6
, addr
, remote
, sizeof(local
));
5305 addr
= &entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
;
5306 inet_ntop(AF_INET
, addr
, local
, sizeof(local
));
5307 addr
= &entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
;
5308 inet_ntop(AF_INET
, addr
, remote
, sizeof(local
));
5314 CFIL_LOG(level
, "<%s>: <UDP so %llx, entry %p, sockID %llu> lport %d fport %d laddr %s faddr %s",
5316 (uint64_t)VM_KERNEL_ADDRPERM(so
), entry
, sockId
,
5317 ntohs(entry
->cfentry_lport
), ntohs(entry
->cfentry_fport
), local
, remote
);
5321 cfil_inp_log(int level
, struct socket
*so
, const char* msg
)
5323 struct inpcb
*inp
= NULL
;
5324 char local
[MAX_IPv6_STR_LEN
+ 6];
5325 char remote
[MAX_IPv6_STR_LEN
+ 6];
5332 inp
= sotoinpcb(so
);
5337 local
[0] = remote
[0] = 0x0;
5340 if (inp
->inp_vflag
& INP_IPV6
) {
5341 addr
= &inp
->in6p_laddr
.s6_addr32
;
5342 inet_ntop(AF_INET6
, addr
, local
, sizeof(local
));
5343 addr
= &inp
->in6p_faddr
.s6_addr32
;
5344 inet_ntop(AF_INET6
, addr
, remote
, sizeof(local
));
5348 addr
= &inp
->inp_laddr
.s_addr
;
5349 inet_ntop(AF_INET
, addr
, local
, sizeof(local
));
5350 addr
= &inp
->inp_faddr
.s_addr
;
5351 inet_ntop(AF_INET
, addr
, remote
, sizeof(local
));
5354 if (so
->so_cfil
!= NULL
) {
5355 CFIL_LOG(level
, "<%s>: <%s so %llx - flags 0x%x 0x%x, sockID %llu> lport %d fport %d laddr %s faddr %s",
5356 msg
, IS_UDP(so
) ? "UDP" : "TCP",
5357 (uint64_t)VM_KERNEL_ADDRPERM(so
), inp
->inp_flags
, inp
->inp_socket
->so_flags
, so
->so_cfil
->cfi_sock_id
,
5358 ntohs(inp
->inp_lport
), ntohs(inp
->inp_fport
), local
, remote
);
5360 CFIL_LOG(level
, "<%s>: <%s so %llx - flags 0x%x 0x%x> lport %d fport %d laddr %s faddr %s",
5361 msg
, IS_UDP(so
) ? "UDP" : "TCP",
5362 (uint64_t)VM_KERNEL_ADDRPERM(so
), inp
->inp_flags
, inp
->inp_socket
->so_flags
,
5363 ntohs(inp
->inp_lport
), ntohs(inp
->inp_fport
), local
, remote
);
5368 cfil_info_log(int level
, struct cfil_info
*cfil_info
, const char* msg
)
5370 if (cfil_info
== NULL
) {
5374 if (cfil_info
->cfi_hash_entry
!= NULL
) {
5375 cfil_hash_entry_log(level
, cfil_info
->cfi_so
, cfil_info
->cfi_hash_entry
, cfil_info
->cfi_sock_id
, msg
);
5377 cfil_inp_log(level
, cfil_info
->cfi_so
, msg
);
5382 cfil_db_init(struct socket
*so
)
5385 struct cfil_db
*db
= NULL
;
5387 CFIL_LOG(LOG_INFO
, "");
5389 db
= zalloc(cfil_db_zone
);
5394 bzero(db
, sizeof(struct cfil_db
));
5396 db
->cfdb_hashbase
= hashinit(CFILHASHSIZE
, M_CFIL
, &db
->cfdb_hashmask
);
5397 if (db
->cfdb_hashbase
== NULL
) {
5398 zfree(cfil_db_zone
, db
);
5404 so
->so_cfil_db
= db
;
5411 cfil_db_free(struct socket
*so
)
5413 struct cfil_hash_entry
*entry
= NULL
;
5414 struct cfil_hash_entry
*temp_entry
= NULL
;
5415 struct cfilhashhead
*cfilhash
= NULL
;
5416 struct cfil_db
*db
= NULL
;
5418 CFIL_LOG(LOG_INFO
, "");
5420 if (so
== NULL
|| so
->so_cfil_db
== NULL
) {
5423 db
= so
->so_cfil_db
;
5426 CFIL_LOG(LOG_ERR
, "CFIL: LIFECYCLE: <so %llx, db %p> freeing db (count == %d)",
5427 (uint64_t)VM_KERNEL_ADDRPERM(so
), db
, db
->cfdb_count
);
5430 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
5431 cfilhash
= &db
->cfdb_hashbase
[i
];
5432 LIST_FOREACH_SAFE(entry
, cfilhash
, cfentry_link
, temp_entry
) {
5433 if (entry
->cfentry_cfil
!= NULL
) {
5435 cfil_info_log(LOG_ERR
, entry
->cfentry_cfil
, "CFIL: LIFECYCLE: DB FREE CLEAN UP");
5437 cfil_info_free(entry
->cfentry_cfil
);
5438 OSIncrementAtomic(&cfil_stats
.cfs_sock_detached
);
5439 entry
->cfentry_cfil
= NULL
;
5442 cfil_db_delete_entry(db
, entry
);
5443 if (so
->so_flags
& SOF_CONTENT_FILTER
) {
5444 if (db
->cfdb_count
== 0) {
5445 so
->so_flags
&= ~SOF_CONTENT_FILTER
;
5447 VERIFY(so
->so_usecount
> 0);
5453 // Make sure all entries are cleaned up!
5454 VERIFY(db
->cfdb_count
== 0);
5456 CFIL_LOG(LOG_ERR
, "CFIL: LIFECYCLE: so usecount %d", so
->so_usecount
);
5459 FREE(db
->cfdb_hashbase
, M_CFIL
);
5460 zfree(cfil_db_zone
, db
);
5461 so
->so_cfil_db
= NULL
;
5465 fill_cfil_hash_entry_from_address(struct cfil_hash_entry
*entry
, bool isLocal
, struct sockaddr
*addr
)
5467 struct sockaddr_in
*sin
= NULL
;
5468 struct sockaddr_in6
*sin6
= NULL
;
5470 if (entry
== NULL
|| addr
== NULL
) {
5474 switch (addr
->sa_family
) {
5476 sin
= satosin(addr
);
5477 if (sin
->sin_len
!= sizeof(*sin
)) {
5480 if (isLocal
== TRUE
) {
5481 entry
->cfentry_lport
= sin
->sin_port
;
5482 entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
= sin
->sin_addr
.s_addr
;
5484 entry
->cfentry_fport
= sin
->sin_port
;
5485 entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
= sin
->sin_addr
.s_addr
;
5487 entry
->cfentry_family
= AF_INET
;
5490 sin6
= satosin6(addr
);
5491 if (sin6
->sin6_len
!= sizeof(*sin6
)) {
5494 if (isLocal
== TRUE
) {
5495 entry
->cfentry_lport
= sin6
->sin6_port
;
5496 entry
->cfentry_laddr
.addr6
= sin6
->sin6_addr
;
5498 entry
->cfentry_fport
= sin6
->sin6_port
;
5499 entry
->cfentry_faddr
.addr6
= sin6
->sin6_addr
;
5501 entry
->cfentry_family
= AF_INET6
;
5509 fill_cfil_hash_entry_from_inp(struct cfil_hash_entry
*entry
, bool isLocal
, struct inpcb
*inp
)
5511 if (entry
== NULL
|| inp
== NULL
) {
5515 if (inp
->inp_vflag
& INP_IPV4
) {
5516 if (isLocal
== TRUE
) {
5517 entry
->cfentry_lport
= inp
->inp_lport
;
5518 entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
= inp
->inp_laddr
.s_addr
;
5520 entry
->cfentry_fport
= inp
->inp_fport
;
5521 entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
= inp
->inp_faddr
.s_addr
;
5523 entry
->cfentry_family
= AF_INET
;
5525 } else if (inp
->inp_vflag
& INP_IPV6
) {
5526 if (isLocal
== TRUE
) {
5527 entry
->cfentry_lport
= inp
->inp_lport
;
5528 entry
->cfentry_laddr
.addr6
= inp
->in6p_laddr
;
5530 entry
->cfentry_fport
= inp
->inp_fport
;
5531 entry
->cfentry_faddr
.addr6
= inp
->in6p_faddr
;
5533 entry
->cfentry_family
= AF_INET6
;
5540 check_port(struct sockaddr
*addr
, u_short port
)
5542 struct sockaddr_in
*sin
= NULL
;
5543 struct sockaddr_in6
*sin6
= NULL
;
5545 if (addr
== NULL
|| port
== 0) {
5549 switch (addr
->sa_family
) {
5551 sin
= satosin(addr
);
5552 if (sin
->sin_len
!= sizeof(*sin
)) {
5555 if (port
== ntohs(sin
->sin_port
)) {
5560 sin6
= satosin6(addr
);
5561 if (sin6
->sin6_len
!= sizeof(*sin6
)) {
5564 if (port
== ntohs(sin6
->sin6_port
)) {
5574 struct cfil_hash_entry
*
5575 cfil_db_lookup_entry_with_sockid(struct cfil_db
*db
, u_int64_t sock_id
)
5577 struct cfilhashhead
*cfilhash
= NULL
;
5578 u_int32_t flowhash
= (u_int32_t
)(sock_id
& 0x0ffffffff);
5579 struct cfil_hash_entry
*nextentry
;
5581 if (db
== NULL
|| db
->cfdb_hashbase
== NULL
|| sock_id
== 0) {
5585 flowhash
&= db
->cfdb_hashmask
;
5586 cfilhash
= &db
->cfdb_hashbase
[flowhash
];
5588 LIST_FOREACH(nextentry
, cfilhash
, cfentry_link
) {
5589 if (nextentry
->cfentry_cfil
!= NULL
&&
5590 nextentry
->cfentry_cfil
->cfi_sock_id
== sock_id
) {
5591 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> matched <id %llu, hash %u>",
5592 (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
), nextentry
->cfentry_cfil
->cfi_sock_id
, flowhash
);
5593 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, nextentry
, 0, "CFIL: UDP found entry");
5598 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> NOT matched <id %llu, hash %u>",
5599 (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
), sock_id
, flowhash
);
5603 struct cfil_hash_entry
*
5604 cfil_db_lookup_entry(struct cfil_db
*db
, struct sockaddr
*local
, struct sockaddr
*remote
)
5606 struct cfil_hash_entry matchentry
;
5607 struct cfil_hash_entry
*nextentry
= NULL
;
5608 struct inpcb
*inp
= sotoinpcb(db
->cfdb_so
);
5609 u_int32_t hashkey_faddr
= 0, hashkey_laddr
= 0;
5610 int inp_hash_element
= 0;
5611 struct cfilhashhead
*cfilhash
= NULL
;
5613 CFIL_LOG(LOG_INFO
, "");
5619 if (local
!= NULL
) {
5620 fill_cfil_hash_entry_from_address(&matchentry
, TRUE
, local
);
5622 fill_cfil_hash_entry_from_inp(&matchentry
, TRUE
, inp
);
5624 if (remote
!= NULL
) {
5625 fill_cfil_hash_entry_from_address(&matchentry
, FALSE
, remote
);
5627 fill_cfil_hash_entry_from_inp(&matchentry
, FALSE
, inp
);
5631 if (inp
->inp_vflag
& INP_IPV6
) {
5632 hashkey_faddr
= matchentry
.cfentry_faddr
.addr6
.s6_addr32
[3];
5633 hashkey_laddr
= matchentry
.cfentry_laddr
.addr6
.s6_addr32
[3];
5637 hashkey_faddr
= matchentry
.cfentry_faddr
.addr46
.ia46_addr4
.s_addr
;
5638 hashkey_laddr
= matchentry
.cfentry_laddr
.addr46
.ia46_addr4
.s_addr
;
5641 inp_hash_element
= CFIL_HASH(hashkey_laddr
, hashkey_faddr
,
5642 matchentry
.cfentry_lport
, matchentry
.cfentry_fport
);
5643 inp_hash_element
&= db
->cfdb_hashmask
;
5645 cfilhash
= &db
->cfdb_hashbase
[inp_hash_element
];
5647 LIST_FOREACH(nextentry
, cfilhash
, cfentry_link
) {
5649 if ((inp
->inp_vflag
& INP_IPV6
) &&
5650 nextentry
->cfentry_lport
== matchentry
.cfentry_lport
&&
5651 nextentry
->cfentry_fport
== matchentry
.cfentry_fport
&&
5652 IN6_ARE_ADDR_EQUAL(&nextentry
->cfentry_laddr
.addr6
, &matchentry
.cfentry_laddr
.addr6
) &&
5653 IN6_ARE_ADDR_EQUAL(&nextentry
->cfentry_faddr
.addr6
, &matchentry
.cfentry_faddr
.addr6
)) {
5655 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, &matchentry
, 0, "CFIL LOOKUP ENTRY: UDP V6 found entry");
5660 if (nextentry
->cfentry_lport
== matchentry
.cfentry_lport
&&
5661 nextentry
->cfentry_fport
== matchentry
.cfentry_fport
&&
5662 nextentry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
== matchentry
.cfentry_laddr
.addr46
.ia46_addr4
.s_addr
&&
5663 nextentry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
== matchentry
.cfentry_faddr
.addr46
.ia46_addr4
.s_addr
) {
5665 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, &matchentry
, 0, "CFIL LOOKUP ENTRY: UDP V4 found entry");
5673 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, &matchentry
, 0, "CFIL LOOKUP ENTRY: UDP no entry found");
5679 cfil_db_delete_entry(struct cfil_db
*db
, struct cfil_hash_entry
*hash_entry
)
5681 if (hash_entry
== NULL
) {
5684 if (db
== NULL
|| db
->cfdb_count
== 0) {
5688 if (db
->cfdb_only_entry
== hash_entry
) {
5689 db
->cfdb_only_entry
= NULL
;
5691 LIST_REMOVE(hash_entry
, cfentry_link
);
5692 zfree(cfil_hash_entry_zone
, hash_entry
);
5695 struct cfil_hash_entry
*
5696 cfil_db_add_entry(struct cfil_db
*db
, struct sockaddr
*local
, struct sockaddr
*remote
)
5698 struct cfil_hash_entry
*entry
= NULL
;
5699 struct inpcb
*inp
= sotoinpcb(db
->cfdb_so
);
5700 u_int32_t hashkey_faddr
= 0, hashkey_laddr
= 0;
5701 int inp_hash_element
= 0;
5702 struct cfilhashhead
*cfilhash
= NULL
;
5704 CFIL_LOG(LOG_INFO
, "");
5710 entry
= zalloc(cfil_hash_entry_zone
);
5711 if (entry
== NULL
) {
5714 bzero(entry
, sizeof(struct cfil_hash_entry
));
5716 if (local
!= NULL
) {
5717 fill_cfil_hash_entry_from_address(entry
, TRUE
, local
);
5719 fill_cfil_hash_entry_from_inp(entry
, TRUE
, inp
);
5721 if (remote
!= NULL
) {
5722 fill_cfil_hash_entry_from_address(entry
, FALSE
, remote
);
5724 fill_cfil_hash_entry_from_inp(entry
, FALSE
, inp
);
5726 entry
->cfentry_lastused
= net_uptime();
5729 if (inp
->inp_vflag
& INP_IPV6
) {
5730 hashkey_faddr
= entry
->cfentry_faddr
.addr6
.s6_addr32
[3];
5731 hashkey_laddr
= entry
->cfentry_laddr
.addr6
.s6_addr32
[3];
5735 hashkey_faddr
= entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
;
5736 hashkey_laddr
= entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
;
5738 entry
->cfentry_flowhash
= CFIL_HASH(hashkey_laddr
, hashkey_faddr
,
5739 entry
->cfentry_lport
, entry
->cfentry_fport
);
5740 inp_hash_element
= entry
->cfentry_flowhash
& db
->cfdb_hashmask
;
5742 cfilhash
= &db
->cfdb_hashbase
[inp_hash_element
];
5744 LIST_INSERT_HEAD(cfilhash
, entry
, cfentry_link
);
5746 db
->cfdb_only_entry
= entry
;
5747 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, entry
, 0, "CFIL: cfil_db_add_entry: ADDED");
5750 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> total count %d", (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
), db
->cfdb_count
);
5755 cfil_db_get_cfil_info(struct cfil_db
*db
, cfil_sock_id_t id
)
5757 struct cfil_hash_entry
*hash_entry
= NULL
;
5759 CFIL_LOG(LOG_INFO
, "");
5761 if (db
== NULL
|| id
== 0) {
5762 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> NULL DB <id %llu>",
5763 db
? (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
) : 0, id
);
5767 // This is an optimization for connected UDP socket which only has one flow.
5768 // No need to do the hash lookup.
5769 if (db
->cfdb_count
== 1) {
5770 if (db
->cfdb_only_entry
&& db
->cfdb_only_entry
->cfentry_cfil
&&
5771 db
->cfdb_only_entry
->cfentry_cfil
->cfi_sock_id
== id
) {
5772 return db
->cfdb_only_entry
->cfentry_cfil
;
5776 hash_entry
= cfil_db_lookup_entry_with_sockid(db
, id
);
5777 return hash_entry
!= NULL
? hash_entry
->cfentry_cfil
: NULL
;
5780 struct cfil_hash_entry
*
5781 cfil_sock_udp_get_flow(struct socket
*so
, uint32_t filter_control_unit
, bool outgoing
, struct sockaddr
*local
, struct sockaddr
*remote
)
5783 struct cfil_hash_entry
*hash_entry
= NULL
;
5786 socket_lock_assert_owned(so
);
5788 // If new socket, allocate cfil db
5789 if (so
->so_cfil_db
== NULL
) {
5790 if (cfil_db_init(so
) != 0) {
5795 // See if flow already exists.
5796 hash_entry
= cfil_db_lookup_entry(so
->so_cfil_db
, local
, remote
);
5797 if (hash_entry
!= NULL
) {
5801 hash_entry
= cfil_db_add_entry(so
->so_cfil_db
, local
, remote
);
5802 if (hash_entry
== NULL
) {
5803 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_no_mem
);
5804 CFIL_LOG(LOG_ERR
, "CFIL: UDP failed to add entry");
5808 if (cfil_info_alloc(so
, hash_entry
) == NULL
||
5809 hash_entry
->cfentry_cfil
== NULL
) {
5810 cfil_db_delete_entry(so
->so_cfil_db
, hash_entry
);
5811 CFIL_LOG(LOG_ERR
, "CFIL: UDP failed to alloc cfil_info");
5812 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_no_mem
);
5815 hash_entry
->cfentry_cfil
->cfi_dir
= outgoing
? CFS_CONNECTION_DIR_OUT
: CFS_CONNECTION_DIR_IN
;
5818 cfil_info_log(LOG_ERR
, hash_entry
->cfentry_cfil
, "CFIL: LIFECYCLE: ADDED");
5821 if (cfil_info_attach_unit(so
, filter_control_unit
, hash_entry
->cfentry_cfil
) == 0) {
5822 cfil_info_free(hash_entry
->cfentry_cfil
);
5823 cfil_db_delete_entry(so
->so_cfil_db
, hash_entry
);
5824 CFIL_LOG(LOG_ERR
, "CFIL: UDP cfil_info_attach_unit(%u) failed",
5825 filter_control_unit
);
5826 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_failed
);
5829 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> filter_control_unit %u sockID %llu attached",
5830 (uint64_t)VM_KERNEL_ADDRPERM(so
),
5831 filter_control_unit
, hash_entry
->cfentry_cfil
->cfi_sock_id
);
5833 so
->so_flags
|= SOF_CONTENT_FILTER
;
5834 OSIncrementAtomic(&cfil_stats
.cfs_sock_attached
);
5836 /* Hold a reference on the socket for each flow */
5839 error
= cfil_dispatch_attach_event(so
, hash_entry
->cfentry_cfil
, 0,
5840 outgoing
? CFS_CONNECTION_DIR_OUT
: CFS_CONNECTION_DIR_IN
);
5841 /* We can recover from flow control or out of memory errors */
5842 if (error
!= 0 && error
!= ENOBUFS
&& error
!= ENOMEM
) {
5846 CFIL_INFO_VERIFY(hash_entry
->cfentry_cfil
);
5851 cfil_sock_udp_handle_data(bool outgoing
, struct socket
*so
,
5852 struct sockaddr
*local
, struct sockaddr
*remote
,
5853 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
5855 #pragma unused(outgoing, so, local, remote, data, control, flags)
5857 uint32_t filter_control_unit
;
5858 struct cfil_hash_entry
*hash_entry
= NULL
;
5859 struct cfil_info
*cfil_info
= NULL
;
5861 socket_lock_assert_owned(so
);
5863 if (cfil_active_count
== 0) {
5864 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP no active filter");
5865 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_in_vain
);
5869 // Socket has been blessed
5870 if ((so
->so_flags1
& SOF1_CONTENT_FILTER_SKIP
) != 0) {
5874 filter_control_unit
= necp_socket_get_content_filter_control_unit(so
);
5875 if (filter_control_unit
== 0) {
5876 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP failed to get control unit");
5880 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
5884 if ((filter_control_unit
& NECP_MASK_USERSPACE_ONLY
) != 0) {
5885 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP user space only");
5886 OSIncrementAtomic(&cfil_stats
.cfs_sock_userspace_only
);
5890 hash_entry
= cfil_sock_udp_get_flow(so
, filter_control_unit
, outgoing
, local
, remote
);
5891 if (hash_entry
== NULL
|| hash_entry
->cfentry_cfil
== NULL
) {
5892 CFIL_LOG(LOG_ERR
, "CFIL: Falied to create UDP flow");
5895 // Update last used timestamp, this is for flow Idle TO
5896 hash_entry
->cfentry_lastused
= net_uptime();
5897 cfil_info
= hash_entry
->cfentry_cfil
;
5899 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
5901 cfil_hash_entry_log(LOG_DEBUG
, so
, hash_entry
, 0, "CFIL: UDP DROP");
5905 if (control
!= NULL
) {
5906 OSIncrementAtomic(&cfil_stats
.cfs_data_in_control
);
5908 if (data
->m_type
== MT_OOBDATA
) {
5909 CFIL_LOG(LOG_ERR
, "so %llx MSG_OOB",
5910 (uint64_t)VM_KERNEL_ADDRPERM(so
));
5911 OSIncrementAtomic(&cfil_stats
.cfs_data_in_oob
);
5914 error
= cfil_data_common(so
, cfil_info
, outgoing
, remote
, data
, control
, flags
);
5920 * Go through all UDP flows for specified socket and returns TRUE if
5921 * any flow is still attached. If need_wait is TRUE, wait on first
5925 cfil_filters_udp_attached(struct socket
*so
, bool need_wait
)
5928 lck_mtx_t
*mutex_held
;
5929 struct cfilhashhead
*cfilhash
= NULL
;
5930 struct cfil_db
*db
= NULL
;
5931 struct cfil_hash_entry
*hash_entry
= NULL
;
5932 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
5933 struct cfil_info
*cfil_info
= NULL
;
5934 struct cfil_entry
*entry
= NULL
;
5938 uint64_t sock_flow_id
= 0;
5940 socket_lock_assert_owned(so
);
5942 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
5943 if (so
->so_proto
->pr_getlock
!= NULL
) {
5944 mutex_held
= (*so
->so_proto
->pr_getlock
)(so
, PR_F_WILLUNLOCK
);
5946 mutex_held
= so
->so_proto
->pr_domain
->dom_mtx
;
5948 LCK_MTX_ASSERT(mutex_held
, LCK_MTX_ASSERT_OWNED
);
5950 db
= so
->so_cfil_db
;
5952 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
5953 cfilhash
= &db
->cfdb_hashbase
[i
];
5955 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
5956 if (hash_entry
->cfentry_cfil
!= NULL
) {
5957 cfil_info
= hash_entry
->cfentry_cfil
;
5958 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
5959 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
5961 /* Are we attached to the filter? */
5962 if (entry
->cfe_filter
== NULL
) {
5966 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
5969 if ((entry
->cfe_flags
& CFEF_CFIL_DETACHED
) != 0) {
5975 if (need_wait
== TRUE
) {
5977 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAIT FOR FLOW TO FINISH");
5980 ts
.tv_sec
= cfil_close_wait_timeout
/ 1000;
5981 ts
.tv_nsec
= (cfil_close_wait_timeout
% 1000) *
5982 NSEC_PER_USEC
* 1000;
5984 OSIncrementAtomic(&cfil_stats
.cfs_close_wait
);
5985 cfil_info
->cfi_flags
|= CFIF_CLOSE_WAIT
;
5986 sock_flow_id
= cfil_info
->cfi_sock_id
;
5988 error
= msleep((caddr_t
)cfil_info
, mutex_held
,
5989 PSOCK
| PCATCH
, "cfil_filters_udp_attached", &ts
);
5991 // Woke up from sleep, validate if cfil_info is still valid
5992 if (so
->so_cfil_db
== NULL
||
5993 (cfil_info
!= cfil_db_get_cfil_info(so
->so_cfil_db
, sock_flow_id
))) {
5994 // cfil_info is not valid, do not continue
5998 cfil_info
->cfi_flags
&= ~CFIF_CLOSE_WAIT
;
6001 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAIT FOR FLOW DONE");
6005 * Force close in case of timeout
6008 OSIncrementAtomic(&cfil_stats
.cfs_close_wait_timeout
);
6010 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAIT FOR FLOW TIMED OUT, FORCE DETACH");
6012 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
6027 cfil_sock_udp_data_pending(struct sockbuf
*sb
, bool check_thread
)
6029 struct socket
*so
= sb
->sb_so
;
6030 struct cfi_buf
*cfi_buf
;
6031 uint64_t pending
= 0;
6032 uint64_t total_pending
= 0;
6033 struct cfilhashhead
*cfilhash
= NULL
;
6034 struct cfil_db
*db
= NULL
;
6035 struct cfil_hash_entry
*hash_entry
= NULL
;
6036 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6038 socket_lock_assert_owned(so
);
6040 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
&&
6041 (check_thread
== FALSE
|| so
->so_snd
.sb_cfil_thread
!= current_thread())) {
6042 db
= so
->so_cfil_db
;
6044 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6045 cfilhash
= &db
->cfdb_hashbase
[i
];
6047 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6048 if (hash_entry
->cfentry_cfil
!= NULL
) {
6049 if ((sb
->sb_flags
& SB_RECV
) == 0) {
6050 cfi_buf
= &hash_entry
->cfentry_cfil
->cfi_snd
;
6052 cfi_buf
= &hash_entry
->cfentry_cfil
->cfi_rcv
;
6055 pending
= cfi_buf
->cfi_pending_last
- cfi_buf
->cfi_pending_first
;
6057 * If we are limited by the "chars of mbufs used" roughly
6058 * adjust so we won't overcommit
6060 if ((uint64_t)cfi_buf
->cfi_pending_mbcnt
> pending
) {
6061 pending
= cfi_buf
->cfi_pending_mbcnt
;
6064 total_pending
+= pending
;
6069 VERIFY(total_pending
< INT32_MAX
);
6071 CFIL_LOG(LOG_DEBUG
, "CFIL: <so %llx> total pending %llu <check_thread %d>",
6072 (uint64_t)VM_KERNEL_ADDRPERM(so
),
6073 total_pending
, check_thread
);
6077 return (int32_t)(total_pending
);
6081 cfil_sock_udp_notify_shutdown(struct socket
*so
, int how
, int drop_flag
, int shut_flag
)
6083 struct cfil_info
*cfil_info
= NULL
;
6084 struct cfilhashhead
*cfilhash
= NULL
;
6085 struct cfil_db
*db
= NULL
;
6086 struct cfil_hash_entry
*hash_entry
= NULL
;
6087 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6092 socket_lock_assert_owned(so
);
6094 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6095 db
= so
->so_cfil_db
;
6097 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6098 cfilhash
= &db
->cfdb_hashbase
[i
];
6100 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6101 if (hash_entry
->cfentry_cfil
!= NULL
) {
6102 cfil_info
= hash_entry
->cfentry_cfil
;
6104 // This flow is marked as DROP
6105 if (cfil_info
->cfi_flags
& drop_flag
) {
6110 // This flow has been shut already, skip
6111 if (cfil_info
->cfi_flags
& shut_flag
) {
6114 // Mark flow as shut
6115 cfil_info
->cfi_flags
|= shut_flag
;
6118 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6119 /* Disconnect incoming side */
6120 if (how
!= SHUT_WR
) {
6121 error
= cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 0);
6123 /* Disconnect outgoing side */
6124 if (how
!= SHUT_RD
) {
6125 error
= cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 1);
6133 if (done_count
== 0) {
6140 cfil_sock_udp_shutdown(struct socket
*so
, int *how
)
6144 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || (so
->so_cfil_db
== NULL
)) {
6148 socket_lock_assert_owned(so
);
6150 CFIL_LOG(LOG_INFO
, "so %llx how %d",
6151 (uint64_t)VM_KERNEL_ADDRPERM(so
), *how
);
6154 * Check the state of the socket before the content filter
6156 if (*how
!= SHUT_WR
&& (so
->so_state
& SS_CANTRCVMORE
) != 0) {
6157 /* read already shut down */
6161 if (*how
!= SHUT_RD
&& (so
->so_state
& SS_CANTSENDMORE
) != 0) {
6162 /* write already shut down */
6168 * shutdown read: SHUT_RD or SHUT_RDWR
6170 if (*how
!= SHUT_WR
) {
6171 error
= cfil_sock_udp_notify_shutdown(so
, SHUT_RD
, CFIF_DROP
, CFIF_SHUT_RD
);
6177 * shutdown write: SHUT_WR or SHUT_RDWR
6179 if (*how
!= SHUT_RD
) {
6180 error
= cfil_sock_udp_notify_shutdown(so
, SHUT_WR
, CFIF_DROP
, CFIF_SHUT_WR
);
6186 * When outgoing data is pending, we delay the shutdown at the
6187 * protocol level until the content filters give the final
6188 * verdict on the pending data.
6190 if (cfil_sock_data_pending(&so
->so_snd
) != 0) {
6192 * When shutting down the read and write sides at once
6193 * we can proceed to the final shutdown of the read
6194 * side. Otherwise, we just return.
6196 if (*how
== SHUT_WR
) {
6197 error
= EJUSTRETURN
;
6198 } else if (*how
== SHUT_RDWR
) {
6208 cfil_sock_udp_close_wait(struct socket
*so
)
6210 socket_lock_assert_owned(so
);
6212 while (cfil_filters_udp_attached(so
, FALSE
)) {
6214 * Notify the filters we are going away so they can detach
6216 cfil_sock_udp_notify_shutdown(so
, SHUT_RDWR
, 0, 0);
6219 * Make sure we need to wait after the filter are notified
6220 * of the disconnection
6222 if (cfil_filters_udp_attached(so
, TRUE
) == 0) {
6229 cfil_sock_udp_is_closed(struct socket
*so
)
6231 struct cfil_info
*cfil_info
= NULL
;
6232 struct cfilhashhead
*cfilhash
= NULL
;
6233 struct cfil_db
*db
= NULL
;
6234 struct cfil_hash_entry
*hash_entry
= NULL
;
6235 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6239 socket_lock_assert_owned(so
);
6241 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6242 db
= so
->so_cfil_db
;
6244 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6245 cfilhash
= &db
->cfdb_hashbase
[i
];
6247 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6248 if (hash_entry
->cfentry_cfil
!= NULL
) {
6249 cfil_info
= hash_entry
->cfentry_cfil
;
6251 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6252 /* Let the filters know of the closing */
6253 error
= cfil_dispatch_closed_event(so
, cfil_info
, kcunit
);
6256 /* Last chance to push passed data out */
6257 error
= cfil_acquire_sockbuf(so
, cfil_info
, 1);
6259 cfil_service_inject_queue(so
, cfil_info
, 1);
6261 cfil_release_sockbuf(so
, 1);
6263 cfil_info
->cfi_flags
|= CFIF_SOCK_CLOSED
;
6265 /* Pending data needs to go */
6266 cfil_flush_queues(so
, cfil_info
);
6268 CFIL_INFO_VERIFY(cfil_info
);
6276 cfil_sock_udp_buf_update(struct sockbuf
*sb
)
6278 struct cfil_info
*cfil_info
= NULL
;
6279 struct cfilhashhead
*cfilhash
= NULL
;
6280 struct cfil_db
*db
= NULL
;
6281 struct cfil_hash_entry
*hash_entry
= NULL
;
6282 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6285 struct socket
*so
= sb
->sb_so
;
6287 socket_lock_assert_owned(so
);
6289 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6294 db
= so
->so_cfil_db
;
6296 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6297 cfilhash
= &db
->cfdb_hashbase
[i
];
6299 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6300 if (hash_entry
->cfentry_cfil
!= NULL
) {
6301 cfil_info
= hash_entry
->cfentry_cfil
;
6303 if ((sb
->sb_flags
& SB_RECV
) == 0) {
6304 if ((cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_OUT
) == 0) {
6308 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_out_retry
);
6310 if ((cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_IN
) == 0) {
6314 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_in_retry
);
6317 CFIL_LOG(LOG_NOTICE
, "so %llx outgoing %d",
6318 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
);
6320 error
= cfil_acquire_sockbuf(so
, cfil_info
, outgoing
);
6322 cfil_service_inject_queue(so
, cfil_info
, outgoing
);
6324 cfil_release_sockbuf(so
, outgoing
);
6332 cfil_filter_show(u_int32_t kcunit
)
6334 struct content_filter
*cfc
= NULL
;
6335 struct cfil_entry
*entry
;
6338 if (content_filters
== NULL
) {
6341 if (kcunit
> MAX_CONTENT_FILTER
) {
6345 cfil_rw_lock_shared(&cfil_lck_rw
);
6347 if (content_filters
[kcunit
- 1] == NULL
) {
6348 cfil_rw_unlock_shared(&cfil_lck_rw
);
6351 cfc
= content_filters
[kcunit
- 1];
6353 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: Filter <unit %d, entry count %d> flags <%lx>:",
6354 kcunit
, cfc
->cf_sock_count
, (unsigned long)cfc
->cf_flags
);
6355 if (cfc
->cf_flags
& CFF_DETACHING
) {
6356 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: - DETACHING");
6358 if (cfc
->cf_flags
& CFF_ACTIVE
) {
6359 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: - ACTIVE");
6361 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
6362 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: - FLOW CONTROLLED");
6365 TAILQ_FOREACH(entry
, &cfc
->cf_sock_entries
, cfe_link
) {
6366 if (entry
->cfe_cfil_info
&& entry
->cfe_cfil_info
->cfi_so
) {
6367 struct cfil_info
*cfil_info
= entry
->cfe_cfil_info
;
6371 if (entry
->cfe_flags
& CFEF_CFIL_DETACHED
) {
6372 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: FILTER SHOW: - DETACHED");
6374 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: FILTER SHOW: - ATTACHED");
6379 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: Filter - total entries shown: %d", count
);
6381 cfil_rw_unlock_shared(&cfil_lck_rw
);
6385 cfil_info_show(void)
6387 struct cfil_info
*cfil_info
;
6390 cfil_rw_lock_shared(&cfil_lck_rw
);
6392 CFIL_LOG(LOG_ERR
, "CFIL: INFO SHOW: count %d", cfil_sock_attached_count
);
6394 TAILQ_FOREACH(cfil_info
, &cfil_sock_head
, cfi_link
) {
6397 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: INFO SHOW");
6399 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
6400 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - DROP");
6402 if (cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) {
6403 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - CLOSE_WAIT");
6405 if (cfil_info
->cfi_flags
& CFIF_SOCK_CLOSED
) {
6406 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - SOCK_CLOSED");
6408 if (cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_IN
) {
6409 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - RETRY_INJECT_IN");
6411 if (cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_OUT
) {
6412 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - RETRY_INJECT_OUT");
6414 if (cfil_info
->cfi_flags
& CFIF_SHUT_WR
) {
6415 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - SHUT_WR");
6417 if (cfil_info
->cfi_flags
& CFIF_SHUT_RD
) {
6418 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - SHUT_RD");
6422 CFIL_LOG(LOG_ERR
, "CFIL: INFO SHOW: total cfil_info shown: %d", count
);
6424 cfil_rw_unlock_shared(&cfil_lck_rw
);
6428 cfil_info_idle_timed_out(struct cfil_info
*cfil_info
, int timeout
, u_int32_t current_time
)
6430 if (cfil_info
&& cfil_info
->cfi_hash_entry
&&
6431 (current_time
- cfil_info
->cfi_hash_entry
->cfentry_lastused
>= (u_int32_t
)timeout
)) {
6433 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: flow IDLE timeout expired");
6441 cfil_info_action_timed_out(struct cfil_info
*cfil_info
, int timeout
)
6443 struct cfil_entry
*entry
;
6444 struct timeval current_tv
;
6445 struct timeval diff_time
;
6447 if (cfil_info
== NULL
) {
6452 * If we have queued up more data than passed offset and we haven't received
6453 * an action from user space for a while (the user space filter might have crashed),
6454 * return action timed out.
6456 if (cfil_info
->cfi_snd
.cfi_pending_last
> cfil_info
->cfi_snd
.cfi_pass_offset
||
6457 cfil_info
->cfi_rcv
.cfi_pending_last
> cfil_info
->cfi_rcv
.cfi_pass_offset
) {
6458 microuptime(¤t_tv
);
6460 for (int kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6461 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
6463 if (entry
->cfe_filter
== NULL
) {
6467 if (cfil_info
->cfi_snd
.cfi_pending_last
> entry
->cfe_snd
.cfe_pass_offset
||
6468 cfil_info
->cfi_rcv
.cfi_pending_last
> entry
->cfe_rcv
.cfe_pass_offset
) {
6469 // haven't gotten an action from this filter, check timeout
6470 timersub(¤t_tv
, &entry
->cfe_last_action
, &diff_time
);
6471 if (diff_time
.tv_sec
>= timeout
) {
6473 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: flow ACTION timeout expired");
6484 cfil_info_buffer_threshold_exceeded(struct cfil_info
*cfil_info
)
6486 if (cfil_info
== NULL
) {
6491 * Clean up flow if it exceeded queue thresholds
6493 if (cfil_info
->cfi_snd
.cfi_tail_drop_cnt
||
6494 cfil_info
->cfi_rcv
.cfi_tail_drop_cnt
) {
6496 CFIL_LOG(LOG_ERR
, "CFIL: queue threshold exceeded: mbuf max <count: %d bytes: %d> tail drop count <OUT: %d IN: %d>",
6497 cfil_udp_gc_mbuf_num_max
,
6498 cfil_udp_gc_mbuf_cnt_max
,
6499 cfil_info
->cfi_snd
.cfi_tail_drop_cnt
,
6500 cfil_info
->cfi_rcv
.cfi_tail_drop_cnt
);
6501 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: queue threshold exceeded");
6510 cfil_udp_gc_thread_sleep(bool forever
)
6513 (void) assert_wait((event_t
) &cfil_sock_udp_attached_count
,
6514 THREAD_INTERRUPTIBLE
);
6516 uint64_t deadline
= 0;
6517 nanoseconds_to_absolutetime(UDP_FLOW_GC_RUN_INTERVAL_NSEC
, &deadline
);
6518 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
6520 (void) assert_wait_deadline(&cfil_sock_udp_attached_count
,
6521 THREAD_INTERRUPTIBLE
, deadline
);
6526 cfil_udp_gc_thread_func(void *v
, wait_result_t w
)
6528 #pragma unused(v, w)
6530 ASSERT(cfil_udp_gc_thread
== current_thread());
6531 thread_set_thread_name(current_thread(), "CFIL_UPD_GC");
6533 // Kick off gc shortly
6534 cfil_udp_gc_thread_sleep(false);
6535 thread_block_parameter((thread_continue_t
) cfil_info_udp_expire
, NULL
);
6540 cfil_info_udp_expire(void *v
, wait_result_t w
)
6542 #pragma unused(v, w)
6544 static uint64_t expired_array
[UDP_FLOW_GC_MAX_COUNT
];
6545 static uint32_t expired_count
= 0;
6547 struct cfil_info
*cfil_info
;
6548 struct cfil_hash_entry
*hash_entry
;
6551 u_int32_t current_time
= 0;
6553 current_time
= net_uptime();
6555 // Get all expired UDP flow ids
6556 cfil_rw_lock_shared(&cfil_lck_rw
);
6558 if (cfil_sock_udp_attached_count
== 0) {
6559 cfil_rw_unlock_shared(&cfil_lck_rw
);
6563 TAILQ_FOREACH(cfil_info
, &cfil_sock_head
, cfi_link
) {
6564 if (expired_count
>= UDP_FLOW_GC_MAX_COUNT
) {
6568 if (IS_UDP(cfil_info
->cfi_so
)) {
6569 if (cfil_info_idle_timed_out(cfil_info
, UDP_FLOW_GC_IDLE_TO
, current_time
) ||
6570 cfil_info_action_timed_out(cfil_info
, UDP_FLOW_GC_ACTION_TO
) ||
6571 cfil_info_buffer_threshold_exceeded(cfil_info
)) {
6572 expired_array
[expired_count
] = cfil_info
->cfi_sock_id
;
6577 cfil_rw_unlock_shared(&cfil_lck_rw
);
6579 if (expired_count
== 0) {
6583 for (uint32_t i
= 0; i
< expired_count
; i
++) {
6584 // Search for socket (UDP only and lock so)
6585 so
= cfil_socket_from_sock_id(expired_array
[i
], true);
6590 cfil_info
= cfil_db_get_cfil_info(so
->so_cfil_db
, expired_array
[i
]);
6591 if (cfil_info
== NULL
) {
6595 db
= so
->so_cfil_db
;
6596 hash_entry
= cfil_info
->cfi_hash_entry
;
6598 if (db
== NULL
|| hash_entry
== NULL
) {
6602 #if GC_DEBUG || LIFECYCLE_DEBUG
6603 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: GC CLEAN UP");
6606 cfil_db_delete_entry(db
, hash_entry
);
6607 cfil_info_free(cfil_info
);
6608 OSIncrementAtomic(&cfil_stats
.cfs_sock_detached
);
6610 if (so
->so_flags
& SOF_CONTENT_FILTER
) {
6611 if (db
->cfdb_count
== 0) {
6612 so
->so_flags
&= ~SOF_CONTENT_FILTER
;
6614 VERIFY(so
->so_usecount
> 0);
6618 socket_unlock(so
, 1);
6622 CFIL_LOG(LOG_ERR
, "CFIL: UDP flow idle timeout check: expired %d idle flows", expired_count
);
6628 // Sleep forever (until waken up) if no more UDP flow to clean
6629 cfil_rw_lock_shared(&cfil_lck_rw
);
6630 cfil_udp_gc_thread_sleep(cfil_sock_udp_attached_count
== 0 ? true : false);
6631 cfil_rw_unlock_shared(&cfil_lck_rw
);
6632 thread_block_parameter((thread_continue_t
)cfil_info_udp_expire
, NULL
);
6637 cfil_udp_save_socket_state(struct cfil_info
*cfil_info
, struct mbuf
*m
)
6639 struct m_tag
*tag
= NULL
;
6640 struct cfil_tag
*ctag
= NULL
;
6641 struct cfil_hash_entry
*hash_entry
= NULL
;
6643 if (cfil_info
== NULL
|| cfil_info
->cfi_so
== NULL
||
6644 cfil_info
->cfi_hash_entry
== NULL
|| m
== NULL
|| !(m
->m_flags
& M_PKTHDR
)) {
6648 /* Allocate a tag */
6649 tag
= m_tag_create(KERNEL_MODULE_TAG_ID
, KERNEL_TAG_TYPE_CFIL_UDP
,
6650 sizeof(struct cfil_tag
), M_DONTWAIT
, m
);
6653 ctag
= (struct cfil_tag
*)(tag
+ 1);
6654 ctag
->cfil_so_state_change_cnt
= cfil_info
->cfi_so
->so_state_change_cnt
;
6655 ctag
->cfil_so_options
= cfil_info
->cfi_so
->so_options
;
6657 hash_entry
= cfil_info
->cfi_hash_entry
;
6658 if (hash_entry
->cfentry_family
== AF_INET6
) {
6659 fill_ip6_sockaddr_4_6(&ctag
->cfil_faddr
,
6660 &hash_entry
->cfentry_faddr
.addr6
,
6661 hash_entry
->cfentry_fport
);
6662 } else if (hash_entry
->cfentry_family
== AF_INET
) {
6663 fill_ip_sockaddr_4_6(&ctag
->cfil_faddr
,
6664 hash_entry
->cfentry_faddr
.addr46
.ia46_addr4
,
6665 hash_entry
->cfentry_fport
);
6667 m_tag_prepend(m
, tag
);
6674 cfil_udp_get_socket_state(struct mbuf
*m
, uint32_t *state_change_cnt
, short *options
,
6675 struct sockaddr
**faddr
)
6677 struct m_tag
*tag
= NULL
;
6678 struct cfil_tag
*ctag
= NULL
;
6680 tag
= m_tag_locate(m
, KERNEL_MODULE_TAG_ID
, KERNEL_TAG_TYPE_CFIL_UDP
, NULL
);
6682 ctag
= (struct cfil_tag
*)(tag
+ 1);
6683 if (state_change_cnt
) {
6684 *state_change_cnt
= ctag
->cfil_so_state_change_cnt
;
6687 *options
= ctag
->cfil_so_options
;
6690 *faddr
= (struct sockaddr
*) &ctag
->cfil_faddr
;
6694 * Unlink tag and hand it over to caller.
6695 * Note that caller will be responsible to free it.
6697 m_tag_unlink(m
, tag
);