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_sock_attached_stats_count
= 0; /* Number of sockets requested periodic stats report */
363 uint32_t cfil_close_wait_timeout
= 1000; /* in milliseconds */
365 static kern_ctl_ref cfil_kctlref
= NULL
;
367 static lck_grp_attr_t
*cfil_lck_grp_attr
= NULL
;
368 static lck_attr_t
*cfil_lck_attr
= NULL
;
369 static lck_grp_t
*cfil_lck_grp
= NULL
;
370 decl_lck_rw_data(static, cfil_lck_rw
);
372 #define CFIL_RW_LCK_MAX 8
374 int cfil_rw_nxt_lck
= 0;
375 void* cfil_rw_lock_history
[CFIL_RW_LCK_MAX
];
377 int cfil_rw_nxt_unlck
= 0;
378 void* cfil_rw_unlock_history
[CFIL_RW_LCK_MAX
];
380 #define CONTENT_FILTER_ZONE_NAME "content_filter"
381 #define CONTENT_FILTER_ZONE_MAX 10
382 static struct zone
*content_filter_zone
= NULL
; /* zone for content_filter */
385 #define CFIL_INFO_ZONE_NAME "cfil_info"
386 #define CFIL_INFO_ZONE_MAX 1024
387 static struct zone
*cfil_info_zone
= NULL
; /* zone for cfil_info */
389 MBUFQ_HEAD(cfil_mqhead
);
392 uint64_t q_start
; /* offset of first byte in queue */
393 uint64_t q_end
; /* offset of last byte in queue */
394 struct cfil_mqhead q_mq
;
400 * The is one entry per content filter
403 TAILQ_ENTRY(cfil_entry
) cfe_link
;
404 SLIST_ENTRY(cfil_entry
) cfe_order_link
;
405 struct content_filter
*cfe_filter
;
407 struct cfil_info
*cfe_cfil_info
;
409 uint32_t cfe_necp_control_unit
;
410 struct timeval cfe_last_event
; /* To user space */
411 struct timeval cfe_last_action
; /* From user space */
412 uint64_t cfe_byte_inbound_count_reported
; /* stats already been reported */
413 uint64_t cfe_byte_outbound_count_reported
; /* stats already been reported */
414 struct timeval cfe_stats_report_ts
; /* Timestamp for last stats report */
415 uint32_t cfe_stats_report_frequency
; /* Interval for stats report in msecs */
416 boolean_t cfe_laddr_sent
;
420 * cfe_pending_q holds data that has been delivered to
421 * the filter and for which we are waiting for an action
423 struct cfil_queue cfe_pending_q
;
425 * This queue is for data that has not be delivered to
426 * the content filter (new data, pass peek or flow control)
428 struct cfil_queue cfe_ctl_q
;
430 uint64_t cfe_pass_offset
;
431 uint64_t cfe_peek_offset
;
436 #define CFEF_CFIL_ATTACHED 0x0001 /* was attached to filter */
437 #define CFEF_SENT_SOCK_ATTACHED 0x0002 /* sock attach event was sent */
438 #define CFEF_DATA_START 0x0004 /* can send data event */
439 #define CFEF_FLOW_CONTROLLED 0x0008 /* wait for flow control lift */
440 #define CFEF_SENT_DISCONNECT_IN 0x0010 /* event was sent */
441 #define CFEF_SENT_DISCONNECT_OUT 0x0020 /* event was sent */
442 #define CFEF_SENT_SOCK_CLOSED 0x0040 /* closed event was sent */
443 #define CFEF_CFIL_DETACHED 0x0080 /* filter was detached */
446 #define CFI_ADD_TIME_LOG(cfil, t1, t0, op) \
447 struct timeval _tdiff; \
448 if ((cfil)->cfi_op_list_ctr < CFI_MAX_TIME_LOG_ENTRY) { \
449 timersub(t1, t0, &_tdiff); \
450 (cfil)->cfi_op_time[(cfil)->cfi_op_list_ctr] = (uint32_t)(_tdiff.tv_sec * 1000 + _tdiff.tv_usec / 1000);\
451 (cfil)->cfi_op_list[(cfil)->cfi_op_list_ctr] = (unsigned char)op; \
452 (cfil)->cfi_op_list_ctr ++; \
455 struct cfil_hash_entry
;
460 * There is a struct cfil_info per socket
463 TAILQ_ENTRY(cfil_info
) cfi_link
;
464 TAILQ_ENTRY(cfil_info
) cfi_link_stats
;
465 struct socket
*cfi_so
;
467 uint64_t cfi_sock_id
;
468 struct timeval64 cfi_first_event
;
469 uint32_t cfi_op_list_ctr
;
470 uint32_t cfi_op_time
[CFI_MAX_TIME_LOG_ENTRY
]; /* time interval in microseconds since first event */
471 unsigned char cfi_op_list
[CFI_MAX_TIME_LOG_ENTRY
];
472 union sockaddr_in_4_6 cfi_so_attach_faddr
; /* faddr at the time of attach */
473 union sockaddr_in_4_6 cfi_so_attach_laddr
; /* laddr at the time of attach */
476 uint64_t cfi_byte_inbound_count
;
477 uint64_t cfi_byte_outbound_count
;
479 boolean_t cfi_isSignatureLatest
; /* Indicates if signature covers latest flow attributes */
482 * cfi_pending_first and cfi_pending_last describe the total
483 * amount of data outstanding for all the filters on
484 * this socket and data in the flow queue
485 * cfi_pending_mbcnt counts in sballoc() "chars of mbufs used"
487 uint64_t cfi_pending_first
;
488 uint64_t cfi_pending_last
;
489 uint32_t cfi_pending_mbcnt
;
490 uint32_t cfi_pending_mbnum
;
491 uint32_t cfi_tail_drop_cnt
;
493 * cfi_pass_offset is the minimum of all the filters
495 uint64_t cfi_pass_offset
;
497 * cfi_inject_q holds data that needs to be re-injected
498 * into the socket after filtering and that can
499 * be queued because of flow control
501 struct cfil_queue cfi_inject_q
;
504 struct cfil_entry cfi_entries
[MAX_CONTENT_FILTER
];
505 struct cfil_hash_entry
*cfi_hash_entry
;
506 SLIST_HEAD(, cfil_entry
) cfi_ordered_entries
;
507 } __attribute__((aligned(8)));
509 #define CFIF_DROP 0x0001 /* drop action applied */
510 #define CFIF_CLOSE_WAIT 0x0002 /* waiting for filter to close */
511 #define CFIF_SOCK_CLOSED 0x0004 /* socket is closed */
512 #define CFIF_RETRY_INJECT_IN 0x0010 /* inject in failed */
513 #define CFIF_RETRY_INJECT_OUT 0x0020 /* inject out failed */
514 #define CFIF_SHUT_WR 0x0040 /* shutdown write */
515 #define CFIF_SHUT_RD 0x0080 /* shutdown read */
516 #define CFIF_SOCKET_CONNECTED 0x0100 /* socket is connected */
517 #define CFIF_INITIAL_VERDICT 0x0200 /* received initial verdict */
519 #define CFI_MASK_GENCNT 0xFFFFFFFF00000000 /* upper 32 bits */
520 #define CFI_SHIFT_GENCNT 32
521 #define CFI_MASK_FLOWHASH 0x00000000FFFFFFFF /* lower 32 bits */
522 #define CFI_SHIFT_FLOWHASH 0
524 #define CFI_ENTRY_KCUNIT(i, e) (((e) - &((i)->cfi_entries[0])) + 1)
526 TAILQ_HEAD(cfil_sock_head
, cfil_info
) cfil_sock_head
;
527 TAILQ_HEAD(cfil_sock_head_stats
, cfil_info
) cfil_sock_head_stats
;
529 #define CFIL_QUEUE_VERIFY(x) if (cfil_debug) cfil_queue_verify(x)
530 #define CFIL_INFO_VERIFY(x) if (cfil_debug) cfil_info_verify(x)
535 LIST_HEAD(cfilhashhead
, cfil_hash_entry
);
536 #define CFILHASHSIZE 16
537 #define CFIL_HASH(laddr, faddr, lport, fport) ((faddr) ^ ((laddr) >> 16) ^ (fport) ^ (lport))
538 #define IS_UDP(so) (so && so->so_proto && so->so_proto->pr_type == SOCK_DGRAM && so->so_proto->pr_protocol == IPPROTO_UDP)
539 #define UNCONNECTED(inp) (inp && (((inp->inp_vflag & INP_IPV4) && (inp->inp_faddr.s_addr == INADDR_ANY)) || \
540 ((inp->inp_vflag & INP_IPV6) && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))))
541 #define IS_ENTRY_ATTACHED(cfil_info, kcunit) (cfil_info != NULL && (kcunit <= MAX_CONTENT_FILTER) && \
542 cfil_info->cfi_entries[kcunit - 1].cfe_filter != NULL)
543 #define IS_DNS(local, remote) (check_port(local, 53) || check_port(remote, 53) || check_port(local, 5353) || check_port(remote, 5353))
544 #define IS_INITIAL_TFO_DATA(so) (so && (so->so_flags1 & SOF1_PRECONNECT_DATA) && (so->so_state & SS_ISCONNECTING))
545 #define NULLADDRESS(addr) ((addr.sa.sa_len == 0) || \
546 (addr.sa.sa_family == AF_INET && addr.sin.sin_addr.s_addr == 0) || \
547 (addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&addr.sin6.sin6_addr)))
550 * Periodic Statistics Report:
552 static struct thread
*cfil_stats_report_thread
;
553 #define CFIL_STATS_REPORT_INTERVAL_MIN_MSEC 500 // Highest report frequency
554 #define CFIL_STATS_REPORT_RUN_INTERVAL_NSEC (CFIL_STATS_REPORT_INTERVAL_MIN_MSEC * NSEC_PER_MSEC)
555 #define CFIL_STATS_REPORT_MAX_COUNT 50 // Max stats to be reported per run
557 /* This buffer must have same layout as struct cfil_msg_stats_report */
558 struct cfil_stats_report_buffer
{
559 struct cfil_msg_hdr msghdr
;
561 struct cfil_msg_sock_stats stats
[CFIL_STATS_REPORT_MAX_COUNT
];
563 static struct cfil_stats_report_buffer
*global_cfil_stats_report_buffers
[MAX_CONTENT_FILTER
];
564 static uint32_t global_cfil_stats_counts
[MAX_CONTENT_FILTER
];
567 * UDP Garbage Collection:
569 static struct thread
*cfil_udp_gc_thread
;
570 #define UDP_FLOW_GC_IDLE_TO 30 // Flow Idle Timeout in seconds
571 #define UDP_FLOW_GC_ACTION_TO 10 // Flow Action Timeout (no action from user space) in seconds
572 #define UDP_FLOW_GC_MAX_COUNT 100 // Max UDP flows to be handled per run
573 #define UDP_FLOW_GC_RUN_INTERVAL_NSEC (10 * NSEC_PER_SEC) // GC wakes up every 10 seconds
576 * UDP flow queue thresholds
578 #define UDP_FLOW_GC_MBUF_CNT_MAX (2 << MBSHIFT) // Max mbuf byte count in flow queue (2MB)
579 #define UDP_FLOW_GC_MBUF_NUM_MAX (UDP_FLOW_GC_MBUF_CNT_MAX >> MCLSHIFT) // Max mbuf count in flow queue (1K)
580 #define UDP_FLOW_GC_MBUF_SHIFT 5 // Shift to get 1/32 of platform limits
582 * UDP flow queue threshold globals:
584 static unsigned int cfil_udp_gc_mbuf_num_max
= UDP_FLOW_GC_MBUF_NUM_MAX
;
585 static unsigned int cfil_udp_gc_mbuf_cnt_max
= UDP_FLOW_GC_MBUF_CNT_MAX
;
588 * struct cfil_hash_entry
590 * Hash entry for cfil_info
592 struct cfil_hash_entry
{
593 LIST_ENTRY(cfil_hash_entry
) cfentry_link
;
594 struct cfil_info
*cfentry_cfil
;
595 u_short cfentry_fport
;
596 u_short cfentry_lport
;
597 sa_family_t cfentry_family
;
598 u_int32_t cfentry_flowhash
;
599 u_int64_t cfentry_lastused
;
601 /* foreign host table entry */
602 struct in_addr_4in6 addr46
;
603 struct in6_addr addr6
;
606 /* local host table entry */
607 struct in_addr_4in6 addr46
;
608 struct in6_addr addr6
;
615 * For each UDP socket, this is a hash table maintaining all cfil_info structs
616 * keyed by the flow 4-tuples <lport,fport,laddr,faddr>.
619 struct socket
*cfdb_so
;
620 uint32_t cfdb_count
; /* Number of total content filters */
621 struct cfilhashhead
*cfdb_hashbase
;
622 u_long cfdb_hashmask
;
623 struct cfil_hash_entry
*cfdb_only_entry
; /* Optimization for connected UDP */
627 * CFIL specific mbuf tag:
628 * Save state of socket at the point of data entry into cfil.
629 * Use saved state for reinjection at protocol layer.
632 union sockaddr_in_4_6 cfil_faddr
;
633 uint32_t cfil_so_state_change_cnt
;
634 short cfil_so_options
;
637 #define CFIL_HASH_ENTRY_ZONE_NAME "cfil_entry_hash"
638 #define CFIL_HASH_ENTRY_ZONE_MAX 1024
639 static struct zone
*cfil_hash_entry_zone
= NULL
;
641 #define CFIL_DB_ZONE_NAME "cfil_db"
642 #define CFIL_DB_ZONE_MAX 1024
643 static struct zone
*cfil_db_zone
= NULL
;
649 struct cfil_stats cfil_stats
;
652 * For troubleshooting
654 int cfil_log_level
= LOG_ERR
;
657 // Debug controls added for selective debugging.
658 // Disabled for production. If enabled,
659 // these will have performance impact
660 #define LIFECYCLE_DEBUG 0
661 #define VERDICT_DEBUG 0
665 #define STATS_DEBUG 0
668 * Sysctls for logs and statistics
670 static int sysctl_cfil_filter_list(struct sysctl_oid
*, void *, int,
671 struct sysctl_req
*);
672 static int sysctl_cfil_sock_list(struct sysctl_oid
*, void *, int,
673 struct sysctl_req
*);
675 SYSCTL_NODE(_net
, OID_AUTO
, cfil
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "cfil");
677 SYSCTL_INT(_net_cfil
, OID_AUTO
, log
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
678 &cfil_log_level
, 0, "");
680 SYSCTL_INT(_net_cfil
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
683 SYSCTL_UINT(_net_cfil
, OID_AUTO
, sock_attached_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
684 &cfil_sock_attached_count
, 0, "");
686 SYSCTL_UINT(_net_cfil
, OID_AUTO
, active_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
687 &cfil_active_count
, 0, "");
689 SYSCTL_UINT(_net_cfil
, OID_AUTO
, close_wait_timeout
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
690 &cfil_close_wait_timeout
, 0, "");
692 static int cfil_sbtrim
= 1;
693 SYSCTL_UINT(_net_cfil
, OID_AUTO
, sbtrim
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
694 &cfil_sbtrim
, 0, "");
696 SYSCTL_PROC(_net_cfil
, OID_AUTO
, filter_list
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
697 0, 0, sysctl_cfil_filter_list
, "S,cfil_filter_stat", "");
699 SYSCTL_PROC(_net_cfil
, OID_AUTO
, sock_list
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
700 0, 0, sysctl_cfil_sock_list
, "S,cfil_sock_stat", "");
702 SYSCTL_STRUCT(_net_cfil
, OID_AUTO
, stats
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
703 &cfil_stats
, cfil_stats
, "");
706 * Forward declaration to appease the compiler
708 static int cfil_action_data_pass(struct socket
*, struct cfil_info
*, uint32_t, int,
710 static int cfil_action_drop(struct socket
*, struct cfil_info
*, uint32_t);
711 static int cfil_action_bless_client(uint32_t, struct cfil_msg_hdr
*);
712 static int cfil_action_set_crypto_key(uint32_t, struct cfil_msg_hdr
*);
713 static int cfil_dispatch_closed_event(struct socket
*, struct cfil_info
*, int);
714 static int cfil_data_common(struct socket
*, struct cfil_info
*, int, struct sockaddr
*,
715 struct mbuf
*, struct mbuf
*, uint32_t);
716 static int cfil_data_filter(struct socket
*, struct cfil_info
*, uint32_t, int,
717 struct mbuf
*, uint64_t);
718 static void fill_ip_sockaddr_4_6(union sockaddr_in_4_6
*,
719 struct in_addr
, u_int16_t
);
720 static void fill_ip6_sockaddr_4_6(union sockaddr_in_4_6
*,
721 struct in6_addr
*, u_int16_t
);
723 static int cfil_dispatch_attach_event(struct socket
*, struct cfil_info
*, uint32_t, int);
724 static void cfil_info_free(struct cfil_info
*);
725 static struct cfil_info
* cfil_info_alloc(struct socket
*, struct cfil_hash_entry
*);
726 static int cfil_info_attach_unit(struct socket
*, uint32_t, struct cfil_info
*);
727 static struct socket
* cfil_socket_from_sock_id(cfil_sock_id_t
, bool);
728 static struct socket
* cfil_socket_from_client_uuid(uuid_t
, bool *);
729 static int cfil_service_pending_queue(struct socket
*, struct cfil_info
*, uint32_t, int);
730 static int cfil_data_service_ctl_q(struct socket
*, struct cfil_info
*, uint32_t, int);
731 static void cfil_info_verify(struct cfil_info
*);
732 static int cfil_update_data_offsets(struct socket
*, struct cfil_info
*, uint32_t, int,
734 static int cfil_acquire_sockbuf(struct socket
*, struct cfil_info
*, int);
735 static void cfil_release_sockbuf(struct socket
*, int);
736 static int cfil_filters_attached(struct socket
*);
738 static void cfil_rw_lock_exclusive(lck_rw_t
*);
739 static void cfil_rw_unlock_exclusive(lck_rw_t
*);
740 static void cfil_rw_lock_shared(lck_rw_t
*);
741 static void cfil_rw_unlock_shared(lck_rw_t
*);
742 static boolean_t
cfil_rw_lock_shared_to_exclusive(lck_rw_t
*);
743 static void cfil_rw_lock_exclusive_to_shared(lck_rw_t
*);
745 static unsigned int cfil_data_length(struct mbuf
*, int *, int *);
746 static errno_t
cfil_db_init(struct socket
*);
747 static void cfil_db_free(struct socket
*so
);
748 struct cfil_hash_entry
*cfil_db_lookup_entry(struct cfil_db
*, struct sockaddr
*, struct sockaddr
*);
749 struct cfil_hash_entry
*cfil_db_lookup_entry_with_sockid(struct cfil_db
*, u_int64_t
);
750 struct cfil_hash_entry
*cfil_db_add_entry(struct cfil_db
*, struct sockaddr
*, struct sockaddr
*);
751 void cfil_db_delete_entry(struct cfil_db
*, struct cfil_hash_entry
*);
752 struct cfil_hash_entry
*cfil_sock_udp_get_flow(struct socket
*, uint32_t, bool, struct sockaddr
*, struct sockaddr
*);
753 struct cfil_info
*cfil_db_get_cfil_info(struct cfil_db
*, cfil_sock_id_t
);
754 static errno_t
cfil_sock_udp_handle_data(bool, struct socket
*, struct sockaddr
*, struct sockaddr
*,
755 struct mbuf
*, struct mbuf
*, uint32_t);
756 static int32_t cfil_sock_udp_data_pending(struct sockbuf
*, bool);
757 static void cfil_sock_udp_is_closed(struct socket
*);
758 static int cfil_sock_udp_notify_shutdown(struct socket
*, int, int, int);
759 static int cfil_sock_udp_shutdown(struct socket
*, int *);
760 static void cfil_sock_udp_close_wait(struct socket
*);
761 static void cfil_sock_udp_buf_update(struct sockbuf
*);
762 static int cfil_filters_udp_attached(struct socket
*, bool);
763 static void cfil_get_flow_address_v6(struct cfil_hash_entry
*, struct inpcb
*,
764 struct in6_addr
**, struct in6_addr
**,
765 u_int16_t
*, u_int16_t
*);
766 static void cfil_get_flow_address(struct cfil_hash_entry
*, struct inpcb
*,
767 struct in_addr
*, struct in_addr
*,
768 u_int16_t
*, u_int16_t
*);
769 static void cfil_info_log(int, struct cfil_info
*, const char *);
770 void cfil_filter_show(u_int32_t
);
771 void cfil_info_show(void);
772 bool cfil_info_idle_timed_out(struct cfil_info
*, int, u_int32_t
);
773 bool cfil_info_action_timed_out(struct cfil_info
*, int);
774 bool cfil_info_buffer_threshold_exceeded(struct cfil_info
*);
775 struct m_tag
*cfil_udp_save_socket_state(struct cfil_info
*, struct mbuf
*);
776 static void cfil_udp_gc_thread_func(void *, wait_result_t
);
777 static void cfil_info_udp_expire(void *, wait_result_t
);
778 static bool fill_cfil_hash_entry_from_address(struct cfil_hash_entry
*, bool, struct sockaddr
*);
779 static void cfil_sock_received_verdict(struct socket
*so
);
780 static void cfil_fill_event_msg_addresses(struct cfil_hash_entry
*, struct inpcb
*,
781 union sockaddr_in_4_6
*, union sockaddr_in_4_6
*,
782 boolean_t
, boolean_t
);
783 static void cfil_stats_report_thread_func(void *, wait_result_t
);
784 static void cfil_stats_report(void *v
, wait_result_t w
);
786 bool check_port(struct sockaddr
*, u_short
);
789 * Content filter global read write lock
793 cfil_rw_lock_exclusive(lck_rw_t
*lck
)
797 lr_saved
= __builtin_return_address(0);
799 lck_rw_lock_exclusive(lck
);
801 cfil_rw_lock_history
[cfil_rw_nxt_lck
] = lr_saved
;
802 cfil_rw_nxt_lck
= (cfil_rw_nxt_lck
+ 1) % CFIL_RW_LCK_MAX
;
806 cfil_rw_unlock_exclusive(lck_rw_t
*lck
)
810 lr_saved
= __builtin_return_address(0);
812 lck_rw_unlock_exclusive(lck
);
814 cfil_rw_unlock_history
[cfil_rw_nxt_unlck
] = lr_saved
;
815 cfil_rw_nxt_unlck
= (cfil_rw_nxt_unlck
+ 1) % CFIL_RW_LCK_MAX
;
819 cfil_rw_lock_shared(lck_rw_t
*lck
)
823 lr_saved
= __builtin_return_address(0);
825 lck_rw_lock_shared(lck
);
827 cfil_rw_lock_history
[cfil_rw_nxt_lck
] = lr_saved
;
828 cfil_rw_nxt_lck
= (cfil_rw_nxt_lck
+ 1) % CFIL_RW_LCK_MAX
;
832 cfil_rw_unlock_shared(lck_rw_t
*lck
)
836 lr_saved
= __builtin_return_address(0);
838 lck_rw_unlock_shared(lck
);
840 cfil_rw_unlock_history
[cfil_rw_nxt_unlck
] = lr_saved
;
841 cfil_rw_nxt_unlck
= (cfil_rw_nxt_unlck
+ 1) % CFIL_RW_LCK_MAX
;
845 cfil_rw_lock_shared_to_exclusive(lck_rw_t
*lck
)
850 lr_saved
= __builtin_return_address(0);
852 upgraded
= lck_rw_lock_shared_to_exclusive(lck
);
854 cfil_rw_unlock_history
[cfil_rw_nxt_unlck
] = lr_saved
;
855 cfil_rw_nxt_unlck
= (cfil_rw_nxt_unlck
+ 1) % CFIL_RW_LCK_MAX
;
861 cfil_rw_lock_exclusive_to_shared(lck_rw_t
*lck
)
865 lr_saved
= __builtin_return_address(0);
867 lck_rw_lock_exclusive_to_shared(lck
);
869 cfil_rw_lock_history
[cfil_rw_nxt_lck
] = lr_saved
;
870 cfil_rw_nxt_lck
= (cfil_rw_nxt_lck
+ 1) % CFIL_RW_LCK_MAX
;
874 cfil_rw_lock_assert_held(lck_rw_t
*lck
, int exclusive
)
877 #pragma unused(lck, exclusive)
880 exclusive
? LCK_RW_ASSERT_EXCLUSIVE
: LCK_RW_ASSERT_HELD
);
884 * Return the number of bytes in the mbuf chain using the same
885 * method as m_length() or sballoc()
887 * Returns data len - starting from PKT start
888 * - retmbcnt - optional param to get total mbuf bytes in chain
889 * - retmbnum - optional param to get number of mbufs in chain
892 cfil_data_length(struct mbuf
*m
, int *retmbcnt
, int *retmbnum
)
895 unsigned int pktlen
= 0;
899 // Locate the start of data
900 for (m0
= m
; m0
!= NULL
; m0
= m0
->m_next
) {
901 if (m0
->m_flags
& M_PKTHDR
) {
906 CFIL_LOG(LOG_ERR
, "cfil_data_length: no M_PKTHDR");
911 if (retmbcnt
== NULL
&& retmbnum
== NULL
) {
918 for (m0
= m
; m0
!= NULL
; m0
= m0
->m_next
) {
922 if (m0
->m_flags
& M_EXT
) {
923 mbcnt
+= m0
->m_ext
.ext_size
;
936 cfil_data_start(struct mbuf
*m
)
940 // Locate the start of data
941 for (m0
= m
; m0
!= NULL
; m0
= m0
->m_next
) {
942 if (m0
->m_flags
& M_PKTHDR
) {
950 * Common mbuf queue utilities
954 cfil_queue_init(struct cfil_queue
*cfq
)
958 MBUFQ_INIT(&cfq
->q_mq
);
961 static inline uint64_t
962 cfil_queue_drain(struct cfil_queue
*cfq
)
964 uint64_t drained
= cfq
->q_start
- cfq
->q_end
;
967 MBUFQ_DRAIN(&cfq
->q_mq
);
972 /* Return 1 when empty, 0 otherwise */
974 cfil_queue_empty(struct cfil_queue
*cfq
)
976 return MBUFQ_EMPTY(&cfq
->q_mq
);
979 static inline uint64_t
980 cfil_queue_offset_first(struct cfil_queue
*cfq
)
985 static inline uint64_t
986 cfil_queue_offset_last(struct cfil_queue
*cfq
)
991 static inline uint64_t
992 cfil_queue_len(struct cfil_queue
*cfq
)
994 return cfq
->q_end
- cfq
->q_start
;
998 * Routines to verify some fundamental assumptions
1002 cfil_queue_verify(struct cfil_queue
*cfq
)
1007 uint64_t queuesize
= 0;
1009 /* Verify offset are ordered */
1010 VERIFY(cfq
->q_start
<= cfq
->q_end
);
1013 * When queue is empty, the offsets are equal otherwise the offsets
1016 VERIFY((MBUFQ_EMPTY(&cfq
->q_mq
) && cfq
->q_start
== cfq
->q_end
) ||
1017 (!MBUFQ_EMPTY(&cfq
->q_mq
) &&
1018 cfq
->q_start
!= cfq
->q_end
));
1020 MBUFQ_FOREACH(chain
, &cfq
->q_mq
) {
1021 size_t chainsize
= 0;
1023 unsigned int mlen
= cfil_data_length(m
, NULL
, NULL
);
1024 // skip the addr and control stuff if present
1025 m
= cfil_data_start(m
);
1028 m
== (void *)M_TAG_FREE_PATTERN
||
1029 m
->m_next
== (void *)M_TAG_FREE_PATTERN
||
1030 m
->m_nextpkt
== (void *)M_TAG_FREE_PATTERN
) {
1031 panic("%s - mq %p is free at %p", __func__
,
1034 for (n
= m
; n
!= NULL
; n
= n
->m_next
) {
1035 if (n
->m_type
!= MT_DATA
&&
1036 n
->m_type
!= MT_HEADER
&&
1037 n
->m_type
!= MT_OOBDATA
) {
1038 panic("%s - %p unsupported type %u", __func__
,
1041 chainsize
+= n
->m_len
;
1043 if (mlen
!= chainsize
) {
1044 panic("%s - %p m_length() %u != chainsize %lu",
1045 __func__
, m
, mlen
, chainsize
);
1047 queuesize
+= chainsize
;
1049 if (queuesize
!= cfq
->q_end
- cfq
->q_start
) {
1050 panic("%s - %p queuesize %llu != offsetdiffs %llu", __func__
,
1051 m
, queuesize
, cfq
->q_end
- cfq
->q_start
);
1056 cfil_queue_enqueue(struct cfil_queue
*cfq
, mbuf_t m
, size_t len
)
1058 CFIL_QUEUE_VERIFY(cfq
);
1060 MBUFQ_ENQUEUE(&cfq
->q_mq
, m
);
1063 CFIL_QUEUE_VERIFY(cfq
);
1067 cfil_queue_remove(struct cfil_queue
*cfq
, mbuf_t m
, size_t len
)
1069 CFIL_QUEUE_VERIFY(cfq
);
1071 VERIFY(cfil_data_length(m
, NULL
, NULL
) == len
);
1073 MBUFQ_REMOVE(&cfq
->q_mq
, m
);
1074 MBUFQ_NEXT(m
) = NULL
;
1075 cfq
->q_start
+= len
;
1077 CFIL_QUEUE_VERIFY(cfq
);
1081 cfil_queue_first(struct cfil_queue
*cfq
)
1083 return MBUFQ_FIRST(&cfq
->q_mq
);
1087 cfil_queue_next(struct cfil_queue
*cfq
, mbuf_t m
)
1090 return MBUFQ_NEXT(m
);
1094 cfil_entry_buf_verify(struct cfe_buf
*cfe_buf
)
1096 CFIL_QUEUE_VERIFY(&cfe_buf
->cfe_ctl_q
);
1097 CFIL_QUEUE_VERIFY(&cfe_buf
->cfe_pending_q
);
1099 /* Verify the queues are ordered so that pending is before ctl */
1100 VERIFY(cfe_buf
->cfe_ctl_q
.q_start
>= cfe_buf
->cfe_pending_q
.q_end
);
1102 /* The peek offset cannot be less than the pass offset */
1103 VERIFY(cfe_buf
->cfe_peek_offset
>= cfe_buf
->cfe_pass_offset
);
1105 /* Make sure we've updated the offset we peeked at */
1106 VERIFY(cfe_buf
->cfe_ctl_q
.q_start
<= cfe_buf
->cfe_peeked
);
1110 cfil_entry_verify(struct cfil_entry
*entry
)
1112 cfil_entry_buf_verify(&entry
->cfe_snd
);
1113 cfil_entry_buf_verify(&entry
->cfe_rcv
);
1117 cfil_info_buf_verify(struct cfi_buf
*cfi_buf
)
1119 CFIL_QUEUE_VERIFY(&cfi_buf
->cfi_inject_q
);
1121 VERIFY(cfi_buf
->cfi_pending_first
<= cfi_buf
->cfi_pending_last
);
1125 cfil_info_verify(struct cfil_info
*cfil_info
)
1129 if (cfil_info
== NULL
) {
1133 cfil_info_buf_verify(&cfil_info
->cfi_snd
);
1134 cfil_info_buf_verify(&cfil_info
->cfi_rcv
);
1136 for (i
= 0; i
< MAX_CONTENT_FILTER
; i
++) {
1137 cfil_entry_verify(&cfil_info
->cfi_entries
[i
]);
1142 verify_content_filter(struct content_filter
*cfc
)
1144 struct cfil_entry
*entry
;
1147 VERIFY(cfc
->cf_sock_count
>= 0);
1149 TAILQ_FOREACH(entry
, &cfc
->cf_sock_entries
, cfe_link
) {
1151 VERIFY(cfc
== entry
->cfe_filter
);
1153 VERIFY(count
== cfc
->cf_sock_count
);
1157 * Kernel control socket callbacks
1160 cfil_ctl_connect(kern_ctl_ref kctlref
, struct sockaddr_ctl
*sac
,
1164 struct content_filter
*cfc
= NULL
;
1166 CFIL_LOG(LOG_NOTICE
, "");
1168 cfc
= zalloc(content_filter_zone
);
1170 CFIL_LOG(LOG_ERR
, "zalloc failed");
1174 bzero(cfc
, sizeof(struct content_filter
));
1176 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1177 if (content_filters
== NULL
) {
1178 struct content_filter
**tmp
;
1180 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1183 struct content_filter
**,
1184 MAX_CONTENT_FILTER
* sizeof(struct content_filter
*),
1188 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1190 if (tmp
== NULL
&& content_filters
== NULL
) {
1192 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1195 /* Another thread may have won the race */
1196 if (content_filters
!= NULL
) {
1199 content_filters
= tmp
;
1203 if (sac
->sc_unit
== 0 || sac
->sc_unit
> MAX_CONTENT_FILTER
) {
1204 CFIL_LOG(LOG_ERR
, "bad sc_unit %u", sac
->sc_unit
);
1206 } else if (content_filters
[sac
->sc_unit
- 1] != NULL
) {
1207 CFIL_LOG(LOG_ERR
, "sc_unit %u in use", sac
->sc_unit
);
1211 * kernel control socket kcunit numbers start at 1
1213 content_filters
[sac
->sc_unit
- 1] = cfc
;
1215 cfc
->cf_kcref
= kctlref
;
1216 cfc
->cf_kcunit
= sac
->sc_unit
;
1217 TAILQ_INIT(&cfc
->cf_sock_entries
);
1220 cfil_active_count
++;
1222 // Allocate periodic stats buffer for this filter
1223 if (global_cfil_stats_report_buffers
[cfc
->cf_kcunit
- 1] == NULL
) {
1224 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1226 struct cfil_stats_report_buffer
*buf
;
1229 struct cfil_stats_report_buffer
*,
1230 sizeof(struct cfil_stats_report_buffer
),
1234 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1238 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1242 /* Another thread may have won the race */
1243 if (global_cfil_stats_report_buffers
[cfc
->cf_kcunit
- 1] != NULL
) {
1246 global_cfil_stats_report_buffers
[cfc
->cf_kcunit
- 1] = buf
;
1250 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1252 if (error
!= 0 && cfc
!= NULL
) {
1253 zfree(content_filter_zone
, cfc
);
1257 OSIncrementAtomic(&cfil_stats
.cfs_ctl_connect_ok
);
1259 OSIncrementAtomic(&cfil_stats
.cfs_ctl_connect_fail
);
1262 CFIL_LOG(LOG_INFO
, "return %d cfil_active_count %u kcunit %u",
1263 error
, cfil_active_count
, sac
->sc_unit
);
1269 cfil_ctl_disconnect(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
)
1271 #pragma unused(kctlref)
1273 struct content_filter
*cfc
;
1274 struct cfil_entry
*entry
;
1275 uint64_t sock_flow_id
= 0;
1277 CFIL_LOG(LOG_NOTICE
, "");
1279 if (content_filters
== NULL
) {
1280 CFIL_LOG(LOG_ERR
, "no content filter");
1284 if (kcunit
> MAX_CONTENT_FILTER
) {
1285 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1286 kcunit
, MAX_CONTENT_FILTER
);
1291 cfc
= (struct content_filter
*)unitinfo
;
1296 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1297 if (content_filters
[kcunit
- 1] != cfc
|| cfc
->cf_kcunit
!= kcunit
) {
1298 CFIL_LOG(LOG_ERR
, "bad unit info %u)",
1300 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1303 cfc
->cf_flags
|= CFF_DETACHING
;
1305 * Remove all sockets from the filter
1307 while ((entry
= TAILQ_FIRST(&cfc
->cf_sock_entries
)) != NULL
) {
1308 cfil_rw_lock_assert_held(&cfil_lck_rw
, 1);
1310 verify_content_filter(cfc
);
1312 * Accept all outstanding data by pushing to next filter
1315 * TBD: Actually we should make sure all data has been pushed
1318 if (entry
->cfe_cfil_info
&& entry
->cfe_cfil_info
->cfi_so
) {
1319 struct cfil_info
*cfil_info
= entry
->cfe_cfil_info
;
1320 struct socket
*so
= cfil_info
->cfi_so
;
1321 sock_flow_id
= cfil_info
->cfi_sock_id
;
1323 /* Need to let data flow immediately */
1324 entry
->cfe_flags
|= CFEF_SENT_SOCK_ATTACHED
|
1328 * Respect locking hierarchy
1330 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1335 * When cfe_filter is NULL the filter is detached
1336 * and the entry has been removed from cf_sock_entries
1338 if ((so
->so_cfil
== NULL
&& so
->so_cfil_db
== NULL
) || entry
->cfe_filter
== NULL
) {
1339 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1343 (void) cfil_action_data_pass(so
, cfil_info
, kcunit
, 1,
1347 (void) cfil_action_data_pass(so
, cfil_info
, kcunit
, 0,
1351 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1354 * Check again to make sure if the cfil_info is still valid
1355 * as the socket may have been unlocked when when calling
1356 * cfil_acquire_sockbuf()
1358 if (entry
->cfe_filter
== NULL
||
1359 (so
->so_cfil
== NULL
&& cfil_db_get_cfil_info(so
->so_cfil_db
, sock_flow_id
) == NULL
)) {
1363 /* The filter is now detached */
1364 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
1366 cfil_info_log(LOG_DEBUG
, cfil_info
, "CFIL: LIFECYCLE: - FILTER DISCONNECTED");
1368 CFIL_LOG(LOG_NOTICE
, "so %llx detached %u",
1369 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
1370 if ((cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) &&
1371 cfil_filters_attached(so
) == 0) {
1372 CFIL_LOG(LOG_NOTICE
, "so %llx waking",
1373 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1374 wakeup((caddr_t
)cfil_info
);
1378 * Remove the filter entry from the content filter
1379 * but leave the rest of the state intact as the queues
1380 * may not be empty yet
1382 entry
->cfe_filter
= NULL
;
1383 entry
->cfe_necp_control_unit
= 0;
1385 TAILQ_REMOVE(&cfc
->cf_sock_entries
, entry
, cfe_link
);
1386 cfc
->cf_sock_count
--;
1388 socket_unlock(so
, 1);
1391 verify_content_filter(cfc
);
1393 /* Free the stats buffer for this filter */
1394 if (global_cfil_stats_report_buffers
[cfc
->cf_kcunit
- 1] != NULL
) {
1395 FREE(global_cfil_stats_report_buffers
[cfc
->cf_kcunit
- 1], M_TEMP
);
1396 global_cfil_stats_report_buffers
[cfc
->cf_kcunit
- 1] = NULL
;
1398 VERIFY(cfc
->cf_sock_count
== 0);
1401 * Make filter inactive
1403 content_filters
[kcunit
- 1] = NULL
;
1404 cfil_active_count
--;
1405 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1407 if (cfc
->cf_crypto_state
!= NULL
) {
1408 cfil_crypto_cleanup_state(cfc
->cf_crypto_state
);
1409 cfc
->cf_crypto_state
= NULL
;
1412 zfree(content_filter_zone
, cfc
);
1415 OSIncrementAtomic(&cfil_stats
.cfs_ctl_disconnect_ok
);
1417 OSIncrementAtomic(&cfil_stats
.cfs_ctl_disconnect_fail
);
1420 CFIL_LOG(LOG_INFO
, "return %d cfil_active_count %u kcunit %u",
1421 error
, cfil_active_count
, kcunit
);
1427 * cfil_acquire_sockbuf()
1429 * Prevent any other thread from acquiring the sockbuf
1430 * We use sb_cfil_thread as a semaphore to prevent other threads from
1431 * messing with the sockbuf -- see sblock()
1432 * Note: We do not set SB_LOCK here because the thread may check or modify
1433 * SB_LOCK several times until it calls cfil_release_sockbuf() -- currently
1434 * sblock(), sbunlock() or sodefunct()
1437 cfil_acquire_sockbuf(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
)
1439 thread_t tp
= current_thread();
1440 struct sockbuf
*sb
= outgoing
? &so
->so_snd
: &so
->so_rcv
;
1441 lck_mtx_t
*mutex_held
;
1445 * Wait until no thread is holding the sockbuf and other content
1446 * filter threads have released the sockbuf
1448 while ((sb
->sb_flags
& SB_LOCK
) ||
1449 (sb
->sb_cfil_thread
!= NULL
&& sb
->sb_cfil_thread
!= tp
)) {
1450 if (so
->so_proto
->pr_getlock
!= NULL
) {
1451 mutex_held
= (*so
->so_proto
->pr_getlock
)(so
, PR_F_WILLUNLOCK
);
1453 mutex_held
= so
->so_proto
->pr_domain
->dom_mtx
;
1456 LCK_MTX_ASSERT(mutex_held
, LCK_MTX_ASSERT_OWNED
);
1459 VERIFY(sb
->sb_wantlock
!= 0);
1461 msleep(&sb
->sb_flags
, mutex_held
, PSOCK
, "cfil_acquire_sockbuf",
1464 VERIFY(sb
->sb_wantlock
!= 0);
1468 * Use reference count for repetitive calls on same thread
1470 if (sb
->sb_cfil_refs
== 0) {
1471 VERIFY(sb
->sb_cfil_thread
== NULL
);
1472 VERIFY((sb
->sb_flags
& SB_LOCK
) == 0);
1474 sb
->sb_cfil_thread
= tp
;
1475 sb
->sb_flags
|= SB_LOCK
;
1479 /* We acquire the socket buffer when we need to cleanup */
1480 if (cfil_info
== NULL
) {
1481 CFIL_LOG(LOG_ERR
, "so %llx cfil detached",
1482 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1484 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
1485 CFIL_LOG(LOG_ERR
, "so %llx drop set",
1486 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1494 cfil_release_sockbuf(struct socket
*so
, int outgoing
)
1496 struct sockbuf
*sb
= outgoing
? &so
->so_snd
: &so
->so_rcv
;
1497 thread_t tp
= current_thread();
1499 socket_lock_assert_owned(so
);
1501 if (sb
->sb_cfil_thread
!= NULL
&& sb
->sb_cfil_thread
!= tp
) {
1502 panic("%s sb_cfil_thread %p not current %p", __func__
,
1503 sb
->sb_cfil_thread
, tp
);
1506 * Don't panic if we are defunct because SB_LOCK has
1507 * been cleared by sodefunct()
1509 if (!(so
->so_flags
& SOF_DEFUNCT
) && !(sb
->sb_flags
& SB_LOCK
)) {
1510 panic("%s SB_LOCK not set on %p", __func__
,
1514 * We can unlock when the thread unwinds to the last reference
1517 if (sb
->sb_cfil_refs
== 0) {
1518 sb
->sb_cfil_thread
= NULL
;
1519 sb
->sb_flags
&= ~SB_LOCK
;
1521 if (sb
->sb_wantlock
> 0) {
1522 wakeup(&sb
->sb_flags
);
1528 cfil_sock_id_from_socket(struct socket
*so
)
1530 if ((so
->so_flags
& SOF_CONTENT_FILTER
) && so
->so_cfil
) {
1531 return so
->so_cfil
->cfi_sock_id
;
1533 return CFIL_SOCK_ID_NONE
;
1538 cfil_socket_safe_lock(struct inpcb
*inp
)
1540 if (in_pcb_checkstate(inp
, WNT_ACQUIRE
, 0) != WNT_STOPUSING
) {
1541 socket_lock(inp
->inp_socket
, 1);
1542 if (in_pcb_checkstate(inp
, WNT_RELEASE
, 1) != WNT_STOPUSING
) {
1545 socket_unlock(inp
->inp_socket
, 1);
1550 static struct socket
*
1551 cfil_socket_from_sock_id(cfil_sock_id_t cfil_sock_id
, bool udp_only
)
1553 struct socket
*so
= NULL
;
1554 u_int64_t gencnt
= cfil_sock_id
>> 32;
1555 u_int32_t flowhash
= (u_int32_t
)(cfil_sock_id
& 0x0ffffffff);
1556 struct inpcb
*inp
= NULL
;
1557 struct inpcbinfo
*pcbinfo
= NULL
;
1560 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT: search for socket: id %llu gencnt %llx flowhash %x", cfil_sock_id
, gencnt
, flowhash
);
1568 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1569 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1570 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1571 inp
->inp_socket
!= NULL
&&
1572 inp
->inp_flowhash
== flowhash
&&
1573 (inp
->inp_socket
->so_gencnt
& 0x0ffffffff) == gencnt
&&
1574 inp
->inp_socket
->so_cfil
!= NULL
) {
1575 if (cfil_socket_safe_lock(inp
)) {
1576 so
= inp
->inp_socket
;
1581 lck_rw_done(pcbinfo
->ipi_lock
);
1589 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1590 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1591 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1592 inp
->inp_socket
!= NULL
&&
1593 inp
->inp_socket
->so_cfil_db
!= NULL
&&
1594 (inp
->inp_socket
->so_gencnt
& 0x0ffffffff) == gencnt
) {
1595 if (cfil_socket_safe_lock(inp
)) {
1596 so
= inp
->inp_socket
;
1601 lck_rw_done(pcbinfo
->ipi_lock
);
1605 OSIncrementAtomic(&cfil_stats
.cfs_sock_id_not_found
);
1607 "no socket for sock_id %llx gencnt %llx flowhash %x",
1608 cfil_sock_id
, gencnt
, flowhash
);
1614 static struct socket
*
1615 cfil_socket_from_client_uuid(uuid_t necp_client_uuid
, bool *cfil_attached
)
1617 struct socket
*so
= NULL
;
1618 struct inpcb
*inp
= NULL
;
1619 struct inpcbinfo
*pcbinfo
= &tcbinfo
;
1621 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1622 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1623 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1624 inp
->inp_socket
!= NULL
&&
1625 uuid_compare(inp
->necp_client_uuid
, necp_client_uuid
) == 0) {
1626 *cfil_attached
= (inp
->inp_socket
->so_cfil
!= NULL
);
1627 if (cfil_socket_safe_lock(inp
)) {
1628 so
= inp
->inp_socket
;
1633 lck_rw_done(pcbinfo
->ipi_lock
);
1639 lck_rw_lock_shared(pcbinfo
->ipi_lock
);
1640 LIST_FOREACH(inp
, pcbinfo
->ipi_listhead
, inp_list
) {
1641 if (inp
->inp_state
!= INPCB_STATE_DEAD
&&
1642 inp
->inp_socket
!= NULL
&&
1643 uuid_compare(inp
->necp_client_uuid
, necp_client_uuid
) == 0) {
1644 *cfil_attached
= (inp
->inp_socket
->so_cfil_db
!= NULL
);
1645 if (cfil_socket_safe_lock(inp
)) {
1646 so
= inp
->inp_socket
;
1651 lck_rw_done(pcbinfo
->ipi_lock
);
1658 cfil_info_stats_toggle(struct cfil_info
*cfil_info
, struct cfil_entry
*entry
, uint32_t report_frequency
)
1660 struct cfil_info
*cfil
= NULL
;
1661 Boolean found
= FALSE
;
1664 if (cfil_info
== NULL
) {
1668 if (report_frequency
) {
1669 if (entry
== NULL
) {
1673 // Update stats reporting frequency.
1674 if (entry
->cfe_stats_report_frequency
!= report_frequency
) {
1675 entry
->cfe_stats_report_frequency
= report_frequency
;
1676 if (entry
->cfe_stats_report_frequency
< CFIL_STATS_REPORT_INTERVAL_MIN_MSEC
) {
1677 entry
->cfe_stats_report_frequency
= CFIL_STATS_REPORT_INTERVAL_MIN_MSEC
;
1679 microuptime(&entry
->cfe_stats_report_ts
);
1681 // Insert cfil_info into list only if it is not in yet.
1682 TAILQ_FOREACH(cfil
, &cfil_sock_head_stats
, cfi_link_stats
) {
1683 if (cfil
== cfil_info
) {
1688 TAILQ_INSERT_TAIL(&cfil_sock_head_stats
, cfil_info
, cfi_link_stats
);
1690 // Wake up stats thread if this is first flow added
1691 if (cfil_sock_attached_stats_count
== 0) {
1692 thread_wakeup((caddr_t
)&cfil_sock_attached_stats_count
);
1694 cfil_sock_attached_stats_count
++;
1696 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT RECEIVED - STATS FLOW INSERTED: <so %llx sockID %llu> stats frequency %d msecs",
1697 cfil_info
->cfi_so
? (uint64_t)VM_KERNEL_ADDRPERM(cfil_info
->cfi_so
) : 0,
1698 cfil_info
->cfi_sock_id
,
1699 entry
->cfe_stats_report_frequency
);
1703 // Turn off stats reporting for this filter.
1704 if (entry
!= NULL
) {
1705 // Already off, no change.
1706 if (entry
->cfe_stats_report_frequency
== 0) {
1710 entry
->cfe_stats_report_frequency
= 0;
1711 // If cfil_info still has filter(s) asking for stats, no need to remove from list.
1712 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
1713 if (cfil_info
->cfi_entries
[kcunit
- 1].cfe_stats_report_frequency
> 0) {
1719 // No more filter asking for stats for this cfil_info, remove from list.
1720 if (!TAILQ_EMPTY(&cfil_sock_head_stats
)) {
1722 TAILQ_FOREACH(cfil
, &cfil_sock_head_stats
, cfi_link_stats
) {
1723 if (cfil
== cfil_info
) {
1729 cfil_sock_attached_stats_count
--;
1730 TAILQ_REMOVE(&cfil_sock_head_stats
, cfil_info
, cfi_link_stats
);
1732 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT RECEIVED - STATS FLOW DELETED: <so %llx sockID %llu> stats frequency reset",
1733 cfil_info
->cfi_so
? (uint64_t)VM_KERNEL_ADDRPERM(cfil_info
->cfi_so
) : 0,
1734 cfil_info
->cfi_sock_id
);
1742 cfil_ctl_send(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
, mbuf_t m
,
1745 #pragma unused(kctlref, flags)
1747 struct cfil_msg_hdr
*msghdr
;
1748 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
1750 struct cfil_msg_action
*action_msg
;
1751 struct cfil_entry
*entry
;
1752 struct cfil_info
*cfil_info
= NULL
;
1753 unsigned int data_len
= 0;
1755 CFIL_LOG(LOG_INFO
, "");
1757 if (content_filters
== NULL
) {
1758 CFIL_LOG(LOG_ERR
, "no content filter");
1762 if (kcunit
> MAX_CONTENT_FILTER
) {
1763 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1764 kcunit
, MAX_CONTENT_FILTER
);
1769 CFIL_LOG(LOG_ERR
, "null mbuf");
1773 data_len
= m_length(m
);
1775 if (data_len
< sizeof(struct cfil_msg_hdr
)) {
1776 CFIL_LOG(LOG_ERR
, "too short %u", data_len
);
1780 msghdr
= (struct cfil_msg_hdr
*)mbuf_data(m
);
1781 if (msghdr
->cfm_version
!= CFM_VERSION_CURRENT
) {
1782 CFIL_LOG(LOG_ERR
, "bad version %u", msghdr
->cfm_version
);
1786 if (msghdr
->cfm_type
!= CFM_TYPE_ACTION
) {
1787 CFIL_LOG(LOG_ERR
, "bad type %u", msghdr
->cfm_type
);
1791 if (msghdr
->cfm_len
> data_len
) {
1792 CFIL_LOG(LOG_ERR
, "bad length %u", msghdr
->cfm_len
);
1797 /* Validate action operation */
1798 switch (msghdr
->cfm_op
) {
1799 case CFM_OP_DATA_UPDATE
:
1801 &cfil_stats
.cfs_ctl_action_data_update
);
1804 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_drop
);
1806 case CFM_OP_BLESS_CLIENT
:
1807 if (msghdr
->cfm_len
!= sizeof(struct cfil_msg_bless_client
)) {
1808 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_len
);
1810 CFIL_LOG(LOG_ERR
, "bad len: %u for op %u",
1815 error
= cfil_action_bless_client(kcunit
, msghdr
);
1817 case CFM_OP_SET_CRYPTO_KEY
:
1818 if (msghdr
->cfm_len
!= sizeof(struct cfil_msg_set_crypto_key
)) {
1819 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_len
);
1821 CFIL_LOG(LOG_ERR
, "bad len: %u for op %u",
1826 error
= cfil_action_set_crypto_key(kcunit
, msghdr
);
1829 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_op
);
1830 CFIL_LOG(LOG_ERR
, "bad op %u", msghdr
->cfm_op
);
1834 if (msghdr
->cfm_len
!= sizeof(struct cfil_msg_action
)) {
1835 OSIncrementAtomic(&cfil_stats
.cfs_ctl_action_bad_len
);
1837 CFIL_LOG(LOG_ERR
, "bad len: %u for op %u",
1842 cfil_rw_lock_shared(&cfil_lck_rw
);
1843 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
1844 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
1847 cfil_rw_unlock_shared(&cfil_lck_rw
);
1850 cfil_rw_unlock_shared(&cfil_lck_rw
);
1852 // Search for socket (TCP+UDP and lock so)
1853 so
= cfil_socket_from_sock_id(msghdr
->cfm_sock_id
, false);
1855 CFIL_LOG(LOG_NOTICE
, "bad sock_id %llx",
1856 msghdr
->cfm_sock_id
);
1861 cfil_info
= so
->so_cfil_db
!= NULL
?
1862 cfil_db_get_cfil_info(so
->so_cfil_db
, msghdr
->cfm_sock_id
) : so
->so_cfil
;
1864 if (cfil_info
== NULL
) {
1865 CFIL_LOG(LOG_NOTICE
, "so %llx <id %llu> not attached",
1866 (uint64_t)VM_KERNEL_ADDRPERM(so
), msghdr
->cfm_sock_id
);
1869 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
1870 CFIL_LOG(LOG_NOTICE
, "so %llx drop set",
1871 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1875 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
1876 if (entry
->cfe_filter
== NULL
) {
1877 CFIL_LOG(LOG_NOTICE
, "so %llx no filter",
1878 (uint64_t)VM_KERNEL_ADDRPERM(so
));
1883 if (entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) {
1884 entry
->cfe_flags
|= CFEF_DATA_START
;
1887 "so %llx attached not sent for %u",
1888 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
1893 microuptime(&entry
->cfe_last_action
);
1894 CFI_ADD_TIME_LOG(cfil_info
, &entry
->cfe_last_action
, &cfil_info
->cfi_first_event
, msghdr
->cfm_op
);
1896 action_msg
= (struct cfil_msg_action
*)msghdr
;
1898 switch (msghdr
->cfm_op
) {
1899 case CFM_OP_DATA_UPDATE
:
1901 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT RECEIVED: <so %llx sockID %llu> <IN peek:%llu pass:%llu, OUT peek:%llu pass:%llu>",
1902 (uint64_t)VM_KERNEL_ADDRPERM(so
),
1903 cfil_info
->cfi_sock_id
,
1904 action_msg
->cfa_in_peek_offset
, action_msg
->cfa_in_pass_offset
,
1905 action_msg
->cfa_out_peek_offset
, action_msg
->cfa_out_pass_offset
);
1908 * Received verdict, at this point we know this
1909 * socket connection is allowed. Unblock thread
1910 * immediately before proceeding to process the verdict.
1912 cfil_sock_received_verdict(so
);
1914 if (action_msg
->cfa_out_peek_offset
!= 0 ||
1915 action_msg
->cfa_out_pass_offset
!= 0) {
1916 error
= cfil_action_data_pass(so
, cfil_info
, kcunit
, 1,
1917 action_msg
->cfa_out_pass_offset
,
1918 action_msg
->cfa_out_peek_offset
);
1920 if (error
== EJUSTRETURN
) {
1926 if (action_msg
->cfa_in_peek_offset
!= 0 ||
1927 action_msg
->cfa_in_pass_offset
!= 0) {
1928 error
= cfil_action_data_pass(so
, cfil_info
, kcunit
, 0,
1929 action_msg
->cfa_in_pass_offset
,
1930 action_msg
->cfa_in_peek_offset
);
1932 if (error
== EJUSTRETURN
) {
1936 // Toggle stats reporting according to received verdict.
1937 cfil_rw_lock_exclusive(&cfil_lck_rw
);
1938 cfil_info_stats_toggle(cfil_info
, entry
, action_msg
->cfa_stats_frequency
);
1939 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
1945 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT DROP RECEIVED: <so %llx sockID %llu> <IN peek:%llu pass:%llu, OUT peek:%llu pass:%llu>",
1946 (uint64_t)VM_KERNEL_ADDRPERM(so
),
1947 cfil_info
->cfi_sock_id
,
1948 action_msg
->cfa_in_peek_offset
, action_msg
->cfa_in_pass_offset
,
1949 action_msg
->cfa_out_peek_offset
, action_msg
->cfa_out_pass_offset
);
1951 error
= cfil_action_drop(so
, cfil_info
, kcunit
);
1952 cfil_sock_received_verdict(so
);
1960 socket_unlock(so
, 1);
1965 OSIncrementAtomic(&cfil_stats
.cfs_ctl_send_ok
);
1967 OSIncrementAtomic(&cfil_stats
.cfs_ctl_send_bad
);
1974 cfil_ctl_getopt(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
,
1975 int opt
, void *data
, size_t *len
)
1977 #pragma unused(kctlref, opt)
1978 struct cfil_info
*cfil_info
= NULL
;
1980 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
1982 CFIL_LOG(LOG_NOTICE
, "");
1984 cfil_rw_lock_shared(&cfil_lck_rw
);
1986 if (content_filters
== NULL
) {
1987 CFIL_LOG(LOG_ERR
, "no content filter");
1991 if (kcunit
> MAX_CONTENT_FILTER
) {
1992 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
1993 kcunit
, MAX_CONTENT_FILTER
);
1997 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
1998 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
2004 case CFIL_OPT_NECP_CONTROL_UNIT
:
2005 if (*len
< sizeof(uint32_t)) {
2006 CFIL_LOG(LOG_ERR
, "len too small %lu", *len
);
2011 *(uint32_t *)data
= cfc
->cf_necp_control_unit
;
2014 case CFIL_OPT_GET_SOCKET_INFO
:
2015 if (*len
!= sizeof(struct cfil_opt_sock_info
)) {
2016 CFIL_LOG(LOG_ERR
, "len does not match %lu", *len
);
2021 CFIL_LOG(LOG_ERR
, "data not passed");
2026 struct cfil_opt_sock_info
*sock_info
=
2027 (struct cfil_opt_sock_info
*) data
;
2029 // Unlock here so that we never hold both cfil_lck_rw and the
2030 // socket_lock at the same time. Otherwise, this can deadlock
2031 // because soclose() takes the socket_lock and then exclusive
2032 // cfil_lck_rw and we require the opposite order.
2034 // WARNING: Be sure to never use anything protected
2035 // by cfil_lck_rw beyond this point.
2036 // WARNING: Be sure to avoid fallthrough and
2037 // goto return_already_unlocked from this branch.
2038 cfil_rw_unlock_shared(&cfil_lck_rw
);
2040 // Search (TCP+UDP) and lock socket
2041 struct socket
*sock
=
2042 cfil_socket_from_sock_id(sock_info
->cfs_sock_id
, false);
2045 CFIL_LOG(LOG_ERR
, "CFIL: GET_SOCKET_INFO failed: bad sock_id %llu",
2046 sock_info
->cfs_sock_id
);
2049 goto return_already_unlocked
;
2052 cfil_info
= (sock
->so_cfil_db
!= NULL
) ?
2053 cfil_db_get_cfil_info(sock
->so_cfil_db
, sock_info
->cfs_sock_id
) : sock
->so_cfil
;
2055 if (cfil_info
== NULL
) {
2057 CFIL_LOG(LOG_ERR
, "CFIL: GET_SOCKET_INFO failed: so %llx not attached, cannot fetch info",
2058 (uint64_t)VM_KERNEL_ADDRPERM(sock
));
2061 socket_unlock(sock
, 1);
2062 goto return_already_unlocked
;
2065 // Fill out family, type, and protocol
2066 sock_info
->cfs_sock_family
= sock
->so_proto
->pr_domain
->dom_family
;
2067 sock_info
->cfs_sock_type
= sock
->so_proto
->pr_type
;
2068 sock_info
->cfs_sock_protocol
= sock
->so_proto
->pr_protocol
;
2070 // Source and destination addresses
2071 struct inpcb
*inp
= sotoinpcb(sock
);
2072 if (inp
->inp_vflag
& INP_IPV6
) {
2073 struct in6_addr
*laddr
= NULL
, *faddr
= NULL
;
2074 u_int16_t lport
= 0, fport
= 0;
2076 cfil_get_flow_address_v6(cfil_info
->cfi_hash_entry
, inp
,
2077 &laddr
, &faddr
, &lport
, &fport
);
2078 fill_ip6_sockaddr_4_6(&sock_info
->cfs_local
, laddr
, lport
);
2079 fill_ip6_sockaddr_4_6(&sock_info
->cfs_remote
, faddr
, fport
);
2080 } else if (inp
->inp_vflag
& INP_IPV4
) {
2081 struct in_addr laddr
= {.s_addr
= 0}, faddr
= {.s_addr
= 0};
2082 u_int16_t lport
= 0, fport
= 0;
2084 cfil_get_flow_address(cfil_info
->cfi_hash_entry
, inp
,
2085 &laddr
, &faddr
, &lport
, &fport
);
2086 fill_ip_sockaddr_4_6(&sock_info
->cfs_local
, laddr
, lport
);
2087 fill_ip_sockaddr_4_6(&sock_info
->cfs_remote
, faddr
, fport
);
2091 sock_info
->cfs_pid
= sock
->last_pid
;
2092 memcpy(sock_info
->cfs_uuid
, sock
->last_uuid
, sizeof(uuid_t
));
2094 if (sock
->so_flags
& SOF_DELEGATED
) {
2095 sock_info
->cfs_e_pid
= sock
->e_pid
;
2096 memcpy(sock_info
->cfs_e_uuid
, sock
->e_uuid
, sizeof(uuid_t
));
2098 sock_info
->cfs_e_pid
= sock
->last_pid
;
2099 memcpy(sock_info
->cfs_e_uuid
, sock
->last_uuid
, sizeof(uuid_t
));
2102 socket_unlock(sock
, 1);
2104 goto return_already_unlocked
;
2106 error
= ENOPROTOOPT
;
2110 cfil_rw_unlock_shared(&cfil_lck_rw
);
2114 return_already_unlocked
:
2120 cfil_ctl_setopt(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
,
2121 int opt
, void *data
, size_t len
)
2123 #pragma unused(kctlref, opt)
2125 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
2127 CFIL_LOG(LOG_NOTICE
, "");
2129 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2131 if (content_filters
== NULL
) {
2132 CFIL_LOG(LOG_ERR
, "no content filter");
2136 if (kcunit
> MAX_CONTENT_FILTER
) {
2137 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
2138 kcunit
, MAX_CONTENT_FILTER
);
2142 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
2143 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
2149 case CFIL_OPT_NECP_CONTROL_UNIT
:
2150 if (len
< sizeof(uint32_t)) {
2151 CFIL_LOG(LOG_ERR
, "CFIL_OPT_NECP_CONTROL_UNIT "
2152 "len too small %lu", len
);
2156 if (cfc
->cf_necp_control_unit
!= 0) {
2157 CFIL_LOG(LOG_ERR
, "CFIL_OPT_NECP_CONTROL_UNIT "
2159 cfc
->cf_necp_control_unit
);
2163 cfc
->cf_necp_control_unit
= *(uint32_t *)data
;
2166 error
= ENOPROTOOPT
;
2170 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2177 cfil_ctl_rcvd(kern_ctl_ref kctlref
, u_int32_t kcunit
, void *unitinfo
, int flags
)
2179 #pragma unused(kctlref, flags)
2180 struct content_filter
*cfc
= (struct content_filter
*)unitinfo
;
2181 struct socket
*so
= NULL
;
2183 struct cfil_entry
*entry
;
2184 struct cfil_info
*cfil_info
= NULL
;
2186 CFIL_LOG(LOG_INFO
, "");
2188 if (content_filters
== NULL
) {
2189 CFIL_LOG(LOG_ERR
, "no content filter");
2190 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_bad
);
2193 if (kcunit
> MAX_CONTENT_FILTER
) {
2194 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
2195 kcunit
, MAX_CONTENT_FILTER
);
2196 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_bad
);
2199 cfil_rw_lock_shared(&cfil_lck_rw
);
2200 if (cfc
!= (void *)content_filters
[kcunit
- 1]) {
2201 CFIL_LOG(LOG_ERR
, "unitinfo does not match for kcunit %u",
2203 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_bad
);
2206 /* Let's assume the flow control is lifted */
2207 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
2208 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
2209 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2212 cfc
->cf_flags
&= ~CFF_FLOW_CONTROLLED
;
2214 cfil_rw_lock_exclusive_to_shared(&cfil_lck_rw
);
2215 LCK_RW_ASSERT(&cfil_lck_rw
, LCK_RW_ASSERT_SHARED
);
2218 * Flow control will be raised again as soon as an entry cannot enqueue
2219 * to the kernel control socket
2221 while ((cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) == 0) {
2222 verify_content_filter(cfc
);
2224 cfil_rw_lock_assert_held(&cfil_lck_rw
, 0);
2226 /* Find an entry that is flow controlled */
2227 TAILQ_FOREACH(entry
, &cfc
->cf_sock_entries
, cfe_link
) {
2228 if (entry
->cfe_cfil_info
== NULL
||
2229 entry
->cfe_cfil_info
->cfi_so
== NULL
) {
2232 if ((entry
->cfe_flags
& CFEF_FLOW_CONTROLLED
) == 0) {
2236 if (entry
== NULL
) {
2240 OSIncrementAtomic(&cfil_stats
.cfs_ctl_rcvd_flow_lift
);
2242 cfil_info
= entry
->cfe_cfil_info
;
2243 so
= cfil_info
->cfi_so
;
2245 cfil_rw_unlock_shared(&cfil_lck_rw
);
2249 error
= cfil_acquire_sockbuf(so
, cfil_info
, 1);
2251 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, 1);
2253 cfil_release_sockbuf(so
, 1);
2258 error
= cfil_acquire_sockbuf(so
, cfil_info
, 0);
2260 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, 0);
2262 cfil_release_sockbuf(so
, 0);
2265 socket_lock_assert_owned(so
);
2266 socket_unlock(so
, 1);
2268 cfil_rw_lock_shared(&cfil_lck_rw
);
2271 cfil_rw_unlock_shared(&cfil_lck_rw
);
2277 struct kern_ctl_reg kern_ctl
;
2279 vm_size_t content_filter_size
= 0; /* size of content_filter */
2280 vm_size_t cfil_info_size
= 0; /* size of cfil_info */
2281 vm_size_t cfil_hash_entry_size
= 0; /* size of cfil_hash_entry */
2282 vm_size_t cfil_db_size
= 0; /* size of cfil_db */
2283 unsigned int mbuf_limit
= 0;
2285 CFIL_LOG(LOG_NOTICE
, "");
2288 * Compile time verifications
2290 _CASSERT(CFIL_MAX_FILTER_COUNT
== MAX_CONTENT_FILTER
);
2291 _CASSERT(sizeof(struct cfil_filter_stat
) % sizeof(uint32_t) == 0);
2292 _CASSERT(sizeof(struct cfil_entry_stat
) % sizeof(uint32_t) == 0);
2293 _CASSERT(sizeof(struct cfil_sock_stat
) % sizeof(uint32_t) == 0);
2296 * Runtime time verifications
2298 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_in_enqueued
,
2300 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_out_enqueued
,
2302 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_in_peeked
,
2304 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_ctl_q_out_peeked
,
2307 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_pending_q_in_enqueued
,
2309 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_pending_q_out_enqueued
,
2312 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_in_enqueued
,
2314 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_out_enqueued
,
2316 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_in_passed
,
2318 VERIFY(IS_P2ALIGNED(&cfil_stats
.cfs_inject_q_out_passed
,
2322 * Zone for content filters kernel control sockets
2324 content_filter_size
= sizeof(struct content_filter
);
2325 content_filter_zone
= zinit(content_filter_size
,
2326 CONTENT_FILTER_ZONE_MAX
* content_filter_size
,
2328 CONTENT_FILTER_ZONE_NAME
);
2329 if (content_filter_zone
== NULL
) {
2330 panic("%s: zinit(%s) failed", __func__
,
2331 CONTENT_FILTER_ZONE_NAME
);
2334 zone_change(content_filter_zone
, Z_CALLERACCT
, FALSE
);
2335 zone_change(content_filter_zone
, Z_EXPAND
, TRUE
);
2338 * Zone for per socket content filters
2340 cfil_info_size
= sizeof(struct cfil_info
);
2341 cfil_info_zone
= zinit(cfil_info_size
,
2342 CFIL_INFO_ZONE_MAX
* cfil_info_size
,
2344 CFIL_INFO_ZONE_NAME
);
2345 if (cfil_info_zone
== NULL
) {
2346 panic("%s: zinit(%s) failed", __func__
, CFIL_INFO_ZONE_NAME
);
2349 zone_change(cfil_info_zone
, Z_CALLERACCT
, FALSE
);
2350 zone_change(cfil_info_zone
, Z_EXPAND
, TRUE
);
2353 * Zone for content filters cfil hash entries and db
2355 cfil_hash_entry_size
= sizeof(struct cfil_hash_entry
);
2356 cfil_hash_entry_zone
= zinit(cfil_hash_entry_size
,
2357 CFIL_HASH_ENTRY_ZONE_MAX
* cfil_hash_entry_size
,
2359 CFIL_HASH_ENTRY_ZONE_NAME
);
2360 if (cfil_hash_entry_zone
== NULL
) {
2361 panic("%s: zinit(%s) failed", __func__
, CFIL_HASH_ENTRY_ZONE_NAME
);
2364 zone_change(cfil_hash_entry_zone
, Z_CALLERACCT
, FALSE
);
2365 zone_change(cfil_hash_entry_zone
, Z_EXPAND
, TRUE
);
2367 cfil_db_size
= sizeof(struct cfil_db
);
2368 cfil_db_zone
= zinit(cfil_db_size
,
2369 CFIL_DB_ZONE_MAX
* cfil_db_size
,
2372 if (cfil_db_zone
== NULL
) {
2373 panic("%s: zinit(%s) failed", __func__
, CFIL_DB_ZONE_NAME
);
2376 zone_change(cfil_db_zone
, Z_CALLERACCT
, FALSE
);
2377 zone_change(cfil_db_zone
, Z_EXPAND
, TRUE
);
2382 cfil_lck_grp_attr
= lck_grp_attr_alloc_init();
2383 if (cfil_lck_grp_attr
== NULL
) {
2384 panic("%s: lck_grp_attr_alloc_init failed", __func__
);
2387 cfil_lck_grp
= lck_grp_alloc_init("content filter",
2389 if (cfil_lck_grp
== NULL
) {
2390 panic("%s: lck_grp_alloc_init failed", __func__
);
2393 cfil_lck_attr
= lck_attr_alloc_init();
2394 if (cfil_lck_attr
== NULL
) {
2395 panic("%s: lck_attr_alloc_init failed", __func__
);
2398 lck_rw_init(&cfil_lck_rw
, cfil_lck_grp
, cfil_lck_attr
);
2400 TAILQ_INIT(&cfil_sock_head
);
2401 TAILQ_INIT(&cfil_sock_head_stats
);
2404 * Register kernel control
2406 bzero(&kern_ctl
, sizeof(kern_ctl
));
2407 strlcpy(kern_ctl
.ctl_name
, CONTENT_FILTER_CONTROL_NAME
,
2408 sizeof(kern_ctl
.ctl_name
));
2409 kern_ctl
.ctl_flags
= CTL_FLAG_PRIVILEGED
| CTL_FLAG_REG_EXTENDED
;
2410 kern_ctl
.ctl_sendsize
= 512 * 1024; /* enough? */
2411 kern_ctl
.ctl_recvsize
= 512 * 1024; /* enough? */
2412 kern_ctl
.ctl_connect
= cfil_ctl_connect
;
2413 kern_ctl
.ctl_disconnect
= cfil_ctl_disconnect
;
2414 kern_ctl
.ctl_send
= cfil_ctl_send
;
2415 kern_ctl
.ctl_getopt
= cfil_ctl_getopt
;
2416 kern_ctl
.ctl_setopt
= cfil_ctl_setopt
;
2417 kern_ctl
.ctl_rcvd
= cfil_ctl_rcvd
;
2418 error
= ctl_register(&kern_ctl
, &cfil_kctlref
);
2420 CFIL_LOG(LOG_ERR
, "ctl_register failed: %d", error
);
2424 // Spawn thread for gargage collection
2425 if (kernel_thread_start(cfil_udp_gc_thread_func
, NULL
,
2426 &cfil_udp_gc_thread
) != KERN_SUCCESS
) {
2427 panic_plain("%s: Can't create UDP GC thread", __func__
);
2430 /* this must not fail */
2431 VERIFY(cfil_udp_gc_thread
!= NULL
);
2433 // Spawn thread for statistics reporting
2434 if (kernel_thread_start(cfil_stats_report_thread_func
, NULL
,
2435 &cfil_stats_report_thread
) != KERN_SUCCESS
) {
2436 panic_plain("%s: Can't create statistics report thread", __func__
);
2439 /* this must not fail */
2440 VERIFY(cfil_stats_report_thread
!= NULL
);
2442 // Set UDP per-flow mbuf thresholds to 1/32 of platform max
2443 mbuf_limit
= MAX(UDP_FLOW_GC_MBUF_CNT_MAX
, (nmbclusters
<< MCLSHIFT
) >> UDP_FLOW_GC_MBUF_SHIFT
);
2444 cfil_udp_gc_mbuf_num_max
= (mbuf_limit
>> MCLSHIFT
);
2445 cfil_udp_gc_mbuf_cnt_max
= mbuf_limit
;
2447 memset(&global_cfil_stats_report_buffers
, 0, sizeof(global_cfil_stats_report_buffers
));
2451 cfil_info_alloc(struct socket
*so
, struct cfil_hash_entry
*hash_entry
)
2454 struct cfil_info
*cfil_info
= NULL
;
2455 struct inpcb
*inp
= sotoinpcb(so
);
2457 CFIL_LOG(LOG_INFO
, "");
2459 socket_lock_assert_owned(so
);
2461 cfil_info
= zalloc(cfil_info_zone
);
2462 if (cfil_info
== NULL
) {
2465 bzero(cfil_info
, sizeof(struct cfil_info
));
2467 cfil_queue_init(&cfil_info
->cfi_snd
.cfi_inject_q
);
2468 cfil_queue_init(&cfil_info
->cfi_rcv
.cfi_inject_q
);
2470 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
2471 struct cfil_entry
*entry
;
2473 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2474 entry
->cfe_cfil_info
= cfil_info
;
2476 /* Initialize the filter entry */
2477 entry
->cfe_filter
= NULL
;
2478 entry
->cfe_flags
= 0;
2479 entry
->cfe_necp_control_unit
= 0;
2480 entry
->cfe_snd
.cfe_pass_offset
= 0;
2481 entry
->cfe_snd
.cfe_peek_offset
= 0;
2482 entry
->cfe_snd
.cfe_peeked
= 0;
2483 entry
->cfe_rcv
.cfe_pass_offset
= 0;
2484 entry
->cfe_rcv
.cfe_peek_offset
= 0;
2485 entry
->cfe_rcv
.cfe_peeked
= 0;
2487 * Timestamp the last action to avoid pre-maturely
2488 * triggering garbage collection
2490 microuptime(&entry
->cfe_last_action
);
2492 cfil_queue_init(&entry
->cfe_snd
.cfe_pending_q
);
2493 cfil_queue_init(&entry
->cfe_rcv
.cfe_pending_q
);
2494 cfil_queue_init(&entry
->cfe_snd
.cfe_ctl_q
);
2495 cfil_queue_init(&entry
->cfe_rcv
.cfe_ctl_q
);
2498 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2501 * Create a cfi_sock_id that's not the socket pointer!
2504 if (hash_entry
== NULL
) {
2505 // This is the TCP case, cfil_info is tracked per socket
2506 if (inp
->inp_flowhash
== 0) {
2507 inp
->inp_flowhash
= inp_calc_flowhash(inp
);
2510 so
->so_cfil
= cfil_info
;
2511 cfil_info
->cfi_so
= so
;
2512 cfil_info
->cfi_sock_id
=
2513 ((so
->so_gencnt
<< 32) | inp
->inp_flowhash
);
2515 // This is the UDP case, cfil_info is tracked in per-socket hash
2516 cfil_info
->cfi_so
= so
;
2517 hash_entry
->cfentry_cfil
= cfil_info
;
2518 cfil_info
->cfi_hash_entry
= hash_entry
;
2519 cfil_info
->cfi_sock_id
= ((so
->so_gencnt
<< 32) | (hash_entry
->cfentry_flowhash
& 0xffffffff));
2520 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP inp_flowhash %x so_gencnt %llx entry flowhash %x sockID %llx",
2521 inp
->inp_flowhash
, so
->so_gencnt
, hash_entry
->cfentry_flowhash
, cfil_info
->cfi_sock_id
);
2523 // Wake up gc thread if this is first flow added
2524 if (cfil_sock_udp_attached_count
== 0) {
2525 thread_wakeup((caddr_t
)&cfil_sock_udp_attached_count
);
2528 cfil_sock_udp_attached_count
++;
2531 TAILQ_INSERT_TAIL(&cfil_sock_head
, cfil_info
, cfi_link
);
2532 SLIST_INIT(&cfil_info
->cfi_ordered_entries
);
2534 cfil_sock_attached_count
++;
2536 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2539 if (cfil_info
!= NULL
) {
2540 OSIncrementAtomic(&cfil_stats
.cfs_cfi_alloc_ok
);
2542 OSIncrementAtomic(&cfil_stats
.cfs_cfi_alloc_fail
);
2549 cfil_info_attach_unit(struct socket
*so
, uint32_t filter_control_unit
, struct cfil_info
*cfil_info
)
2554 CFIL_LOG(LOG_INFO
, "");
2556 socket_lock_assert_owned(so
);
2558 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2561 content_filters
!= NULL
&& kcunit
<= MAX_CONTENT_FILTER
;
2563 struct content_filter
*cfc
= content_filters
[kcunit
- 1];
2564 struct cfil_entry
*entry
;
2565 struct cfil_entry
*iter_entry
;
2566 struct cfil_entry
*iter_prev
;
2571 if (!(cfc
->cf_necp_control_unit
& filter_control_unit
)) {
2575 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2577 entry
->cfe_filter
= cfc
;
2578 entry
->cfe_necp_control_unit
= cfc
->cf_necp_control_unit
;
2579 TAILQ_INSERT_TAIL(&cfc
->cf_sock_entries
, entry
, cfe_link
);
2580 cfc
->cf_sock_count
++;
2582 /* Insert the entry into the list ordered by control unit */
2584 SLIST_FOREACH(iter_entry
, &cfil_info
->cfi_ordered_entries
, cfe_order_link
) {
2585 if (entry
->cfe_necp_control_unit
< iter_entry
->cfe_necp_control_unit
) {
2588 iter_prev
= iter_entry
;
2591 if (iter_prev
== NULL
) {
2592 SLIST_INSERT_HEAD(&cfil_info
->cfi_ordered_entries
, entry
, cfe_order_link
);
2594 SLIST_INSERT_AFTER(iter_prev
, entry
, cfe_order_link
);
2597 verify_content_filter(cfc
);
2599 entry
->cfe_flags
|= CFEF_CFIL_ATTACHED
;
2602 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2608 cfil_info_free(struct cfil_info
*cfil_info
)
2611 uint64_t in_drain
= 0;
2612 uint64_t out_drained
= 0;
2614 if (cfil_info
== NULL
) {
2618 CFIL_LOG(LOG_INFO
, "");
2620 cfil_rw_lock_exclusive(&cfil_lck_rw
);
2623 content_filters
!= NULL
&& kcunit
<= MAX_CONTENT_FILTER
;
2625 struct cfil_entry
*entry
;
2626 struct content_filter
*cfc
;
2628 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2630 /* Don't be silly and try to detach twice */
2631 if (entry
->cfe_filter
== NULL
) {
2635 cfc
= content_filters
[kcunit
- 1];
2637 VERIFY(cfc
== entry
->cfe_filter
);
2639 entry
->cfe_filter
= NULL
;
2640 entry
->cfe_necp_control_unit
= 0;
2641 TAILQ_REMOVE(&cfc
->cf_sock_entries
, entry
, cfe_link
);
2642 cfc
->cf_sock_count
--;
2644 verify_content_filter(cfc
);
2646 if (cfil_info
->cfi_hash_entry
!= NULL
) {
2647 cfil_sock_udp_attached_count
--;
2649 cfil_sock_attached_count
--;
2650 TAILQ_REMOVE(&cfil_sock_head
, cfil_info
, cfi_link
);
2652 // Turn off stats reporting for cfil_info.
2653 cfil_info_stats_toggle(cfil_info
, NULL
, 0);
2655 out_drained
+= cfil_queue_drain(&cfil_info
->cfi_snd
.cfi_inject_q
);
2656 in_drain
+= cfil_queue_drain(&cfil_info
->cfi_rcv
.cfi_inject_q
);
2658 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
2659 struct cfil_entry
*entry
;
2661 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
2662 out_drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_pending_q
);
2663 in_drain
+= cfil_queue_drain(&entry
->cfe_rcv
.cfe_pending_q
);
2664 out_drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_ctl_q
);
2665 in_drain
+= cfil_queue_drain(&entry
->cfe_rcv
.cfe_ctl_q
);
2667 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
2670 OSIncrementAtomic(&cfil_stats
.cfs_flush_out_free
);
2673 OSIncrementAtomic(&cfil_stats
.cfs_flush_in_free
);
2676 zfree(cfil_info_zone
, cfil_info
);
2680 * Received a verdict from userspace for a socket.
2681 * Perform any delayed operation if needed.
2684 cfil_sock_received_verdict(struct socket
*so
)
2686 if (so
== NULL
|| so
->so_cfil
== NULL
) {
2690 so
->so_cfil
->cfi_flags
|= CFIF_INITIAL_VERDICT
;
2693 * If socket has already been connected, trigger
2694 * soisconnected now.
2696 if (so
->so_cfil
->cfi_flags
& CFIF_SOCKET_CONNECTED
) {
2697 so
->so_cfil
->cfi_flags
&= ~CFIF_SOCKET_CONNECTED
;
2704 * Entry point from Sockets layer
2705 * The socket is locked.
2707 * Checks if a connected socket is subject to filter and
2708 * pending the initial verdict.
2711 cfil_sock_connected_pending_verdict(struct socket
*so
)
2713 if (so
== NULL
|| so
->so_cfil
== NULL
) {
2717 if (so
->so_cfil
->cfi_flags
& CFIF_INITIAL_VERDICT
) {
2721 * Remember that this protocol is already connected, so
2722 * we will trigger soisconnected() upon receipt of
2723 * initial verdict later.
2725 so
->so_cfil
->cfi_flags
|= CFIF_SOCKET_CONNECTED
;
2731 cfil_filter_present(void)
2733 return cfil_active_count
> 0;
2737 * Entry point from Sockets layer
2738 * The socket is locked.
2741 cfil_sock_attach(struct socket
*so
, struct sockaddr
*local
, struct sockaddr
*remote
, int dir
)
2744 uint32_t filter_control_unit
;
2746 socket_lock_assert_owned(so
);
2748 /* Limit ourselves to TCP that are not MPTCP subflows */
2749 if ((so
->so_proto
->pr_domain
->dom_family
!= PF_INET
&&
2750 so
->so_proto
->pr_domain
->dom_family
!= PF_INET6
) ||
2751 so
->so_proto
->pr_type
!= SOCK_STREAM
||
2752 so
->so_proto
->pr_protocol
!= IPPROTO_TCP
||
2753 (so
->so_flags
& SOF_MP_SUBFLOW
) != 0 ||
2754 (so
->so_flags1
& SOF1_CONTENT_FILTER_SKIP
) != 0) {
2758 filter_control_unit
= necp_socket_get_content_filter_control_unit(so
);
2759 if (filter_control_unit
== 0) {
2763 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
2766 if ((filter_control_unit
& NECP_MASK_USERSPACE_ONLY
) != 0) {
2767 OSIncrementAtomic(&cfil_stats
.cfs_sock_userspace_only
);
2770 if (cfil_active_count
== 0) {
2771 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_in_vain
);
2774 if (so
->so_cfil
!= NULL
) {
2775 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_already
);
2776 CFIL_LOG(LOG_ERR
, "already attached");
2778 cfil_info_alloc(so
, NULL
);
2779 if (so
->so_cfil
== NULL
) {
2781 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_no_mem
);
2784 so
->so_cfil
->cfi_dir
= dir
;
2786 if (cfil_info_attach_unit(so
, filter_control_unit
, so
->so_cfil
) == 0) {
2787 CFIL_LOG(LOG_ERR
, "cfil_info_attach_unit(%u) failed",
2788 filter_control_unit
);
2789 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_failed
);
2792 CFIL_LOG(LOG_INFO
, "so %llx filter_control_unit %u sockID %llx",
2793 (uint64_t)VM_KERNEL_ADDRPERM(so
),
2794 filter_control_unit
, so
->so_cfil
->cfi_sock_id
);
2796 so
->so_flags
|= SOF_CONTENT_FILTER
;
2797 OSIncrementAtomic(&cfil_stats
.cfs_sock_attached
);
2799 /* Hold a reference on the socket */
2803 * Save passed addresses for attach event msg (in case resend
2806 if (remote
!= NULL
) {
2807 memcpy(&so
->so_cfil
->cfi_so_attach_faddr
, remote
, remote
->sa_len
);
2809 if (local
!= NULL
) {
2810 memcpy(&so
->so_cfil
->cfi_so_attach_laddr
, local
, local
->sa_len
);
2813 error
= cfil_dispatch_attach_event(so
, so
->so_cfil
, 0, dir
);
2814 /* We can recover from flow control or out of memory errors */
2815 if (error
== ENOBUFS
|| error
== ENOMEM
) {
2817 } else if (error
!= 0) {
2821 CFIL_INFO_VERIFY(so
->so_cfil
);
2827 * Entry point from Sockets layer
2828 * The socket is locked.
2831 cfil_sock_detach(struct socket
*so
)
2839 if (so
->so_flags
& SOF_CONTENT_FILTER
) {
2840 so
->so_flags
&= ~SOF_CONTENT_FILTER
;
2841 VERIFY(so
->so_usecount
> 0);
2844 cfil_info_free(so
->so_cfil
);
2846 OSIncrementAtomic(&cfil_stats
.cfs_sock_detached
);
2852 * Fill in the address info of an event message from either
2853 * the socket or passed in address info.
2856 cfil_fill_event_msg_addresses(struct cfil_hash_entry
*entry
, struct inpcb
*inp
,
2857 union sockaddr_in_4_6
*sin_src
, union sockaddr_in_4_6
*sin_dst
,
2858 boolean_t isIPv4
, boolean_t outgoing
)
2861 struct in_addr laddr
= {0}, faddr
= {0};
2862 u_int16_t lport
= 0, fport
= 0;
2864 cfil_get_flow_address(entry
, inp
, &laddr
, &faddr
, &lport
, &fport
);
2867 fill_ip_sockaddr_4_6(sin_src
, laddr
, lport
);
2868 fill_ip_sockaddr_4_6(sin_dst
, faddr
, fport
);
2870 fill_ip_sockaddr_4_6(sin_src
, faddr
, fport
);
2871 fill_ip_sockaddr_4_6(sin_dst
, laddr
, lport
);
2874 struct in6_addr
*laddr
= NULL
, *faddr
= NULL
;
2875 u_int16_t lport
= 0, fport
= 0;
2877 cfil_get_flow_address_v6(entry
, inp
, &laddr
, &faddr
, &lport
, &fport
);
2879 fill_ip6_sockaddr_4_6(sin_src
, laddr
, lport
);
2880 fill_ip6_sockaddr_4_6(sin_dst
, faddr
, fport
);
2882 fill_ip6_sockaddr_4_6(sin_src
, faddr
, fport
);
2883 fill_ip6_sockaddr_4_6(sin_dst
, laddr
, lport
);
2889 cfil_dispatch_attach_event_sign(cfil_crypto_state_t crypto_state
,
2890 struct cfil_info
*cfil_info
,
2891 struct cfil_msg_sock_attached
*msg
)
2893 struct cfil_crypto_data data
= {};
2895 if (crypto_state
== NULL
|| msg
== NULL
|| cfil_info
== NULL
) {
2899 data
.sock_id
= msg
->cfs_msghdr
.cfm_sock_id
;
2900 data
.direction
= msg
->cfs_conn_dir
;
2902 data
.pid
= msg
->cfs_pid
;
2903 data
.effective_pid
= msg
->cfs_e_pid
;
2904 uuid_copy(data
.uuid
, msg
->cfs_uuid
);
2905 uuid_copy(data
.effective_uuid
, msg
->cfs_e_uuid
);
2906 data
.socketProtocol
= msg
->cfs_sock_protocol
;
2907 if (data
.direction
== CFS_CONNECTION_DIR_OUT
) {
2908 data
.remote
.sin6
= msg
->cfs_dst
.sin6
;
2909 data
.local
.sin6
= msg
->cfs_src
.sin6
;
2911 data
.remote
.sin6
= msg
->cfs_src
.sin6
;
2912 data
.local
.sin6
= msg
->cfs_dst
.sin6
;
2915 // At attach, if local address is already present, no need to re-sign subsequent data messages.
2916 if (!NULLADDRESS(data
.local
)) {
2917 cfil_info
->cfi_isSignatureLatest
= true;
2920 msg
->cfs_signature_length
= sizeof(cfil_crypto_signature
);
2921 if (cfil_crypto_sign_data(crypto_state
, &data
, msg
->cfs_signature
, &msg
->cfs_signature_length
) != 0) {
2922 msg
->cfs_signature_length
= 0;
2923 CFIL_LOG(LOG_ERR
, "CFIL: Failed to sign attached msg <sockID %llu>",
2924 msg
->cfs_msghdr
.cfm_sock_id
);
2932 cfil_dispatch_data_event_sign(cfil_crypto_state_t crypto_state
,
2933 struct socket
*so
, struct cfil_info
*cfil_info
,
2934 struct cfil_msg_data_event
*msg
)
2936 struct cfil_crypto_data data
= {};
2938 if (crypto_state
== NULL
|| msg
== NULL
||
2939 so
== NULL
|| cfil_info
== NULL
) {
2943 data
.sock_id
= cfil_info
->cfi_sock_id
;
2944 data
.direction
= cfil_info
->cfi_dir
;
2945 data
.pid
= so
->last_pid
;
2946 memcpy(data
.uuid
, so
->last_uuid
, sizeof(uuid_t
));
2947 if (so
->so_flags
& SOF_DELEGATED
) {
2948 data
.effective_pid
= so
->e_pid
;
2949 memcpy(data
.effective_uuid
, so
->e_uuid
, sizeof(uuid_t
));
2951 data
.effective_pid
= so
->last_pid
;
2952 memcpy(data
.effective_uuid
, so
->last_uuid
, sizeof(uuid_t
));
2954 data
.socketProtocol
= so
->so_proto
->pr_protocol
;
2956 if (data
.direction
== CFS_CONNECTION_DIR_OUT
) {
2957 data
.remote
.sin6
= msg
->cfc_dst
.sin6
;
2958 data
.local
.sin6
= msg
->cfc_src
.sin6
;
2960 data
.remote
.sin6
= msg
->cfc_src
.sin6
;
2961 data
.local
.sin6
= msg
->cfc_dst
.sin6
;
2964 // At first data, local address may show up for the first time, update address cache and
2965 // no need to re-sign subsequent data messages anymore.
2966 if (!NULLADDRESS(data
.local
)) {
2967 memcpy(&cfil_info
->cfi_so_attach_laddr
, &data
.local
, data
.local
.sa
.sa_len
);
2968 cfil_info
->cfi_isSignatureLatest
= true;
2971 msg
->cfd_signature_length
= sizeof(cfil_crypto_signature
);
2972 if (cfil_crypto_sign_data(crypto_state
, &data
, msg
->cfd_signature
, &msg
->cfd_signature_length
) != 0) {
2973 msg
->cfd_signature_length
= 0;
2974 CFIL_LOG(LOG_ERR
, "CFIL: Failed to sign data msg <sockID %llu>",
2975 msg
->cfd_msghdr
.cfm_sock_id
);
2983 cfil_dispatch_closed_event_sign(cfil_crypto_state_t crypto_state
,
2984 struct socket
*so
, struct cfil_info
*cfil_info
,
2985 struct cfil_msg_sock_closed
*msg
)
2987 struct cfil_crypto_data data
= {};
2988 struct cfil_hash_entry hash_entry
= {};
2989 struct cfil_hash_entry
*hash_entry_ptr
= NULL
;
2990 struct inpcb
*inp
= (struct inpcb
*)so
->so_pcb
;
2992 if (crypto_state
== NULL
|| msg
== NULL
||
2993 so
== NULL
|| inp
== NULL
|| cfil_info
== NULL
) {
2997 data
.sock_id
= cfil_info
->cfi_sock_id
;
2998 data
.direction
= cfil_info
->cfi_dir
;
3000 data
.pid
= so
->last_pid
;
3001 memcpy(data
.uuid
, so
->last_uuid
, sizeof(uuid_t
));
3002 if (so
->so_flags
& SOF_DELEGATED
) {
3003 data
.effective_pid
= so
->e_pid
;
3004 memcpy(data
.effective_uuid
, so
->e_uuid
, sizeof(uuid_t
));
3006 data
.effective_pid
= so
->last_pid
;
3007 memcpy(data
.effective_uuid
, so
->last_uuid
, sizeof(uuid_t
));
3009 data
.socketProtocol
= so
->so_proto
->pr_protocol
;
3012 * Fill in address info:
3013 * For UDP, use the cfil_info hash entry directly.
3014 * For TCP, compose an hash entry with the saved addresses.
3016 if (cfil_info
->cfi_hash_entry
!= NULL
) {
3017 hash_entry_ptr
= cfil_info
->cfi_hash_entry
;
3018 } else if (cfil_info
->cfi_so_attach_faddr
.sa
.sa_len
> 0 ||
3019 cfil_info
->cfi_so_attach_laddr
.sa
.sa_len
> 0) {
3020 fill_cfil_hash_entry_from_address(&hash_entry
, TRUE
, &cfil_info
->cfi_so_attach_laddr
.sa
);
3021 fill_cfil_hash_entry_from_address(&hash_entry
, FALSE
, &cfil_info
->cfi_so_attach_faddr
.sa
);
3022 hash_entry_ptr
= &hash_entry
;
3024 if (hash_entry_ptr
!= NULL
) {
3025 boolean_t outgoing
= (cfil_info
->cfi_dir
== CFS_CONNECTION_DIR_OUT
);
3026 union sockaddr_in_4_6
*src
= outgoing
? &data
.local
: &data
.remote
;
3027 union sockaddr_in_4_6
*dst
= outgoing
? &data
.remote
: &data
.local
;
3028 cfil_fill_event_msg_addresses(hash_entry_ptr
, inp
, src
, dst
, inp
->inp_vflag
& INP_IPV4
, outgoing
);
3031 data
.byte_count_in
= cfil_info
->cfi_byte_inbound_count
;
3032 data
.byte_count_out
= cfil_info
->cfi_byte_outbound_count
;
3034 msg
->cfc_signature_length
= sizeof(cfil_crypto_signature
);
3035 if (cfil_crypto_sign_data(crypto_state
, &data
, msg
->cfc_signature
, &msg
->cfc_signature_length
) != 0) {
3036 msg
->cfc_signature_length
= 0;
3037 CFIL_LOG(LOG_ERR
, "CFIL: Failed to sign closed msg <sockID %llu>",
3038 msg
->cfc_msghdr
.cfm_sock_id
);
3046 cfil_dispatch_attach_event(struct socket
*so
, struct cfil_info
*cfil_info
,
3047 uint32_t kcunit
, int conn_dir
)
3050 struct cfil_entry
*entry
= NULL
;
3051 struct cfil_msg_sock_attached msg_attached
;
3052 struct content_filter
*cfc
= NULL
;
3053 struct inpcb
*inp
= (struct inpcb
*)so
->so_pcb
;
3054 struct cfil_hash_entry
*hash_entry_ptr
= NULL
;
3055 struct cfil_hash_entry hash_entry
;
3057 memset(&hash_entry
, 0, sizeof(struct cfil_hash_entry
));
3058 proc_t p
= PROC_NULL
;
3059 task_t t
= TASK_NULL
;
3061 socket_lock_assert_owned(so
);
3063 cfil_rw_lock_shared(&cfil_lck_rw
);
3065 if (so
->so_proto
== NULL
|| so
->so_proto
->pr_domain
== NULL
) {
3071 entry
= SLIST_FIRST(&cfil_info
->cfi_ordered_entries
);
3073 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3076 if (entry
== NULL
) {
3080 cfc
= entry
->cfe_filter
;
3085 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
)) {
3090 kcunit
= CFI_ENTRY_KCUNIT(cfil_info
, entry
);
3093 CFIL_LOG(LOG_INFO
, "so %llx filter_control_unit %u kcunit %u",
3094 (uint64_t)VM_KERNEL_ADDRPERM(so
), entry
->cfe_necp_control_unit
, kcunit
);
3096 /* Would be wasteful to try when flow controlled */
3097 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3102 bzero(&msg_attached
, sizeof(struct cfil_msg_sock_attached
));
3103 msg_attached
.cfs_msghdr
.cfm_len
= sizeof(struct cfil_msg_sock_attached
);
3104 msg_attached
.cfs_msghdr
.cfm_version
= CFM_VERSION_CURRENT
;
3105 msg_attached
.cfs_msghdr
.cfm_type
= CFM_TYPE_EVENT
;
3106 msg_attached
.cfs_msghdr
.cfm_op
= CFM_OP_SOCKET_ATTACHED
;
3107 msg_attached
.cfs_msghdr
.cfm_sock_id
= entry
->cfe_cfil_info
->cfi_sock_id
;
3109 msg_attached
.cfs_sock_family
= so
->so_proto
->pr_domain
->dom_family
;
3110 msg_attached
.cfs_sock_type
= so
->so_proto
->pr_type
;
3111 msg_attached
.cfs_sock_protocol
= so
->so_proto
->pr_protocol
;
3112 msg_attached
.cfs_pid
= so
->last_pid
;
3113 memcpy(msg_attached
.cfs_uuid
, so
->last_uuid
, sizeof(uuid_t
));
3114 if (so
->so_flags
& SOF_DELEGATED
) {
3115 msg_attached
.cfs_e_pid
= so
->e_pid
;
3116 memcpy(msg_attached
.cfs_e_uuid
, so
->e_uuid
, sizeof(uuid_t
));
3118 msg_attached
.cfs_e_pid
= so
->last_pid
;
3119 memcpy(msg_attached
.cfs_e_uuid
, so
->last_uuid
, sizeof(uuid_t
));
3123 * Fill in address info:
3124 * For UDP, use the cfil_info hash entry directly.
3125 * For TCP, compose an hash entry with the saved addresses.
3127 if (cfil_info
->cfi_hash_entry
!= NULL
) {
3128 hash_entry_ptr
= cfil_info
->cfi_hash_entry
;
3129 } else if (cfil_info
->cfi_so_attach_faddr
.sa
.sa_len
> 0 ||
3130 cfil_info
->cfi_so_attach_laddr
.sa
.sa_len
> 0) {
3131 fill_cfil_hash_entry_from_address(&hash_entry
, TRUE
, &cfil_info
->cfi_so_attach_laddr
.sa
);
3132 fill_cfil_hash_entry_from_address(&hash_entry
, FALSE
, &cfil_info
->cfi_so_attach_faddr
.sa
);
3133 hash_entry_ptr
= &hash_entry
;
3135 if (hash_entry_ptr
!= NULL
) {
3136 cfil_fill_event_msg_addresses(hash_entry_ptr
, inp
,
3137 &msg_attached
.cfs_src
, &msg_attached
.cfs_dst
,
3138 inp
->inp_vflag
& INP_IPV4
, conn_dir
== CFS_CONNECTION_DIR_OUT
);
3140 msg_attached
.cfs_conn_dir
= conn_dir
;
3142 if (msg_attached
.cfs_e_pid
!= 0) {
3143 p
= proc_find(msg_attached
.cfs_e_pid
);
3144 if (p
!= PROC_NULL
) {
3146 if (t
!= TASK_NULL
) {
3147 audit_token_t audit_token
;
3148 mach_msg_type_number_t count
= TASK_AUDIT_TOKEN_COUNT
;
3149 if (task_info(t
, TASK_AUDIT_TOKEN
, (task_info_t
)&audit_token
, &count
) == KERN_SUCCESS
) {
3150 memcpy(&msg_attached
.cfs_audit_token
, &audit_token
, sizeof(msg_attached
.cfs_audit_token
));
3152 CFIL_LOG(LOG_ERR
, "CFIL: Failed to get process audit token <sockID %llu> ",
3153 entry
->cfe_cfil_info
->cfi_sock_id
);
3160 cfil_dispatch_attach_event_sign(entry
->cfe_filter
->cf_crypto_state
, cfil_info
, &msg_attached
);
3163 CFIL_LOG(LOG_DEBUG
, "CFIL: LIFECYCLE: SENDING ATTACH UP <sockID %llu> ",
3164 entry
->cfe_cfil_info
->cfi_sock_id
);
3167 error
= ctl_enqueuedata(entry
->cfe_filter
->cf_kcref
,
3168 entry
->cfe_filter
->cf_kcunit
,
3170 sizeof(struct cfil_msg_sock_attached
),
3173 CFIL_LOG(LOG_ERR
, "ctl_enqueuedata() failed: %d", error
);
3176 microuptime(&entry
->cfe_last_event
);
3177 cfil_info
->cfi_first_event
.tv_sec
= entry
->cfe_last_event
.tv_sec
;
3178 cfil_info
->cfi_first_event
.tv_usec
= entry
->cfe_last_event
.tv_usec
;
3180 entry
->cfe_flags
|= CFEF_SENT_SOCK_ATTACHED
;
3181 OSIncrementAtomic(&cfil_stats
.cfs_attach_event_ok
);
3184 /* We can recover from flow control */
3185 if (error
== ENOBUFS
) {
3186 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3187 OSIncrementAtomic(&cfil_stats
.cfs_attach_event_flow_control
);
3189 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3190 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3193 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3195 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3198 OSIncrementAtomic(&cfil_stats
.cfs_attach_event_fail
);
3201 cfil_rw_unlock_shared(&cfil_lck_rw
);
3207 cfil_dispatch_disconnect_event(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
)
3210 struct mbuf
*msg
= NULL
;
3211 struct cfil_entry
*entry
;
3212 struct cfe_buf
*entrybuf
;
3213 struct cfil_msg_hdr msg_disconnected
;
3214 struct content_filter
*cfc
;
3216 socket_lock_assert_owned(so
);
3218 cfil_rw_lock_shared(&cfil_lck_rw
);
3220 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3222 entrybuf
= &entry
->cfe_snd
;
3224 entrybuf
= &entry
->cfe_rcv
;
3227 cfc
= entry
->cfe_filter
;
3232 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3233 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3236 * Send the disconnection event once
3238 if ((outgoing
&& (entry
->cfe_flags
& CFEF_SENT_DISCONNECT_OUT
)) ||
3239 (!outgoing
&& (entry
->cfe_flags
& CFEF_SENT_DISCONNECT_IN
))) {
3240 CFIL_LOG(LOG_INFO
, "so %llx disconnect already sent",
3241 (uint64_t)VM_KERNEL_ADDRPERM(so
));
3246 * We're not disconnected as long as some data is waiting
3247 * to be delivered to the filter
3249 if (outgoing
&& cfil_queue_empty(&entrybuf
->cfe_ctl_q
) == 0) {
3250 CFIL_LOG(LOG_INFO
, "so %llx control queue not empty",
3251 (uint64_t)VM_KERNEL_ADDRPERM(so
));
3255 /* Would be wasteful to try when flow controlled */
3256 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3262 cfil_info_log(LOG_ERR
, cfil_info
, outgoing
?
3263 "CFIL: LIFECYCLE: OUT - SENDING DISCONNECT UP":
3264 "CFIL: LIFECYCLE: IN - SENDING DISCONNECT UP");
3267 bzero(&msg_disconnected
, sizeof(struct cfil_msg_hdr
));
3268 msg_disconnected
.cfm_len
= sizeof(struct cfil_msg_hdr
);
3269 msg_disconnected
.cfm_version
= CFM_VERSION_CURRENT
;
3270 msg_disconnected
.cfm_type
= CFM_TYPE_EVENT
;
3271 msg_disconnected
.cfm_op
= outgoing
? CFM_OP_DISCONNECT_OUT
:
3272 CFM_OP_DISCONNECT_IN
;
3273 msg_disconnected
.cfm_sock_id
= entry
->cfe_cfil_info
->cfi_sock_id
;
3274 error
= ctl_enqueuedata(entry
->cfe_filter
->cf_kcref
,
3275 entry
->cfe_filter
->cf_kcunit
,
3277 sizeof(struct cfil_msg_hdr
),
3280 CFIL_LOG(LOG_ERR
, "ctl_enqueuembuf() failed: %d", error
);
3284 microuptime(&entry
->cfe_last_event
);
3285 CFI_ADD_TIME_LOG(cfil_info
, &entry
->cfe_last_event
, &cfil_info
->cfi_first_event
, msg_disconnected
.cfm_op
);
3287 /* Remember we have sent the disconnection message */
3289 entry
->cfe_flags
|= CFEF_SENT_DISCONNECT_OUT
;
3290 OSIncrementAtomic(&cfil_stats
.cfs_disconnect_out_event_ok
);
3292 entry
->cfe_flags
|= CFEF_SENT_DISCONNECT_IN
;
3293 OSIncrementAtomic(&cfil_stats
.cfs_disconnect_in_event_ok
);
3296 if (error
== ENOBUFS
) {
3297 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3299 &cfil_stats
.cfs_disconnect_event_flow_control
);
3301 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3302 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3305 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3307 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3311 &cfil_stats
.cfs_disconnect_event_fail
);
3314 cfil_rw_unlock_shared(&cfil_lck_rw
);
3320 cfil_dispatch_closed_event(struct socket
*so
, struct cfil_info
*cfil_info
, int kcunit
)
3322 struct cfil_entry
*entry
;
3323 struct cfil_msg_sock_closed msg_closed
;
3325 struct content_filter
*cfc
;
3327 socket_lock_assert_owned(so
);
3329 cfil_rw_lock_shared(&cfil_lck_rw
);
3331 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3332 cfc
= entry
->cfe_filter
;
3337 CFIL_LOG(LOG_INFO
, "so %llx kcunit %d",
3338 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
3340 /* Would be wasteful to try when flow controlled */
3341 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3346 * Send a single closed message per filter
3348 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_CLOSED
) != 0) {
3351 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
3355 microuptime(&entry
->cfe_last_event
);
3356 CFI_ADD_TIME_LOG(cfil_info
, &entry
->cfe_last_event
, &cfil_info
->cfi_first_event
, CFM_OP_SOCKET_CLOSED
);
3358 bzero(&msg_closed
, sizeof(struct cfil_msg_sock_closed
));
3359 msg_closed
.cfc_msghdr
.cfm_len
= sizeof(struct cfil_msg_sock_closed
);
3360 msg_closed
.cfc_msghdr
.cfm_version
= CFM_VERSION_CURRENT
;
3361 msg_closed
.cfc_msghdr
.cfm_type
= CFM_TYPE_EVENT
;
3362 msg_closed
.cfc_msghdr
.cfm_op
= CFM_OP_SOCKET_CLOSED
;
3363 msg_closed
.cfc_msghdr
.cfm_sock_id
= entry
->cfe_cfil_info
->cfi_sock_id
;
3364 msg_closed
.cfc_first_event
.tv_sec
= cfil_info
->cfi_first_event
.tv_sec
;
3365 msg_closed
.cfc_first_event
.tv_usec
= cfil_info
->cfi_first_event
.tv_usec
;
3366 memcpy(msg_closed
.cfc_op_time
, cfil_info
->cfi_op_time
, sizeof(uint32_t) * CFI_MAX_TIME_LOG_ENTRY
);
3367 memcpy(msg_closed
.cfc_op_list
, cfil_info
->cfi_op_list
, sizeof(unsigned char) * CFI_MAX_TIME_LOG_ENTRY
);
3368 msg_closed
.cfc_op_list_ctr
= cfil_info
->cfi_op_list_ctr
;
3369 msg_closed
.cfc_byte_inbound_count
= cfil_info
->cfi_byte_inbound_count
;
3370 msg_closed
.cfc_byte_outbound_count
= cfil_info
->cfi_byte_outbound_count
;
3372 cfil_dispatch_closed_event_sign(entry
->cfe_filter
->cf_crypto_state
, so
, cfil_info
, &msg_closed
);
3375 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
);
3378 * if (msg_closed.cfc_op_list_ctr > CFI_MAX_TIME_LOG_ENTRY) {
3379 * msg_closed.cfc_op_list_ctr = CFI_MAX_TIME_LOG_ENTRY; // just in case
3381 * for (unsigned int i = 0; i < msg_closed.cfc_op_list_ctr ; i++) {
3382 * 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]);
3386 error
= ctl_enqueuedata(entry
->cfe_filter
->cf_kcref
,
3387 entry
->cfe_filter
->cf_kcunit
,
3389 sizeof(struct cfil_msg_sock_closed
),
3392 CFIL_LOG(LOG_ERR
, "ctl_enqueuedata() failed: %d",
3397 entry
->cfe_flags
|= CFEF_SENT_SOCK_CLOSED
;
3398 OSIncrementAtomic(&cfil_stats
.cfs_closed_event_ok
);
3400 /* We can recover from flow control */
3401 if (error
== ENOBUFS
) {
3402 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3403 OSIncrementAtomic(&cfil_stats
.cfs_closed_event_flow_control
);
3405 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3406 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3409 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3411 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3414 OSIncrementAtomic(&cfil_stats
.cfs_closed_event_fail
);
3417 cfil_rw_unlock_shared(&cfil_lck_rw
);
3424 fill_ip6_sockaddr_4_6(union sockaddr_in_4_6
*sin46
,
3425 struct in6_addr
*ip6
, u_int16_t port
)
3427 if (sin46
== NULL
) {
3431 struct sockaddr_in6
*sin6
= &sin46
->sin6
;
3433 sin6
->sin6_family
= AF_INET6
;
3434 sin6
->sin6_len
= sizeof(*sin6
);
3435 sin6
->sin6_port
= port
;
3436 sin6
->sin6_addr
= *ip6
;
3437 if (IN6_IS_SCOPE_EMBED(&sin6
->sin6_addr
)) {
3438 sin6
->sin6_scope_id
= ntohs(sin6
->sin6_addr
.s6_addr16
[1]);
3439 sin6
->sin6_addr
.s6_addr16
[1] = 0;
3444 fill_ip_sockaddr_4_6(union sockaddr_in_4_6
*sin46
,
3445 struct in_addr ip
, u_int16_t port
)
3447 if (sin46
== NULL
) {
3451 struct sockaddr_in
*sin
= &sin46
->sin
;
3453 sin
->sin_family
= AF_INET
;
3454 sin
->sin_len
= sizeof(*sin
);
3455 sin
->sin_port
= port
;
3456 sin
->sin_addr
.s_addr
= ip
.s_addr
;
3460 cfil_get_flow_address_v6(struct cfil_hash_entry
*entry
, struct inpcb
*inp
,
3461 struct in6_addr
**laddr
, struct in6_addr
**faddr
,
3462 u_int16_t
*lport
, u_int16_t
*fport
)
3464 if (entry
!= NULL
) {
3465 *laddr
= &entry
->cfentry_laddr
.addr6
;
3466 *faddr
= &entry
->cfentry_faddr
.addr6
;
3467 *lport
= entry
->cfentry_lport
;
3468 *fport
= entry
->cfentry_fport
;
3470 *laddr
= &inp
->in6p_laddr
;
3471 *faddr
= &inp
->in6p_faddr
;
3472 *lport
= inp
->inp_lport
;
3473 *fport
= inp
->inp_fport
;
3478 cfil_get_flow_address(struct cfil_hash_entry
*entry
, struct inpcb
*inp
,
3479 struct in_addr
*laddr
, struct in_addr
*faddr
,
3480 u_int16_t
*lport
, u_int16_t
*fport
)
3482 if (entry
!= NULL
) {
3483 *laddr
= entry
->cfentry_laddr
.addr46
.ia46_addr4
;
3484 *faddr
= entry
->cfentry_faddr
.addr46
.ia46_addr4
;
3485 *lport
= entry
->cfentry_lport
;
3486 *fport
= entry
->cfentry_fport
;
3488 *laddr
= inp
->inp_laddr
;
3489 *faddr
= inp
->inp_faddr
;
3490 *lport
= inp
->inp_lport
;
3491 *fport
= inp
->inp_fport
;
3496 cfil_dispatch_data_event(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
3497 struct mbuf
*data
, unsigned int copyoffset
, unsigned int copylen
)
3500 struct mbuf
*copy
= NULL
;
3501 struct mbuf
*msg
= NULL
;
3502 unsigned int one
= 1;
3503 struct cfil_msg_data_event
*data_req
;
3505 struct inpcb
*inp
= (struct inpcb
*)so
->so_pcb
;
3506 struct cfil_entry
*entry
;
3507 struct cfe_buf
*entrybuf
;
3508 struct content_filter
*cfc
;
3511 cfil_rw_lock_shared(&cfil_lck_rw
);
3513 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3515 entrybuf
= &entry
->cfe_snd
;
3517 entrybuf
= &entry
->cfe_rcv
;
3520 cfc
= entry
->cfe_filter
;
3525 data
= cfil_data_start(data
);
3526 if (data
== NULL
|| (data
->m_flags
& M_PKTHDR
) == 0) {
3527 CFIL_LOG(LOG_ERR
, "NOT PKTHDR");
3531 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3532 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3534 socket_lock_assert_owned(so
);
3536 /* Would be wasteful to try */
3537 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
3542 /* Make a copy of the data to pass to kernel control socket */
3543 copy
= m_copym_mode(data
, copyoffset
, copylen
, M_DONTWAIT
,
3546 CFIL_LOG(LOG_ERR
, "m_copym_mode() failed");
3551 /* We need an mbuf packet for the message header */
3552 hdrsize
= sizeof(struct cfil_msg_data_event
);
3553 error
= mbuf_allocpacket(MBUF_DONTWAIT
, hdrsize
, &one
, &msg
);
3555 CFIL_LOG(LOG_ERR
, "mbuf_allocpacket() failed");
3558 * ENOBUFS is to indicate flow control
3563 mbuf_setlen(msg
, hdrsize
);
3564 mbuf_pkthdr_setlen(msg
, hdrsize
+ copylen
);
3566 data_req
= (struct cfil_msg_data_event
*)mbuf_data(msg
);
3567 bzero(data_req
, hdrsize
);
3568 data_req
->cfd_msghdr
.cfm_len
= hdrsize
+ copylen
;
3569 data_req
->cfd_msghdr
.cfm_version
= 1;
3570 data_req
->cfd_msghdr
.cfm_type
= CFM_TYPE_EVENT
;
3571 data_req
->cfd_msghdr
.cfm_op
=
3572 outgoing
? CFM_OP_DATA_OUT
: CFM_OP_DATA_IN
;
3573 data_req
->cfd_msghdr
.cfm_sock_id
=
3574 entry
->cfe_cfil_info
->cfi_sock_id
;
3575 data_req
->cfd_start_offset
= entrybuf
->cfe_peeked
;
3576 data_req
->cfd_end_offset
= entrybuf
->cfe_peeked
+ copylen
;
3579 * Copy address/port into event msg.
3580 * For non connected sockets need to copy addresses from passed
3583 cfil_fill_event_msg_addresses(cfil_info
->cfi_hash_entry
, inp
,
3584 &data_req
->cfc_src
, &data_req
->cfc_dst
,
3585 inp
->inp_vflag
& INP_IPV4
, outgoing
);
3587 if (cfil_info
->cfi_isSignatureLatest
== false) {
3588 cfil_dispatch_data_event_sign(entry
->cfe_filter
->cf_crypto_state
, so
, cfil_info
, data_req
);
3592 CFI_ADD_TIME_LOG(cfil_info
, &tv
, &cfil_info
->cfi_first_event
, data_req
->cfd_msghdr
.cfm_op
);
3594 /* Pass the message to the content filter */
3595 error
= ctl_enqueuembuf(entry
->cfe_filter
->cf_kcref
,
3596 entry
->cfe_filter
->cf_kcunit
,
3599 CFIL_LOG(LOG_ERR
, "ctl_enqueuembuf() failed: %d", error
);
3603 entry
->cfe_flags
&= ~CFEF_FLOW_CONTROLLED
;
3604 OSIncrementAtomic(&cfil_stats
.cfs_data_event_ok
);
3607 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT ACTION: so %llx sockID %llu outgoing %d: mbuf %llx copyoffset %u copylen %u",
3608 (uint64_t)VM_KERNEL_ADDRPERM(so
), cfil_info
->cfi_sock_id
, outgoing
, (uint64_t)VM_KERNEL_ADDRPERM(data
), copyoffset
, copylen
);
3612 if (error
== ENOBUFS
) {
3613 entry
->cfe_flags
|= CFEF_FLOW_CONTROLLED
;
3615 &cfil_stats
.cfs_data_event_flow_control
);
3617 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
3618 cfil_rw_lock_exclusive(&cfil_lck_rw
);
3621 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
3623 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
3626 OSIncrementAtomic(&cfil_stats
.cfs_data_event_fail
);
3629 cfil_rw_unlock_shared(&cfil_lck_rw
);
3635 * Process the queue of data waiting to be delivered to content filter
3638 cfil_data_service_ctl_q(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
)
3641 struct mbuf
*data
, *tmp
= NULL
;
3642 unsigned int datalen
= 0, copylen
= 0, copyoffset
= 0;
3643 struct cfil_entry
*entry
;
3644 struct cfe_buf
*entrybuf
;
3645 uint64_t currentoffset
= 0;
3647 if (cfil_info
== NULL
) {
3651 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3652 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3654 socket_lock_assert_owned(so
);
3656 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3658 entrybuf
= &entry
->cfe_snd
;
3660 entrybuf
= &entry
->cfe_rcv
;
3663 /* Send attached message if not yet done */
3664 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
3665 error
= cfil_dispatch_attach_event(so
, cfil_info
, CFI_ENTRY_KCUNIT(cfil_info
, entry
),
3666 outgoing
? CFS_CONNECTION_DIR_OUT
: CFS_CONNECTION_DIR_IN
);
3668 /* We can recover from flow control */
3669 if (error
== ENOBUFS
|| error
== ENOMEM
) {
3674 } else if ((entry
->cfe_flags
& CFEF_DATA_START
) == 0) {
3675 OSIncrementAtomic(&cfil_stats
.cfs_ctl_q_not_started
);
3680 CFIL_LOG(LOG_DEBUG
, "CFIL: SERVICE CTL-Q: pass_offset %llu peeked %llu peek_offset %llu",
3681 entrybuf
->cfe_pass_offset
,
3682 entrybuf
->cfe_peeked
,
3683 entrybuf
->cfe_peek_offset
);
3686 /* Move all data that can pass */
3687 while ((data
= cfil_queue_first(&entrybuf
->cfe_ctl_q
)) != NULL
&&
3688 entrybuf
->cfe_ctl_q
.q_start
< entrybuf
->cfe_pass_offset
) {
3689 datalen
= cfil_data_length(data
, NULL
, NULL
);
3692 if (entrybuf
->cfe_ctl_q
.q_start
+ datalen
<=
3693 entrybuf
->cfe_pass_offset
) {
3695 * The first mbuf can fully pass
3700 * The first mbuf can partially pass
3702 copylen
= entrybuf
->cfe_pass_offset
-
3703 entrybuf
->cfe_ctl_q
.q_start
;
3705 VERIFY(copylen
<= datalen
);
3709 "CFIL: SERVICE CTL-Q PASSING: %llx first %llu peeked %llu pass %llu peek %llu"
3710 "datalen %u copylen %u",
3711 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3712 entrybuf
->cfe_ctl_q
.q_start
,
3713 entrybuf
->cfe_peeked
,
3714 entrybuf
->cfe_pass_offset
,
3715 entrybuf
->cfe_peek_offset
,
3720 * Data that passes has been peeked at explicitly or
3723 if (entrybuf
->cfe_ctl_q
.q_start
+ copylen
>
3724 entrybuf
->cfe_peeked
) {
3725 entrybuf
->cfe_peeked
=
3726 entrybuf
->cfe_ctl_q
.q_start
+ copylen
;
3729 * Stop on partial pass
3731 if (copylen
< datalen
) {
3735 /* All good, move full data from ctl queue to pending queue */
3736 cfil_queue_remove(&entrybuf
->cfe_ctl_q
, data
, datalen
);
3738 cfil_queue_enqueue(&entrybuf
->cfe_pending_q
, data
, datalen
);
3740 OSAddAtomic64(datalen
,
3741 &cfil_stats
.cfs_pending_q_out_enqueued
);
3743 OSAddAtomic64(datalen
,
3744 &cfil_stats
.cfs_pending_q_in_enqueued
);
3747 CFIL_INFO_VERIFY(cfil_info
);
3750 "%llx first %llu peeked %llu pass %llu peek %llu"
3751 "datalen %u copylen %u",
3752 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3753 entrybuf
->cfe_ctl_q
.q_start
,
3754 entrybuf
->cfe_peeked
,
3755 entrybuf
->cfe_pass_offset
,
3756 entrybuf
->cfe_peek_offset
,
3761 /* Now deal with remaining data the filter wants to peek at */
3762 for (data
= cfil_queue_first(&entrybuf
->cfe_ctl_q
),
3763 currentoffset
= entrybuf
->cfe_ctl_q
.q_start
;
3764 data
!= NULL
&& currentoffset
< entrybuf
->cfe_peek_offset
;
3765 data
= cfil_queue_next(&entrybuf
->cfe_ctl_q
, data
),
3766 currentoffset
+= datalen
) {
3767 datalen
= cfil_data_length(data
, NULL
, NULL
);
3770 /* We've already peeked at this mbuf */
3771 if (currentoffset
+ datalen
<= entrybuf
->cfe_peeked
) {
3775 * The data in the first mbuf may have been
3776 * partially peeked at
3778 copyoffset
= entrybuf
->cfe_peeked
- currentoffset
;
3779 VERIFY(copyoffset
< datalen
);
3780 copylen
= datalen
- copyoffset
;
3781 VERIFY(copylen
<= datalen
);
3783 * Do not copy more than needed
3785 if (currentoffset
+ copyoffset
+ copylen
>
3786 entrybuf
->cfe_peek_offset
) {
3787 copylen
= entrybuf
->cfe_peek_offset
-
3788 (currentoffset
+ copyoffset
);
3793 "CFIL: SERVICE CTL-Q PEEKING: %llx current %llu peeked %llu pass %llu peek %llu "
3794 "datalen %u copylen %u copyoffset %u",
3795 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3797 entrybuf
->cfe_peeked
,
3798 entrybuf
->cfe_pass_offset
,
3799 entrybuf
->cfe_peek_offset
,
3800 datalen
, copylen
, copyoffset
);
3804 * Stop if there is nothing more to peek at
3810 * Let the filter get a peek at this span of data
3812 error
= cfil_dispatch_data_event(so
, cfil_info
, kcunit
,
3813 outgoing
, data
, copyoffset
, copylen
);
3815 /* On error, leave data in ctl_q */
3818 entrybuf
->cfe_peeked
+= copylen
;
3820 OSAddAtomic64(copylen
,
3821 &cfil_stats
.cfs_ctl_q_out_peeked
);
3823 OSAddAtomic64(copylen
,
3824 &cfil_stats
.cfs_ctl_q_in_peeked
);
3827 /* Stop when data could not be fully peeked at */
3828 if (copylen
+ copyoffset
< datalen
) {
3832 CFIL_INFO_VERIFY(cfil_info
);
3835 "%llx first %llu peeked %llu pass %llu peek %llu"
3836 "datalen %u copylen %u copyoffset %u",
3837 (uint64_t)VM_KERNEL_ADDRPERM(tmp
),
3839 entrybuf
->cfe_peeked
,
3840 entrybuf
->cfe_pass_offset
,
3841 entrybuf
->cfe_peek_offset
,
3842 datalen
, copylen
, copyoffset
);
3846 * Process data that has passed the filter
3848 error
= cfil_service_pending_queue(so
, cfil_info
, kcunit
, outgoing
);
3850 CFIL_LOG(LOG_ERR
, "cfil_service_pending_queue() error %d",
3856 * Dispatch disconnect events that could not be sent
3858 if (cfil_info
== NULL
) {
3860 } else if (outgoing
) {
3861 if ((cfil_info
->cfi_flags
& CFIF_SHUT_WR
) &&
3862 !(entry
->cfe_flags
& CFEF_SENT_DISCONNECT_OUT
)) {
3863 cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 1);
3866 if ((cfil_info
->cfi_flags
& CFIF_SHUT_RD
) &&
3867 !(entry
->cfe_flags
& CFEF_SENT_DISCONNECT_IN
)) {
3868 cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 0);
3874 "first %llu peeked %llu pass %llu peek %llu",
3875 entrybuf
->cfe_ctl_q
.q_start
,
3876 entrybuf
->cfe_peeked
,
3877 entrybuf
->cfe_pass_offset
,
3878 entrybuf
->cfe_peek_offset
);
3880 CFIL_INFO_VERIFY(cfil_info
);
3885 * cfil_data_filter()
3887 * Process data for a content filter installed on a socket
3890 cfil_data_filter(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
3891 struct mbuf
*data
, uint64_t datalen
)
3894 struct cfil_entry
*entry
;
3895 struct cfe_buf
*entrybuf
;
3897 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
3898 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
3900 socket_lock_assert_owned(so
);
3902 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
3904 entrybuf
= &entry
->cfe_snd
;
3906 entrybuf
= &entry
->cfe_rcv
;
3909 /* Are we attached to the filter? */
3910 if (entry
->cfe_filter
== NULL
) {
3915 /* Dispatch to filters */
3916 cfil_queue_enqueue(&entrybuf
->cfe_ctl_q
, data
, datalen
);
3918 OSAddAtomic64(datalen
,
3919 &cfil_stats
.cfs_ctl_q_out_enqueued
);
3921 OSAddAtomic64(datalen
,
3922 &cfil_stats
.cfs_ctl_q_in_enqueued
);
3925 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, outgoing
);
3927 CFIL_LOG(LOG_ERR
, "cfil_data_service_ctl_q() error %d",
3931 * We have to return EJUSTRETURN in all cases to avoid double free
3934 error
= EJUSTRETURN
;
3936 CFIL_INFO_VERIFY(cfil_info
);
3938 CFIL_LOG(LOG_INFO
, "return %d", error
);
3943 * cfil_service_inject_queue() re-inject data that passed the
3947 cfil_service_inject_queue(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
)
3950 unsigned int datalen
;
3954 struct cfi_buf
*cfi_buf
;
3955 struct cfil_queue
*inject_q
;
3956 int need_rwakeup
= 0;
3959 if (cfil_info
== NULL
) {
3963 socket_lock_assert_owned(so
);
3966 cfi_buf
= &cfil_info
->cfi_snd
;
3967 cfil_info
->cfi_flags
&= ~CFIF_RETRY_INJECT_OUT
;
3969 cfi_buf
= &cfil_info
->cfi_rcv
;
3970 cfil_info
->cfi_flags
&= ~CFIF_RETRY_INJECT_IN
;
3972 inject_q
= &cfi_buf
->cfi_inject_q
;
3974 if (cfil_queue_empty(inject_q
)) {
3978 #if DATA_DEBUG | VERDICT_DEBUG
3979 CFIL_LOG(LOG_ERR
, "CFIL: SERVICE INJECT-Q: <so %llx> outgoing %d queue len %llu",
3980 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
, cfil_queue_len(inject_q
));
3983 while ((data
= cfil_queue_first(inject_q
)) != NULL
) {
3984 datalen
= cfil_data_length(data
, &mbcnt
, &mbnum
);
3987 CFIL_LOG(LOG_DEBUG
, "CFIL: SERVICE INJECT-Q: <%s>: <so %llx> data %llx datalen %u (mbcnt %u)",
3988 remote_addr_ptr
? "UNCONNECTED" : "CONNECTED",
3989 (uint64_t)VM_KERNEL_ADDRPERM(so
), (uint64_t)VM_KERNEL_ADDRPERM(data
), datalen
, mbcnt
);
3992 /* Remove data from queue and adjust stats */
3993 cfil_queue_remove(inject_q
, data
, datalen
);
3994 cfi_buf
->cfi_pending_first
+= datalen
;
3995 cfi_buf
->cfi_pending_mbcnt
-= mbcnt
;
3996 cfi_buf
->cfi_pending_mbnum
-= mbnum
;
3997 cfil_info_buf_verify(cfi_buf
);
4000 error
= sosend_reinject(so
, NULL
, data
, NULL
, 0);
4003 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: Error: sosend_reinject() failed");
4004 CFIL_LOG(LOG_ERR
, "### sosend() failed %d", error
);
4008 // At least one injection succeeded, need to wake up pending threads.
4011 data
->m_flags
|= M_SKIPCFIL
;
4014 * NOTE: We currently only support TCP and UDP.
4015 * For RAWIP, MPTCP and message TCP we'll
4016 * need to call the appropriate sbappendxxx()
4017 * of fix sock_inject_data_in()
4019 if (IS_UDP(so
) == TRUE
) {
4020 if (sbappendchain(&so
->so_rcv
, data
, 0)) {
4024 if (sbappendstream(&so
->so_rcv
, data
)) {
4031 OSAddAtomic64(datalen
,
4032 &cfil_stats
.cfs_inject_q_out_passed
);
4034 OSAddAtomic64(datalen
,
4035 &cfil_stats
.cfs_inject_q_in_passed
);
4041 #if DATA_DEBUG | VERDICT_DEBUG
4042 CFIL_LOG(LOG_ERR
, "CFIL: SERVICE INJECT-Q: <so %llx> injected %d",
4043 (uint64_t)VM_KERNEL_ADDRPERM(so
), count
);
4046 /* A single wakeup is for several packets is more efficient */
4048 if (outgoing
== TRUE
) {
4055 if (error
!= 0 && cfil_info
) {
4056 if (error
== ENOBUFS
) {
4057 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_nobufs
);
4059 if (error
== ENOMEM
) {
4060 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_nomem
);
4064 cfil_info
->cfi_flags
|= CFIF_RETRY_INJECT_OUT
;
4065 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_out_fail
);
4067 cfil_info
->cfi_flags
|= CFIF_RETRY_INJECT_IN
;
4068 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_in_fail
);
4075 if (cfil_info
&& (cfil_info
->cfi_flags
& CFIF_SHUT_WR
)) {
4076 cfil_sock_notify_shutdown(so
, SHUT_WR
);
4077 if (cfil_sock_data_pending(&so
->so_snd
) == 0) {
4078 soshutdownlock_final(so
, SHUT_WR
);
4081 if (cfil_info
&& (cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
)) {
4082 if (cfil_filters_attached(so
) == 0) {
4083 CFIL_LOG(LOG_INFO
, "so %llx waking",
4084 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4085 wakeup((caddr_t
)cfil_info
);
4089 CFIL_INFO_VERIFY(cfil_info
);
4095 cfil_service_pending_queue(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
)
4097 uint64_t passlen
, curlen
;
4099 unsigned int datalen
;
4101 struct cfil_entry
*entry
;
4102 struct cfe_buf
*entrybuf
;
4103 struct cfil_queue
*pending_q
;
4105 CFIL_LOG(LOG_INFO
, "so %llx kcunit %u outgoing %d",
4106 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
, outgoing
);
4108 socket_lock_assert_owned(so
);
4110 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4112 entrybuf
= &entry
->cfe_snd
;
4114 entrybuf
= &entry
->cfe_rcv
;
4117 pending_q
= &entrybuf
->cfe_pending_q
;
4119 passlen
= entrybuf
->cfe_pass_offset
- pending_q
->q_start
;
4122 * Locate the chunks of data that we can pass to the next filter
4123 * A data chunk must be on mbuf boundaries
4126 while ((data
= cfil_queue_first(pending_q
)) != NULL
) {
4127 struct cfil_entry
*iter_entry
;
4128 datalen
= cfil_data_length(data
, NULL
, NULL
);
4132 "CFIL: SERVICE PENDING-Q: data %llx datalen %u passlen %llu curlen %llu",
4133 (uint64_t)VM_KERNEL_ADDRPERM(data
), datalen
,
4137 if (curlen
+ datalen
> passlen
) {
4141 cfil_queue_remove(pending_q
, data
, datalen
);
4145 for (iter_entry
= SLIST_NEXT(entry
, cfe_order_link
);
4147 iter_entry
= SLIST_NEXT(iter_entry
, cfe_order_link
)) {
4148 error
= cfil_data_filter(so
, cfil_info
, CFI_ENTRY_KCUNIT(cfil_info
, iter_entry
), outgoing
,
4150 /* 0 means passed so we can continue */
4155 /* When data has passed all filters, re-inject */
4159 &cfil_info
->cfi_snd
.cfi_inject_q
,
4161 OSAddAtomic64(datalen
,
4162 &cfil_stats
.cfs_inject_q_out_enqueued
);
4165 &cfil_info
->cfi_rcv
.cfi_inject_q
,
4167 OSAddAtomic64(datalen
,
4168 &cfil_stats
.cfs_inject_q_in_enqueued
);
4173 CFIL_INFO_VERIFY(cfil_info
);
4179 cfil_update_data_offsets(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
4180 uint64_t pass_offset
, uint64_t peek_offset
)
4183 struct cfil_entry
*entry
= NULL
;
4184 struct cfe_buf
*entrybuf
;
4187 CFIL_LOG(LOG_INFO
, "pass %llu peek %llu", pass_offset
, peek_offset
);
4189 socket_lock_assert_owned(so
);
4191 if (cfil_info
== NULL
) {
4192 CFIL_LOG(LOG_ERR
, "so %llx cfil detached",
4193 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4196 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4197 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4198 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4203 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4205 entrybuf
= &entry
->cfe_snd
;
4207 entrybuf
= &entry
->cfe_rcv
;
4210 /* Record updated offsets for this content filter */
4211 if (pass_offset
> entrybuf
->cfe_pass_offset
) {
4212 entrybuf
->cfe_pass_offset
= pass_offset
;
4214 if (entrybuf
->cfe_peek_offset
< entrybuf
->cfe_pass_offset
) {
4215 entrybuf
->cfe_peek_offset
= entrybuf
->cfe_pass_offset
;
4219 CFIL_LOG(LOG_INFO
, "pass_offset %llu <= cfe_pass_offset %llu",
4220 pass_offset
, entrybuf
->cfe_pass_offset
);
4222 /* Filter does not want or need to see data that's allowed to pass */
4223 if (peek_offset
> entrybuf
->cfe_pass_offset
&&
4224 peek_offset
> entrybuf
->cfe_peek_offset
) {
4225 entrybuf
->cfe_peek_offset
= peek_offset
;
4233 /* Move data held in control queue to pending queue if needed */
4234 error
= cfil_data_service_ctl_q(so
, cfil_info
, kcunit
, outgoing
);
4236 CFIL_LOG(LOG_ERR
, "cfil_data_service_ctl_q() error %d",
4240 error
= EJUSTRETURN
;
4244 * The filter is effectively detached when pass all from both sides
4245 * or when the socket is closed and no more data is waiting
4246 * to be delivered to the filter
4248 if (entry
!= NULL
&&
4249 ((entry
->cfe_snd
.cfe_pass_offset
== CFM_MAX_OFFSET
&&
4250 entry
->cfe_rcv
.cfe_pass_offset
== CFM_MAX_OFFSET
) ||
4251 ((cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) &&
4252 cfil_queue_empty(&entry
->cfe_snd
.cfe_ctl_q
) &&
4253 cfil_queue_empty(&entry
->cfe_rcv
.cfe_ctl_q
)))) {
4254 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
4256 cfil_info_log(LOG_ERR
, cfil_info
, outgoing
?
4257 "CFIL: LIFECYCLE: OUT - PASSED ALL - DETACH":
4258 "CFIL: LIFECYCLE: IN - PASSED ALL - DETACH");
4260 CFIL_LOG(LOG_INFO
, "so %llx detached %u",
4261 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
4262 if ((cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) &&
4263 cfil_filters_attached(so
) == 0) {
4265 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAKING");
4267 CFIL_LOG(LOG_INFO
, "so %llx waking",
4268 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4269 wakeup((caddr_t
)cfil_info
);
4272 CFIL_INFO_VERIFY(cfil_info
);
4273 CFIL_LOG(LOG_INFO
, "return %d", error
);
4278 * Update pass offset for socket when no data is pending
4281 cfil_set_socket_pass_offset(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
)
4283 struct cfi_buf
*cfi_buf
;
4284 struct cfil_entry
*entry
;
4285 struct cfe_buf
*entrybuf
;
4287 uint64_t pass_offset
= 0;
4289 if (cfil_info
== NULL
) {
4293 CFIL_LOG(LOG_INFO
, "so %llx outgoing %d",
4294 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
);
4296 socket_lock_assert_owned(so
);
4299 cfi_buf
= &cfil_info
->cfi_snd
;
4301 cfi_buf
= &cfil_info
->cfi_rcv
;
4304 CFIL_LOG(LOG_DEBUG
, "CFIL: <so %llx, sockID %llu> outgoing %d cfi_pending_first %llu cfi_pending_last %llu",
4305 (uint64_t)VM_KERNEL_ADDRPERM(so
), cfil_info
->cfi_sock_id
, outgoing
,
4306 cfi_buf
->cfi_pending_first
, cfi_buf
->cfi_pending_last
);
4308 if (cfi_buf
->cfi_pending_last
- cfi_buf
->cfi_pending_first
== 0) {
4309 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4310 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4312 /* Are we attached to a filter? */
4313 if (entry
->cfe_filter
== NULL
) {
4318 entrybuf
= &entry
->cfe_snd
;
4320 entrybuf
= &entry
->cfe_rcv
;
4323 if (pass_offset
== 0 ||
4324 entrybuf
->cfe_pass_offset
< pass_offset
) {
4325 pass_offset
= entrybuf
->cfe_pass_offset
;
4328 cfi_buf
->cfi_pass_offset
= pass_offset
;
4331 CFIL_LOG(LOG_DEBUG
, "CFIL: <so %llx, sockID %llu>, cfi_pass_offset %llu",
4332 (uint64_t)VM_KERNEL_ADDRPERM(so
), cfil_info
->cfi_sock_id
, cfi_buf
->cfi_pass_offset
);
4338 cfil_action_data_pass(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
, int outgoing
,
4339 uint64_t pass_offset
, uint64_t peek_offset
)
4343 CFIL_LOG(LOG_INFO
, "");
4345 socket_lock_assert_owned(so
);
4347 error
= cfil_acquire_sockbuf(so
, cfil_info
, outgoing
);
4349 CFIL_LOG(LOG_INFO
, "so %llx %s dropped",
4350 (uint64_t)VM_KERNEL_ADDRPERM(so
),
4351 outgoing
? "out" : "in");
4355 error
= cfil_update_data_offsets(so
, cfil_info
, kcunit
, outgoing
,
4356 pass_offset
, peek_offset
);
4358 cfil_service_inject_queue(so
, cfil_info
, outgoing
);
4360 cfil_set_socket_pass_offset(so
, cfil_info
, outgoing
);
4362 CFIL_INFO_VERIFY(cfil_info
);
4363 cfil_release_sockbuf(so
, outgoing
);
4370 cfil_flush_queues(struct socket
*so
, struct cfil_info
*cfil_info
)
4372 struct cfil_entry
*entry
;
4376 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || cfil_info
== NULL
) {
4380 socket_lock_assert_owned(so
);
4383 * Flush the output queues and ignore errors as long as
4386 (void) cfil_acquire_sockbuf(so
, cfil_info
, 1);
4387 if (cfil_info
!= NULL
) {
4389 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4390 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4392 drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_ctl_q
);
4393 drained
+= cfil_queue_drain(&entry
->cfe_snd
.cfe_pending_q
);
4395 drained
+= cfil_queue_drain(&cfil_info
->cfi_snd
.cfi_inject_q
);
4398 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4400 &cfil_stats
.cfs_flush_out_drop
);
4403 &cfil_stats
.cfs_flush_out_close
);
4407 cfil_release_sockbuf(so
, 1);
4410 * Flush the input queues
4412 (void) cfil_acquire_sockbuf(so
, cfil_info
, 0);
4413 if (cfil_info
!= NULL
) {
4415 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4416 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4418 drained
+= cfil_queue_drain(
4419 &entry
->cfe_rcv
.cfe_ctl_q
);
4420 drained
+= cfil_queue_drain(
4421 &entry
->cfe_rcv
.cfe_pending_q
);
4423 drained
+= cfil_queue_drain(&cfil_info
->cfi_rcv
.cfi_inject_q
);
4426 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4428 &cfil_stats
.cfs_flush_in_drop
);
4431 &cfil_stats
.cfs_flush_in_close
);
4435 cfil_release_sockbuf(so
, 0);
4437 CFIL_INFO_VERIFY(cfil_info
);
4441 cfil_action_drop(struct socket
*so
, struct cfil_info
*cfil_info
, uint32_t kcunit
)
4444 struct cfil_entry
*entry
;
4447 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || cfil_info
== NULL
) {
4451 socket_lock_assert_owned(so
);
4453 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4455 /* Are we attached to the filter? */
4456 if (entry
->cfe_filter
== NULL
) {
4460 cfil_info
->cfi_flags
|= CFIF_DROP
;
4465 * Force the socket to be marked defunct
4466 * (forcing fixed along with rdar://19391339)
4468 if (so
->so_cfil_db
== NULL
) {
4469 error
= sosetdefunct(p
, so
,
4470 SHUTDOWN_SOCKET_LEVEL_CONTENT_FILTER
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
,
4473 /* Flush the socket buffer and disconnect */
4475 error
= sodefunct(p
, so
,
4476 SHUTDOWN_SOCKET_LEVEL_CONTENT_FILTER
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
);
4480 /* The filter is done, mark as detached */
4481 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
4483 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: DROP - DETACH");
4485 CFIL_LOG(LOG_INFO
, "so %llx detached %u",
4486 (uint64_t)VM_KERNEL_ADDRPERM(so
), kcunit
);
4488 /* Pending data needs to go */
4489 cfil_flush_queues(so
, cfil_info
);
4491 if (cfil_info
&& (cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
)) {
4492 if (cfil_filters_attached(so
) == 0) {
4493 CFIL_LOG(LOG_INFO
, "so %llx waking",
4494 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4495 wakeup((caddr_t
)cfil_info
);
4503 cfil_action_bless_client(uint32_t kcunit
, struct cfil_msg_hdr
*msghdr
)
4506 struct cfil_info
*cfil_info
= NULL
;
4508 bool cfil_attached
= false;
4509 struct cfil_msg_bless_client
*blessmsg
= (struct cfil_msg_bless_client
*)msghdr
;
4511 // Search and lock socket
4512 struct socket
*so
= cfil_socket_from_client_uuid(blessmsg
->cfb_client_uuid
, &cfil_attached
);
4516 // The client gets a pass automatically
4517 cfil_info
= (so
->so_cfil_db
!= NULL
) ?
4518 cfil_db_get_cfil_info(so
->so_cfil_db
, msghdr
->cfm_sock_id
) : so
->so_cfil
;
4520 if (cfil_attached
) {
4522 if (cfil_info
!= NULL
) {
4523 CFIL_LOG(LOG_ERR
, "CFIL: VERDICT RECEIVED: BLESS %s <so %llx sockID %llu>",
4524 cfil_info
->cfi_hash_entry
? "UDP" : "TCP",
4525 (uint64_t)VM_KERNEL_ADDRPERM(so
),
4526 cfil_info
->cfi_sock_id
);
4529 cfil_sock_received_verdict(so
);
4530 (void)cfil_action_data_pass(so
, cfil_info
, kcunit
, 1, CFM_MAX_OFFSET
, CFM_MAX_OFFSET
);
4531 (void)cfil_action_data_pass(so
, cfil_info
, kcunit
, 0, CFM_MAX_OFFSET
, CFM_MAX_OFFSET
);
4533 so
->so_flags1
|= SOF1_CONTENT_FILTER_SKIP
;
4535 socket_unlock(so
, 1);
4542 cfil_action_set_crypto_key(uint32_t kcunit
, struct cfil_msg_hdr
*msghdr
)
4544 struct content_filter
*cfc
= NULL
;
4545 cfil_crypto_state_t crypto_state
= NULL
;
4546 struct cfil_msg_set_crypto_key
*keymsg
= (struct cfil_msg_set_crypto_key
*)msghdr
;
4548 CFIL_LOG(LOG_NOTICE
, "");
4550 if (content_filters
== NULL
) {
4551 CFIL_LOG(LOG_ERR
, "no content filter");
4554 if (kcunit
> MAX_CONTENT_FILTER
) {
4555 CFIL_LOG(LOG_ERR
, "kcunit %u > MAX_CONTENT_FILTER (%d)",
4556 kcunit
, MAX_CONTENT_FILTER
);
4559 crypto_state
= cfil_crypto_init_client((uint8_t *)keymsg
->crypto_key
);
4560 if (crypto_state
== NULL
) {
4561 CFIL_LOG(LOG_ERR
, "failed to initialize crypto state for unit %u)",
4566 cfil_rw_lock_exclusive(&cfil_lck_rw
);
4568 cfc
= content_filters
[kcunit
- 1];
4569 if (cfc
->cf_kcunit
!= kcunit
) {
4570 CFIL_LOG(LOG_ERR
, "bad unit info %u)",
4572 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
4573 cfil_crypto_cleanup_state(crypto_state
);
4576 if (cfc
->cf_crypto_state
!= NULL
) {
4577 cfil_crypto_cleanup_state(cfc
->cf_crypto_state
);
4578 cfc
->cf_crypto_state
= NULL
;
4580 cfc
->cf_crypto_state
= crypto_state
;
4582 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
4587 cfil_update_entry_offsets(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
, unsigned int datalen
)
4589 struct cfil_entry
*entry
;
4590 struct cfe_buf
*entrybuf
;
4593 CFIL_LOG(LOG_INFO
, "so %llx outgoing %d datalen %u",
4594 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
, datalen
);
4596 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4597 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
4599 /* Are we attached to the filter? */
4600 if (entry
->cfe_filter
== NULL
) {
4605 entrybuf
= &entry
->cfe_snd
;
4607 entrybuf
= &entry
->cfe_rcv
;
4610 entrybuf
->cfe_ctl_q
.q_start
+= datalen
;
4611 entrybuf
->cfe_pass_offset
= entrybuf
->cfe_ctl_q
.q_start
;
4612 entrybuf
->cfe_peeked
= entrybuf
->cfe_ctl_q
.q_start
;
4613 if (entrybuf
->cfe_peek_offset
< entrybuf
->cfe_pass_offset
) {
4614 entrybuf
->cfe_peek_offset
= entrybuf
->cfe_pass_offset
;
4617 entrybuf
->cfe_ctl_q
.q_end
+= datalen
;
4619 entrybuf
->cfe_pending_q
.q_start
+= datalen
;
4620 entrybuf
->cfe_pending_q
.q_end
+= datalen
;
4622 CFIL_INFO_VERIFY(cfil_info
);
4627 cfil_data_common(struct socket
*so
, struct cfil_info
*cfil_info
, int outgoing
, struct sockaddr
*to
,
4628 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
4630 #pragma unused(to, control, flags)
4632 unsigned int datalen
;
4636 struct cfi_buf
*cfi_buf
;
4637 struct mbuf
*chain
= NULL
;
4639 if (cfil_info
== NULL
) {
4640 CFIL_LOG(LOG_ERR
, "so %llx cfil detached",
4641 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4644 } else if (cfil_info
->cfi_flags
& CFIF_DROP
) {
4645 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4646 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4651 datalen
= cfil_data_length(data
, &mbcnt
, &mbnum
);
4654 cfi_buf
= &cfil_info
->cfi_snd
;
4655 cfil_info
->cfi_byte_outbound_count
+= datalen
;
4657 cfi_buf
= &cfil_info
->cfi_rcv
;
4658 cfil_info
->cfi_byte_inbound_count
+= datalen
;
4661 cfi_buf
->cfi_pending_last
+= datalen
;
4662 cfi_buf
->cfi_pending_mbcnt
+= mbcnt
;
4663 cfi_buf
->cfi_pending_mbnum
+= mbnum
;
4666 if (cfi_buf
->cfi_pending_mbnum
> cfil_udp_gc_mbuf_num_max
||
4667 cfi_buf
->cfi_pending_mbcnt
> cfil_udp_gc_mbuf_cnt_max
) {
4668 cfi_buf
->cfi_tail_drop_cnt
++;
4669 cfi_buf
->cfi_pending_mbcnt
-= mbcnt
;
4670 cfi_buf
->cfi_pending_mbnum
-= mbnum
;
4675 cfil_info_buf_verify(cfi_buf
);
4678 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",
4679 (uint64_t)VM_KERNEL_ADDRPERM(so
),
4680 outgoing
? "OUT" : "IN",
4681 (uint64_t)VM_KERNEL_ADDRPERM(data
), datalen
, data
->m_flags
,
4682 (uint64_t)VM_KERNEL_ADDRPERM(data
->m_nextpkt
),
4683 cfi_buf
->cfi_pending_last
,
4684 cfi_buf
->cfi_pending_mbcnt
,
4685 cfi_buf
->cfi_pass_offset
);
4688 /* Fast path when below pass offset */
4689 if (cfi_buf
->cfi_pending_last
<= cfi_buf
->cfi_pass_offset
) {
4690 cfil_update_entry_offsets(so
, cfil_info
, outgoing
, datalen
);
4692 CFIL_LOG(LOG_DEBUG
, "CFIL: QUEUEING DATA: FAST PATH");
4695 struct cfil_entry
*iter_entry
;
4696 SLIST_FOREACH(iter_entry
, &cfil_info
->cfi_ordered_entries
, cfe_order_link
) {
4697 // Is cfil attached to this filter?
4698 kcunit
= CFI_ENTRY_KCUNIT(cfil_info
, iter_entry
);
4699 if (IS_ENTRY_ATTACHED(cfil_info
, kcunit
)) {
4700 if (IS_UDP(so
) && chain
== NULL
) {
4702 * Chain addr (incoming only TDB), control (optional) and data into one chain.
4703 * This full chain will be reinjected into socket after recieving verdict.
4705 (void) cfil_udp_save_socket_state(cfil_info
, data
);
4706 chain
= sbconcat_mbufs(NULL
, outgoing
? NULL
: to
, data
, control
);
4707 if (chain
== NULL
) {
4712 error
= cfil_data_filter(so
, cfil_info
, kcunit
, outgoing
, data
,
4715 /* 0 means passed so continue with next filter */
4722 /* Move cursor if no filter claimed the data */
4724 cfi_buf
->cfi_pending_first
+= datalen
;
4725 cfi_buf
->cfi_pending_mbcnt
-= mbcnt
;
4726 cfi_buf
->cfi_pending_mbnum
-= mbnum
;
4727 cfil_info_buf_verify(cfi_buf
);
4730 CFIL_INFO_VERIFY(cfil_info
);
4736 * Callback from socket layer sosendxxx()
4739 cfil_sock_data_out(struct socket
*so
, struct sockaddr
*to
,
4740 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
4745 return cfil_sock_udp_handle_data(TRUE
, so
, NULL
, to
, data
, control
, flags
);
4748 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4753 * Pass initial data for TFO.
4755 if (IS_INITIAL_TFO_DATA(so
)) {
4759 socket_lock_assert_owned(so
);
4761 if (so
->so_cfil
->cfi_flags
& CFIF_DROP
) {
4762 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4763 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4766 if (control
!= NULL
) {
4767 CFIL_LOG(LOG_ERR
, "so %llx control",
4768 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4769 OSIncrementAtomic(&cfil_stats
.cfs_data_out_control
);
4771 if ((flags
& MSG_OOB
)) {
4772 CFIL_LOG(LOG_ERR
, "so %llx MSG_OOB",
4773 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4774 OSIncrementAtomic(&cfil_stats
.cfs_data_out_oob
);
4776 if ((so
->so_snd
.sb_flags
& SB_LOCK
) == 0) {
4777 panic("so %p SB_LOCK not set", so
);
4780 if (so
->so_snd
.sb_cfil_thread
!= NULL
) {
4781 panic("%s sb_cfil_thread %p not NULL", __func__
,
4782 so
->so_snd
.sb_cfil_thread
);
4785 error
= cfil_data_common(so
, so
->so_cfil
, 1, to
, data
, control
, flags
);
4791 * Callback from socket layer sbappendxxx()
4794 cfil_sock_data_in(struct socket
*so
, struct sockaddr
*from
,
4795 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
4800 return cfil_sock_udp_handle_data(FALSE
, so
, NULL
, from
, data
, control
, flags
);
4803 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4808 * Pass initial data for TFO.
4810 if (IS_INITIAL_TFO_DATA(so
)) {
4814 socket_lock_assert_owned(so
);
4816 if (so
->so_cfil
->cfi_flags
& CFIF_DROP
) {
4817 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4818 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4821 if (control
!= NULL
) {
4822 CFIL_LOG(LOG_ERR
, "so %llx control",
4823 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4824 OSIncrementAtomic(&cfil_stats
.cfs_data_in_control
);
4826 if (data
->m_type
== MT_OOBDATA
) {
4827 CFIL_LOG(LOG_ERR
, "so %llx MSG_OOB",
4828 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4829 OSIncrementAtomic(&cfil_stats
.cfs_data_in_oob
);
4831 error
= cfil_data_common(so
, so
->so_cfil
, 0, from
, data
, control
, flags
);
4837 * Callback from socket layer soshutdownxxx()
4839 * We may delay the shutdown write if there's outgoing data in process.
4841 * There is no point in delaying the shutdown read because the process
4842 * indicated that it does not want to read anymore data.
4845 cfil_sock_shutdown(struct socket
*so
, int *how
)
4850 return cfil_sock_udp_shutdown(so
, how
);
4853 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4857 socket_lock_assert_owned(so
);
4859 CFIL_LOG(LOG_INFO
, "so %llx how %d",
4860 (uint64_t)VM_KERNEL_ADDRPERM(so
), *how
);
4863 * Check the state of the socket before the content filter
4865 if (*how
!= SHUT_WR
&& (so
->so_state
& SS_CANTRCVMORE
) != 0) {
4866 /* read already shut down */
4870 if (*how
!= SHUT_RD
&& (so
->so_state
& SS_CANTSENDMORE
) != 0) {
4871 /* write already shut down */
4876 if ((so
->so_cfil
->cfi_flags
& CFIF_DROP
) != 0) {
4877 CFIL_LOG(LOG_ERR
, "so %llx drop set",
4878 (uint64_t)VM_KERNEL_ADDRPERM(so
));
4883 * shutdown read: SHUT_RD or SHUT_RDWR
4885 if (*how
!= SHUT_WR
) {
4886 if (so
->so_cfil
->cfi_flags
& CFIF_SHUT_RD
) {
4890 so
->so_cfil
->cfi_flags
|= CFIF_SHUT_RD
;
4891 cfil_sock_notify_shutdown(so
, SHUT_RD
);
4894 * shutdown write: SHUT_WR or SHUT_RDWR
4896 if (*how
!= SHUT_RD
) {
4897 if (so
->so_cfil
->cfi_flags
& CFIF_SHUT_WR
) {
4901 so
->so_cfil
->cfi_flags
|= CFIF_SHUT_WR
;
4902 cfil_sock_notify_shutdown(so
, SHUT_WR
);
4904 * When outgoing data is pending, we delay the shutdown at the
4905 * protocol level until the content filters give the final
4906 * verdict on the pending data.
4908 if (cfil_sock_data_pending(&so
->so_snd
) != 0) {
4910 * When shutting down the read and write sides at once
4911 * we can proceed to the final shutdown of the read
4912 * side. Otherwise, we just return.
4914 if (*how
== SHUT_WR
) {
4915 error
= EJUSTRETURN
;
4916 } else if (*how
== SHUT_RDWR
) {
4926 * This is called when the socket is closed and there is no more
4927 * opportunity for filtering
4930 cfil_sock_is_closed(struct socket
*so
)
4936 cfil_sock_udp_is_closed(so
);
4940 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4944 CFIL_LOG(LOG_INFO
, "so %llx", (uint64_t)VM_KERNEL_ADDRPERM(so
));
4946 socket_lock_assert_owned(so
);
4948 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4949 /* Let the filters know of the closing */
4950 error
= cfil_dispatch_closed_event(so
, so
->so_cfil
, kcunit
);
4953 /* Last chance to push passed data out */
4954 error
= cfil_acquire_sockbuf(so
, so
->so_cfil
, 1);
4956 cfil_service_inject_queue(so
, so
->so_cfil
, 1);
4958 cfil_release_sockbuf(so
, 1);
4960 so
->so_cfil
->cfi_flags
|= CFIF_SOCK_CLOSED
;
4962 /* Pending data needs to go */
4963 cfil_flush_queues(so
, so
->so_cfil
);
4965 CFIL_INFO_VERIFY(so
->so_cfil
);
4969 * This is called when the socket is disconnected so let the filters
4970 * know about the disconnection and that no more data will come
4972 * The how parameter has the same values as soshutown()
4975 cfil_sock_notify_shutdown(struct socket
*so
, int how
)
4981 cfil_sock_udp_notify_shutdown(so
, how
, 0, 0);
4985 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
4989 CFIL_LOG(LOG_INFO
, "so %llx how %d",
4990 (uint64_t)VM_KERNEL_ADDRPERM(so
), how
);
4992 socket_lock_assert_owned(so
);
4994 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
4995 /* Disconnect incoming side */
4996 if (how
!= SHUT_WR
) {
4997 error
= cfil_dispatch_disconnect_event(so
, so
->so_cfil
, kcunit
, 0);
4999 /* Disconnect outgoing side */
5000 if (how
!= SHUT_RD
) {
5001 error
= cfil_dispatch_disconnect_event(so
, so
->so_cfil
, kcunit
, 1);
5007 cfil_filters_attached(struct socket
*so
)
5009 struct cfil_entry
*entry
;
5014 return cfil_filters_udp_attached(so
, FALSE
);
5017 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
5021 socket_lock_assert_owned(so
);
5023 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
5024 entry
= &so
->so_cfil
->cfi_entries
[kcunit
- 1];
5026 /* Are we attached to the filter? */
5027 if (entry
->cfe_filter
== NULL
) {
5030 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
5033 if ((entry
->cfe_flags
& CFEF_CFIL_DETACHED
) != 0) {
5044 * This is called when the socket is closed and we are waiting for
5045 * the filters to gives the final pass or drop
5048 cfil_sock_close_wait(struct socket
*so
)
5050 lck_mtx_t
*mutex_held
;
5055 cfil_sock_udp_close_wait(so
);
5059 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
5063 CFIL_LOG(LOG_INFO
, "so %llx", (uint64_t)VM_KERNEL_ADDRPERM(so
));
5065 if (so
->so_proto
->pr_getlock
!= NULL
) {
5066 mutex_held
= (*so
->so_proto
->pr_getlock
)(so
, PR_F_WILLUNLOCK
);
5068 mutex_held
= so
->so_proto
->pr_domain
->dom_mtx
;
5070 LCK_MTX_ASSERT(mutex_held
, LCK_MTX_ASSERT_OWNED
);
5072 while (cfil_filters_attached(so
)) {
5074 * Notify the filters we are going away so they can detach
5076 cfil_sock_notify_shutdown(so
, SHUT_RDWR
);
5079 * Make sure we need to wait after the filter are notified
5080 * of the disconnection
5082 if (cfil_filters_attached(so
) == 0) {
5086 CFIL_LOG(LOG_INFO
, "so %llx waiting",
5087 (uint64_t)VM_KERNEL_ADDRPERM(so
));
5089 ts
.tv_sec
= cfil_close_wait_timeout
/ 1000;
5090 ts
.tv_nsec
= (cfil_close_wait_timeout
% 1000) *
5091 NSEC_PER_USEC
* 1000;
5093 OSIncrementAtomic(&cfil_stats
.cfs_close_wait
);
5094 so
->so_cfil
->cfi_flags
|= CFIF_CLOSE_WAIT
;
5095 error
= msleep((caddr_t
)so
->so_cfil
, mutex_held
,
5096 PSOCK
| PCATCH
, "cfil_sock_close_wait", &ts
);
5097 so
->so_cfil
->cfi_flags
&= ~CFIF_CLOSE_WAIT
;
5099 CFIL_LOG(LOG_NOTICE
, "so %llx timed out %d",
5100 (uint64_t)VM_KERNEL_ADDRPERM(so
), (error
!= 0));
5103 * Force close in case of timeout
5106 OSIncrementAtomic(&cfil_stats
.cfs_close_wait_timeout
);
5113 * Returns the size of the data held by the content filter by using
5116 cfil_sock_data_pending(struct sockbuf
*sb
)
5118 struct socket
*so
= sb
->sb_so
;
5119 uint64_t pending
= 0;
5122 return cfil_sock_udp_data_pending(sb
, FALSE
);
5125 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil
!= NULL
) {
5126 struct cfi_buf
*cfi_buf
;
5128 socket_lock_assert_owned(so
);
5130 if ((sb
->sb_flags
& SB_RECV
) == 0) {
5131 cfi_buf
= &so
->so_cfil
->cfi_snd
;
5133 cfi_buf
= &so
->so_cfil
->cfi_rcv
;
5136 pending
= cfi_buf
->cfi_pending_last
-
5137 cfi_buf
->cfi_pending_first
;
5140 * If we are limited by the "chars of mbufs used" roughly
5141 * adjust so we won't overcommit
5143 if (pending
> (uint64_t)cfi_buf
->cfi_pending_mbcnt
) {
5144 pending
= cfi_buf
->cfi_pending_mbcnt
;
5148 VERIFY(pending
< INT32_MAX
);
5150 return (int32_t)(pending
);
5154 * Return the socket buffer space used by data being held by content filters
5155 * so processes won't clog the socket buffer
5158 cfil_sock_data_space(struct sockbuf
*sb
)
5160 struct socket
*so
= sb
->sb_so
;
5161 uint64_t pending
= 0;
5164 return cfil_sock_udp_data_pending(sb
, TRUE
);
5167 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil
!= NULL
&&
5168 so
->so_snd
.sb_cfil_thread
!= current_thread()) {
5169 struct cfi_buf
*cfi_buf
;
5171 socket_lock_assert_owned(so
);
5173 if ((sb
->sb_flags
& SB_RECV
) == 0) {
5174 cfi_buf
= &so
->so_cfil
->cfi_snd
;
5176 cfi_buf
= &so
->so_cfil
->cfi_rcv
;
5179 pending
= cfi_buf
->cfi_pending_last
-
5180 cfi_buf
->cfi_pending_first
;
5183 * If we are limited by the "chars of mbufs used" roughly
5184 * adjust so we won't overcommit
5186 if ((uint64_t)cfi_buf
->cfi_pending_mbcnt
> pending
) {
5187 pending
= cfi_buf
->cfi_pending_mbcnt
;
5191 VERIFY(pending
< INT32_MAX
);
5193 return (int32_t)(pending
);
5197 * A callback from the socket and protocol layer when data becomes
5198 * available in the socket buffer to give a chance for the content filter
5199 * to re-inject data that was held back
5202 cfil_sock_buf_update(struct sockbuf
*sb
)
5206 struct socket
*so
= sb
->sb_so
;
5209 cfil_sock_udp_buf_update(sb
);
5213 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || so
->so_cfil
== NULL
) {
5221 socket_lock_assert_owned(so
);
5223 if ((sb
->sb_flags
& SB_RECV
) == 0) {
5224 if ((so
->so_cfil
->cfi_flags
& CFIF_RETRY_INJECT_OUT
) == 0) {
5228 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_out_retry
);
5230 if ((so
->so_cfil
->cfi_flags
& CFIF_RETRY_INJECT_IN
) == 0) {
5234 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_in_retry
);
5237 CFIL_LOG(LOG_NOTICE
, "so %llx outgoing %d",
5238 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
);
5240 error
= cfil_acquire_sockbuf(so
, so
->so_cfil
, outgoing
);
5242 cfil_service_inject_queue(so
, so
->so_cfil
, outgoing
);
5244 cfil_release_sockbuf(so
, outgoing
);
5248 sysctl_cfil_filter_list(struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
5249 struct sysctl_req
*req
)
5251 #pragma unused(oidp, arg1, arg2)
5257 if (req
->newptr
!= USER_ADDR_NULL
) {
5261 cfil_rw_lock_shared(&cfil_lck_rw
);
5263 for (i
= 0; content_filters
!= NULL
&& i
< MAX_CONTENT_FILTER
; i
++) {
5264 struct cfil_filter_stat filter_stat
;
5265 struct content_filter
*cfc
= content_filters
[i
];
5271 /* If just asking for the size */
5272 if (req
->oldptr
== USER_ADDR_NULL
) {
5273 len
+= sizeof(struct cfil_filter_stat
);
5277 bzero(&filter_stat
, sizeof(struct cfil_filter_stat
));
5278 filter_stat
.cfs_len
= sizeof(struct cfil_filter_stat
);
5279 filter_stat
.cfs_filter_id
= cfc
->cf_kcunit
;
5280 filter_stat
.cfs_flags
= cfc
->cf_flags
;
5281 filter_stat
.cfs_sock_count
= cfc
->cf_sock_count
;
5282 filter_stat
.cfs_necp_control_unit
= cfc
->cf_necp_control_unit
;
5284 error
= SYSCTL_OUT(req
, &filter_stat
,
5285 sizeof(struct cfil_filter_stat
));
5290 /* If just asking for the size */
5291 if (req
->oldptr
== USER_ADDR_NULL
) {
5295 cfil_rw_unlock_shared(&cfil_lck_rw
);
5298 if (req
->oldptr
!= USER_ADDR_NULL
) {
5299 for (i
= 1; content_filters
!= NULL
&& i
<= MAX_CONTENT_FILTER
; i
++) {
5300 cfil_filter_show(i
);
5309 sysctl_cfil_sock_list(struct sysctl_oid
*oidp
, void *arg1
, int arg2
,
5310 struct sysctl_req
*req
)
5312 #pragma unused(oidp, arg1, arg2)
5315 struct cfil_info
*cfi
;
5318 if (req
->newptr
!= USER_ADDR_NULL
) {
5322 cfil_rw_lock_shared(&cfil_lck_rw
);
5325 * If just asking for the size,
5327 if (req
->oldptr
== USER_ADDR_NULL
) {
5328 req
->oldidx
= cfil_sock_attached_count
*
5329 sizeof(struct cfil_sock_stat
);
5330 /* Bump the length in case new sockets gets attached */
5331 req
->oldidx
+= req
->oldidx
>> 3;
5335 TAILQ_FOREACH(cfi
, &cfil_sock_head
, cfi_link
) {
5336 struct cfil_entry
*entry
;
5337 struct cfil_sock_stat stat
;
5338 struct socket
*so
= cfi
->cfi_so
;
5340 bzero(&stat
, sizeof(struct cfil_sock_stat
));
5341 stat
.cfs_len
= sizeof(struct cfil_sock_stat
);
5342 stat
.cfs_sock_id
= cfi
->cfi_sock_id
;
5343 stat
.cfs_flags
= cfi
->cfi_flags
;
5346 stat
.cfs_pid
= so
->last_pid
;
5347 memcpy(stat
.cfs_uuid
, so
->last_uuid
,
5349 if (so
->so_flags
& SOF_DELEGATED
) {
5350 stat
.cfs_e_pid
= so
->e_pid
;
5351 memcpy(stat
.cfs_e_uuid
, so
->e_uuid
,
5354 stat
.cfs_e_pid
= so
->last_pid
;
5355 memcpy(stat
.cfs_e_uuid
, so
->last_uuid
,
5359 stat
.cfs_sock_family
= so
->so_proto
->pr_domain
->dom_family
;
5360 stat
.cfs_sock_type
= so
->so_proto
->pr_type
;
5361 stat
.cfs_sock_protocol
= so
->so_proto
->pr_protocol
;
5364 stat
.cfs_snd
.cbs_pending_first
=
5365 cfi
->cfi_snd
.cfi_pending_first
;
5366 stat
.cfs_snd
.cbs_pending_last
=
5367 cfi
->cfi_snd
.cfi_pending_last
;
5368 stat
.cfs_snd
.cbs_inject_q_len
=
5369 cfil_queue_len(&cfi
->cfi_snd
.cfi_inject_q
);
5370 stat
.cfs_snd
.cbs_pass_offset
=
5371 cfi
->cfi_snd
.cfi_pass_offset
;
5373 stat
.cfs_rcv
.cbs_pending_first
=
5374 cfi
->cfi_rcv
.cfi_pending_first
;
5375 stat
.cfs_rcv
.cbs_pending_last
=
5376 cfi
->cfi_rcv
.cfi_pending_last
;
5377 stat
.cfs_rcv
.cbs_inject_q_len
=
5378 cfil_queue_len(&cfi
->cfi_rcv
.cfi_inject_q
);
5379 stat
.cfs_rcv
.cbs_pass_offset
=
5380 cfi
->cfi_rcv
.cfi_pass_offset
;
5382 for (i
= 0; i
< MAX_CONTENT_FILTER
; i
++) {
5383 struct cfil_entry_stat
*estat
;
5384 struct cfe_buf
*ebuf
;
5385 struct cfe_buf_stat
*sbuf
;
5387 entry
= &cfi
->cfi_entries
[i
];
5389 estat
= &stat
.ces_entries
[i
];
5391 estat
->ces_len
= sizeof(struct cfil_entry_stat
);
5392 estat
->ces_filter_id
= entry
->cfe_filter
?
5393 entry
->cfe_filter
->cf_kcunit
: 0;
5394 estat
->ces_flags
= entry
->cfe_flags
;
5395 estat
->ces_necp_control_unit
=
5396 entry
->cfe_necp_control_unit
;
5398 estat
->ces_last_event
.tv_sec
=
5399 (int64_t)entry
->cfe_last_event
.tv_sec
;
5400 estat
->ces_last_event
.tv_usec
=
5401 (int64_t)entry
->cfe_last_event
.tv_usec
;
5403 estat
->ces_last_action
.tv_sec
=
5404 (int64_t)entry
->cfe_last_action
.tv_sec
;
5405 estat
->ces_last_action
.tv_usec
=
5406 (int64_t)entry
->cfe_last_action
.tv_usec
;
5408 ebuf
= &entry
->cfe_snd
;
5409 sbuf
= &estat
->ces_snd
;
5410 sbuf
->cbs_pending_first
=
5411 cfil_queue_offset_first(&ebuf
->cfe_pending_q
);
5412 sbuf
->cbs_pending_last
=
5413 cfil_queue_offset_last(&ebuf
->cfe_pending_q
);
5414 sbuf
->cbs_ctl_first
=
5415 cfil_queue_offset_first(&ebuf
->cfe_ctl_q
);
5416 sbuf
->cbs_ctl_last
=
5417 cfil_queue_offset_last(&ebuf
->cfe_ctl_q
);
5418 sbuf
->cbs_pass_offset
= ebuf
->cfe_pass_offset
;
5419 sbuf
->cbs_peek_offset
= ebuf
->cfe_peek_offset
;
5420 sbuf
->cbs_peeked
= ebuf
->cfe_peeked
;
5422 ebuf
= &entry
->cfe_rcv
;
5423 sbuf
= &estat
->ces_rcv
;
5424 sbuf
->cbs_pending_first
=
5425 cfil_queue_offset_first(&ebuf
->cfe_pending_q
);
5426 sbuf
->cbs_pending_last
=
5427 cfil_queue_offset_last(&ebuf
->cfe_pending_q
);
5428 sbuf
->cbs_ctl_first
=
5429 cfil_queue_offset_first(&ebuf
->cfe_ctl_q
);
5430 sbuf
->cbs_ctl_last
=
5431 cfil_queue_offset_last(&ebuf
->cfe_ctl_q
);
5432 sbuf
->cbs_pass_offset
= ebuf
->cfe_pass_offset
;
5433 sbuf
->cbs_peek_offset
= ebuf
->cfe_peek_offset
;
5434 sbuf
->cbs_peeked
= ebuf
->cfe_peeked
;
5436 error
= SYSCTL_OUT(req
, &stat
,
5437 sizeof(struct cfil_sock_stat
));
5443 cfil_rw_unlock_shared(&cfil_lck_rw
);
5446 if (req
->oldptr
!= USER_ADDR_NULL
) {
5455 * UDP Socket Support
5458 cfil_hash_entry_log(int level
, struct socket
*so
, struct cfil_hash_entry
*entry
, uint64_t sockId
, const char* msg
)
5460 char local
[MAX_IPv6_STR_LEN
+ 6];
5461 char remote
[MAX_IPv6_STR_LEN
+ 6];
5464 // No sock or not UDP, no-op
5465 if (so
== NULL
|| entry
== NULL
) {
5469 local
[0] = remote
[0] = 0x0;
5471 switch (entry
->cfentry_family
) {
5473 addr
= &entry
->cfentry_laddr
.addr6
;
5474 inet_ntop(AF_INET6
, addr
, local
, sizeof(local
));
5475 addr
= &entry
->cfentry_faddr
.addr6
;
5476 inet_ntop(AF_INET6
, addr
, remote
, sizeof(local
));
5479 addr
= &entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
;
5480 inet_ntop(AF_INET
, addr
, local
, sizeof(local
));
5481 addr
= &entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
;
5482 inet_ntop(AF_INET
, addr
, remote
, sizeof(local
));
5488 CFIL_LOG(level
, "<%s>: <UDP so %llx, entry %p, sockID %llu> lport %d fport %d laddr %s faddr %s",
5490 (uint64_t)VM_KERNEL_ADDRPERM(so
), entry
, sockId
,
5491 ntohs(entry
->cfentry_lport
), ntohs(entry
->cfentry_fport
), local
, remote
);
5495 cfil_inp_log(int level
, struct socket
*so
, const char* msg
)
5497 struct inpcb
*inp
= NULL
;
5498 char local
[MAX_IPv6_STR_LEN
+ 6];
5499 char remote
[MAX_IPv6_STR_LEN
+ 6];
5506 inp
= sotoinpcb(so
);
5511 local
[0] = remote
[0] = 0x0;
5514 if (inp
->inp_vflag
& INP_IPV6
) {
5515 addr
= &inp
->in6p_laddr
.s6_addr32
;
5516 inet_ntop(AF_INET6
, addr
, local
, sizeof(local
));
5517 addr
= &inp
->in6p_faddr
.s6_addr32
;
5518 inet_ntop(AF_INET6
, addr
, remote
, sizeof(local
));
5522 addr
= &inp
->inp_laddr
.s_addr
;
5523 inet_ntop(AF_INET
, addr
, local
, sizeof(local
));
5524 addr
= &inp
->inp_faddr
.s_addr
;
5525 inet_ntop(AF_INET
, addr
, remote
, sizeof(local
));
5528 if (so
->so_cfil
!= NULL
) {
5529 CFIL_LOG(level
, "<%s>: <%s so %llx - flags 0x%x 0x%x, sockID %llu> lport %d fport %d laddr %s faddr %s",
5530 msg
, IS_UDP(so
) ? "UDP" : "TCP",
5531 (uint64_t)VM_KERNEL_ADDRPERM(so
), inp
->inp_flags
, inp
->inp_socket
->so_flags
, so
->so_cfil
->cfi_sock_id
,
5532 ntohs(inp
->inp_lport
), ntohs(inp
->inp_fport
), local
, remote
);
5534 CFIL_LOG(level
, "<%s>: <%s so %llx - flags 0x%x 0x%x> lport %d fport %d laddr %s faddr %s",
5535 msg
, IS_UDP(so
) ? "UDP" : "TCP",
5536 (uint64_t)VM_KERNEL_ADDRPERM(so
), inp
->inp_flags
, inp
->inp_socket
->so_flags
,
5537 ntohs(inp
->inp_lport
), ntohs(inp
->inp_fport
), local
, remote
);
5542 cfil_info_log(int level
, struct cfil_info
*cfil_info
, const char* msg
)
5544 if (cfil_info
== NULL
) {
5548 if (cfil_info
->cfi_hash_entry
!= NULL
) {
5549 cfil_hash_entry_log(level
, cfil_info
->cfi_so
, cfil_info
->cfi_hash_entry
, cfil_info
->cfi_sock_id
, msg
);
5551 cfil_inp_log(level
, cfil_info
->cfi_so
, msg
);
5556 cfil_db_init(struct socket
*so
)
5559 struct cfil_db
*db
= NULL
;
5561 CFIL_LOG(LOG_INFO
, "");
5563 db
= zalloc(cfil_db_zone
);
5568 bzero(db
, sizeof(struct cfil_db
));
5570 db
->cfdb_hashbase
= hashinit(CFILHASHSIZE
, M_CFIL
, &db
->cfdb_hashmask
);
5571 if (db
->cfdb_hashbase
== NULL
) {
5572 zfree(cfil_db_zone
, db
);
5578 so
->so_cfil_db
= db
;
5585 cfil_db_free(struct socket
*so
)
5587 struct cfil_hash_entry
*entry
= NULL
;
5588 struct cfil_hash_entry
*temp_entry
= NULL
;
5589 struct cfilhashhead
*cfilhash
= NULL
;
5590 struct cfil_db
*db
= NULL
;
5592 CFIL_LOG(LOG_INFO
, "");
5594 if (so
== NULL
|| so
->so_cfil_db
== NULL
) {
5597 db
= so
->so_cfil_db
;
5600 CFIL_LOG(LOG_ERR
, "CFIL: LIFECYCLE: <so %llx, db %p> freeing db (count == %d)",
5601 (uint64_t)VM_KERNEL_ADDRPERM(so
), db
, db
->cfdb_count
);
5604 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
5605 cfilhash
= &db
->cfdb_hashbase
[i
];
5606 LIST_FOREACH_SAFE(entry
, cfilhash
, cfentry_link
, temp_entry
) {
5607 if (entry
->cfentry_cfil
!= NULL
) {
5609 cfil_info_log(LOG_ERR
, entry
->cfentry_cfil
, "CFIL: LIFECYCLE: DB FREE CLEAN UP");
5611 cfil_info_free(entry
->cfentry_cfil
);
5612 OSIncrementAtomic(&cfil_stats
.cfs_sock_detached
);
5613 entry
->cfentry_cfil
= NULL
;
5616 cfil_db_delete_entry(db
, entry
);
5617 if (so
->so_flags
& SOF_CONTENT_FILTER
) {
5618 if (db
->cfdb_count
== 0) {
5619 so
->so_flags
&= ~SOF_CONTENT_FILTER
;
5621 VERIFY(so
->so_usecount
> 0);
5627 // Make sure all entries are cleaned up!
5628 VERIFY(db
->cfdb_count
== 0);
5630 CFIL_LOG(LOG_ERR
, "CFIL: LIFECYCLE: so usecount %d", so
->so_usecount
);
5633 FREE(db
->cfdb_hashbase
, M_CFIL
);
5634 zfree(cfil_db_zone
, db
);
5635 so
->so_cfil_db
= NULL
;
5639 fill_cfil_hash_entry_from_address(struct cfil_hash_entry
*entry
, bool isLocal
, struct sockaddr
*addr
)
5641 struct sockaddr_in
*sin
= NULL
;
5642 struct sockaddr_in6
*sin6
= NULL
;
5644 if (entry
== NULL
|| addr
== NULL
) {
5648 switch (addr
->sa_family
) {
5650 sin
= satosin(addr
);
5651 if (sin
->sin_len
!= sizeof(*sin
)) {
5654 if (isLocal
== TRUE
) {
5655 entry
->cfentry_lport
= sin
->sin_port
;
5656 entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
= sin
->sin_addr
.s_addr
;
5658 entry
->cfentry_fport
= sin
->sin_port
;
5659 entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
= sin
->sin_addr
.s_addr
;
5661 entry
->cfentry_family
= AF_INET
;
5664 sin6
= satosin6(addr
);
5665 if (sin6
->sin6_len
!= sizeof(*sin6
)) {
5668 if (isLocal
== TRUE
) {
5669 entry
->cfentry_lport
= sin6
->sin6_port
;
5670 entry
->cfentry_laddr
.addr6
= sin6
->sin6_addr
;
5672 entry
->cfentry_fport
= sin6
->sin6_port
;
5673 entry
->cfentry_faddr
.addr6
= sin6
->sin6_addr
;
5675 entry
->cfentry_family
= AF_INET6
;
5683 fill_cfil_hash_entry_from_inp(struct cfil_hash_entry
*entry
, bool isLocal
, struct inpcb
*inp
)
5685 if (entry
== NULL
|| inp
== NULL
) {
5689 if (inp
->inp_vflag
& INP_IPV4
) {
5690 if (isLocal
== TRUE
) {
5691 entry
->cfentry_lport
= inp
->inp_lport
;
5692 entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
= inp
->inp_laddr
.s_addr
;
5694 entry
->cfentry_fport
= inp
->inp_fport
;
5695 entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
= inp
->inp_faddr
.s_addr
;
5697 entry
->cfentry_family
= AF_INET
;
5699 } else if (inp
->inp_vflag
& INP_IPV6
) {
5700 if (isLocal
== TRUE
) {
5701 entry
->cfentry_lport
= inp
->inp_lport
;
5702 entry
->cfentry_laddr
.addr6
= inp
->in6p_laddr
;
5704 entry
->cfentry_fport
= inp
->inp_fport
;
5705 entry
->cfentry_faddr
.addr6
= inp
->in6p_faddr
;
5707 entry
->cfentry_family
= AF_INET6
;
5714 check_port(struct sockaddr
*addr
, u_short port
)
5716 struct sockaddr_in
*sin
= NULL
;
5717 struct sockaddr_in6
*sin6
= NULL
;
5719 if (addr
== NULL
|| port
== 0) {
5723 switch (addr
->sa_family
) {
5725 sin
= satosin(addr
);
5726 if (sin
->sin_len
!= sizeof(*sin
)) {
5729 if (port
== ntohs(sin
->sin_port
)) {
5734 sin6
= satosin6(addr
);
5735 if (sin6
->sin6_len
!= sizeof(*sin6
)) {
5738 if (port
== ntohs(sin6
->sin6_port
)) {
5748 struct cfil_hash_entry
*
5749 cfil_db_lookup_entry_with_sockid(struct cfil_db
*db
, u_int64_t sock_id
)
5751 struct cfilhashhead
*cfilhash
= NULL
;
5752 u_int32_t flowhash
= (u_int32_t
)(sock_id
& 0x0ffffffff);
5753 struct cfil_hash_entry
*nextentry
;
5755 if (db
== NULL
|| db
->cfdb_hashbase
== NULL
|| sock_id
== 0) {
5759 flowhash
&= db
->cfdb_hashmask
;
5760 cfilhash
= &db
->cfdb_hashbase
[flowhash
];
5762 LIST_FOREACH(nextentry
, cfilhash
, cfentry_link
) {
5763 if (nextentry
->cfentry_cfil
!= NULL
&&
5764 nextentry
->cfentry_cfil
->cfi_sock_id
== sock_id
) {
5765 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> matched <id %llu, hash %u>",
5766 (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
), nextentry
->cfentry_cfil
->cfi_sock_id
, flowhash
);
5767 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, nextentry
, 0, "CFIL: UDP found entry");
5772 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> NOT matched <id %llu, hash %u>",
5773 (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
), sock_id
, flowhash
);
5777 struct cfil_hash_entry
*
5778 cfil_db_lookup_entry(struct cfil_db
*db
, struct sockaddr
*local
, struct sockaddr
*remote
)
5780 struct cfil_hash_entry matchentry
;
5781 struct cfil_hash_entry
*nextentry
= NULL
;
5782 struct inpcb
*inp
= sotoinpcb(db
->cfdb_so
);
5783 u_int32_t hashkey_faddr
= 0, hashkey_laddr
= 0;
5784 int inp_hash_element
= 0;
5785 struct cfilhashhead
*cfilhash
= NULL
;
5787 CFIL_LOG(LOG_INFO
, "");
5793 if (local
!= NULL
) {
5794 fill_cfil_hash_entry_from_address(&matchentry
, TRUE
, local
);
5796 fill_cfil_hash_entry_from_inp(&matchentry
, TRUE
, inp
);
5798 if (remote
!= NULL
) {
5799 fill_cfil_hash_entry_from_address(&matchentry
, FALSE
, remote
);
5801 fill_cfil_hash_entry_from_inp(&matchentry
, FALSE
, inp
);
5805 if (inp
->inp_vflag
& INP_IPV6
) {
5806 hashkey_faddr
= matchentry
.cfentry_faddr
.addr6
.s6_addr32
[3];
5807 hashkey_laddr
= matchentry
.cfentry_laddr
.addr6
.s6_addr32
[3];
5811 hashkey_faddr
= matchentry
.cfentry_faddr
.addr46
.ia46_addr4
.s_addr
;
5812 hashkey_laddr
= matchentry
.cfentry_laddr
.addr46
.ia46_addr4
.s_addr
;
5815 inp_hash_element
= CFIL_HASH(hashkey_laddr
, hashkey_faddr
,
5816 matchentry
.cfentry_lport
, matchentry
.cfentry_fport
);
5817 inp_hash_element
&= db
->cfdb_hashmask
;
5819 cfilhash
= &db
->cfdb_hashbase
[inp_hash_element
];
5821 LIST_FOREACH(nextentry
, cfilhash
, cfentry_link
) {
5823 if ((inp
->inp_vflag
& INP_IPV6
) &&
5824 nextentry
->cfentry_lport
== matchentry
.cfentry_lport
&&
5825 nextentry
->cfentry_fport
== matchentry
.cfentry_fport
&&
5826 IN6_ARE_ADDR_EQUAL(&nextentry
->cfentry_laddr
.addr6
, &matchentry
.cfentry_laddr
.addr6
) &&
5827 IN6_ARE_ADDR_EQUAL(&nextentry
->cfentry_faddr
.addr6
, &matchentry
.cfentry_faddr
.addr6
)) {
5829 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, &matchentry
, 0, "CFIL LOOKUP ENTRY: UDP V6 found entry");
5834 if (nextentry
->cfentry_lport
== matchentry
.cfentry_lport
&&
5835 nextentry
->cfentry_fport
== matchentry
.cfentry_fport
&&
5836 nextentry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
== matchentry
.cfentry_laddr
.addr46
.ia46_addr4
.s_addr
&&
5837 nextentry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
== matchentry
.cfentry_faddr
.addr46
.ia46_addr4
.s_addr
) {
5839 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, &matchentry
, 0, "CFIL LOOKUP ENTRY: UDP V4 found entry");
5847 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, &matchentry
, 0, "CFIL LOOKUP ENTRY: UDP no entry found");
5853 cfil_db_delete_entry(struct cfil_db
*db
, struct cfil_hash_entry
*hash_entry
)
5855 if (hash_entry
== NULL
) {
5858 if (db
== NULL
|| db
->cfdb_count
== 0) {
5862 if (db
->cfdb_only_entry
== hash_entry
) {
5863 db
->cfdb_only_entry
= NULL
;
5865 LIST_REMOVE(hash_entry
, cfentry_link
);
5866 zfree(cfil_hash_entry_zone
, hash_entry
);
5869 struct cfil_hash_entry
*
5870 cfil_db_add_entry(struct cfil_db
*db
, struct sockaddr
*local
, struct sockaddr
*remote
)
5872 struct cfil_hash_entry
*entry
= NULL
;
5873 struct inpcb
*inp
= sotoinpcb(db
->cfdb_so
);
5874 u_int32_t hashkey_faddr
= 0, hashkey_laddr
= 0;
5875 int inp_hash_element
= 0;
5876 struct cfilhashhead
*cfilhash
= NULL
;
5878 CFIL_LOG(LOG_INFO
, "");
5884 entry
= zalloc(cfil_hash_entry_zone
);
5885 if (entry
== NULL
) {
5888 bzero(entry
, sizeof(struct cfil_hash_entry
));
5890 if (local
!= NULL
) {
5891 fill_cfil_hash_entry_from_address(entry
, TRUE
, local
);
5893 fill_cfil_hash_entry_from_inp(entry
, TRUE
, inp
);
5895 if (remote
!= NULL
) {
5896 fill_cfil_hash_entry_from_address(entry
, FALSE
, remote
);
5898 fill_cfil_hash_entry_from_inp(entry
, FALSE
, inp
);
5900 entry
->cfentry_lastused
= net_uptime();
5903 if (inp
->inp_vflag
& INP_IPV6
) {
5904 hashkey_faddr
= entry
->cfentry_faddr
.addr6
.s6_addr32
[3];
5905 hashkey_laddr
= entry
->cfentry_laddr
.addr6
.s6_addr32
[3];
5909 hashkey_faddr
= entry
->cfentry_faddr
.addr46
.ia46_addr4
.s_addr
;
5910 hashkey_laddr
= entry
->cfentry_laddr
.addr46
.ia46_addr4
.s_addr
;
5912 entry
->cfentry_flowhash
= CFIL_HASH(hashkey_laddr
, hashkey_faddr
,
5913 entry
->cfentry_lport
, entry
->cfentry_fport
);
5914 inp_hash_element
= entry
->cfentry_flowhash
& db
->cfdb_hashmask
;
5916 cfilhash
= &db
->cfdb_hashbase
[inp_hash_element
];
5918 LIST_INSERT_HEAD(cfilhash
, entry
, cfentry_link
);
5920 db
->cfdb_only_entry
= entry
;
5921 cfil_hash_entry_log(LOG_DEBUG
, db
->cfdb_so
, entry
, 0, "CFIL: cfil_db_add_entry: ADDED");
5924 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> total count %d", (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
), db
->cfdb_count
);
5929 cfil_db_get_cfil_info(struct cfil_db
*db
, cfil_sock_id_t id
)
5931 struct cfil_hash_entry
*hash_entry
= NULL
;
5933 CFIL_LOG(LOG_INFO
, "");
5935 if (db
== NULL
|| id
== 0) {
5936 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> NULL DB <id %llu>",
5937 db
? (uint64_t)VM_KERNEL_ADDRPERM(db
->cfdb_so
) : 0, id
);
5941 // This is an optimization for connected UDP socket which only has one flow.
5942 // No need to do the hash lookup.
5943 if (db
->cfdb_count
== 1) {
5944 if (db
->cfdb_only_entry
&& db
->cfdb_only_entry
->cfentry_cfil
&&
5945 db
->cfdb_only_entry
->cfentry_cfil
->cfi_sock_id
== id
) {
5946 return db
->cfdb_only_entry
->cfentry_cfil
;
5950 hash_entry
= cfil_db_lookup_entry_with_sockid(db
, id
);
5951 return hash_entry
!= NULL
? hash_entry
->cfentry_cfil
: NULL
;
5954 struct cfil_hash_entry
*
5955 cfil_sock_udp_get_flow(struct socket
*so
, uint32_t filter_control_unit
, bool outgoing
, struct sockaddr
*local
, struct sockaddr
*remote
)
5957 struct cfil_hash_entry
*hash_entry
= NULL
;
5960 socket_lock_assert_owned(so
);
5962 // If new socket, allocate cfil db
5963 if (so
->so_cfil_db
== NULL
) {
5964 if (cfil_db_init(so
) != 0) {
5969 // See if flow already exists.
5970 hash_entry
= cfil_db_lookup_entry(so
->so_cfil_db
, local
, remote
);
5971 if (hash_entry
!= NULL
) {
5975 hash_entry
= cfil_db_add_entry(so
->so_cfil_db
, local
, remote
);
5976 if (hash_entry
== NULL
) {
5977 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_no_mem
);
5978 CFIL_LOG(LOG_ERR
, "CFIL: UDP failed to add entry");
5982 if (cfil_info_alloc(so
, hash_entry
) == NULL
||
5983 hash_entry
->cfentry_cfil
== NULL
) {
5984 cfil_db_delete_entry(so
->so_cfil_db
, hash_entry
);
5985 CFIL_LOG(LOG_ERR
, "CFIL: UDP failed to alloc cfil_info");
5986 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_no_mem
);
5989 hash_entry
->cfentry_cfil
->cfi_dir
= outgoing
? CFS_CONNECTION_DIR_OUT
: CFS_CONNECTION_DIR_IN
;
5992 cfil_info_log(LOG_ERR
, hash_entry
->cfentry_cfil
, "CFIL: LIFECYCLE: ADDED");
5995 if (cfil_info_attach_unit(so
, filter_control_unit
, hash_entry
->cfentry_cfil
) == 0) {
5996 cfil_info_free(hash_entry
->cfentry_cfil
);
5997 cfil_db_delete_entry(so
->so_cfil_db
, hash_entry
);
5998 CFIL_LOG(LOG_ERR
, "CFIL: UDP cfil_info_attach_unit(%u) failed",
5999 filter_control_unit
);
6000 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_failed
);
6003 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP <so %llx> filter_control_unit %u sockID %llu attached",
6004 (uint64_t)VM_KERNEL_ADDRPERM(so
),
6005 filter_control_unit
, hash_entry
->cfentry_cfil
->cfi_sock_id
);
6007 so
->so_flags
|= SOF_CONTENT_FILTER
;
6008 OSIncrementAtomic(&cfil_stats
.cfs_sock_attached
);
6010 /* Hold a reference on the socket for each flow */
6013 error
= cfil_dispatch_attach_event(so
, hash_entry
->cfentry_cfil
, 0,
6014 outgoing
? CFS_CONNECTION_DIR_OUT
: CFS_CONNECTION_DIR_IN
);
6015 /* We can recover from flow control or out of memory errors */
6016 if (error
!= 0 && error
!= ENOBUFS
&& error
!= ENOMEM
) {
6020 CFIL_INFO_VERIFY(hash_entry
->cfentry_cfil
);
6025 cfil_sock_udp_handle_data(bool outgoing
, struct socket
*so
,
6026 struct sockaddr
*local
, struct sockaddr
*remote
,
6027 struct mbuf
*data
, struct mbuf
*control
, uint32_t flags
)
6029 #pragma unused(outgoing, so, local, remote, data, control, flags)
6031 uint32_t filter_control_unit
;
6032 struct cfil_hash_entry
*hash_entry
= NULL
;
6033 struct cfil_info
*cfil_info
= NULL
;
6035 socket_lock_assert_owned(so
);
6037 if (cfil_active_count
== 0) {
6038 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP no active filter");
6039 OSIncrementAtomic(&cfil_stats
.cfs_sock_attach_in_vain
);
6043 // Socket has been blessed
6044 if ((so
->so_flags1
& SOF1_CONTENT_FILTER_SKIP
) != 0) {
6048 filter_control_unit
= necp_socket_get_content_filter_control_unit(so
);
6049 if (filter_control_unit
== 0) {
6050 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP failed to get control unit");
6054 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
6058 if ((filter_control_unit
& NECP_MASK_USERSPACE_ONLY
) != 0) {
6059 CFIL_LOG(LOG_DEBUG
, "CFIL: UDP user space only");
6060 OSIncrementAtomic(&cfil_stats
.cfs_sock_userspace_only
);
6064 hash_entry
= cfil_sock_udp_get_flow(so
, filter_control_unit
, outgoing
, local
, remote
);
6065 if (hash_entry
== NULL
|| hash_entry
->cfentry_cfil
== NULL
) {
6066 CFIL_LOG(LOG_ERR
, "CFIL: Falied to create UDP flow");
6069 // Update last used timestamp, this is for flow Idle TO
6070 hash_entry
->cfentry_lastused
= net_uptime();
6071 cfil_info
= hash_entry
->cfentry_cfil
;
6073 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
6075 cfil_hash_entry_log(LOG_DEBUG
, so
, hash_entry
, 0, "CFIL: UDP DROP");
6079 if (control
!= NULL
) {
6080 OSIncrementAtomic(&cfil_stats
.cfs_data_in_control
);
6082 if (data
->m_type
== MT_OOBDATA
) {
6083 CFIL_LOG(LOG_ERR
, "so %llx MSG_OOB",
6084 (uint64_t)VM_KERNEL_ADDRPERM(so
));
6085 OSIncrementAtomic(&cfil_stats
.cfs_data_in_oob
);
6088 error
= cfil_data_common(so
, cfil_info
, outgoing
, remote
, data
, control
, flags
);
6094 * Go through all UDP flows for specified socket and returns TRUE if
6095 * any flow is still attached. If need_wait is TRUE, wait on first
6099 cfil_filters_udp_attached(struct socket
*so
, bool need_wait
)
6102 lck_mtx_t
*mutex_held
;
6103 struct cfilhashhead
*cfilhash
= NULL
;
6104 struct cfil_db
*db
= NULL
;
6105 struct cfil_hash_entry
*hash_entry
= NULL
;
6106 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6107 struct cfil_info
*cfil_info
= NULL
;
6108 struct cfil_entry
*entry
= NULL
;
6112 uint64_t sock_flow_id
= 0;
6114 socket_lock_assert_owned(so
);
6116 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6117 if (so
->so_proto
->pr_getlock
!= NULL
) {
6118 mutex_held
= (*so
->so_proto
->pr_getlock
)(so
, PR_F_WILLUNLOCK
);
6120 mutex_held
= so
->so_proto
->pr_domain
->dom_mtx
;
6122 LCK_MTX_ASSERT(mutex_held
, LCK_MTX_ASSERT_OWNED
);
6124 db
= so
->so_cfil_db
;
6126 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6127 cfilhash
= &db
->cfdb_hashbase
[i
];
6129 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6130 if (hash_entry
->cfentry_cfil
!= NULL
) {
6131 cfil_info
= hash_entry
->cfentry_cfil
;
6132 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6133 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
6135 /* Are we attached to the filter? */
6136 if (entry
->cfe_filter
== NULL
) {
6140 if ((entry
->cfe_flags
& CFEF_SENT_SOCK_ATTACHED
) == 0) {
6143 if ((entry
->cfe_flags
& CFEF_CFIL_DETACHED
) != 0) {
6149 if (need_wait
== TRUE
) {
6151 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAIT FOR FLOW TO FINISH");
6154 ts
.tv_sec
= cfil_close_wait_timeout
/ 1000;
6155 ts
.tv_nsec
= (cfil_close_wait_timeout
% 1000) *
6156 NSEC_PER_USEC
* 1000;
6158 OSIncrementAtomic(&cfil_stats
.cfs_close_wait
);
6159 cfil_info
->cfi_flags
|= CFIF_CLOSE_WAIT
;
6160 sock_flow_id
= cfil_info
->cfi_sock_id
;
6162 error
= msleep((caddr_t
)cfil_info
, mutex_held
,
6163 PSOCK
| PCATCH
, "cfil_filters_udp_attached", &ts
);
6165 // Woke up from sleep, validate if cfil_info is still valid
6166 if (so
->so_cfil_db
== NULL
||
6167 (cfil_info
!= cfil_db_get_cfil_info(so
->so_cfil_db
, sock_flow_id
))) {
6168 // cfil_info is not valid, do not continue
6172 cfil_info
->cfi_flags
&= ~CFIF_CLOSE_WAIT
;
6175 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAIT FOR FLOW DONE");
6179 * Force close in case of timeout
6182 OSIncrementAtomic(&cfil_stats
.cfs_close_wait_timeout
);
6184 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: WAIT FOR FLOW TIMED OUT, FORCE DETACH");
6186 entry
->cfe_flags
|= CFEF_CFIL_DETACHED
;
6201 cfil_sock_udp_data_pending(struct sockbuf
*sb
, bool check_thread
)
6203 struct socket
*so
= sb
->sb_so
;
6204 struct cfi_buf
*cfi_buf
;
6205 uint64_t pending
= 0;
6206 uint64_t total_pending
= 0;
6207 struct cfilhashhead
*cfilhash
= NULL
;
6208 struct cfil_db
*db
= NULL
;
6209 struct cfil_hash_entry
*hash_entry
= NULL
;
6210 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6212 socket_lock_assert_owned(so
);
6214 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
&&
6215 (check_thread
== FALSE
|| so
->so_snd
.sb_cfil_thread
!= current_thread())) {
6216 db
= so
->so_cfil_db
;
6218 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6219 cfilhash
= &db
->cfdb_hashbase
[i
];
6221 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6222 if (hash_entry
->cfentry_cfil
!= NULL
) {
6223 if ((sb
->sb_flags
& SB_RECV
) == 0) {
6224 cfi_buf
= &hash_entry
->cfentry_cfil
->cfi_snd
;
6226 cfi_buf
= &hash_entry
->cfentry_cfil
->cfi_rcv
;
6229 pending
= cfi_buf
->cfi_pending_last
- cfi_buf
->cfi_pending_first
;
6231 * If we are limited by the "chars of mbufs used" roughly
6232 * adjust so we won't overcommit
6234 if ((uint64_t)cfi_buf
->cfi_pending_mbcnt
> pending
) {
6235 pending
= cfi_buf
->cfi_pending_mbcnt
;
6238 total_pending
+= pending
;
6243 VERIFY(total_pending
< INT32_MAX
);
6245 CFIL_LOG(LOG_DEBUG
, "CFIL: <so %llx> total pending %llu <check_thread %d>",
6246 (uint64_t)VM_KERNEL_ADDRPERM(so
),
6247 total_pending
, check_thread
);
6251 return (int32_t)(total_pending
);
6255 cfil_sock_udp_notify_shutdown(struct socket
*so
, int how
, int drop_flag
, int shut_flag
)
6257 struct cfil_info
*cfil_info
= NULL
;
6258 struct cfilhashhead
*cfilhash
= NULL
;
6259 struct cfil_db
*db
= NULL
;
6260 struct cfil_hash_entry
*hash_entry
= NULL
;
6261 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6266 socket_lock_assert_owned(so
);
6268 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6269 db
= so
->so_cfil_db
;
6271 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6272 cfilhash
= &db
->cfdb_hashbase
[i
];
6274 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6275 if (hash_entry
->cfentry_cfil
!= NULL
) {
6276 cfil_info
= hash_entry
->cfentry_cfil
;
6278 // This flow is marked as DROP
6279 if (cfil_info
->cfi_flags
& drop_flag
) {
6284 // This flow has been shut already, skip
6285 if (cfil_info
->cfi_flags
& shut_flag
) {
6288 // Mark flow as shut
6289 cfil_info
->cfi_flags
|= shut_flag
;
6292 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6293 /* Disconnect incoming side */
6294 if (how
!= SHUT_WR
) {
6295 error
= cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 0);
6297 /* Disconnect outgoing side */
6298 if (how
!= SHUT_RD
) {
6299 error
= cfil_dispatch_disconnect_event(so
, cfil_info
, kcunit
, 1);
6307 if (done_count
== 0) {
6314 cfil_sock_udp_shutdown(struct socket
*so
, int *how
)
6318 if ((so
->so_flags
& SOF_CONTENT_FILTER
) == 0 || (so
->so_cfil_db
== NULL
)) {
6322 socket_lock_assert_owned(so
);
6324 CFIL_LOG(LOG_INFO
, "so %llx how %d",
6325 (uint64_t)VM_KERNEL_ADDRPERM(so
), *how
);
6328 * Check the state of the socket before the content filter
6330 if (*how
!= SHUT_WR
&& (so
->so_state
& SS_CANTRCVMORE
) != 0) {
6331 /* read already shut down */
6335 if (*how
!= SHUT_RD
&& (so
->so_state
& SS_CANTSENDMORE
) != 0) {
6336 /* write already shut down */
6342 * shutdown read: SHUT_RD or SHUT_RDWR
6344 if (*how
!= SHUT_WR
) {
6345 error
= cfil_sock_udp_notify_shutdown(so
, SHUT_RD
, CFIF_DROP
, CFIF_SHUT_RD
);
6351 * shutdown write: SHUT_WR or SHUT_RDWR
6353 if (*how
!= SHUT_RD
) {
6354 error
= cfil_sock_udp_notify_shutdown(so
, SHUT_WR
, CFIF_DROP
, CFIF_SHUT_WR
);
6360 * When outgoing data is pending, we delay the shutdown at the
6361 * protocol level until the content filters give the final
6362 * verdict on the pending data.
6364 if (cfil_sock_data_pending(&so
->so_snd
) != 0) {
6366 * When shutting down the read and write sides at once
6367 * we can proceed to the final shutdown of the read
6368 * side. Otherwise, we just return.
6370 if (*how
== SHUT_WR
) {
6371 error
= EJUSTRETURN
;
6372 } else if (*how
== SHUT_RDWR
) {
6382 cfil_sock_udp_close_wait(struct socket
*so
)
6384 socket_lock_assert_owned(so
);
6386 while (cfil_filters_udp_attached(so
, FALSE
)) {
6388 * Notify the filters we are going away so they can detach
6390 cfil_sock_udp_notify_shutdown(so
, SHUT_RDWR
, 0, 0);
6393 * Make sure we need to wait after the filter are notified
6394 * of the disconnection
6396 if (cfil_filters_udp_attached(so
, TRUE
) == 0) {
6403 cfil_sock_udp_is_closed(struct socket
*so
)
6405 struct cfil_info
*cfil_info
= NULL
;
6406 struct cfilhashhead
*cfilhash
= NULL
;
6407 struct cfil_db
*db
= NULL
;
6408 struct cfil_hash_entry
*hash_entry
= NULL
;
6409 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6413 socket_lock_assert_owned(so
);
6415 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6416 db
= so
->so_cfil_db
;
6418 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6419 cfilhash
= &db
->cfdb_hashbase
[i
];
6421 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6422 if (hash_entry
->cfentry_cfil
!= NULL
) {
6423 cfil_info
= hash_entry
->cfentry_cfil
;
6425 for (kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6426 /* Let the filters know of the closing */
6427 error
= cfil_dispatch_closed_event(so
, cfil_info
, kcunit
);
6430 /* Last chance to push passed data out */
6431 error
= cfil_acquire_sockbuf(so
, cfil_info
, 1);
6433 cfil_service_inject_queue(so
, cfil_info
, 1);
6435 cfil_release_sockbuf(so
, 1);
6437 cfil_info
->cfi_flags
|= CFIF_SOCK_CLOSED
;
6439 /* Pending data needs to go */
6440 cfil_flush_queues(so
, cfil_info
);
6442 CFIL_INFO_VERIFY(cfil_info
);
6450 cfil_sock_udp_buf_update(struct sockbuf
*sb
)
6452 struct cfil_info
*cfil_info
= NULL
;
6453 struct cfilhashhead
*cfilhash
= NULL
;
6454 struct cfil_db
*db
= NULL
;
6455 struct cfil_hash_entry
*hash_entry
= NULL
;
6456 struct cfil_hash_entry
*temp_hash_entry
= NULL
;
6459 struct socket
*so
= sb
->sb_so
;
6461 socket_lock_assert_owned(so
);
6463 if ((so
->so_flags
& SOF_CONTENT_FILTER
) != 0 && so
->so_cfil_db
!= NULL
) {
6468 db
= so
->so_cfil_db
;
6470 for (int i
= 0; i
< CFILHASHSIZE
; i
++) {
6471 cfilhash
= &db
->cfdb_hashbase
[i
];
6473 LIST_FOREACH_SAFE(hash_entry
, cfilhash
, cfentry_link
, temp_hash_entry
) {
6474 if (hash_entry
->cfentry_cfil
!= NULL
) {
6475 cfil_info
= hash_entry
->cfentry_cfil
;
6477 if ((sb
->sb_flags
& SB_RECV
) == 0) {
6478 if ((cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_OUT
) == 0) {
6482 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_out_retry
);
6484 if ((cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_IN
) == 0) {
6488 OSIncrementAtomic(&cfil_stats
.cfs_inject_q_in_retry
);
6491 CFIL_LOG(LOG_NOTICE
, "so %llx outgoing %d",
6492 (uint64_t)VM_KERNEL_ADDRPERM(so
), outgoing
);
6494 error
= cfil_acquire_sockbuf(so
, cfil_info
, outgoing
);
6496 cfil_service_inject_queue(so
, cfil_info
, outgoing
);
6498 cfil_release_sockbuf(so
, outgoing
);
6506 cfil_filter_show(u_int32_t kcunit
)
6508 struct content_filter
*cfc
= NULL
;
6509 struct cfil_entry
*entry
;
6512 if (content_filters
== NULL
) {
6515 if (kcunit
> MAX_CONTENT_FILTER
) {
6519 cfil_rw_lock_shared(&cfil_lck_rw
);
6521 if (content_filters
[kcunit
- 1] == NULL
) {
6522 cfil_rw_unlock_shared(&cfil_lck_rw
);
6525 cfc
= content_filters
[kcunit
- 1];
6527 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: Filter <unit %d, entry count %d> flags <%lx>:",
6528 kcunit
, cfc
->cf_sock_count
, (unsigned long)cfc
->cf_flags
);
6529 if (cfc
->cf_flags
& CFF_DETACHING
) {
6530 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: - DETACHING");
6532 if (cfc
->cf_flags
& CFF_ACTIVE
) {
6533 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: - ACTIVE");
6535 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
6536 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: - FLOW CONTROLLED");
6539 TAILQ_FOREACH(entry
, &cfc
->cf_sock_entries
, cfe_link
) {
6540 if (entry
->cfe_cfil_info
&& entry
->cfe_cfil_info
->cfi_so
) {
6541 struct cfil_info
*cfil_info
= entry
->cfe_cfil_info
;
6545 if (entry
->cfe_flags
& CFEF_CFIL_DETACHED
) {
6546 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: FILTER SHOW: - DETACHED");
6548 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: FILTER SHOW: - ATTACHED");
6553 CFIL_LOG(LOG_ERR
, "CFIL: FILTER SHOW: Filter - total entries shown: %d", count
);
6555 cfil_rw_unlock_shared(&cfil_lck_rw
);
6559 cfil_info_show(void)
6561 struct cfil_info
*cfil_info
;
6564 cfil_rw_lock_shared(&cfil_lck_rw
);
6566 CFIL_LOG(LOG_ERR
, "CFIL: INFO SHOW: count %d", cfil_sock_attached_count
);
6568 TAILQ_FOREACH(cfil_info
, &cfil_sock_head
, cfi_link
) {
6571 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: INFO SHOW");
6573 if (cfil_info
->cfi_flags
& CFIF_DROP
) {
6574 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - DROP");
6576 if (cfil_info
->cfi_flags
& CFIF_CLOSE_WAIT
) {
6577 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - CLOSE_WAIT");
6579 if (cfil_info
->cfi_flags
& CFIF_SOCK_CLOSED
) {
6580 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - SOCK_CLOSED");
6582 if (cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_IN
) {
6583 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - RETRY_INJECT_IN");
6585 if (cfil_info
->cfi_flags
& CFIF_RETRY_INJECT_OUT
) {
6586 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - RETRY_INJECT_OUT");
6588 if (cfil_info
->cfi_flags
& CFIF_SHUT_WR
) {
6589 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - SHUT_WR");
6591 if (cfil_info
->cfi_flags
& CFIF_SHUT_RD
) {
6592 CFIL_LOG(LOG_ERR
, "CFIL: INFO FLAG - SHUT_RD");
6596 CFIL_LOG(LOG_ERR
, "CFIL: INFO SHOW: total cfil_info shown: %d", count
);
6598 cfil_rw_unlock_shared(&cfil_lck_rw
);
6602 cfil_info_idle_timed_out(struct cfil_info
*cfil_info
, int timeout
, u_int32_t current_time
)
6604 if (cfil_info
&& cfil_info
->cfi_hash_entry
&&
6605 (current_time
- cfil_info
->cfi_hash_entry
->cfentry_lastused
>= (u_int32_t
)timeout
)) {
6607 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: flow IDLE timeout expired");
6615 cfil_info_action_timed_out(struct cfil_info
*cfil_info
, int timeout
)
6617 struct cfil_entry
*entry
;
6618 struct timeval current_tv
;
6619 struct timeval diff_time
;
6621 if (cfil_info
== NULL
) {
6626 * If we have queued up more data than passed offset and we haven't received
6627 * an action from user space for a while (the user space filter might have crashed),
6628 * return action timed out.
6630 if (cfil_info
->cfi_snd
.cfi_pending_last
> cfil_info
->cfi_snd
.cfi_pass_offset
||
6631 cfil_info
->cfi_rcv
.cfi_pending_last
> cfil_info
->cfi_rcv
.cfi_pass_offset
) {
6632 microuptime(¤t_tv
);
6634 for (int kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
6635 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
6637 if (entry
->cfe_filter
== NULL
) {
6641 if (cfil_info
->cfi_snd
.cfi_pending_last
> entry
->cfe_snd
.cfe_pass_offset
||
6642 cfil_info
->cfi_rcv
.cfi_pending_last
> entry
->cfe_rcv
.cfe_pass_offset
) {
6643 // haven't gotten an action from this filter, check timeout
6644 timersub(¤t_tv
, &entry
->cfe_last_action
, &diff_time
);
6645 if (diff_time
.tv_sec
>= timeout
) {
6647 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: flow ACTION timeout expired");
6658 cfil_info_buffer_threshold_exceeded(struct cfil_info
*cfil_info
)
6660 if (cfil_info
== NULL
) {
6665 * Clean up flow if it exceeded queue thresholds
6667 if (cfil_info
->cfi_snd
.cfi_tail_drop_cnt
||
6668 cfil_info
->cfi_rcv
.cfi_tail_drop_cnt
) {
6670 CFIL_LOG(LOG_ERR
, "CFIL: queue threshold exceeded: mbuf max <count: %d bytes: %d> tail drop count <OUT: %d IN: %d>",
6671 cfil_udp_gc_mbuf_num_max
,
6672 cfil_udp_gc_mbuf_cnt_max
,
6673 cfil_info
->cfi_snd
.cfi_tail_drop_cnt
,
6674 cfil_info
->cfi_rcv
.cfi_tail_drop_cnt
);
6675 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: queue threshold exceeded");
6684 cfil_udp_gc_thread_sleep(bool forever
)
6687 (void) assert_wait((event_t
) &cfil_sock_udp_attached_count
,
6688 THREAD_INTERRUPTIBLE
);
6690 uint64_t deadline
= 0;
6691 nanoseconds_to_absolutetime(UDP_FLOW_GC_RUN_INTERVAL_NSEC
, &deadline
);
6692 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
6694 (void) assert_wait_deadline(&cfil_sock_udp_attached_count
,
6695 THREAD_INTERRUPTIBLE
, deadline
);
6700 cfil_udp_gc_thread_func(void *v
, wait_result_t w
)
6702 #pragma unused(v, w)
6704 ASSERT(cfil_udp_gc_thread
== current_thread());
6705 thread_set_thread_name(current_thread(), "CFIL_UPD_GC");
6707 // Kick off gc shortly
6708 cfil_udp_gc_thread_sleep(false);
6709 thread_block_parameter((thread_continue_t
) cfil_info_udp_expire
, NULL
);
6714 cfil_info_udp_expire(void *v
, wait_result_t w
)
6716 #pragma unused(v, w)
6718 static uint64_t expired_array
[UDP_FLOW_GC_MAX_COUNT
];
6719 static uint32_t expired_count
= 0;
6721 struct cfil_info
*cfil_info
;
6722 struct cfil_hash_entry
*hash_entry
;
6725 u_int64_t current_time
= 0;
6727 current_time
= net_uptime();
6729 // Get all expired UDP flow ids
6730 cfil_rw_lock_shared(&cfil_lck_rw
);
6732 if (cfil_sock_udp_attached_count
== 0) {
6733 cfil_rw_unlock_shared(&cfil_lck_rw
);
6737 TAILQ_FOREACH(cfil_info
, &cfil_sock_head
, cfi_link
) {
6738 if (expired_count
>= UDP_FLOW_GC_MAX_COUNT
) {
6742 if (IS_UDP(cfil_info
->cfi_so
)) {
6743 if (cfil_info_idle_timed_out(cfil_info
, UDP_FLOW_GC_IDLE_TO
, current_time
) ||
6744 cfil_info_action_timed_out(cfil_info
, UDP_FLOW_GC_ACTION_TO
) ||
6745 cfil_info_buffer_threshold_exceeded(cfil_info
)) {
6746 expired_array
[expired_count
] = cfil_info
->cfi_sock_id
;
6751 cfil_rw_unlock_shared(&cfil_lck_rw
);
6753 if (expired_count
== 0) {
6757 for (uint32_t i
= 0; i
< expired_count
; i
++) {
6758 // Search for socket (UDP only and lock so)
6759 so
= cfil_socket_from_sock_id(expired_array
[i
], true);
6764 cfil_info
= cfil_db_get_cfil_info(so
->so_cfil_db
, expired_array
[i
]);
6765 if (cfil_info
== NULL
) {
6769 db
= so
->so_cfil_db
;
6770 hash_entry
= cfil_info
->cfi_hash_entry
;
6772 if (db
== NULL
|| hash_entry
== NULL
) {
6776 #if GC_DEBUG || LIFECYCLE_DEBUG
6777 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: GC CLEAN UP");
6780 cfil_db_delete_entry(db
, hash_entry
);
6781 cfil_info_free(cfil_info
);
6782 OSIncrementAtomic(&cfil_stats
.cfs_sock_detached
);
6784 if (so
->so_flags
& SOF_CONTENT_FILTER
) {
6785 if (db
->cfdb_count
== 0) {
6786 so
->so_flags
&= ~SOF_CONTENT_FILTER
;
6788 VERIFY(so
->so_usecount
> 0);
6792 socket_unlock(so
, 1);
6796 CFIL_LOG(LOG_ERR
, "CFIL: UDP flow idle timeout check: expired %d idle flows", expired_count
);
6802 // Sleep forever (until waken up) if no more UDP flow to clean
6803 cfil_rw_lock_shared(&cfil_lck_rw
);
6804 cfil_udp_gc_thread_sleep(cfil_sock_udp_attached_count
== 0 ? true : false);
6805 cfil_rw_unlock_shared(&cfil_lck_rw
);
6806 thread_block_parameter((thread_continue_t
)cfil_info_udp_expire
, NULL
);
6811 cfil_udp_save_socket_state(struct cfil_info
*cfil_info
, struct mbuf
*m
)
6813 struct m_tag
*tag
= NULL
;
6814 struct cfil_tag
*ctag
= NULL
;
6815 struct cfil_hash_entry
*hash_entry
= NULL
;
6817 if (cfil_info
== NULL
|| cfil_info
->cfi_so
== NULL
||
6818 cfil_info
->cfi_hash_entry
== NULL
|| m
== NULL
|| !(m
->m_flags
& M_PKTHDR
)) {
6822 /* Allocate a tag */
6823 tag
= m_tag_create(KERNEL_MODULE_TAG_ID
, KERNEL_TAG_TYPE_CFIL_UDP
,
6824 sizeof(struct cfil_tag
), M_DONTWAIT
, m
);
6827 ctag
= (struct cfil_tag
*)(tag
+ 1);
6828 ctag
->cfil_so_state_change_cnt
= cfil_info
->cfi_so
->so_state_change_cnt
;
6829 ctag
->cfil_so_options
= cfil_info
->cfi_so
->so_options
;
6831 hash_entry
= cfil_info
->cfi_hash_entry
;
6832 if (hash_entry
->cfentry_family
== AF_INET6
) {
6833 fill_ip6_sockaddr_4_6(&ctag
->cfil_faddr
,
6834 &hash_entry
->cfentry_faddr
.addr6
,
6835 hash_entry
->cfentry_fport
);
6836 } else if (hash_entry
->cfentry_family
== AF_INET
) {
6837 fill_ip_sockaddr_4_6(&ctag
->cfil_faddr
,
6838 hash_entry
->cfentry_faddr
.addr46
.ia46_addr4
,
6839 hash_entry
->cfentry_fport
);
6841 m_tag_prepend(m
, tag
);
6848 cfil_udp_get_socket_state(struct mbuf
*m
, uint32_t *state_change_cnt
, short *options
,
6849 struct sockaddr
**faddr
)
6851 struct m_tag
*tag
= NULL
;
6852 struct cfil_tag
*ctag
= NULL
;
6854 tag
= m_tag_locate(m
, KERNEL_MODULE_TAG_ID
, KERNEL_TAG_TYPE_CFIL_UDP
, NULL
);
6856 ctag
= (struct cfil_tag
*)(tag
+ 1);
6857 if (state_change_cnt
) {
6858 *state_change_cnt
= ctag
->cfil_so_state_change_cnt
;
6861 *options
= ctag
->cfil_so_options
;
6864 *faddr
= (struct sockaddr
*) &ctag
->cfil_faddr
;
6868 * Unlink tag and hand it over to caller.
6869 * Note that caller will be responsible to free it.
6871 m_tag_unlink(m
, tag
);
6878 cfil_dispatch_stats_event_locked(int kcunit
, struct cfil_stats_report_buffer
*buffer
, uint32_t stats_count
)
6880 struct content_filter
*cfc
= NULL
;
6884 if (buffer
== NULL
|| stats_count
== 0) {
6888 if (content_filters
== NULL
|| kcunit
> MAX_CONTENT_FILTER
) {
6892 cfc
= content_filters
[kcunit
- 1];
6897 /* Would be wasteful to try */
6898 if (cfc
->cf_flags
& CFF_FLOW_CONTROLLED
) {
6903 msgsize
= sizeof(struct cfil_msg_stats_report
) + (sizeof(struct cfil_msg_sock_stats
) * stats_count
);
6904 buffer
->msghdr
.cfm_len
= msgsize
;
6905 buffer
->msghdr
.cfm_version
= 1;
6906 buffer
->msghdr
.cfm_type
= CFM_TYPE_EVENT
;
6907 buffer
->msghdr
.cfm_op
= CFM_OP_STATS
;
6908 buffer
->msghdr
.cfm_sock_id
= 0;
6909 buffer
->count
= stats_count
;
6912 CFIL_LOG(LOG_ERR
, "STATS (kcunit %d): msg size %lu - %lu %lu %lu",
6914 (unsigned long)msgsize
,
6915 (unsigned long)sizeof(struct cfil_msg_stats_report
),
6916 (unsigned long)sizeof(struct cfil_msg_sock_stats
),
6917 (unsigned long)stats_count
);
6920 error
= ctl_enqueuedata(cfc
->cf_kcref
, cfc
->cf_kcunit
,
6925 CFIL_LOG(LOG_ERR
, "ctl_enqueuedata() failed: %d", error
);
6928 OSIncrementAtomic(&cfil_stats
.cfs_stats_event_ok
);
6931 CFIL_LOG(LOG_ERR
, "CFIL: STATS REPORT: send msg to %d", kcunit
);
6936 if (error
== ENOBUFS
) {
6938 &cfil_stats
.cfs_stats_event_flow_control
);
6940 if (!cfil_rw_lock_shared_to_exclusive(&cfil_lck_rw
)) {
6941 cfil_rw_lock_exclusive(&cfil_lck_rw
);
6944 cfc
->cf_flags
|= CFF_FLOW_CONTROLLED
;
6946 cfil_rw_unlock_exclusive(&cfil_lck_rw
);
6947 } else if (error
!= 0) {
6948 OSIncrementAtomic(&cfil_stats
.cfs_stats_event_fail
);
6955 cfil_stats_report_thread_sleep(bool forever
)
6958 CFIL_LOG(LOG_ERR
, "CFIL: STATS COLLECTION SLEEP");
6962 (void) assert_wait((event_t
) &cfil_sock_attached_stats_count
,
6963 THREAD_INTERRUPTIBLE
);
6965 uint64_t deadline
= 0;
6966 nanoseconds_to_absolutetime(CFIL_STATS_REPORT_RUN_INTERVAL_NSEC
, &deadline
);
6967 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
6969 (void) assert_wait_deadline(&cfil_sock_attached_stats_count
,
6970 THREAD_INTERRUPTIBLE
, deadline
);
6975 cfil_stats_report_thread_func(void *v
, wait_result_t w
)
6977 #pragma unused(v, w)
6979 ASSERT(cfil_stats_report_thread
== current_thread());
6980 thread_set_thread_name(current_thread(), "CFIL_STATS_REPORT");
6982 // Kick off gc shortly
6983 cfil_stats_report_thread_sleep(false);
6984 thread_block_parameter((thread_continue_t
) cfil_stats_report
, NULL
);
6989 cfil_stats_collect_flow_stats_for_filter(int kcunit
,
6990 struct cfil_info
*cfil_info
,
6991 struct cfil_entry
*entry
,
6992 struct timeval current_tv
)
6994 struct cfil_stats_report_buffer
*buffer
= NULL
;
6995 struct cfil_msg_sock_stats
*flow_array
= NULL
;
6996 struct cfil_msg_sock_stats
*stats
= NULL
;
6997 struct inpcb
*inp
= NULL
;
6998 struct timeval diff_time
;
6999 uint64_t diff_time_usecs
;
7002 if (entry
->cfe_stats_report_frequency
== 0) {
7006 buffer
= global_cfil_stats_report_buffers
[kcunit
- 1];
7007 if (buffer
== NULL
) {
7009 CFIL_LOG(LOG_ERR
, "CFIL: STATS: no buffer");
7014 timersub(¤t_tv
, &entry
->cfe_stats_report_ts
, &diff_time
);
7015 diff_time_usecs
= (diff_time
.tv_sec
* USEC_PER_SEC
) + diff_time
.tv_usec
;
7018 CFIL_LOG(LOG_ERR
, "CFIL: STATS REPORT - elapsed time - ts %llu %llu cur ts %llu %llu diff %llu %llu (usecs %llu) @freq %llu usecs sockID %llu",
7019 (unsigned long long)entry
->cfe_stats_report_ts
.tv_sec
,
7020 (unsigned long long)entry
->cfe_stats_report_ts
.tv_usec
,
7021 (unsigned long long)current_tv
.tv_sec
,
7022 (unsigned long long)current_tv
.tv_usec
,
7023 (unsigned long long)diff_time
.tv_sec
,
7024 (unsigned long long)diff_time
.tv_usec
,
7025 (unsigned long long)diff_time_usecs
,
7026 (unsigned long long)((entry
->cfe_stats_report_frequency
* NSEC_PER_MSEC
) / NSEC_PER_USEC
),
7027 cfil_info
->cfi_sock_id
);
7030 // Compare elapsed time in usecs
7031 if (diff_time_usecs
>= (entry
->cfe_stats_report_frequency
* NSEC_PER_MSEC
) / NSEC_PER_USEC
) {
7033 CFIL_LOG(LOG_ERR
, "CFIL: STATS REPORT - in %llu reported %llu",
7034 cfil_info
->cfi_byte_inbound_count
,
7035 entry
->cfe_byte_inbound_count_reported
);
7036 CFIL_LOG(LOG_ERR
, "CFIL: STATS REPORT - out %llu reported %llu",
7037 cfil_info
->cfi_byte_outbound_count
,
7038 entry
->cfe_byte_outbound_count_reported
);
7040 // Check if flow has new bytes that have not been reported
7041 if (entry
->cfe_byte_inbound_count_reported
< cfil_info
->cfi_byte_inbound_count
||
7042 entry
->cfe_byte_outbound_count_reported
< cfil_info
->cfi_byte_outbound_count
) {
7043 flow_array
= (struct cfil_msg_sock_stats
*)&buffer
->stats
;
7044 index
= global_cfil_stats_counts
[kcunit
- 1];
7046 stats
= &flow_array
[index
];
7047 stats
->cfs_sock_id
= cfil_info
->cfi_sock_id
;
7048 stats
->cfs_byte_inbound_count
= cfil_info
->cfi_byte_inbound_count
;
7049 stats
->cfs_byte_outbound_count
= cfil_info
->cfi_byte_outbound_count
;
7051 if (entry
->cfe_laddr_sent
== false) {
7052 /* cache it if necessary */
7053 if (cfil_info
->cfi_so_attach_laddr
.sa
.sa_len
== 0) {
7054 inp
= cfil_info
->cfi_so
? sotoinpcb(cfil_info
->cfi_so
) : NULL
;
7056 boolean_t outgoing
= (cfil_info
->cfi_dir
== CFS_CONNECTION_DIR_OUT
);
7057 union sockaddr_in_4_6
*src
= outgoing
? &cfil_info
->cfi_so_attach_laddr
: NULL
;
7058 union sockaddr_in_4_6
*dst
= outgoing
? NULL
: &cfil_info
->cfi_so_attach_laddr
;
7059 cfil_fill_event_msg_addresses(cfil_info
->cfi_hash_entry
, inp
,
7060 src
, dst
, inp
->inp_vflag
& INP_IPV4
, outgoing
);
7064 if (cfil_info
->cfi_so_attach_laddr
.sa
.sa_len
!= 0) {
7065 stats
->cfs_laddr
.sin6
= cfil_info
->cfi_so_attach_laddr
.sin6
;
7066 entry
->cfe_laddr_sent
= true;
7070 global_cfil_stats_counts
[kcunit
- 1]++;
7072 entry
->cfe_stats_report_ts
= current_tv
;
7073 entry
->cfe_byte_inbound_count_reported
= cfil_info
->cfi_byte_inbound_count
;
7074 entry
->cfe_byte_outbound_count_reported
= cfil_info
->cfi_byte_outbound_count
;
7076 cfil_info_log(LOG_ERR
, cfil_info
, "CFIL: LIFECYCLE: STATS COLLECTED");
7078 CFI_ADD_TIME_LOG(cfil_info
, ¤t_tv
, &cfil_info
->cfi_first_event
, CFM_OP_STATS
);
7086 cfil_stats_report(void *v
, wait_result_t w
)
7088 #pragma unused(v, w)
7090 struct cfil_info
*cfil_info
= NULL
;
7091 struct cfil_entry
*entry
= NULL
;
7092 struct timeval current_tv
;
7093 uint32_t flow_count
= 0;
7094 uint64_t saved_next_sock_id
= 0; // Next sock id to be reported for next loop
7095 bool flow_reported
= false;
7098 CFIL_LOG(LOG_ERR
, "CFIL: STATS COLLECTION RUNNING");
7102 // Collect all sock ids of flows that has new stats
7103 cfil_rw_lock_shared(&cfil_lck_rw
);
7105 if (cfil_sock_attached_stats_count
== 0) {
7107 CFIL_LOG(LOG_ERR
, "CFIL: STATS: no flow");
7109 cfil_rw_unlock_shared(&cfil_lck_rw
);
7113 for (int kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
7114 if (global_cfil_stats_report_buffers
[kcunit
- 1] != NULL
) {
7115 memset(global_cfil_stats_report_buffers
[kcunit
- 1], 0, sizeof(struct cfil_stats_report_buffer
));
7117 global_cfil_stats_counts
[kcunit
- 1] = 0;
7120 microuptime(¤t_tv
);
7123 TAILQ_FOREACH(cfil_info
, &cfil_sock_head_stats
, cfi_link_stats
) {
7124 if (saved_next_sock_id
!= 0 &&
7125 saved_next_sock_id
== cfil_info
->cfi_sock_id
) {
7126 // Here is where we left off previously, start accumulating
7127 saved_next_sock_id
= 0;
7130 if (saved_next_sock_id
== 0) {
7131 if (flow_count
>= CFIL_STATS_REPORT_MAX_COUNT
) {
7132 // Examine a fixed number of flows each round. Remember the current flow
7133 // so we can start from here for next loop
7134 saved_next_sock_id
= cfil_info
->cfi_sock_id
;
7138 flow_reported
= false;
7139 for (int kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
7140 entry
= &cfil_info
->cfi_entries
[kcunit
- 1];
7141 if (entry
->cfe_filter
== NULL
) {
7143 CFIL_LOG(LOG_NOTICE
, "CFIL: STATS REPORT - so %llx no filter",
7144 cfil_info
->cfi_so
? (uint64_t)VM_KERNEL_ADDRPERM(cfil_info
->cfi_so
) : 0);
7149 if ((entry
->cfe_stats_report_frequency
> 0) &&
7150 cfil_stats_collect_flow_stats_for_filter(kcunit
, cfil_info
, entry
, current_tv
) == true) {
7151 flow_reported
= true;
7154 if (flow_reported
== true) {
7160 if (flow_count
> 0) {
7162 CFIL_LOG(LOG_ERR
, "CFIL: STATS reporting for %d flows", flow_count
);
7164 for (int kcunit
= 1; kcunit
<= MAX_CONTENT_FILTER
; kcunit
++) {
7165 if (global_cfil_stats_report_buffers
[kcunit
- 1] != NULL
&&
7166 global_cfil_stats_counts
[kcunit
- 1] > 0) {
7167 cfil_dispatch_stats_event_locked(kcunit
,
7168 global_cfil_stats_report_buffers
[kcunit
- 1],
7169 global_cfil_stats_counts
[kcunit
- 1]);
7173 cfil_rw_unlock_shared(&cfil_lck_rw
);
7177 cfil_rw_unlock_shared(&cfil_lck_rw
);
7179 // Loop again if we haven't finished the whole cfil_info list
7180 } while (saved_next_sock_id
!= 0);
7184 // Sleep forever (until waken up) if no more flow to report
7185 cfil_rw_lock_shared(&cfil_lck_rw
);
7186 cfil_stats_report_thread_sleep(cfil_sock_attached_stats_count
== 0 ? true : false);
7187 cfil_rw_unlock_shared(&cfil_lck_rw
);
7188 thread_block_parameter((thread_continue_t
) cfil_stats_report
, NULL
);