2 * Copyright (c) 2013-2021 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/kern_control.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/proc_uuid_policy.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/coalition.h>
46 #include <sys/codesign.h>
47 #include <kern/cs_blobs.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip6.h>
50 #include <netinet/tcp.h>
51 #include <netinet/tcp_var.h>
52 #include <netinet/tcp_cache.h>
53 #include <netinet/udp.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_tclass.h>
56 #include <netinet6/esp.h>
57 #include <net/flowhash.h>
58 #include <net/if_var.h>
59 #include <sys/kauth.h>
60 #include <sys/sysctl.h>
61 #include <sys/sysproto.h>
63 #include <sys/kern_event.h>
64 #include <sys/file_internal.h>
65 #include <IOKit/IOBSD.h>
66 #include <libkern/crypto/rand.h>
67 #include <corecrypto/cchmac.h>
68 #include <corecrypto/ccsha2.h>
69 #include <os/refcnt.h>
70 #include <mach-o/loader.h>
71 #include <net/network_agent.h>
73 #include <netinet/flow_divert_proto.h>
76 * NECP - Network Extension Control Policy database
77 * ------------------------------------------------
78 * The goal of this module is to allow clients connecting via a
79 * policy file descriptor to create high-level policy sessions, which
80 * are ingested into low-level kernel policies that control and tag
81 * traffic at the application, socket, and IP layers.
83 * ------------------------------------------------
85 * ------------------------------------------------
86 * Each session owns a list of session policies, each of which can
87 * specify any combination of conditions and a single result. Each
88 * session also has a priority level (such as High, Default, or Low)
89 * which is requested by the client. Based on the requested level,
90 * a session order value is assigned to the session, which will be used
91 * to sort kernel policies generated by the session. The session client
92 * can specify the sub-order for each policy it creates which will be
93 * used to further sort the kernel policies.
95 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
97 * ------------------------------------------------
99 * ------------------------------------------------
100 * Whenever a session send the Apply command, its policies are ingested
101 * and generate kernel policies. There are two phases of kernel policy
104 * 1. The session policy is parsed to create kernel policies at the socket
105 * and IP layers, when applicable. For example, a policy that requires
106 * all traffic from App1 to Pass will generate a socket kernel policy to
107 * match App1 and mark packets with ID1, and also an IP policy to match
108 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
109 * resulting kernel policies are added to the global socket and IP layer
111 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
114 * necp_kernel_socket_policies necp_kernel_ip_output_policies
116 * 2. Once the global lists of kernel policies have been filled out, each
117 * list is traversed to create optimized sub-lists ("Maps") which are used during
118 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
119 * which hashes incoming packets based on marked socket-layer policies, and removes
120 * duplicate or overlapping policies. Socket policies are sent into two maps,
121 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
122 * The app layer map is used for policy checks coming in from user space, and is one
123 * list with duplicate and overlapping policies removed. The socket map hashes based
124 * on app UUID, and removes duplicate and overlapping policies.
125 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
126 * |-> necp_kernel_socket_policies_map
128 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
130 * ------------------------------------------------
132 * ------------------------------------------------
133 * The Drop All Level is a sysctl that controls the level at which policies are allowed
134 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
135 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
136 * by a session with a priority level better than (numerically less than) the
137 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
138 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
139 * session orders to be dropped.
142 u_int32_t necp_drop_all_order
= 0;
143 u_int32_t necp_drop_all_level
= 0;
145 u_int32_t necp_pass_loopback
= NECP_LOOPBACK_PASS_ALL
;
146 u_int32_t necp_pass_keepalives
= 1; // 0=Off, 1=On
147 u_int32_t necp_pass_interpose
= 1; // 0=Off, 1=On
148 u_int32_t necp_restrict_multicast
= 1; // 0=Off, 1=On
149 u_int32_t necp_dedup_policies
= 0; // 0=Off, 1=On
151 u_int32_t necp_drop_unentitled_order
= 0;
152 #ifdef XNU_TARGET_OS_WATCH
153 u_int32_t necp_drop_unentitled_level
= NECP_SESSION_PRIORITY_CONTROL
+ 1; // Block all unentitled traffic from policies below control level
154 #else // XNU_TARGET_OS_WATCH
155 u_int32_t necp_drop_unentitled_level
= 0;
156 #endif // XNU_TARGET_OS_WATCH
158 u_int32_t necp_debug
= 0; // 0=None, 1=Basic, 2=EveryMatch
160 os_log_t necp_log_handle
= NULL
;
162 u_int32_t necp_session_count
= 0;
164 ZONE_DECLARE(necp_session_policy_zone
, "necp_session_policy",
165 sizeof(struct necp_session_policy
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
166 ZONE_DECLARE(necp_socket_policy_zone
, "necp_socket_policy",
167 sizeof(struct necp_kernel_socket_policy
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
168 ZONE_DECLARE(necp_ip_policy_zone
, "necp_ip_policy",
169 sizeof(struct necp_kernel_ip_output_policy
), ZC_ZFREE_CLEARMEM
| ZC_NOENCRYPT
);
171 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
172 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
173 LIST_INSERT_HEAD((head), elm, field); \
175 LIST_FOREACH(tmpelm, head, field) { \
176 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
177 LIST_INSERT_AFTER(tmpelm, elm, field); \
184 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
185 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
186 LIST_INSERT_HEAD((head), elm, field); \
188 LIST_FOREACH(tmpelm, head, field) { \
189 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) { \
190 LIST_INSERT_AFTER(tmpelm, elm, field); \
197 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
198 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) { \
199 LIST_INSERT_HEAD((head), elm, field); \
201 LIST_FOREACH(tmpelm, head, field) { \
202 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield))) { \
203 LIST_INSERT_AFTER(tmpelm, elm, field); \
210 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
212 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt) \
213 ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT)))
215 #define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
216 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
217 #define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
218 #define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
219 #define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
220 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
221 #define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
222 #define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
223 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
224 #define NECP_KERNEL_CONDITION_APP_ID 0x000200
225 #define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
226 #define NECP_KERNEL_CONDITION_DOMAIN 0x000800
227 #define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
228 #define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
229 #define NECP_KERNEL_CONDITION_PID 0x004000
230 #define NECP_KERNEL_CONDITION_UID 0x008000
231 #define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
232 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
233 #define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
234 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
235 #define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
236 #define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
237 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
238 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
239 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
240 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
241 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
242 #define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
243 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
244 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
245 #define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
246 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
248 #define NECP_MAX_POLICY_RESULT_SIZE 512
249 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
250 #define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
251 #define NECP_MAX_POLICY_LIST_COUNT 1024
254 NECP_BYPASS_TYPE_NONE
= 0,
255 NECP_BYPASS_TYPE_INTCOPROC
= 1,
256 NECP_BYPASS_TYPE_LOOPBACK
= 2,
257 } necp_socket_bypass_type_t
;
259 // Cap the policy size at the max result + conditions size, with room for extra TLVs
260 #define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
262 struct necp_service_registration
{
263 LIST_ENTRY(necp_service_registration
) session_chain
;
264 LIST_ENTRY(necp_service_registration
) kernel_chain
;
265 u_int32_t service_id
;
268 struct necp_session
{
269 u_int8_t necp_fd_type
;
270 u_int32_t control_unit
;
271 u_int32_t session_priority
; // Descriptive priority rating
272 u_int32_t session_order
;
274 necp_policy_id last_policy_id
;
276 decl_lck_mtx_data(, lock
);
278 bool proc_locked
; // Messages must come from proc_uuid
283 LIST_HEAD(_policies
, necp_session_policy
) policies
;
285 LIST_HEAD(_services
, necp_service_registration
) services
;
287 TAILQ_ENTRY(necp_session
) chain
;
290 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
291 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
293 static TAILQ_HEAD(_necp_session_list
, necp_session
) necp_session_list
;
295 struct necp_socket_info
{
299 union necp_sockaddr_union local_addr
;
300 union necp_sockaddr_union remote_addr
;
301 u_int32_t bound_interface_index
;
302 u_int32_t traffic_class
;
304 u_int32_t application_id
;
305 u_int32_t real_application_id
;
306 u_int32_t account_id
;
307 u_int32_t drop_order
;
308 u_int32_t client_flags
;
311 unsigned has_client
: 1;
312 unsigned is_platform_binary
: 1;
313 unsigned used_responsible_pid
: 1;
314 unsigned is_loopback
: 1;
315 unsigned real_is_platform_binary
: 1;
316 unsigned is_delegated
: 1;
317 unsigned __pad_bits
: 6;
320 static lck_grp_attr_t
*necp_kernel_policy_grp_attr
= NULL
;
321 static lck_attr_t
*necp_kernel_policy_mtx_attr
= NULL
;
322 static lck_grp_t
*necp_kernel_policy_mtx_grp
= NULL
;
323 decl_lck_rw_data(static, necp_kernel_policy_lock
);
325 static lck_grp_attr_t
*necp_route_rule_grp_attr
= NULL
;
326 static lck_attr_t
*necp_route_rule_mtx_attr
= NULL
;
327 static lck_grp_t
*necp_route_rule_mtx_grp
= NULL
;
328 decl_lck_rw_data(static, necp_route_rule_lock
);
330 os_refgrp_decl(static, necp_refgrp
, "NECPRefGroup", NULL
);
333 * On modification, invalidate cached lookups by bumping the generation count.
334 * Other calls will need to take the slowpath of taking
335 * the subsystem lock.
337 static volatile int32_t necp_kernel_socket_policies_gencount
;
338 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
339 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
340 necp_kernel_socket_policies_gencount = 1; \
346 * Allow priviledged processes to bypass the default drop-all
347 * via entitlement check. For OSX, since entitlement check is
348 * not supported for configd, configd signing identity is checked
351 #define SIGNING_ID_CONFIGD "com.apple.configd"
352 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
355 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
= 0,
356 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
= 1,
357 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
= 2,
358 } necp_drop_all_bypass_check_result_t
;
360 static u_int32_t necp_kernel_application_policies_condition_mask
;
361 static size_t necp_kernel_application_policies_count
;
362 static u_int32_t necp_kernel_socket_policies_condition_mask
;
363 static size_t necp_kernel_socket_policies_count
;
364 static size_t necp_kernel_socket_policies_non_app_count
;
365 static LIST_HEAD(_necpkernelsocketconnectpolicies
, necp_kernel_socket_policy
) necp_kernel_socket_policies
;
366 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
367 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
368 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_map
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
369 static struct necp_kernel_socket_policy
**necp_kernel_socket_policies_app_layer_map
;
371 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
372 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
373 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
375 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
378 static u_int32_t necp_kernel_ip_output_policies_condition_mask
;
379 static size_t necp_kernel_ip_output_policies_count
;
380 static size_t necp_kernel_ip_output_policies_non_id_count
;
381 static LIST_HEAD(_necpkernelipoutputpolicies
, necp_kernel_ip_output_policy
) necp_kernel_ip_output_policies
;
382 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
383 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
384 static struct necp_kernel_ip_output_policy
**necp_kernel_ip_output_policies_map
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
385 static struct necp_kernel_socket_policy pass_policy
=
387 .id
= NECP_KERNEL_POLICY_ID_NO_MATCH
,
388 .result
= NECP_KERNEL_POLICY_RESULT_PASS
,
391 static struct necp_session
*necp_create_session(void);
392 static void necp_delete_session(struct necp_session
*session
);
394 static necp_policy_id
necp_handle_policy_add(struct necp_session
*session
,
395 u_int8_t
*tlv_buffer
, size_t tlv_buffer_length
, int offset
, int *error
);
396 static int necp_handle_policy_dump_all(user_addr_t out_buffer
, size_t out_buffer_length
);
398 #define MAX_RESULT_STRING_LEN 64
399 static inline const char * necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
401 static struct necp_session_policy
*necp_policy_create(struct necp_session
*session
, necp_policy_order order
, u_int8_t
*conditions_array
, u_int32_t conditions_array_size
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
, u_int8_t
*result
, u_int32_t result_size
);
402 static struct necp_session_policy
*necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
);
403 static bool necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
);
404 static bool necp_policy_mark_all_for_deletion(struct necp_session
*session
);
405 static bool necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
);
406 static void necp_policy_apply_all(struct necp_session
*session
);
408 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_order order
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, char *cond_custom_entitlement
, u_int32_t cond_account_id
, char *domain
, pid_t cond_pid
, int32_t cond_pidversion
, uid_t cond_uid
, ifnet_t cond_bound_interface
, struct necp_policy_condition_tc_range cond_traffic_class
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, struct necp_policy_condition_agent_type
*cond_agent_type
, struct necp_policy_condition_sdk_version
*cond_sdk_version
, u_int32_t cond_client_flags
, char *cond_signing_identifier
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
409 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
);
410 static bool necp_kernel_socket_policies_reprocess(void);
411 static bool necp_kernel_socket_policies_update_uuid_table(void);
412 static inline struct necp_kernel_socket_policy
*necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy
**policy_search_array
, struct necp_socket_info
*info
, necp_kernel_policy_filter
*return_filter
, u_int32_t
*return_route_rule_id_array
, size_t *return_route_rule_id_array_count
, size_t route_rule_id_array_count
, necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
, u_int32_t
*return_netagent_array
, u_int32_t
*return_netagent_use_flags_array
, size_t netagent_array_count
, struct necp_client_parameter_netagent_type
*required_agent_types
, u_int32_t num_required_agent_types
, proc_t proc
, u_int16_t pf_tag
, necp_kernel_policy_id
*skip_policy_id
, struct rtentry
*rt
, necp_kernel_policy_result
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t
*return_drop_all_bypass
, u_int32_t
*return_flow_divert_aggregate_unit
);
414 static necp_kernel_policy_id
necp_kernel_ip_output_policy_add(necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_kernel_policy_id cond_policy_id
, ifnet_t cond_bound_interface
, u_int32_t cond_last_interface_index
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
);
415 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
);
416 static bool necp_kernel_ip_output_policies_reprocess(void);
418 static bool necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
);
419 static bool necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
);
420 static bool necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
);
421 static int necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
);
422 static bool necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
);
423 static bool necp_addr_is_empty(struct sockaddr
*addr
);
424 static bool necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
, u_int32_t bound_interface_index
);
425 static bool necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
);
427 struct necp_uuid_id_mapping
{
428 LIST_ENTRY(necp_uuid_id_mapping
) chain
;
431 os_refcnt_t refcount
;
432 u_int32_t table_usecount
; // Add to UUID policy table count
434 static size_t necp_num_uuid_app_id_mappings
;
435 static bool necp_uuid_app_id_mappings_dirty
;
436 #define NECP_UUID_APP_ID_HASH_SIZE 64
437 static u_long necp_uuid_app_id_hash_mask
;
438 static u_long necp_uuid_app_id_hash_num_buckets
;
439 static LIST_HEAD(necp_uuid_id_mapping_head
, necp_uuid_id_mapping
) * necp_uuid_app_id_hashtbl
, necp_uuid_service_id_list
; // App map is real hash table, service map is just mapping
440 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
441 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
);
442 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
);
443 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
);
445 static struct necp_uuid_id_mapping
*necp_uuid_lookup_service_id_locked(uuid_t uuid
);
446 static struct necp_uuid_id_mapping
*necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
);
447 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid
);
448 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid
);
449 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id
);
451 struct necp_string_id_mapping
{
452 LIST_ENTRY(necp_string_id_mapping
) chain
;
455 os_refcnt_t refcount
;
457 static LIST_HEAD(necp_string_id_mapping_list
, necp_string_id_mapping
) necp_account_id_list
;
458 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
459 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *domain
);
460 static struct necp_string_id_mapping
*necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
);
462 static struct necp_kernel_socket_policy
*necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
);
463 static struct necp_kernel_ip_output_policy
*necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
);
465 static LIST_HEAD(_necp_kernel_service_list
, necp_service_registration
) necp_registered_service_list
;
467 static char *necp_create_trimmed_domain(char *string
, size_t length
);
468 static inline int necp_count_dots(char *string
, size_t length
);
470 static char *necp_copy_string(char *string
, size_t length
);
471 static bool necp_update_qos_marking(struct ifnet
*ifp
, u_int32_t route_rule_id
);
473 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid > UINT16_MAX)
475 #define MAX_ROUTE_RULE_INTERFACES 10
476 struct necp_route_rule
{
477 LIST_ENTRY(necp_route_rule
) chain
;
479 u_int32_t netagent_id
;
480 u_int8_t default_action
;
481 u_int8_t cellular_action
;
482 u_int8_t wifi_action
;
483 u_int8_t wired_action
;
484 u_int8_t expensive_action
;
485 u_int8_t constrained_action
;
486 u_int exception_if_indices
[MAX_ROUTE_RULE_INTERFACES
];
487 u_int8_t exception_if_actions
[MAX_ROUTE_RULE_INTERFACES
];
488 os_refcnt_t refcount
;
490 static LIST_HEAD(necp_route_rule_list
, necp_route_rule
) necp_route_rules
;
491 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list
*list
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
);
492 static bool necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
);
493 static bool necp_route_is_allowed(struct rtentry
*route
, ifnet_t interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
);
494 static uint32_t necp_route_get_netagent(struct rtentry
*route
, u_int32_t route_rule_id
);
495 static struct necp_route_rule
*necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
);
496 static inline void necp_get_parent_cred_result(proc_t proc
, struct necp_socket_info
*info
);
498 #define MAX_AGGREGATE_ROUTE_RULES 16
499 struct necp_aggregate_route_rule
{
500 LIST_ENTRY(necp_aggregate_route_rule
) chain
;
502 u_int32_t rule_ids
[MAX_AGGREGATE_ROUTE_RULES
];
504 static LIST_HEAD(necp_aggregate_route_rule_list
, necp_aggregate_route_rule
) necp_aggregate_route_rules
;
505 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t
*rule_ids
);
507 // Sysctl definitions
508 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
;
509 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
;
511 SYSCTL_NODE(_net
, OID_AUTO
, necp
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "NECP");
512 SYSCTL_INT(_net_necp
, NECPCTL_DEDUP_POLICIES
, dedup_policies
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_dedup_policies
, 0, "");
513 SYSCTL_INT(_net_necp
, NECPCTL_RESTRICT_MULTICAST
, restrict_multicast
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_restrict_multicast
, 0, "");
514 SYSCTL_INT(_net_necp
, NECPCTL_PASS_LOOPBACK
, pass_loopback
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_loopback
, 0, "");
515 SYSCTL_INT(_net_necp
, NECPCTL_PASS_KEEPALIVES
, pass_keepalives
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_keepalives
, 0, "");
516 SYSCTL_INT(_net_necp
, NECPCTL_PASS_INTERPOSE
, pass_interpose
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_pass_interpose
, 0, "");
517 SYSCTL_INT(_net_necp
, NECPCTL_DEBUG
, debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_debug
, 0, "");
518 SYSCTL_PROC(_net_necp
, NECPCTL_DROP_UNENTITLED_LEVEL
, drop_unentitled_level
, CTLTYPE_INT
| CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_drop_unentitled_level
, 0, &sysctl_handle_necp_unentitled_level
, "IU", "");
519 SYSCTL_PROC(_net_necp
, NECPCTL_DROP_ALL_LEVEL
, drop_all_level
, CTLTYPE_INT
| CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_drop_all_level
, 0, &sysctl_handle_necp_level
, "IU", "");
520 SYSCTL_LONG(_net_necp
, NECPCTL_SOCKET_POLICY_COUNT
, socket_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_socket_policies_count
, "");
521 SYSCTL_LONG(_net_necp
, NECPCTL_SOCKET_NON_APP_POLICY_COUNT
, socket_non_app_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_socket_policies_non_app_count
, "");
522 SYSCTL_LONG(_net_necp
, NECPCTL_IP_POLICY_COUNT
, ip_policy_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_kernel_ip_output_policies_count
, "");
523 SYSCTL_INT(_net_necp
, NECPCTL_SESSION_COUNT
, session_count
, CTLFLAG_LOCKED
| CTLFLAG_RD
, &necp_session_count
, 0, "");
525 static struct necp_drop_dest_policy necp_drop_dest_policy
;
526 static int necp_drop_dest_debug
= 0; // 0: off, 1: match, >1: every evaluation
527 SYSCTL_INT(_net_necp
, OID_AUTO
, drop_dest_debug
, CTLFLAG_LOCKED
| CTLFLAG_RW
, &necp_drop_dest_debug
, 0, "");
529 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
;
530 SYSCTL_PROC(_net_necp
, OID_AUTO
, drop_dest_level
, CTLTYPE_STRUCT
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
| CTLFLAG_RW
,
531 0, 0, &sysctl_handle_necp_drop_dest_level
, "S,necp_drop_dest_level", "");
533 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union
*, u_int32_t
);
535 // Session order allocation
537 necp_allocate_new_session_order(u_int32_t priority
, u_int32_t control_unit
)
539 u_int32_t new_order
= 0;
541 // For now, just allocate 1000 orders for each priority
542 if (priority
== NECP_SESSION_PRIORITY_UNKNOWN
|| priority
> NECP_SESSION_NUM_PRIORITIES
) {
543 priority
= NECP_SESSION_PRIORITY_DEFAULT
;
546 // Use the control unit to decide the offset into the priority list
547 new_order
= (control_unit
) + ((priority
- 1) * 1000);
552 static inline u_int32_t
553 necp_get_first_order_for_priority(u_int32_t priority
)
558 return ((priority
- 1) * 1000) + 1;
563 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
565 #pragma unused(arg1, arg2)
566 int error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
567 necp_drop_all_order
= necp_get_first_order_for_priority(necp_drop_all_level
);
572 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
574 #pragma unused(arg1, arg2)
575 int error
= sysctl_handle_int(oidp
, oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
576 necp_drop_unentitled_order
= necp_get_first_order_for_priority(necp_drop_unentitled_level
);
580 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
581 static inline u_int32_t
582 _necp_process_drop_order_inner(kauth_cred_t cred
)
584 if (priv_check_cred(cred
, PRIV_NET_PRIVILEGED_CLIENT_ACCESS
, 0) != 0 &&
585 priv_check_cred(cred
, PRIV_NET_PRIVILEGED_SERVER_ACCESS
, 0) != 0) {
586 return necp_drop_unentitled_order
;
592 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
593 #pragma GCC poison _necp_process_drop_order_inner
597 static int necp_session_op_close(struct fileglob
*, vfs_context_t
);
599 static const struct fileops necp_session_fd_ops
= {
600 .fo_type
= DTYPE_NETPOLICY
,
601 .fo_read
= fo_no_read
,
602 .fo_write
= fo_no_write
,
603 .fo_ioctl
= fo_no_ioctl
,
604 .fo_select
= fo_no_select
,
605 .fo_close
= necp_session_op_close
,
606 .fo_drain
= fo_no_drain
,
607 .fo_kqfilter
= fo_no_kqfilter
,
611 necp_is_platform_binary(proc_t proc
)
613 return (proc
!= NULL
) ? (csproc_get_platform_binary(proc
) && cs_valid(proc
)) : 0;
616 static inline necp_drop_all_bypass_check_result_t
617 necp_check_drop_all_bypass_result(proc_t proc
)
620 proc
= current_proc();
622 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
;
626 #if defined(XNU_TARGET_OS_OSX)
627 const char *signing_id
= NULL
;
628 const bool isConfigd
= (necp_is_platform_binary(proc
) &&
629 (signing_id
= cs_identity_get(proc
)) &&
630 (strlen(signing_id
) == SIGNING_ID_CONFIGD_LEN
) &&
631 (memcmp(signing_id
, SIGNING_ID_CONFIGD
, SIGNING_ID_CONFIGD_LEN
) == 0));
633 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
;
637 const task_t task
= proc_task(proc
);
638 if (task
== NULL
|| !IOTaskHasEntitlement(task
, "com.apple.private.necp.drop_all_bypass")) {
639 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
;
641 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE
;
646 necp_session_open(struct proc
*p
, struct necp_session_open_args
*uap
, int *retval
)
650 struct necp_session
*session
= NULL
;
651 struct fileproc
*fp
= NULL
;
654 uid_t uid
= kauth_cred_getuid(proc_ucred(p
));
655 if (uid
!= 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0) != 0) {
656 NECPLOG0(LOG_ERR
, "Process does not hold necessary entitlement to open NECP session");
661 error
= falloc(p
, &fp
, &fd
, vfs_context_current());
666 session
= necp_create_session();
667 if (session
== NULL
) {
672 fp
->fp_glob
->fg_flag
= 0;
673 fp
->fp_glob
->fg_ops
= &necp_session_fd_ops
;
674 fp
->fp_glob
->fg_data
= session
;
677 FDFLAGS_SET(p
, fd
, (UF_EXCLOSE
| UF_FORKCLOSE
));
678 procfdtbl_releasefd(p
, fd
, NULL
);
679 fp_drop(p
, fd
, fp
, 1);
695 necp_session_op_close(struct fileglob
*fg
, vfs_context_t ctx
)
698 struct necp_session
*session
= (struct necp_session
*)fg
->fg_data
;
701 if (session
!= NULL
) {
702 necp_policy_mark_all_for_deletion(session
);
703 necp_policy_apply_all(session
);
704 necp_delete_session(session
);
712 necp_session_find_from_fd(struct proc
*p
, int fd
,
713 struct fileproc
**fpp
, struct necp_session
**session
)
715 struct fileproc
*fp
= NULL
;
716 int error
= fp_get_ftype(p
, fd
, DTYPE_NETPOLICY
, ENODEV
, &fp
);
720 *session
= (struct necp_session
*)fp
->fp_glob
->fg_data
;
721 if ((*session
)->necp_fd_type
!= necp_fd_type_session
) {
722 // Not a client fd, ignore
723 fp_drop(p
, fd
, fp
, 0);
732 necp_session_add_policy(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
735 u_int8_t
*tlv_buffer
= NULL
;
737 if (uap
->in_buffer_length
== 0 || uap
->in_buffer_length
> NECP_MAX_POLICY_SIZE
|| uap
->in_buffer
== 0) {
738 NECPLOG(LOG_ERR
, "necp_session_add_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
);
743 if (uap
->out_buffer_length
< sizeof(necp_policy_id
) || uap
->out_buffer
== 0) {
744 NECPLOG(LOG_ERR
, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap
->out_buffer_length
);
749 if ((tlv_buffer
= _MALLOC(uap
->in_buffer_length
, M_NECP
, M_WAITOK
| M_ZERO
)) == NULL
) {
754 error
= copyin(uap
->in_buffer
, tlv_buffer
, uap
->in_buffer_length
);
756 NECPLOG(LOG_ERR
, "necp_session_add_policy tlv copyin error (%d)", error
);
760 necp_policy_id new_policy_id
= necp_handle_policy_add(session
, tlv_buffer
, uap
->in_buffer_length
, 0, &error
);
762 NECPLOG(LOG_ERR
, "necp_session_add_policy failed to add policy (%d)", error
);
766 error
= copyout(&new_policy_id
, uap
->out_buffer
, sizeof(new_policy_id
));
768 NECPLOG(LOG_ERR
, "necp_session_add_policy policy_id copyout error (%d)", error
);
773 if (tlv_buffer
!= NULL
) {
774 FREE(tlv_buffer
, M_NECP
);
783 necp_session_get_policy(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
786 u_int8_t
*response
= NULL
;
788 if (uap
->in_buffer_length
< sizeof(necp_policy_id
) || uap
->in_buffer
== 0) {
789 NECPLOG(LOG_ERR
, "necp_session_get_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
);
794 necp_policy_id policy_id
= 0;
795 error
= copyin(uap
->in_buffer
, &policy_id
, sizeof(policy_id
));
797 NECPLOG(LOG_ERR
, "necp_session_get_policy policy_id copyin error (%d)", error
);
801 struct necp_session_policy
*policy
= necp_policy_find(session
, policy_id
);
802 if (policy
== NULL
|| policy
->pending_deletion
) {
803 NECPLOG(LOG_ERR
, "Failed to find policy with id %d", policy_id
);
808 u_int32_t order_tlv_size
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_order
);
809 u_int32_t result_tlv_size
= (policy
->result_size
? (sizeof(u_int8_t
) + sizeof(u_int32_t
) + policy
->result_size
) : 0);
810 u_int32_t response_size
= order_tlv_size
+ result_tlv_size
+ policy
->conditions_size
;
812 if (uap
->out_buffer_length
< response_size
|| uap
->out_buffer
== 0) {
813 NECPLOG(LOG_ERR
, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap
->out_buffer_length
, response_size
);
818 if (response_size
> NECP_MAX_POLICY_SIZE
) {
819 NECPLOG(LOG_ERR
, "necp_session_get_policy size too large to copy (%u)", response_size
);
824 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
| M_ZERO
);
825 if (response
== NULL
) {
830 u_int8_t
*cursor
= response
;
831 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
, response
, response_size
);
832 if (result_tlv_size
) {
833 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT
, policy
->result_size
, &policy
->result
, response
, response_size
);
835 if (policy
->conditions_size
) {
836 memcpy(((u_int8_t
*)(void *)(cursor
)), policy
->conditions
, policy
->conditions_size
);
839 error
= copyout(response
, uap
->out_buffer
, response_size
);
841 NECPLOG(LOG_ERR
, "necp_session_get_policy TLV copyout error (%d)", error
);
846 if (response
!= NULL
) {
847 FREE(response
, M_NECP
);
856 necp_session_delete_policy(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
860 if (uap
->in_buffer_length
< sizeof(necp_policy_id
) || uap
->in_buffer
== 0) {
861 NECPLOG(LOG_ERR
, "necp_session_delete_policy invalid input (%zu)", (size_t)uap
->in_buffer_length
);
866 necp_policy_id delete_policy_id
= 0;
867 error
= copyin(uap
->in_buffer
, &delete_policy_id
, sizeof(delete_policy_id
));
869 NECPLOG(LOG_ERR
, "necp_session_delete_policy policy_id copyin error (%d)", error
);
873 struct necp_session_policy
*policy
= necp_policy_find(session
, delete_policy_id
);
874 if (policy
== NULL
|| policy
->pending_deletion
) {
875 NECPLOG(LOG_ERR
, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id
);
880 necp_policy_mark_for_deletion(session
, policy
);
887 necp_session_apply_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
890 necp_policy_apply_all(session
);
896 necp_session_list_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
898 u_int32_t tlv_size
= (sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(necp_policy_id
));
899 u_int32_t response_size
= 0;
900 u_int8_t
*response
= NULL
;
901 int num_policies
= 0;
902 int cur_policy_index
= 0;
904 struct necp_session_policy
*policy
;
906 LIST_FOREACH(policy
, &session
->policies
, chain
) {
907 if (!policy
->pending_deletion
) {
912 if (num_policies
> NECP_MAX_POLICY_LIST_COUNT
) {
913 NECPLOG(LOG_ERR
, "necp_session_list_all size too large to copy (%u policies)", num_policies
);
918 response_size
= num_policies
* tlv_size
;
919 if (uap
->out_buffer_length
< response_size
|| uap
->out_buffer
== 0) {
920 NECPLOG(LOG_ERR
, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap
->out_buffer_length
, response_size
);
925 // Create a response with one Policy ID TLV for each policy
926 MALLOC(response
, u_int8_t
*, response_size
, M_NECP
, M_WAITOK
| M_ZERO
);
927 if (response
== NULL
) {
932 u_int8_t
*cursor
= response
;
933 LIST_FOREACH(policy
, &session
->policies
, chain
) {
934 if (!policy
->pending_deletion
&& cur_policy_index
< num_policies
) {
935 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(u_int32_t
), &policy
->local_id
, response
, response_size
);
940 error
= copyout(response
, uap
->out_buffer
, response_size
);
942 NECPLOG(LOG_ERR
, "necp_session_list_all TLV copyout error (%d)", error
);
947 if (response
!= NULL
) {
948 FREE(response
, M_NECP
);
958 necp_session_delete_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
961 necp_policy_mark_all_for_deletion(session
);
967 necp_session_set_session_priority(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
970 struct necp_session_policy
*policy
= NULL
;
971 struct necp_session_policy
*temp_policy
= NULL
;
973 if (uap
->in_buffer_length
< sizeof(necp_session_priority
) || uap
->in_buffer
== 0) {
974 NECPLOG(LOG_ERR
, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap
->in_buffer_length
);
979 necp_session_priority requested_session_priority
= 0;
980 error
= copyin(uap
->in_buffer
, &requested_session_priority
, sizeof(requested_session_priority
));
982 NECPLOG(LOG_ERR
, "necp_session_set_session_priority priority copyin error (%d)", error
);
986 // Enforce special session priorities with entitlements
987 if (requested_session_priority
== NECP_SESSION_PRIORITY_CONTROL
||
988 requested_session_priority
== NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
||
989 requested_session_priority
== NECP_SESSION_PRIORITY_HIGH_RESTRICTED
) {
990 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
991 if (cred_result
!= 0) {
992 NECPLOG(LOG_ERR
, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority
);
998 if (session
->session_priority
!= requested_session_priority
) {
999 session
->session_priority
= requested_session_priority
;
1000 session
->session_order
= necp_allocate_new_session_order(session
->session_priority
, session
->control_unit
);
1001 session
->dirty
= TRUE
;
1003 // Mark all policies as needing updates
1004 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
1005 policy
->pending_update
= TRUE
;
1015 necp_session_lock_to_process(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1018 session
->proc_locked
= TRUE
;
1024 necp_session_register_service(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1027 struct necp_service_registration
*new_service
= NULL
;
1029 if (uap
->in_buffer_length
< sizeof(uuid_t
) || uap
->in_buffer
== 0) {
1030 NECPLOG(LOG_ERR
, "necp_session_register_service invalid input (%zu)", (size_t)uap
->in_buffer_length
);
1035 uuid_t service_uuid
;
1036 error
= copyin(uap
->in_buffer
, service_uuid
, sizeof(service_uuid
));
1038 NECPLOG(LOG_ERR
, "necp_session_register_service uuid copyin error (%d)", error
);
1042 MALLOC(new_service
, struct necp_service_registration
*, sizeof(*new_service
), M_NECP
, M_WAITOK
| M_ZERO
);
1043 if (new_service
== NULL
) {
1044 NECPLOG0(LOG_ERR
, "Failed to allocate service registration");
1049 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1050 new_service
->service_id
= necp_create_uuid_service_id_mapping(service_uuid
);
1051 LIST_INSERT_HEAD(&session
->services
, new_service
, session_chain
);
1052 LIST_INSERT_HEAD(&necp_registered_service_list
, new_service
, kernel_chain
);
1053 lck_rw_done(&necp_kernel_policy_lock
);
1061 necp_session_unregister_service(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1064 struct necp_service_registration
*service
= NULL
;
1065 struct necp_service_registration
*temp_service
= NULL
;
1066 struct necp_uuid_id_mapping
*mapping
= NULL
;
1068 if (uap
->in_buffer_length
< sizeof(uuid_t
) || uap
->in_buffer
== 0) {
1069 NECPLOG(LOG_ERR
, "necp_session_unregister_service invalid input (%zu)", (size_t)uap
->in_buffer_length
);
1074 uuid_t service_uuid
;
1075 error
= copyin(uap
->in_buffer
, service_uuid
, sizeof(service_uuid
));
1077 NECPLOG(LOG_ERR
, "necp_session_unregister_service uuid copyin error (%d)", error
);
1081 // Remove all matching services for this session
1082 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1083 mapping
= necp_uuid_lookup_service_id_locked(service_uuid
);
1084 if (mapping
!= NULL
) {
1085 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1086 if (service
->service_id
== mapping
->id
) {
1087 LIST_REMOVE(service
, session_chain
);
1088 LIST_REMOVE(service
, kernel_chain
);
1089 FREE(service
, M_NECP
);
1092 necp_remove_uuid_service_id_mapping(service_uuid
);
1094 lck_rw_done(&necp_kernel_policy_lock
);
1102 necp_session_dump_all(struct necp_session
*session
, struct necp_session_action_args
*uap
, int *retval
)
1104 #pragma unused(session)
1107 if (uap
->out_buffer_length
== 0 || uap
->out_buffer
== 0) {
1108 NECPLOG(LOG_ERR
, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap
->out_buffer_length
);
1113 error
= necp_handle_policy_dump_all(uap
->out_buffer
, uap
->out_buffer_length
);
1120 necp_session_action(struct proc
*p
, struct necp_session_action_args
*uap
, int *retval
)
1122 struct fileproc
*fp
;
1124 int return_value
= 0;
1125 struct necp_session
*session
= NULL
;
1127 error
= necp_session_find_from_fd(p
, uap
->necp_fd
, &fp
, &session
);
1129 NECPLOG(LOG_ERR
, "necp_session_action find fd error (%d)", error
);
1133 NECP_SESSION_LOCK(session
);
1135 if (session
->proc_locked
) {
1136 // Verify that the calling process is allowed to do actions
1138 proc_getexecutableuuid(current_proc(), proc_uuid
, sizeof(proc_uuid
));
1139 if (uuid_compare(proc_uuid
, session
->proc_uuid
) != 0) {
1144 // If not locked, update the proc_uuid and proc_pid of the session
1145 proc_getexecutableuuid(current_proc(), session
->proc_uuid
, sizeof(session
->proc_uuid
));
1146 session
->proc_pid
= proc_pid(current_proc());
1149 u_int32_t action
= uap
->action
;
1151 case NECP_SESSION_ACTION_POLICY_ADD
: {
1152 return_value
= necp_session_add_policy(session
, uap
, retval
);
1155 case NECP_SESSION_ACTION_POLICY_GET
: {
1156 return_value
= necp_session_get_policy(session
, uap
, retval
);
1159 case NECP_SESSION_ACTION_POLICY_DELETE
: {
1160 return_value
= necp_session_delete_policy(session
, uap
, retval
);
1163 case NECP_SESSION_ACTION_POLICY_APPLY_ALL
: {
1164 return_value
= necp_session_apply_all(session
, uap
, retval
);
1167 case NECP_SESSION_ACTION_POLICY_LIST_ALL
: {
1168 return_value
= necp_session_list_all(session
, uap
, retval
);
1171 case NECP_SESSION_ACTION_POLICY_DELETE_ALL
: {
1172 return_value
= necp_session_delete_all(session
, uap
, retval
);
1175 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY
: {
1176 return_value
= necp_session_set_session_priority(session
, uap
, retval
);
1179 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC
: {
1180 return_value
= necp_session_lock_to_process(session
, uap
, retval
);
1183 case NECP_SESSION_ACTION_REGISTER_SERVICE
: {
1184 return_value
= necp_session_register_service(session
, uap
, retval
);
1187 case NECP_SESSION_ACTION_UNREGISTER_SERVICE
: {
1188 return_value
= necp_session_unregister_service(session
, uap
, retval
);
1191 case NECP_SESSION_ACTION_POLICY_DUMP_ALL
: {
1192 return_value
= necp_session_dump_all(session
, uap
, retval
);
1196 NECPLOG(LOG_ERR
, "necp_session_action unknown action (%u)", action
);
1197 return_value
= EINVAL
;
1203 NECP_SESSION_UNLOCK(session
);
1204 fp_drop(p
, uap
->necp_fd
, fp
, 0);
1205 return return_value
;
1208 struct necp_resolver_key_state
{
1209 const struct ccdigest_info
*digest_info
;
1210 uint8_t key
[CCSHA256_OUTPUT_SIZE
];
1212 static struct necp_resolver_key_state s_necp_resolver_key_state
;
1215 necp_generate_resolver_key(void)
1217 s_necp_resolver_key_state
.digest_info
= ccsha256_di();
1218 cc_rand_generate(s_necp_resolver_key_state
.key
, sizeof(s_necp_resolver_key_state
.key
));
1222 necp_sign_update_context(const struct ccdigest_info
*di
,
1226 u_int32_t query_length
,
1228 u_int32_t answer_length
)
1230 const uint8_t context
[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1231 const char *context_string
= "NECP Resolver Binder";
1232 uint8_t separator
= 0;
1233 cchmac_update(di
, ctx
, sizeof(context
), context
);
1234 cchmac_update(di
, ctx
, strlen(context_string
), context_string
);
1235 cchmac_update(di
, ctx
, sizeof(separator
), &separator
);
1236 cchmac_update(di
, ctx
, sizeof(uuid_t
), client_id
);
1237 cchmac_update(di
, ctx
, sizeof(query_length
), &query_length
);
1238 cchmac_update(di
, ctx
, query_length
, query
);
1239 cchmac_update(di
, ctx
, sizeof(answer_length
), &answer_length
);
1240 cchmac_update(di
, ctx
, answer_length
, answer
);
1244 necp_sign_resolver_answer(uuid_t client_id
, u_int8_t
*query
, u_int32_t query_length
,
1245 u_int8_t
*answer
, u_int32_t answer_length
,
1246 u_int8_t
*tag
, u_int32_t
*out_tag_length
)
1248 if (s_necp_resolver_key_state
.digest_info
== NULL
) {
1252 if (query
== NULL
||
1253 query_length
== 0 ||
1255 answer_length
== 0 ||
1257 out_tag_length
== NULL
) {
1261 size_t required_tag_length
= s_necp_resolver_key_state
.digest_info
->output_size
;
1262 if (*out_tag_length
< required_tag_length
) {
1266 *out_tag_length
= required_tag_length
;
1268 cchmac_ctx_decl(s_necp_resolver_key_state
.digest_info
->state_size
,
1269 s_necp_resolver_key_state
.digest_info
->block_size
, ctx
);
1270 cchmac_init(s_necp_resolver_key_state
.digest_info
, ctx
,
1271 sizeof(s_necp_resolver_key_state
.key
),
1272 s_necp_resolver_key_state
.key
);
1273 necp_sign_update_context(s_necp_resolver_key_state
.digest_info
,
1274 ctx
, client_id
, query
, query_length
,
1275 answer
, answer_length
);
1276 cchmac_final(s_necp_resolver_key_state
.digest_info
, ctx
, tag
);
1282 necp_validate_resolver_answer(uuid_t client_id
, u_int8_t
*query
, u_int32_t query_length
,
1283 u_int8_t
*answer
, u_int32_t answer_length
,
1284 u_int8_t
*tag
, u_int32_t tag_length
)
1286 if (s_necp_resolver_key_state
.digest_info
== NULL
) {
1290 if (query
== NULL
||
1291 query_length
== 0 ||
1293 answer_length
== 0 ||
1299 size_t required_tag_length
= s_necp_resolver_key_state
.digest_info
->output_size
;
1300 if (tag_length
!= required_tag_length
) {
1304 uint8_t actual_tag
[required_tag_length
];
1306 cchmac_ctx_decl(s_necp_resolver_key_state
.digest_info
->state_size
,
1307 s_necp_resolver_key_state
.digest_info
->block_size
, ctx
);
1308 cchmac_init(s_necp_resolver_key_state
.digest_info
, ctx
,
1309 sizeof(s_necp_resolver_key_state
.key
),
1310 s_necp_resolver_key_state
.key
);
1311 necp_sign_update_context(s_necp_resolver_key_state
.digest_info
,
1312 ctx
, client_id
, query
, query_length
,
1313 answer
, answer_length
);
1314 cchmac_final(s_necp_resolver_key_state
.digest_info
, ctx
, actual_tag
);
1316 return cc_cmp_safe(s_necp_resolver_key_state
.digest_info
->output_size
, tag
, actual_tag
) == 0;
1324 necp_log_handle
= os_log_create("com.apple.xnu.net.necp", "necp");
1326 necp_kernel_policy_grp_attr
= lck_grp_attr_alloc_init();
1327 if (necp_kernel_policy_grp_attr
== NULL
) {
1328 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
1333 necp_kernel_policy_mtx_grp
= lck_grp_alloc_init(NECP_CONTROL_NAME
, necp_kernel_policy_grp_attr
);
1334 if (necp_kernel_policy_mtx_grp
== NULL
) {
1335 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
1340 necp_kernel_policy_mtx_attr
= lck_attr_alloc_init();
1341 if (necp_kernel_policy_mtx_attr
== NULL
) {
1342 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
1347 lck_rw_init(&necp_kernel_policy_lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
);
1349 necp_route_rule_grp_attr
= lck_grp_attr_alloc_init();
1350 if (necp_route_rule_grp_attr
== NULL
) {
1351 NECPLOG0(LOG_ERR
, "lck_grp_attr_alloc_init failed");
1356 necp_route_rule_mtx_grp
= lck_grp_alloc_init("necp_route_rule", necp_route_rule_grp_attr
);
1357 if (necp_route_rule_mtx_grp
== NULL
) {
1358 NECPLOG0(LOG_ERR
, "lck_grp_alloc_init failed");
1363 necp_route_rule_mtx_attr
= lck_attr_alloc_init();
1364 if (necp_route_rule_mtx_attr
== NULL
) {
1365 NECPLOG0(LOG_ERR
, "lck_attr_alloc_init failed");
1370 lck_rw_init(&necp_route_rule_lock
, necp_route_rule_mtx_grp
, necp_route_rule_mtx_attr
);
1374 TAILQ_INIT(&necp_session_list
);
1376 LIST_INIT(&necp_kernel_socket_policies
);
1377 LIST_INIT(&necp_kernel_ip_output_policies
);
1379 LIST_INIT(&necp_account_id_list
);
1381 LIST_INIT(&necp_uuid_service_id_list
);
1383 LIST_INIT(&necp_registered_service_list
);
1385 LIST_INIT(&necp_route_rules
);
1386 LIST_INIT(&necp_aggregate_route_rules
);
1388 necp_generate_resolver_key();
1390 necp_uuid_app_id_hashtbl
= hashinit(NECP_UUID_APP_ID_HASH_SIZE
, M_NECP
, &necp_uuid_app_id_hash_mask
);
1391 necp_uuid_app_id_hash_num_buckets
= necp_uuid_app_id_hash_mask
+ 1;
1392 necp_num_uuid_app_id_mappings
= 0;
1393 necp_uuid_app_id_mappings_dirty
= FALSE
;
1395 necp_kernel_application_policies_condition_mask
= 0;
1396 necp_kernel_socket_policies_condition_mask
= 0;
1397 necp_kernel_ip_output_policies_condition_mask
= 0;
1399 necp_kernel_application_policies_count
= 0;
1400 necp_kernel_socket_policies_count
= 0;
1401 necp_kernel_socket_policies_non_app_count
= 0;
1402 necp_kernel_ip_output_policies_count
= 0;
1403 necp_kernel_ip_output_policies_non_id_count
= 0;
1405 necp_kernel_socket_policies_gencount
= 1;
1407 memset(&necp_kernel_socket_policies_map
, 0, sizeof(necp_kernel_socket_policies_map
));
1408 memset(&necp_kernel_ip_output_policies_map
, 0, sizeof(necp_kernel_ip_output_policies_map
));
1409 necp_kernel_socket_policies_app_layer_map
= NULL
;
1411 necp_drop_unentitled_order
= necp_get_first_order_for_priority(necp_drop_unentitled_level
);
1415 if (necp_kernel_policy_mtx_attr
!= NULL
) {
1416 lck_attr_free(necp_kernel_policy_mtx_attr
);
1417 necp_kernel_policy_mtx_attr
= NULL
;
1419 if (necp_kernel_policy_mtx_grp
!= NULL
) {
1420 lck_grp_free(necp_kernel_policy_mtx_grp
);
1421 necp_kernel_policy_mtx_grp
= NULL
;
1423 if (necp_kernel_policy_grp_attr
!= NULL
) {
1424 lck_grp_attr_free(necp_kernel_policy_grp_attr
);
1425 necp_kernel_policy_grp_attr
= NULL
;
1427 if (necp_route_rule_mtx_attr
!= NULL
) {
1428 lck_attr_free(necp_route_rule_mtx_attr
);
1429 necp_route_rule_mtx_attr
= NULL
;
1431 if (necp_route_rule_mtx_grp
!= NULL
) {
1432 lck_grp_free(necp_route_rule_mtx_grp
);
1433 necp_route_rule_mtx_grp
= NULL
;
1435 if (necp_route_rule_grp_attr
!= NULL
) {
1436 lck_grp_attr_free(necp_route_rule_grp_attr
);
1437 necp_route_rule_grp_attr
= NULL
;
1444 necp_post_change_event(struct kev_necp_policies_changed_data
*necp_event_data
)
1446 struct kev_msg ev_msg
;
1447 memset(&ev_msg
, 0, sizeof(ev_msg
));
1449 ev_msg
.vendor_code
= KEV_VENDOR_APPLE
;
1450 ev_msg
.kev_class
= KEV_NETWORK_CLASS
;
1451 ev_msg
.kev_subclass
= KEV_NECP_SUBCLASS
;
1452 ev_msg
.event_code
= KEV_NECP_POLICIES_CHANGED
;
1454 ev_msg
.dv
[0].data_ptr
= necp_event_data
;
1455 ev_msg
.dv
[0].data_length
= sizeof(necp_event_data
->changed_count
);
1456 ev_msg
.dv
[1].data_length
= 0;
1458 kev_post_msg(&ev_msg
);
1462 necp_buffer_write_tlv_validate(u_int8_t
*cursor
, u_int8_t type
, u_int32_t length
,
1463 u_int8_t
*buffer
, u_int32_t buffer_length
)
1465 if (cursor
< buffer
|| (uintptr_t)(cursor
- buffer
) > buffer_length
) {
1466 NECPLOG0(LOG_ERR
, "Cannot write TLV in buffer (invalid cursor)");
1469 u_int8_t
*next_tlv
= (u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
) + length
);
1470 if (next_tlv
<= buffer
|| // make sure the next TLV start doesn't overflow
1471 (uintptr_t)(next_tlv
- buffer
) > buffer_length
) { // make sure the next TLV has enough room in buffer
1472 NECPLOG(LOG_ERR
, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1473 length
, buffer_length
);
1480 necp_buffer_write_tlv_if_different(u_int8_t
*cursor
, u_int8_t type
,
1481 u_int32_t length
, const void *value
, bool *updated
,
1482 u_int8_t
*buffer
, u_int32_t buffer_length
)
1484 if (!necp_buffer_write_tlv_validate(cursor
, type
, length
, buffer
, buffer_length
)) {
1485 // If we can't fit this TLV, return the current cursor
1488 u_int8_t
*next_tlv
= (u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
) + length
);
1489 if (*updated
|| *(u_int8_t
*)(cursor
) != type
) {
1490 *(u_int8_t
*)(cursor
) = type
;
1493 if (*updated
|| *(u_int32_t
*)(void *)(cursor
+ sizeof(type
)) != length
) {
1494 *(u_int32_t
*)(void *)(cursor
+ sizeof(type
)) = length
;
1498 if (*updated
|| memcmp((u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
)), value
, length
) != 0) {
1499 memcpy((u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
)), value
, length
);
1507 necp_buffer_write_tlv(u_int8_t
*cursor
, u_int8_t type
,
1508 u_int32_t length
, const void *value
,
1509 u_int8_t
*buffer
, u_int32_t buffer_length
)
1511 if (!necp_buffer_write_tlv_validate(cursor
, type
, length
, buffer
, buffer_length
)) {
1514 u_int8_t
*next_tlv
= (u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
) + length
);
1515 *(u_int8_t
*)(cursor
) = type
;
1516 *(u_int32_t
*)(void *)(cursor
+ sizeof(type
)) = length
;
1518 memcpy((u_int8_t
*)(cursor
+ sizeof(type
) + sizeof(length
)), value
, length
);
1525 necp_buffer_get_tlv_type(u_int8_t
*buffer
, int tlv_offset
)
1527 u_int8_t
*type
= NULL
;
1529 if (buffer
== NULL
) {
1533 type
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
);
1534 return type
? *type
: 0;
1538 necp_buffer_get_tlv_length(u_int8_t
*buffer
, int tlv_offset
)
1540 u_int32_t
*length
= NULL
;
1542 if (buffer
== NULL
) {
1546 length
= (u_int32_t
*)(void *)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
));
1547 return length
? *length
: 0;
1551 necp_buffer_get_tlv_value(u_int8_t
*buffer
, int tlv_offset
, u_int32_t
*value_size
)
1553 u_int8_t
*value
= NULL
;
1554 u_int32_t length
= necp_buffer_get_tlv_length(buffer
, tlv_offset
);
1560 *value_size
= length
;
1563 value
= (u_int8_t
*)((u_int8_t
*)buffer
+ tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
));
1568 necp_buffer_find_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int *err
, int next
)
1579 int cursor
= offset
;
1581 u_int32_t curr_length
;
1585 if ((((u_int32_t
)cursor
) + sizeof(curr_type
) + sizeof(curr_length
)) > buffer_length
) {
1589 curr_type
= necp_buffer_get_tlv_type(buffer
, cursor
);
1592 curr_type
= NECP_TLV_NIL
;
1594 curr_length
= necp_buffer_get_tlv_length(buffer
, cursor
);
1595 if (curr_length
> buffer_length
- ((u_int32_t
)cursor
+ sizeof(curr_type
) + sizeof(curr_length
))) {
1599 next_cursor
= (cursor
+ sizeof(curr_type
) + sizeof(curr_length
) + curr_length
);
1600 if (curr_type
== type
) {
1601 // check if entire TLV fits inside buffer
1602 if (((u_int32_t
)next_cursor
) <= buffer_length
) {
1611 cursor
= next_cursor
;
1616 necp_find_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
, int offset
, u_int8_t type
, int *err
, int next
)
1619 if (buffer
!= NULL
) {
1620 cursor
= necp_buffer_find_tlv(buffer
, buffer_length
, offset
, type
, err
, next
);
1626 necp_get_tlv_at_offset(u_int8_t
*buffer
, u_int32_t buffer_length
,
1627 int tlv_offset
, u_int32_t out_buffer_length
, void *out_buffer
, u_int32_t
*value_size
)
1629 if (buffer
== NULL
) {
1630 NECPLOG0(LOG_ERR
, "necp_get_tlv_at_offset buffer is NULL");
1634 // Handle buffer parsing
1636 // Validate that buffer has enough room for any TLV
1637 if (tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) > buffer_length
) {
1638 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
1639 buffer_length
, tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
));
1643 // Validate that buffer has enough room for this TLV
1644 u_int32_t tlv_length
= necp_buffer_get_tlv_length(buffer
, tlv_offset
);
1645 if (tlv_length
> buffer_length
- (tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
))) {
1646 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
1647 tlv_length
, buffer_length
, tlv_offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + tlv_length
);
1651 if (out_buffer
!= NULL
&& out_buffer_length
> 0) {
1652 // Validate that out buffer is large enough for value
1653 if (out_buffer_length
< tlv_length
) {
1654 NECPLOG(LOG_ERR
, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
1655 out_buffer_length
, tlv_length
);
1659 // Get value pointer
1660 u_int8_t
*tlv_value
= necp_buffer_get_tlv_value(buffer
, tlv_offset
, NULL
);
1661 if (tlv_value
== NULL
) {
1662 NECPLOG0(LOG_ERR
, "necp_get_tlv_at_offset tlv_value is NULL");
1667 memcpy(out_buffer
, tlv_value
, tlv_length
);
1671 if (value_size
!= NULL
) {
1672 *value_size
= tlv_length
;
1679 necp_get_tlv(u_int8_t
*buffer
, u_int32_t buffer_length
,
1680 int offset
, u_int8_t type
, u_int32_t buff_len
, void *buff
, u_int32_t
*value_size
)
1684 int tlv_offset
= necp_find_tlv(buffer
, buffer_length
, offset
, type
, &error
, 0);
1685 if (tlv_offset
< 0) {
1689 return necp_get_tlv_at_offset(buffer
, buffer_length
, tlv_offset
, buff_len
, buff
, value_size
);
1692 // Session Management
1694 static struct necp_session
*
1695 necp_create_session(void)
1697 struct necp_session
*new_session
= NULL
;
1699 MALLOC(new_session
, struct necp_session
*, sizeof(*new_session
), M_NECP
, M_WAITOK
| M_ZERO
);
1700 if (new_session
== NULL
) {
1704 new_session
->necp_fd_type
= necp_fd_type_session
;
1705 new_session
->session_priority
= NECP_SESSION_PRIORITY_UNKNOWN
;
1706 new_session
->dirty
= FALSE
;
1707 LIST_INIT(&new_session
->policies
);
1708 lck_mtx_init(&new_session
->lock
, necp_kernel_policy_mtx_grp
, necp_kernel_policy_mtx_attr
);
1711 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1713 // Find the next available control unit
1714 u_int32_t control_unit
= 1;
1715 struct necp_session
*next_session
= NULL
;
1716 TAILQ_FOREACH(next_session
, &necp_session_list
, chain
) {
1717 if (next_session
->control_unit
> control_unit
) {
1718 // Found a gap, grab this control unit
1722 // Try the next control unit, loop around
1723 control_unit
= next_session
->control_unit
+ 1;
1726 new_session
->control_unit
= control_unit
;
1727 new_session
->session_order
= necp_allocate_new_session_order(new_session
->session_priority
, control_unit
);
1729 if (next_session
!= NULL
) {
1730 TAILQ_INSERT_BEFORE(next_session
, new_session
, chain
);
1732 TAILQ_INSERT_TAIL(&necp_session_list
, new_session
, chain
);
1735 necp_session_count
++;
1736 lck_rw_done(&necp_kernel_policy_lock
);
1739 NECPLOG(LOG_DEBUG
, "Created NECP session, control unit %d", control_unit
);
1747 necp_delete_session(struct necp_session
*session
)
1749 if (session
!= NULL
) {
1750 struct necp_service_registration
*service
= NULL
;
1751 struct necp_service_registration
*temp_service
= NULL
;
1752 LIST_FOREACH_SAFE(service
, &session
->services
, session_chain
, temp_service
) {
1753 LIST_REMOVE(service
, session_chain
);
1754 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1755 LIST_REMOVE(service
, kernel_chain
);
1756 lck_rw_done(&necp_kernel_policy_lock
);
1757 FREE(service
, M_NECP
);
1760 NECPLOG0(LOG_DEBUG
, "Deleted NECP session");
1763 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
1764 TAILQ_REMOVE(&necp_session_list
, session
, chain
);
1765 necp_session_count
--;
1766 lck_rw_done(&necp_kernel_policy_lock
);
1768 lck_mtx_destroy(&session
->lock
, necp_kernel_policy_mtx_grp
);
1769 FREE(session
, M_NECP
);
1773 // Session Policy Management
1775 static inline u_int8_t
1776 necp_policy_result_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1778 return (buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0;
1781 static inline u_int32_t
1782 necp_policy_result_get_parameter_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1784 return (buffer
&& length
> sizeof(u_int8_t
)) ? (length
- sizeof(u_int8_t
)) : 0;
1787 static inline u_int8_t
*
1788 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1790 return (buffer
&& length
> sizeof(u_int8_t
)) ? (buffer
+ sizeof(u_int8_t
)) : NULL
;
1794 necp_policy_result_requires_route_rules(u_int8_t
*buffer
, u_int32_t length
)
1796 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1797 if (type
== NECP_POLICY_RESULT_ROUTE_RULES
) {
1804 necp_address_is_valid(struct sockaddr
*address
)
1806 if (address
->sa_family
== AF_INET
) {
1807 return address
->sa_len
== sizeof(struct sockaddr_in
);
1808 } else if (address
->sa_family
== AF_INET6
) {
1809 return address
->sa_len
== sizeof(struct sockaddr_in6
);
1816 necp_policy_result_is_valid(u_int8_t
*buffer
, u_int32_t length
)
1818 bool validated
= FALSE
;
1819 u_int8_t type
= necp_policy_result_get_type_from_buffer(buffer
, length
);
1820 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(buffer
, length
);
1822 case NECP_POLICY_RESULT_PASS
: {
1823 if (parameter_length
== 0 || parameter_length
== sizeof(u_int32_t
)) {
1828 case NECP_POLICY_RESULT_DROP
: {
1829 if (parameter_length
== 0 || parameter_length
== sizeof(u_int32_t
)) {
1834 case NECP_POLICY_RESULT_ROUTE_RULES
:
1835 case NECP_POLICY_RESULT_SCOPED_DIRECT
:
1836 case NECP_POLICY_RESULT_ALLOW_UNENTITLED
: {
1840 case NECP_POLICY_RESULT_SKIP
:
1841 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
1842 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
1843 if (parameter_length
>= sizeof(u_int32_t
)) {
1848 case NECP_POLICY_RESULT_IP_TUNNEL
: {
1849 if (parameter_length
> sizeof(u_int32_t
)) {
1854 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
1855 if (parameter_length
> 0) {
1860 case NECP_POLICY_RESULT_TRIGGER
:
1861 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
1862 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
1863 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
:
1864 case NECP_POLICY_RESULT_USE_NETAGENT
:
1865 case NECP_POLICY_RESULT_NETAGENT_SCOPED
:{
1866 if (parameter_length
>= sizeof(uuid_t
)) {
1878 NECPLOG(LOG_DEBUG
, "Policy result type %d, valid %d", type
, validated
);
1884 static inline u_int8_t
1885 necp_policy_condition_get_type_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1887 return (buffer
&& length
>= sizeof(u_int8_t
)) ? buffer
[0] : 0;
1890 static inline u_int8_t
1891 necp_policy_condition_get_flags_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1893 return (buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? buffer
[1] : 0;
1896 static inline u_int32_t
1897 necp_policy_condition_get_value_length_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1899 return (buffer
&& length
>= (2 * sizeof(u_int8_t
))) ? (length
- (2 * sizeof(u_int8_t
))) : 0;
1902 static inline u_int8_t
*
1903 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t
*buffer
, u_int32_t length
)
1905 return (buffer
&& length
> (2 * sizeof(u_int8_t
))) ? (buffer
+ (2 * sizeof(u_int8_t
))) : NULL
;
1909 necp_policy_condition_is_default(u_int8_t
*buffer
, u_int32_t length
)
1911 return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_DEFAULT
;
1915 necp_policy_condition_is_application(u_int8_t
*buffer
, u_int32_t length
)
1917 return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_APPLICATION
;
1921 necp_policy_condition_is_real_application(u_int8_t
*buffer
, u_int32_t length
)
1923 return necp_policy_condition_get_type_from_buffer(buffer
, length
) == NECP_POLICY_CONDITION_REAL_APPLICATION
;
1927 necp_policy_condition_requires_application(u_int8_t
*buffer
, u_int32_t length
)
1929 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1930 return type
== NECP_POLICY_CONDITION_REAL_APPLICATION
;
1934 necp_policy_condition_requires_real_application(u_int8_t
*buffer
, u_int32_t length
)
1936 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1937 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1938 return type
== NECP_POLICY_CONDITION_ENTITLEMENT
&& condition_length
> 0;
1942 necp_policy_condition_is_valid(u_int8_t
*buffer
, u_int32_t length
, u_int8_t policy_result_type
)
1944 bool validated
= FALSE
;
1945 bool result_cannot_have_ip_layer
= (policy_result_type
== NECP_POLICY_RESULT_SOCKET_DIVERT
||
1946 policy_result_type
== NECP_POLICY_RESULT_SOCKET_FILTER
||
1947 policy_result_type
== NECP_POLICY_RESULT_TRIGGER
||
1948 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
||
1949 policy_result_type
== NECP_POLICY_RESULT_TRIGGER_SCOPED
||
1950 policy_result_type
== NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
||
1951 policy_result_type
== NECP_POLICY_RESULT_SOCKET_SCOPED
||
1952 policy_result_type
== NECP_POLICY_RESULT_ROUTE_RULES
||
1953 policy_result_type
== NECP_POLICY_RESULT_USE_NETAGENT
||
1954 policy_result_type
== NECP_POLICY_RESULT_NETAGENT_SCOPED
||
1955 policy_result_type
== NECP_POLICY_RESULT_SCOPED_DIRECT
||
1956 policy_result_type
== NECP_POLICY_RESULT_ALLOW_UNENTITLED
) ? TRUE
: FALSE
;
1957 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
1958 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(buffer
, length
);
1959 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
1960 u_int8_t flags
= necp_policy_condition_get_flags_from_buffer(buffer
, length
);
1962 case NECP_POLICY_CONDITION_APPLICATION
:
1963 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
1964 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
1965 condition_length
>= sizeof(uuid_t
) &&
1966 condition_value
!= NULL
&&
1967 !uuid_is_null(condition_value
)) {
1972 case NECP_POLICY_CONDITION_DOMAIN
:
1973 case NECP_POLICY_CONDITION_ACCOUNT
:
1974 case NECP_POLICY_CONDITION_BOUND_INTERFACE
:
1975 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
: {
1976 if (condition_length
> 0) {
1981 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
1982 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
1987 case NECP_POLICY_CONDITION_DEFAULT
:
1988 case NECP_POLICY_CONDITION_ALL_INTERFACES
:
1989 case NECP_POLICY_CONDITION_ENTITLEMENT
:
1990 case NECP_POLICY_CONDITION_PLATFORM_BINARY
:
1991 case NECP_POLICY_CONDITION_HAS_CLIENT
:
1992 case NECP_POLICY_CONDITION_LOCAL_NETWORKS
: {
1993 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
)) {
1998 case NECP_POLICY_CONDITION_SDK_VERSION
: {
1999 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
2000 condition_length
>= sizeof(struct necp_policy_condition_sdk_version
)) {
2005 case NECP_POLICY_CONDITION_IP_PROTOCOL
: {
2006 if (condition_length
>= sizeof(u_int16_t
)) {
2011 case NECP_POLICY_CONDITION_PID
: {
2012 if (condition_length
>= sizeof(pid_t
) &&
2013 condition_value
!= NULL
&&
2014 *((pid_t
*)(void *)condition_value
) != 0) {
2019 case NECP_POLICY_CONDITION_UID
: {
2020 if (condition_length
>= sizeof(uid_t
)) {
2025 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
2026 case NECP_POLICY_CONDITION_REMOTE_ADDR
: {
2027 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr
) &&
2028 necp_address_is_valid(&((struct necp_policy_condition_addr
*)(void *)condition_value
)->address
.sa
)) {
2033 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
2034 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
: {
2035 if (!result_cannot_have_ip_layer
&& condition_length
>= sizeof(struct necp_policy_condition_addr_range
) &&
2036 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->start_address
.sa
) &&
2037 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->end_address
.sa
)) {
2042 case NECP_POLICY_CONDITION_AGENT_TYPE
: {
2043 if (!(flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
) &&
2044 condition_length
>= sizeof(struct necp_policy_condition_agent_type
)) {
2049 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
: {
2050 if (condition_length
>= sizeof(u_int16_t
)) {
2055 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
:
2056 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
: {
2057 if (condition_length
>= sizeof(struct necp_policy_condition_addr
) &&
2058 necp_address_is_valid(&((struct necp_policy_condition_addr
*)(void *)condition_value
)->address
.sa
)) {
2063 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
:
2064 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
: {
2065 if (condition_length
>= sizeof(struct necp_policy_condition_addr_range
) &&
2066 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->start_address
.sa
) &&
2067 necp_address_is_valid(&((struct necp_policy_condition_addr_range
*)(void *)condition_value
)->end_address
.sa
)) {
2072 case NECP_POLICY_CONDITION_CLIENT_FLAGS
: {
2073 if (condition_length
== 0 || condition_length
>= sizeof(u_int32_t
)) {
2078 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
: {
2082 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
: {
2086 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
: {
2087 if (condition_length
>= sizeof(u_int16_t
)) {
2088 u_int16_t packet_filter_tags
= *(u_int16_t
*)(void *)condition_value
;
2089 if (packet_filter_tags
> 0 && packet_filter_tags
<= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX
) {
2095 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK
: {
2099 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY
: {
2110 NECPLOG(LOG_DEBUG
, "Policy condition type %d, valid %d", type
, validated
);
2117 necp_policy_route_rule_is_default(u_int8_t
*buffer
, u_int32_t length
)
2119 return necp_policy_condition_get_value_length_from_buffer(buffer
, length
) == 0 &&
2120 necp_policy_condition_get_flags_from_buffer(buffer
, length
) == 0;
2124 necp_policy_route_rule_is_valid(u_int8_t
*buffer
, u_int32_t length
)
2126 bool validated
= FALSE
;
2127 u_int8_t type
= necp_policy_condition_get_type_from_buffer(buffer
, length
);
2129 case NECP_ROUTE_RULE_ALLOW_INTERFACE
: {
2133 case NECP_ROUTE_RULE_DENY_INTERFACE
: {
2137 case NECP_ROUTE_RULE_QOS_MARKING
: {
2141 case NECP_ROUTE_RULE_DENY_LQM_ABORT
: {
2145 case NECP_ROUTE_RULE_USE_NETAGENT
: {
2146 u_int32_t rule_length
= necp_policy_condition_get_value_length_from_buffer(buffer
, length
);
2147 validated
= (rule_length
>= sizeof(uuid_t
));
2157 NECPLOG(LOG_DEBUG
, "Policy route rule type %d, valid %d", type
, validated
);
2164 necp_get_posix_error_for_necp_error(int response_error
)
2166 switch (response_error
) {
2167 case NECP_ERROR_UNKNOWN_PACKET_TYPE
:
2168 case NECP_ERROR_INVALID_TLV
:
2169 case NECP_ERROR_POLICY_RESULT_INVALID
:
2170 case NECP_ERROR_POLICY_CONDITIONS_INVALID
:
2171 case NECP_ERROR_ROUTE_RULES_INVALID
: {
2174 case NECP_ERROR_POLICY_ID_NOT_FOUND
: {
2177 case NECP_ERROR_INVALID_PROCESS
: {
2180 case NECP_ERROR_INTERNAL
:
2187 static necp_policy_id
2188 necp_handle_policy_add(struct necp_session
*session
,
2189 u_int8_t
*tlv_buffer
, size_t tlv_buffer_length
, int offset
, int *return_error
)
2191 bool has_default_condition
= FALSE
;
2192 bool has_non_default_condition
= FALSE
;
2193 bool has_application_condition
= FALSE
;
2194 bool has_real_application_condition
= FALSE
;
2195 bool requires_application_condition
= FALSE
;
2196 bool requires_real_application_condition
= FALSE
;
2197 u_int8_t
*conditions_array
= NULL
;
2198 u_int32_t conditions_array_size
= 0;
2199 int conditions_array_cursor
;
2201 bool has_default_route_rule
= FALSE
;
2202 u_int8_t
*route_rules_array
= NULL
;
2203 u_int32_t route_rules_array_size
= 0;
2204 int route_rules_array_cursor
;
2208 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
2210 necp_policy_order order
= 0;
2211 struct necp_session_policy
*policy
= NULL
;
2212 u_int8_t
*policy_result
= NULL
;
2213 u_int32_t policy_result_size
= 0;
2215 // Read policy order
2216 error
= necp_get_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_ORDER
, sizeof(order
), &order
, NULL
);
2218 NECPLOG(LOG_ERR
, "Failed to get policy order: %d", error
);
2219 response_error
= NECP_ERROR_INVALID_TLV
;
2223 // Read policy result
2224 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_RESULT
, &error
, 0);
2225 if (error
|| cursor
< 0) {
2226 NECPLOG(LOG_ERR
, "Failed to find policy result TLV: %d", error
);
2227 response_error
= NECP_ERROR_INVALID_TLV
;
2230 error
= necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &policy_result_size
);
2231 if (error
|| policy_result_size
== 0) {
2232 NECPLOG(LOG_ERR
, "Failed to get policy result length: %d", error
);
2233 response_error
= NECP_ERROR_INVALID_TLV
;
2236 if (policy_result_size
> NECP_MAX_POLICY_RESULT_SIZE
) {
2237 NECPLOG(LOG_ERR
, "Policy result length too large: %u", policy_result_size
);
2238 response_error
= NECP_ERROR_INVALID_TLV
;
2241 MALLOC(policy_result
, u_int8_t
*, policy_result_size
, M_NECP
, M_WAITOK
);
2242 if (policy_result
== NULL
) {
2243 NECPLOG(LOG_ERR
, "Failed to allocate a policy result buffer (size %d)", policy_result_size
);
2244 response_error
= NECP_ERROR_INTERNAL
;
2247 error
= necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, policy_result_size
, policy_result
, NULL
);
2249 NECPLOG(LOG_ERR
, "Failed to get policy result: %d", error
);
2250 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
2253 if (!necp_policy_result_is_valid(policy_result
, policy_result_size
)) {
2254 NECPLOG0(LOG_ERR
, "Failed to validate policy result");
2255 response_error
= NECP_ERROR_POLICY_RESULT_INVALID
;
2259 if (necp_policy_result_requires_route_rules(policy_result
, policy_result_size
)) {
2260 // Read route rules conditions
2261 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
2263 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
2264 u_int32_t route_rule_size
= 0;
2265 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &route_rule_size
);
2266 if (os_add_overflow(route_rules_array_size
,
2267 (sizeof(u_int8_t
) + sizeof(u_int32_t
) + route_rule_size
),
2268 &route_rules_array_size
)) {
2269 NECPLOG0(LOG_ERR
, "Route rules size overflowed, too large");
2270 response_error
= NECP_ERROR_INVALID_TLV
;
2275 if (route_rules_array_size
== 0) {
2276 NECPLOG0(LOG_ERR
, "Failed to get policy route rules");
2277 response_error
= NECP_ERROR_INVALID_TLV
;
2280 if (route_rules_array_size
> NECP_MAX_ROUTE_RULES_ARRAY_SIZE
) {
2281 NECPLOG(LOG_ERR
, "Route rules length too large: %u", route_rules_array_size
);
2282 response_error
= NECP_ERROR_INVALID_TLV
;
2285 MALLOC(route_rules_array
, u_int8_t
*, route_rules_array_size
, M_NECP
, M_WAITOK
);
2286 if (route_rules_array
== NULL
) {
2287 NECPLOG(LOG_ERR
, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size
);
2288 response_error
= NECP_ERROR_INTERNAL
;
2292 route_rules_array_cursor
= 0;
2293 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_ROUTE_RULE
, &error
, 0);
2295 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_ROUTE_RULE
, &error
, 1)) {
2296 u_int8_t route_rule_type
= NECP_TLV_ROUTE_RULE
;
2297 u_int32_t route_rule_size
= 0;
2298 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &route_rule_size
);
2299 if (route_rule_size
> 0 &&
2300 (sizeof(route_rule_type
) + sizeof(route_rule_size
) + route_rule_size
) <= (route_rules_array_size
- route_rules_array_cursor
)) {
2302 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_type
, sizeof(route_rule_type
));
2303 route_rules_array_cursor
+= sizeof(route_rule_type
);
2306 memcpy((route_rules_array
+ route_rules_array_cursor
), &route_rule_size
, sizeof(route_rule_size
));
2307 route_rules_array_cursor
+= sizeof(route_rule_size
);
2310 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, route_rule_size
, (route_rules_array
+ route_rules_array_cursor
), NULL
);
2312 if (!necp_policy_route_rule_is_valid((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
2313 NECPLOG0(LOG_ERR
, "Failed to validate policy route rule");
2314 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
2318 if (necp_policy_route_rule_is_default((route_rules_array
+ route_rules_array_cursor
), route_rule_size
)) {
2319 if (has_default_route_rule
) {
2320 NECPLOG0(LOG_ERR
, "Failed to validate route rule; contained multiple default route rules");
2321 response_error
= NECP_ERROR_ROUTE_RULES_INVALID
;
2324 has_default_route_rule
= TRUE
;
2327 route_rules_array_cursor
+= route_rule_size
;
2332 // Read policy conditions
2333 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
2335 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
2336 u_int32_t condition_size
= 0;
2337 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &condition_size
);
2339 if (condition_size
> 0) {
2340 if (os_add_overflow(conditions_array_size
,
2341 (sizeof(u_int8_t
) + sizeof(u_int32_t
) + condition_size
),
2342 &conditions_array_size
)) {
2343 NECPLOG0(LOG_ERR
, "Conditions size overflowed, too large");
2344 response_error
= NECP_ERROR_INVALID_TLV
;
2350 if (conditions_array_size
== 0) {
2351 NECPLOG0(LOG_ERR
, "Failed to get policy conditions");
2352 response_error
= NECP_ERROR_INVALID_TLV
;
2355 if (conditions_array_size
> NECP_MAX_CONDITIONS_ARRAY_SIZE
) {
2356 NECPLOG(LOG_ERR
, "Conditions length too large: %u", conditions_array_size
);
2357 response_error
= NECP_ERROR_INVALID_TLV
;
2360 MALLOC(conditions_array
, u_int8_t
*, conditions_array_size
, M_NECP
, M_WAITOK
);
2361 if (conditions_array
== NULL
) {
2362 NECPLOG(LOG_ERR
, "Failed to allocate a policy conditions array (size %d)", conditions_array_size
);
2363 response_error
= NECP_ERROR_INTERNAL
;
2367 conditions_array_cursor
= 0;
2368 for (cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, offset
, NECP_TLV_POLICY_CONDITION
, &error
, 0);
2370 cursor
= necp_find_tlv(tlv_buffer
, tlv_buffer_length
, cursor
, NECP_TLV_POLICY_CONDITION
, &error
, 1)) {
2371 u_int8_t condition_type
= NECP_TLV_POLICY_CONDITION
;
2372 u_int32_t condition_size
= 0;
2373 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, 0, NULL
, &condition_size
);
2374 if (condition_size
> 0 &&
2375 (sizeof(condition_type
) + sizeof(condition_size
) + condition_size
) <= (conditions_array_size
- conditions_array_cursor
)) {
2377 memcpy((conditions_array
+ conditions_array_cursor
), &condition_type
, sizeof(condition_type
));
2378 conditions_array_cursor
+= sizeof(condition_type
);
2381 memcpy((conditions_array
+ conditions_array_cursor
), &condition_size
, sizeof(condition_size
));
2382 conditions_array_cursor
+= sizeof(condition_size
);
2385 necp_get_tlv_at_offset(tlv_buffer
, tlv_buffer_length
, cursor
, condition_size
, (conditions_array
+ conditions_array_cursor
), NULL
);
2386 if (!necp_policy_condition_is_valid((conditions_array
+ conditions_array_cursor
), condition_size
, necp_policy_result_get_type_from_buffer(policy_result
, policy_result_size
))) {
2387 NECPLOG0(LOG_ERR
, "Failed to validate policy condition");
2388 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2392 if (necp_policy_condition_is_default((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2393 has_default_condition
= TRUE
;
2395 has_non_default_condition
= TRUE
;
2397 if (has_default_condition
&& has_non_default_condition
) {
2398 NECPLOG0(LOG_ERR
, "Failed to validate conditions; contained default and non-default conditions");
2399 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2403 if (necp_policy_condition_is_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2404 has_application_condition
= TRUE
;
2407 if (necp_policy_condition_is_real_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2408 has_real_application_condition
= TRUE
;
2411 if (necp_policy_condition_requires_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2412 requires_application_condition
= TRUE
;
2415 if (necp_policy_condition_requires_real_application((conditions_array
+ conditions_array_cursor
), condition_size
)) {
2416 requires_real_application_condition
= TRUE
;
2419 conditions_array_cursor
+= condition_size
;
2423 if (requires_application_condition
&& !has_application_condition
) {
2424 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain application condition");
2425 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2429 if (requires_real_application_condition
&& !has_real_application_condition
) {
2430 NECPLOG0(LOG_ERR
, "Failed to validate conditions; did not contain real application condition");
2431 response_error
= NECP_ERROR_POLICY_CONDITIONS_INVALID
;
2435 if ((policy
= necp_policy_create(session
, order
, conditions_array
, conditions_array_size
, route_rules_array
, route_rules_array_size
, policy_result
, policy_result_size
)) == NULL
) {
2436 response_error
= NECP_ERROR_INTERNAL
;
2440 return policy
->local_id
;
2443 if (policy_result
!= NULL
) {
2444 FREE(policy_result
, M_NECP
);
2446 if (conditions_array
!= NULL
) {
2447 FREE(conditions_array
, M_NECP
);
2449 if (route_rules_array
!= NULL
) {
2450 FREE(route_rules_array
, M_NECP
);
2453 if (return_error
!= NULL
) {
2454 *return_error
= necp_get_posix_error_for_necp_error(response_error
);
2459 static necp_policy_id
2460 necp_policy_get_new_id(struct necp_session
*session
)
2462 session
->last_policy_id
++;
2463 if (session
->last_policy_id
< 1) {
2464 session
->last_policy_id
= 1;
2467 necp_policy_id newid
= session
->last_policy_id
;
2470 NECPLOG0(LOG_ERR
, "Allocate policy id failed.\n");
2478 * For the policy dump response this is the structure:
2480 * <NECP_PACKET_HEADER>
2482 * type : NECP_TLV_POLICY_DUMP
2487 * type : NECP_TLV_POLICY_ID
2492 * type : NECP_TLV_POLICY_ORDER
2497 * type : NECP_TLV_POLICY_RESULT_STRING
2502 * type : NECP_TLV_POLICY_OWNER
2507 * type : NECP_TLV_POLICY_CONDITION
2512 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2517 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2527 * type : NECP_TLV_POLICY_DUMP
2532 * type : NECP_TLV_POLICY_ID
2537 * type : NECP_TLV_POLICY_ORDER
2542 * type : NECP_TLV_POLICY_RESULT_STRING
2547 * type : NECP_TLV_POLICY_OWNER
2552 * type : NECP_TLV_POLICY_CONDITION
2557 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2562 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2574 necp_handle_policy_dump_all(user_addr_t out_buffer
, size_t out_buffer_length
)
2576 struct necp_kernel_socket_policy
*policy
= NULL
;
2578 int policy_count
= 0;
2579 u_int8_t
**tlv_buffer_pointers
= NULL
;
2580 u_int32_t
*tlv_buffer_lengths
= NULL
;
2581 u_int32_t total_tlv_len
= 0;
2582 u_int8_t
*result_buf
= NULL
;
2583 u_int8_t
*result_buf_cursor
= result_buf
;
2584 char result_string
[MAX_RESULT_STRING_LEN
];
2585 char proc_name_string
[MAXCOMLEN
+ 1];
2588 bool error_occured
= false;
2589 u_int32_t response_error
= NECP_ERROR_INTERNAL
;
2591 #define REPORT_ERROR(error) error_occured = true; \
2592 response_error = error; \
2595 #define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
2598 errno_t cred_result
= priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0);
2599 if (cred_result
!= 0) {
2600 NECPLOG0(LOG_ERR
, "Session does not hold the necessary entitlement to get Network Extension Policy information");
2601 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2605 lck_rw_lock_shared(&necp_kernel_policy_lock
);
2608 NECPLOG0(LOG_DEBUG
, "Gathering policies");
2611 policy_count
= necp_kernel_application_policies_count
;
2613 MALLOC(tlv_buffer_pointers
, u_int8_t
* *, sizeof(u_int8_t
*) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2614 if (tlv_buffer_pointers
== NULL
) {
2615 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t
*) * policy_count
);
2616 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2619 MALLOC(tlv_buffer_lengths
, u_int32_t
*, sizeof(u_int32_t
) * policy_count
, M_NECP
, M_NOWAIT
| M_ZERO
);
2620 if (tlv_buffer_lengths
== NULL
) {
2621 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t
) * policy_count
);
2622 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock
, NECP_ERROR_INTERNAL
);
2625 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
2626 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
2628 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
2629 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
2631 necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
);
2632 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
2634 u_int16_t proc_name_len
= strlen(proc_name_string
) + 1;
2635 u_int16_t result_string_len
= strlen(result_string
) + 1;
2638 NECPLOG(LOG_DEBUG
, "Policy: process: %s, result: %s", proc_name_string
, result_string
);
2641 u_int32_t total_allocated_bytes
= sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->id
) + // NECP_TLV_POLICY_ID
2642 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->order
) + // NECP_TLV_POLICY_ORDER
2643 sizeof(u_int8_t
) + sizeof(u_int32_t
) + sizeof(policy
->session_order
) + // NECP_TLV_POLICY_SESSION_ORDER
2644 sizeof(u_int8_t
) + sizeof(u_int32_t
) + result_string_len
+ // NECP_TLV_POLICY_RESULT_STRING
2645 sizeof(u_int8_t
) + sizeof(u_int32_t
) + proc_name_len
+ // NECP_TLV_POLICY_OWNER
2646 sizeof(u_int8_t
) + sizeof(u_int32_t
); // NECP_TLV_POLICY_CONDITION
2648 // We now traverse the condition_mask to see how much space we need to allocate
2649 u_int32_t condition_mask
= policy
->condition_mask
;
2650 u_int8_t num_conditions
= 0;
2651 struct necp_string_id_mapping
*account_id_entry
= NULL
;
2652 char if_name
[IFXNAMSIZ
];
2653 u_int32_t condition_tlv_length
= 0;
2654 memset(if_name
, 0, sizeof(if_name
));
2656 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2659 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2662 if (condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
2665 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2666 snprintf(if_name
, IFXNAMSIZ
, "%s%d", ifnet_name(policy
->cond_bound_interface
), ifnet_unit(policy
->cond_bound_interface
));
2667 condition_tlv_length
+= strlen(if_name
) + 1;
2670 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2671 condition_tlv_length
+= sizeof(policy
->cond_protocol
);
2674 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2675 condition_tlv_length
+= sizeof(uuid_t
);
2678 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2679 condition_tlv_length
+= sizeof(uuid_t
);
2682 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2683 u_int32_t domain_len
= strlen(policy
->cond_domain
) + 1;
2684 condition_tlv_length
+= domain_len
;
2687 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2688 account_id_entry
= necp_lookup_string_with_id_locked(&necp_account_id_list
, policy
->cond_account_id
);
2689 u_int32_t account_id_len
= 0;
2690 if (account_id_entry
) {
2691 account_id_len
= account_id_entry
->string
? strlen(account_id_entry
->string
) + 1 : 0;
2693 condition_tlv_length
+= account_id_len
;
2696 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2697 condition_tlv_length
+= (sizeof(pid_t
) + sizeof(int32_t));
2700 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2701 condition_tlv_length
+= sizeof(uid_t
);
2704 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2705 condition_tlv_length
+= sizeof(struct necp_policy_condition_tc_range
);
2708 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2711 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2712 u_int32_t entitlement_len
= strlen(policy
->cond_custom_entitlement
) + 1;
2713 condition_tlv_length
+= entitlement_len
;
2716 if (condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
2719 if (condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
2720 condition_tlv_length
+= sizeof(struct necp_policy_condition_sdk_version
);
2723 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
2726 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2727 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2728 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2730 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2734 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2735 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2736 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr_range
);
2738 condition_tlv_length
+= sizeof(struct necp_policy_condition_addr
);
2742 if (condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
2743 condition_tlv_length
+= sizeof(struct necp_policy_condition_agent_type
);
2746 if (condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
2747 condition_tlv_length
+= sizeof(u_int32_t
);
2750 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
2753 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
2756 if (condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
2757 u_int32_t identifier_len
= strlen(policy
->cond_signing_identifier
) + 1;
2758 condition_tlv_length
+= identifier_len
;
2761 if (condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
2762 condition_tlv_length
+= sizeof(u_int16_t
);
2765 if (condition_mask
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) {
2768 if (condition_mask
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) {
2773 condition_tlv_length
+= num_conditions
* (sizeof(u_int8_t
) + sizeof(u_int32_t
)); // These are for the condition TLVs. The space for "value" is already accounted for above.
2774 total_allocated_bytes
+= condition_tlv_length
;
2776 u_int8_t
*tlv_buffer
;
2777 MALLOC(tlv_buffer
, u_int8_t
*, total_allocated_bytes
, M_NECP
, M_NOWAIT
| M_ZERO
);
2778 if (tlv_buffer
== NULL
) {
2779 NECPLOG(LOG_DEBUG
, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes
);
2783 u_int8_t
*cursor
= tlv_buffer
;
2784 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ID
, sizeof(policy
->id
), &policy
->id
, tlv_buffer
, total_allocated_bytes
);
2785 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_ORDER
, sizeof(necp_policy_order
), &policy
->order
, tlv_buffer
, total_allocated_bytes
);
2786 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_SESSION_ORDER
, sizeof(policy
->session_order
), &policy
->session_order
, tlv_buffer
, total_allocated_bytes
);
2787 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_RESULT_STRING
, result_string_len
, result_string
, tlv_buffer
, total_allocated_bytes
);
2788 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_OWNER
, proc_name_len
, proc_name_string
, tlv_buffer
, total_allocated_bytes
);
2791 u_int8_t q_cond_buf
[N_QUICK
]; // Minor optimization
2793 u_int8_t
*cond_buf
; // To be used for condition TLVs
2794 if (condition_tlv_length
<= N_QUICK
) {
2795 cond_buf
= q_cond_buf
;
2797 MALLOC(cond_buf
, u_int8_t
*, condition_tlv_length
, M_NECP
, M_NOWAIT
);
2798 if (cond_buf
== NULL
) {
2799 NECPLOG(LOG_DEBUG
, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length
);
2800 FREE(tlv_buffer
, M_NECP
);
2805 memset(cond_buf
, 0, condition_tlv_length
);
2806 u_int8_t
*cond_buf_cursor
= cond_buf
;
2807 if (condition_mask
== NECP_POLICY_CONDITION_DEFAULT
) {
2808 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DEFAULT
, 0, "", cond_buf
, condition_tlv_length
);
2810 if (condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) {
2811 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ALL_INTERFACES
, 0, "", cond_buf
, condition_tlv_length
);
2813 if (condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
2814 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_HAS_CLIENT
, 0, "", cond_buf
, condition_tlv_length
);
2816 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
2817 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_NETWORKS
, 0, "", cond_buf
, condition_tlv_length
);
2819 if (condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
2820 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_BOUND_INTERFACE
, strlen(if_name
) + 1,
2821 if_name
, cond_buf
, condition_tlv_length
);
2823 if (condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
2824 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_IP_PROTOCOL
, sizeof(policy
->cond_protocol
), &policy
->cond_protocol
,
2825 cond_buf
, condition_tlv_length
);
2827 if (condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
2828 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_app_id
);
2829 if (entry
!= NULL
) {
2830 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
,
2831 cond_buf
, condition_tlv_length
);
2834 if (condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
2835 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(policy
->cond_real_app_id
);
2836 if (entry
!= NULL
) {
2837 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REAL_APPLICATION
, sizeof(entry
->uuid
), entry
->uuid
,
2838 cond_buf
, condition_tlv_length
);
2841 if (condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
2842 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DOMAIN
, strlen(policy
->cond_domain
) + 1, policy
->cond_domain
,
2843 cond_buf
, condition_tlv_length
);
2845 if (condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
2846 if (account_id_entry
!= NULL
) {
2847 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ACCOUNT
, strlen(account_id_entry
->string
) + 1, account_id_entry
->string
,
2848 cond_buf
, condition_tlv_length
);
2851 if (condition_mask
& NECP_KERNEL_CONDITION_PID
) {
2852 uint8_t pid_buffer
[sizeof(policy
->cond_pid
) + sizeof(policy
->cond_pid_version
)] = { };
2853 memcpy(pid_buffer
, &policy
->cond_pid
, sizeof(policy
->cond_pid
));
2854 memcpy(pid_buffer
+ sizeof(policy
->cond_pid
), &policy
->cond_pid_version
, sizeof(policy
->cond_pid_version
));
2855 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PID
, sizeof(pid_buffer
), &pid_buffer
,
2856 cond_buf
, condition_tlv_length
);
2858 if (condition_mask
& NECP_KERNEL_CONDITION_UID
) {
2859 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_UID
, sizeof(policy
->cond_uid
), &policy
->cond_uid
,
2860 cond_buf
, condition_tlv_length
);
2862 if (condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
2863 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_TRAFFIC_CLASS
, sizeof(policy
->cond_traffic_class
), &policy
->cond_traffic_class
,
2864 cond_buf
, condition_tlv_length
);
2866 if (condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
2867 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, 0, "",
2868 cond_buf
, condition_tlv_length
);
2870 if (condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
2871 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_ENTITLEMENT
, strlen(policy
->cond_custom_entitlement
) + 1, policy
->cond_custom_entitlement
,
2872 cond_buf
, condition_tlv_length
);
2874 if (condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
2875 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PLATFORM_BINARY
, 0, "", cond_buf
, condition_tlv_length
);
2877 if (condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
2878 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_SDK_VERSION
,
2879 sizeof(policy
->cond_sdk_version
), &policy
->cond_sdk_version
,
2880 cond_buf
, condition_tlv_length
);
2882 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
2883 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
2884 struct necp_policy_condition_addr_range range
;
2885 memcpy(&range
.start_address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2886 memcpy(&range
.end_address
, &policy
->cond_local_end
, sizeof(policy
->cond_local_end
));
2887 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
, sizeof(range
), &range
,
2888 cond_buf
, condition_tlv_length
);
2890 struct necp_policy_condition_addr addr
;
2891 addr
.prefix
= policy
->cond_local_prefix
;
2892 memcpy(&addr
.address
, &policy
->cond_local_start
, sizeof(policy
->cond_local_start
));
2893 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_LOCAL_ADDR
, sizeof(addr
), &addr
,
2894 cond_buf
, condition_tlv_length
);
2897 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
2898 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
2899 struct necp_policy_condition_addr_range range
;
2900 memcpy(&range
.start_address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2901 memcpy(&range
.end_address
, &policy
->cond_remote_end
, sizeof(policy
->cond_remote_end
));
2902 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
, sizeof(range
), &range
,
2903 cond_buf
, condition_tlv_length
);
2905 struct necp_policy_condition_addr addr
;
2906 addr
.prefix
= policy
->cond_remote_prefix
;
2907 memcpy(&addr
.address
, &policy
->cond_remote_start
, sizeof(policy
->cond_remote_start
));
2908 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_REMOTE_ADDR
, sizeof(addr
), &addr
,
2909 cond_buf
, condition_tlv_length
);
2912 if (condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
2913 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_AGENT_TYPE
,
2914 sizeof(policy
->cond_agent_type
), &policy
->cond_agent_type
,
2915 cond_buf
, condition_tlv_length
);
2917 if (condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
2918 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_CLIENT_FLAGS
, sizeof(policy
->cond_client_flags
), &policy
->cond_client_flags
, cond_buf
, condition_tlv_length
);
2920 if (condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
2921 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
, 0, "", cond_buf
, condition_tlv_length
);
2923 if (condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
2924 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
, 0, "", cond_buf
, condition_tlv_length
);
2926 if (condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
2927 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
, strlen(policy
->cond_signing_identifier
) + 1, policy
->cond_signing_identifier
,
2928 cond_buf
, condition_tlv_length
);
2930 if (condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
2931 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
, sizeof(policy
->cond_packet_filter_tags
), &policy
->cond_packet_filter_tags
, cond_buf
, condition_tlv_length
);
2933 if (condition_mask
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) {
2934 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK
, 0, "", cond_buf
, condition_tlv_length
);
2936 if (condition_mask
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) {
2937 cond_buf_cursor
= necp_buffer_write_tlv(cond_buf_cursor
, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY
, 0, "", cond_buf
, condition_tlv_length
);
2941 cursor
= necp_buffer_write_tlv(cursor
, NECP_TLV_POLICY_CONDITION
, cond_buf_cursor
- cond_buf
, cond_buf
, tlv_buffer
, total_allocated_bytes
);
2942 if (cond_buf
!= q_cond_buf
) {
2943 FREE(cond_buf
, M_NECP
);
2946 tlv_buffer_pointers
[policy_i
] = tlv_buffer
;
2947 tlv_buffer_lengths
[policy_i
] = (cursor
- tlv_buffer
);
2949 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
2950 total_tlv_len
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + (cursor
- tlv_buffer
);
2954 lck_rw_done(&necp_kernel_policy_lock
);
2957 if (out_buffer
!= 0) {
2958 if (out_buffer_length
< total_tlv_len
+ sizeof(u_int32_t
)) {
2959 NECPLOG(LOG_DEBUG
, "out_buffer_length too small (%lu < %lu)", out_buffer_length
, total_tlv_len
+ sizeof(u_int32_t
));
2960 REPORT_ERROR(NECP_ERROR_INVALID_TLV
);
2963 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
2964 MALLOC(result_buf
, u_int8_t
*, total_tlv_len
+ sizeof(u_int32_t
), M_NECP
, M_WAITOK
| M_ZERO
);
2965 if (result_buf
== NULL
) {
2966 NECPLOG(LOG_DEBUG
, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len
+ sizeof(u_int32_t
));
2967 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2970 // Add four bytes for total length at the start
2971 memcpy(result_buf
, &total_tlv_len
, sizeof(u_int32_t
));
2974 result_buf_cursor
= result_buf
+ sizeof(u_int32_t
);
2975 for (int i
= 0; i
< policy_count
; i
++) {
2976 if (tlv_buffer_pointers
[i
] != NULL
) {
2977 result_buf_cursor
= necp_buffer_write_tlv(result_buf_cursor
, NECP_TLV_POLICY_DUMP
, tlv_buffer_lengths
[i
], tlv_buffer_pointers
[i
],
2978 result_buf
, total_tlv_len
+ sizeof(u_int32_t
));
2982 int copy_error
= copyout(result_buf
, out_buffer
, total_tlv_len
+ sizeof(u_int32_t
));
2984 NECPLOG(LOG_DEBUG
, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len
+ sizeof(u_int32_t
));
2985 REPORT_ERROR(NECP_ERROR_INTERNAL
);
2991 if (error_occured
) {
2992 error_code
= necp_get_posix_error_for_necp_error(response_error
);
2995 if (result_buf
!= NULL
) {
2996 FREE(result_buf
, M_NECP
);
2999 if (tlv_buffer_pointers
!= NULL
) {
3000 for (int i
= 0; i
< policy_count
; i
++) {
3001 if (tlv_buffer_pointers
[i
] != NULL
) {
3002 FREE(tlv_buffer_pointers
[i
], M_NECP
);
3003 tlv_buffer_pointers
[i
] = NULL
;
3006 FREE(tlv_buffer_pointers
, M_NECP
);
3009 if (tlv_buffer_lengths
!= NULL
) {
3010 FREE(tlv_buffer_lengths
, M_NECP
);
3013 #undef RESET_COND_BUF
3015 #undef UNLOCK_AND_REPORT_ERROR
3020 static struct necp_session_policy
*
3021 necp_policy_create(struct necp_session
*session
, necp_policy_order order
, u_int8_t
*conditions_array
, u_int32_t conditions_array_size
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
, u_int8_t
*result
, u_int32_t result_size
)
3023 struct necp_session_policy
*new_policy
= NULL
;
3024 struct necp_session_policy
*tmp_policy
= NULL
;
3026 if (session
== NULL
|| conditions_array
== NULL
|| result
== NULL
|| result_size
== 0) {
3030 new_policy
= zalloc_flags(necp_session_policy_zone
, Z_WAITOK
| Z_ZERO
);
3031 new_policy
->applied
= FALSE
;
3032 new_policy
->pending_deletion
= FALSE
;
3033 new_policy
->pending_update
= FALSE
;
3034 new_policy
->order
= order
;
3035 new_policy
->conditions
= conditions_array
;
3036 new_policy
->conditions_size
= conditions_array_size
;
3037 new_policy
->route_rules
= route_rules_array
;
3038 new_policy
->route_rules_size
= route_rules_array_size
;
3039 new_policy
->result
= result
;
3040 new_policy
->result_size
= result_size
;
3041 new_policy
->local_id
= necp_policy_get_new_id(session
);
3043 LIST_INSERT_SORTED_ASCENDING(&session
->policies
, new_policy
, chain
, order
, tmp_policy
);
3045 session
->dirty
= TRUE
;
3048 NECPLOG(LOG_DEBUG
, "Created NECP policy, order %d", order
);
3054 static struct necp_session_policy
*
3055 necp_policy_find(struct necp_session
*session
, necp_policy_id policy_id
)
3057 struct necp_session_policy
*policy
= NULL
;
3058 if (policy_id
== 0) {
3062 LIST_FOREACH(policy
, &session
->policies
, chain
) {
3063 if (policy
->local_id
== policy_id
) {
3071 static inline u_int8_t
3072 necp_policy_get_result_type(struct necp_session_policy
*policy
)
3074 return policy
? necp_policy_result_get_type_from_buffer(policy
->result
, policy
->result_size
) : 0;
3077 static inline u_int32_t
3078 necp_policy_get_result_parameter_length(struct necp_session_policy
*policy
)
3080 return policy
? necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) : 0;
3084 necp_policy_get_result_parameter(struct necp_session_policy
*policy
, u_int8_t
*parameter_buffer
, u_int32_t parameter_buffer_length
)
3087 u_int32_t parameter_length
= necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
);
3088 if (parameter_buffer_length
>= parameter_length
) {
3089 u_int8_t
*parameter
= necp_policy_result_get_parameter_pointer_from_buffer(policy
->result
, policy
->result_size
);
3090 if (parameter
&& parameter_buffer
) {
3091 memcpy(parameter_buffer
, parameter
, parameter_length
);
3101 necp_policy_mark_for_deletion(struct necp_session
*session
, struct necp_session_policy
*policy
)
3103 if (session
== NULL
|| policy
== NULL
) {
3107 policy
->pending_deletion
= TRUE
;
3108 session
->dirty
= TRUE
;
3111 NECPLOG0(LOG_DEBUG
, "Marked NECP policy for removal");
3117 necp_policy_mark_all_for_deletion(struct necp_session
*session
)
3119 struct necp_session_policy
*policy
= NULL
;
3120 struct necp_session_policy
*temp_policy
= NULL
;
3122 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
3123 necp_policy_mark_for_deletion(session
, policy
);
3130 necp_policy_delete(struct necp_session
*session
, struct necp_session_policy
*policy
)
3132 if (session
== NULL
|| policy
== NULL
) {
3136 LIST_REMOVE(policy
, chain
);
3138 if (policy
->result
) {
3139 FREE(policy
->result
, M_NECP
);
3140 policy
->result
= NULL
;
3143 if (policy
->conditions
) {
3144 FREE(policy
->conditions
, M_NECP
);
3145 policy
->conditions
= NULL
;
3148 if (policy
->route_rules
) {
3149 FREE(policy
->route_rules
, M_NECP
);
3150 policy
->route_rules
= NULL
;
3153 zfree(necp_session_policy_zone
, policy
);
3156 NECPLOG0(LOG_DEBUG
, "Removed NECP policy");
3162 necp_policy_unapply(struct necp_session_policy
*policy
)
3165 if (policy
== NULL
) {
3169 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3171 // Release local uuid mappings
3172 if (!uuid_is_null(policy
->applied_app_uuid
)) {
3173 bool removed_mapping
= FALSE
;
3174 if (necp_remove_uuid_app_id_mapping(policy
->applied_app_uuid
, &removed_mapping
, TRUE
) && removed_mapping
) {
3175 necp_uuid_app_id_mappings_dirty
= TRUE
;
3176 necp_num_uuid_app_id_mappings
--;
3178 uuid_clear(policy
->applied_app_uuid
);
3180 if (!uuid_is_null(policy
->applied_real_app_uuid
)) {
3181 necp_remove_uuid_app_id_mapping(policy
->applied_real_app_uuid
, NULL
, FALSE
);
3182 uuid_clear(policy
->applied_real_app_uuid
);
3184 if (!uuid_is_null(policy
->applied_result_uuid
)) {
3185 necp_remove_uuid_service_id_mapping(policy
->applied_result_uuid
);
3186 uuid_clear(policy
->applied_result_uuid
);
3189 // Release string mappings
3190 if (policy
->applied_account
!= NULL
) {
3191 necp_remove_string_to_id_mapping(&necp_account_id_list
, policy
->applied_account
);
3192 FREE(policy
->applied_account
, M_NECP
);
3193 policy
->applied_account
= NULL
;
3196 // Release route rule
3197 if (policy
->applied_route_rules_id
!= 0) {
3198 necp_remove_route_rule(&necp_route_rules
, policy
->applied_route_rules_id
);
3199 policy
->applied_route_rules_id
= 0;
3202 // Remove socket policies
3203 for (i
= 0; i
< MAX_KERNEL_SOCKET_POLICIES
; i
++) {
3204 if (policy
->kernel_socket_policies
[i
] != 0) {
3205 necp_kernel_socket_policy_delete(policy
->kernel_socket_policies
[i
]);
3206 policy
->kernel_socket_policies
[i
] = 0;
3210 // Remove IP output policies
3211 for (i
= 0; i
< MAX_KERNEL_IP_OUTPUT_POLICIES
; i
++) {
3212 if (policy
->kernel_ip_output_policies
[i
] != 0) {
3213 necp_kernel_ip_output_policy_delete(policy
->kernel_ip_output_policies
[i
]);
3214 policy
->kernel_ip_output_policies
[i
] = 0;
3218 policy
->applied
= FALSE
;
3223 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
3224 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
3225 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
3226 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
3227 struct necp_policy_result_ip_tunnel
{
3228 u_int32_t secondary_result
;
3229 char interface_name
[IFXNAMSIZ
];
3230 } __attribute__((__packed__
));
3232 struct necp_policy_result_service
{
3235 } __attribute__((__packed__
));
3238 necp_policy_apply(struct necp_session
*session
, struct necp_session_policy
*policy
)
3240 bool socket_only_conditions
= FALSE
;
3241 bool socket_ip_conditions
= FALSE
;
3243 bool socket_layer_non_id_conditions
= FALSE
;
3244 bool ip_output_layer_non_id_conditions
= FALSE
;
3245 bool ip_output_layer_non_id_only
= FALSE
;
3246 bool ip_output_layer_id_condition
= FALSE
;
3247 bool ip_output_layer_tunnel_condition_from_id
= FALSE
;
3248 bool ip_output_layer_tunnel_condition_from_non_id
= FALSE
;
3249 necp_kernel_policy_id cond_ip_output_layer_id
= NECP_KERNEL_POLICY_ID_NONE
;
3251 u_int32_t master_condition_mask
= 0;
3252 u_int32_t master_condition_negated_mask
= 0;
3253 ifnet_t cond_bound_interface
= NULL
;
3254 u_int32_t cond_account_id
= 0;
3255 char *cond_domain
= NULL
;
3256 char *cond_custom_entitlement
= NULL
;
3257 char *cond_signing_identifier
= NULL
;
3259 int32_t cond_pid_version
= 0;
3261 necp_app_id cond_app_id
= 0;
3262 necp_app_id cond_real_app_id
= 0;
3263 struct necp_policy_condition_tc_range cond_traffic_class
;
3264 cond_traffic_class
.start_tc
= 0;
3265 cond_traffic_class
.end_tc
= 0;
3266 u_int16_t cond_protocol
= 0;
3267 union necp_sockaddr_union cond_local_start
;
3268 union necp_sockaddr_union cond_local_end
;
3269 u_int8_t cond_local_prefix
= 0;
3270 union necp_sockaddr_union cond_remote_start
;
3271 union necp_sockaddr_union cond_remote_end
;
3272 u_int8_t cond_remote_prefix
= 0;
3273 u_int32_t cond_client_flags
= 0;
3274 u_int32_t offset
= 0;
3275 u_int8_t ultimate_result
= 0;
3276 u_int32_t secondary_result
= 0;
3277 struct necp_policy_condition_agent_type cond_agent_type
= {};
3278 struct necp_policy_condition_sdk_version cond_sdk_version
= {};
3279 u_int16_t cond_packet_filter_tags
= 0;
3280 necp_kernel_policy_result_parameter secondary_result_parameter
;
3281 memset(&secondary_result_parameter
, 0, sizeof(secondary_result_parameter
));
3282 u_int32_t cond_last_interface_index
= 0;
3283 necp_kernel_policy_result_parameter ultimate_result_parameter
;
3284 memset(&ultimate_result_parameter
, 0, sizeof(ultimate_result_parameter
));
3286 if (policy
== NULL
) {
3290 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3292 // Process conditions
3293 while (offset
< policy
->conditions_size
) {
3294 u_int32_t length
= 0;
3295 u_int8_t
*value
= necp_buffer_get_tlv_value(policy
->conditions
, offset
, &length
);
3297 u_int8_t condition_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
3298 u_int8_t condition_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
3299 bool condition_is_negative
= condition_flags
& NECP_POLICY_CONDITION_FLAGS_NEGATIVE
;
3300 u_int32_t condition_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
3301 u_int8_t
*condition_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
3302 switch (condition_type
) {
3303 case NECP_POLICY_CONDITION_DEFAULT
: {
3304 socket_ip_conditions
= TRUE
;
3307 case NECP_POLICY_CONDITION_ALL_INTERFACES
: {
3308 master_condition_mask
|= NECP_KERNEL_CONDITION_ALL_INTERFACES
;
3309 socket_ip_conditions
= TRUE
;
3312 case NECP_POLICY_CONDITION_HAS_CLIENT
: {
3313 master_condition_mask
|= NECP_KERNEL_CONDITION_HAS_CLIENT
;
3314 socket_only_conditions
= TRUE
;
3317 case NECP_POLICY_CONDITION_ENTITLEMENT
: {
3318 if (condition_length
> 0) {
3319 if (cond_custom_entitlement
== NULL
) {
3320 cond_custom_entitlement
= necp_copy_string((char *)condition_value
, condition_length
);
3321 if (cond_custom_entitlement
!= NULL
) {
3322 master_condition_mask
|= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
;
3323 socket_only_conditions
= TRUE
;
3327 master_condition_mask
|= NECP_KERNEL_CONDITION_ENTITLEMENT
;
3328 socket_only_conditions
= TRUE
;
3332 case NECP_POLICY_CONDITION_PLATFORM_BINARY
: {
3333 master_condition_mask
|= NECP_KERNEL_CONDITION_PLATFORM_BINARY
;
3334 socket_only_conditions
= TRUE
;
3337 case NECP_POLICY_CONDITION_SDK_VERSION
: {
3338 if (condition_length
>= sizeof(cond_sdk_version
)) {
3339 master_condition_mask
|= NECP_KERNEL_CONDITION_SDK_VERSION
;
3340 memcpy(&cond_sdk_version
, condition_value
, sizeof(cond_sdk_version
));
3341 socket_only_conditions
= TRUE
;
3345 case NECP_POLICY_CONDITION_DOMAIN
: {
3346 // Make sure there is only one such rule
3347 if (condition_length
> 0 && cond_domain
== NULL
) {
3348 cond_domain
= necp_create_trimmed_domain((char *)condition_value
, condition_length
);
3349 if (cond_domain
!= NULL
) {
3350 master_condition_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
3351 if (condition_is_negative
) {
3352 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_DOMAIN
;
3354 socket_only_conditions
= TRUE
;
3359 case NECP_POLICY_CONDITION_ACCOUNT
: {
3360 // Make sure there is only one such rule
3361 if (condition_length
> 0 && cond_account_id
== 0 && policy
->applied_account
== NULL
) {
3362 char *string
= NULL
;
3363 MALLOC(string
, char *, condition_length
+ 1, M_NECP
, M_WAITOK
);
3364 if (string
!= NULL
) {
3365 memcpy(string
, condition_value
, condition_length
);
3366 string
[condition_length
] = 0;
3367 cond_account_id
= necp_create_string_to_id_mapping(&necp_account_id_list
, string
);
3368 if (cond_account_id
!= 0) {
3369 policy
->applied_account
= string
; // Save the string in parent policy
3370 master_condition_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
3371 if (condition_is_negative
) {
3372 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_ACCOUNT_ID
;
3374 socket_only_conditions
= TRUE
;
3376 FREE(string
, M_NECP
);
3382 case NECP_POLICY_CONDITION_APPLICATION
: {
3383 // Make sure there is only one such rule, because we save the uuid in the policy
3384 if (condition_length
>= sizeof(uuid_t
) && cond_app_id
== 0) {
3385 bool allocated_mapping
= FALSE
;
3386 uuid_t application_uuid
;
3387 memcpy(application_uuid
, condition_value
, sizeof(uuid_t
));
3388 cond_app_id
= necp_create_uuid_app_id_mapping(application_uuid
, &allocated_mapping
, TRUE
);
3389 if (cond_app_id
!= 0) {
3390 if (allocated_mapping
) {
3391 necp_uuid_app_id_mappings_dirty
= TRUE
;
3392 necp_num_uuid_app_id_mappings
++;
3394 uuid_copy(policy
->applied_app_uuid
, application_uuid
);
3395 master_condition_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
3396 if (condition_is_negative
) {
3397 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_APP_ID
;
3399 socket_only_conditions
= TRUE
;
3404 case NECP_POLICY_CONDITION_REAL_APPLICATION
: {
3405 // Make sure there is only one such rule, because we save the uuid in the policy
3406 if (condition_length
>= sizeof(uuid_t
) && cond_real_app_id
== 0) {
3407 uuid_t real_application_uuid
;
3408 memcpy(real_application_uuid
, condition_value
, sizeof(uuid_t
));
3409 cond_real_app_id
= necp_create_uuid_app_id_mapping(real_application_uuid
, NULL
, FALSE
);
3410 if (cond_real_app_id
!= 0) {
3411 uuid_copy(policy
->applied_real_app_uuid
, real_application_uuid
);
3412 master_condition_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
3413 if (condition_is_negative
) {
3414 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REAL_APP_ID
;
3416 socket_only_conditions
= TRUE
;
3421 case NECP_POLICY_CONDITION_PID
: {
3422 if (condition_length
>= sizeof(pid_t
)) {
3423 master_condition_mask
|= NECP_KERNEL_CONDITION_PID
;
3424 if (condition_is_negative
) {
3425 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PID
;
3427 memcpy(&cond_pid
, condition_value
, sizeof(cond_pid
));
3428 if (condition_length
>= (sizeof(pid_t
) + sizeof(cond_pid_version
))) {
3429 memcpy(&cond_pid_version
, (condition_value
+ sizeof(pid_t
)), sizeof(cond_pid_version
));
3431 socket_only_conditions
= TRUE
;
3435 case NECP_POLICY_CONDITION_UID
: {
3436 if (condition_length
>= sizeof(uid_t
)) {
3437 master_condition_mask
|= NECP_KERNEL_CONDITION_UID
;
3438 if (condition_is_negative
) {
3439 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_UID
;
3441 memcpy(&cond_uid
, condition_value
, sizeof(cond_uid
));
3442 socket_only_conditions
= TRUE
;
3446 case NECP_POLICY_CONDITION_TRAFFIC_CLASS
: {
3447 if (condition_length
>= sizeof(struct necp_policy_condition_tc_range
)) {
3448 master_condition_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
3449 if (condition_is_negative
) {
3450 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_TRAFFIC_CLASS
;
3452 memcpy(&cond_traffic_class
, condition_value
, sizeof(cond_traffic_class
));
3453 socket_only_conditions
= TRUE
;
3457 case NECP_POLICY_CONDITION_BOUND_INTERFACE
: {
3458 if (condition_length
<= IFXNAMSIZ
&& condition_length
> 0) {
3459 char interface_name
[IFXNAMSIZ
];
3460 memcpy(interface_name
, condition_value
, condition_length
);
3461 interface_name
[condition_length
- 1] = 0; // Make sure the string is NULL terminated
3462 if (ifnet_find_by_name(interface_name
, &cond_bound_interface
) == 0) {
3463 master_condition_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3464 if (condition_is_negative
) {
3465 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
3468 socket_ip_conditions
= TRUE
;
3472 case NECP_POLICY_CONDITION_IP_PROTOCOL
:
3473 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
: {
3474 if (condition_length
>= sizeof(u_int16_t
)) {
3475 master_condition_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
3476 if (condition_is_negative
) {
3477 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PROTOCOL
;
3479 memcpy(&cond_protocol
, condition_value
, sizeof(cond_protocol
));
3480 if (condition_type
== NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL
) {
3481 socket_only_conditions
= TRUE
;
3483 socket_ip_conditions
= TRUE
;
3488 case NECP_POLICY_CONDITION_LOCAL_NETWORKS
: {
3489 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_NETWORKS
;
3490 socket_ip_conditions
= TRUE
;
3493 case NECP_POLICY_CONDITION_LOCAL_ADDR
:
3494 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
: {
3495 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
3496 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
3500 cond_local_prefix
= address_struct
->prefix
;
3501 memcpy(&cond_local_start
, &address_struct
->address
, sizeof(address_struct
->address
));
3502 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3503 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3504 if (condition_is_negative
) {
3505 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3506 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
3508 if (condition_type
== NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR
) {
3509 socket_only_conditions
= TRUE
;
3511 socket_ip_conditions
= TRUE
;
3515 case NECP_POLICY_CONDITION_REMOTE_ADDR
:
3516 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
: {
3517 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)condition_value
;
3518 if (!necp_address_is_valid(&address_struct
->address
.sa
)) {
3522 cond_remote_prefix
= address_struct
->prefix
;
3523 memcpy(&cond_remote_start
, &address_struct
->address
, sizeof(address_struct
->address
));
3524 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3525 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3526 if (condition_is_negative
) {
3527 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3528 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
3530 if (condition_type
== NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR
) {
3531 socket_only_conditions
= TRUE
;
3533 socket_ip_conditions
= TRUE
;
3537 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE
:
3538 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
: {
3539 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
3540 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
3541 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
3545 memcpy(&cond_local_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
3546 memcpy(&cond_local_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
3547 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3548 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
3549 if (condition_is_negative
) {
3550 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_START
;
3551 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_END
;
3553 if (condition_type
== NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE
) {
3554 socket_only_conditions
= TRUE
;
3556 socket_ip_conditions
= TRUE
;
3560 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE
:
3561 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
: {
3562 struct necp_policy_condition_addr_range
*address_struct
= (struct necp_policy_condition_addr_range
*)(void *)condition_value
;
3563 if (!necp_address_is_valid(&address_struct
->start_address
.sa
) ||
3564 !necp_address_is_valid(&address_struct
->end_address
.sa
)) {
3568 memcpy(&cond_remote_start
, &address_struct
->start_address
, sizeof(address_struct
->start_address
));
3569 memcpy(&cond_remote_end
, &address_struct
->end_address
, sizeof(address_struct
->end_address
));
3570 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3571 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
3572 if (condition_is_negative
) {
3573 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_START
;
3574 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_END
;
3576 if (condition_type
== NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE
) {
3577 socket_only_conditions
= TRUE
;
3579 socket_ip_conditions
= TRUE
;
3583 case NECP_POLICY_CONDITION_AGENT_TYPE
: {
3584 if (condition_length
>= sizeof(cond_agent_type
)) {
3585 master_condition_mask
|= NECP_KERNEL_CONDITION_AGENT_TYPE
;
3586 memcpy(&cond_agent_type
, condition_value
, sizeof(cond_agent_type
));
3587 socket_only_conditions
= TRUE
;
3591 case NECP_POLICY_CONDITION_CLIENT_FLAGS
: {
3592 if (condition_is_negative
) {
3593 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_CLIENT_FLAGS
;
3595 master_condition_mask
|= NECP_KERNEL_CONDITION_CLIENT_FLAGS
;
3596 socket_only_conditions
= TRUE
;
3597 if (condition_length
>= sizeof(u_int32_t
)) {
3598 memcpy(&cond_client_flags
, condition_value
, sizeof(cond_client_flags
));
3600 // Empty means match on fallback traffic
3601 cond_client_flags
= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC
;
3605 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY
: {
3606 master_condition_mask
|= NECP_KERNEL_CONDITION_LOCAL_EMPTY
;
3607 if (condition_is_negative
) {
3608 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_LOCAL_EMPTY
;
3610 socket_only_conditions
= TRUE
;
3613 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY
: {
3614 master_condition_mask
|= NECP_KERNEL_CONDITION_REMOTE_EMPTY
;
3615 if (condition_is_negative
) {
3616 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_REMOTE_EMPTY
;
3618 socket_only_conditions
= TRUE
;
3621 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER
: {
3622 if (condition_length
> 0) {
3623 if (cond_signing_identifier
== NULL
) {
3624 cond_signing_identifier
= necp_copy_string((char *)condition_value
, condition_length
);
3625 if (cond_signing_identifier
!= NULL
) {
3626 master_condition_mask
|= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
;
3627 socket_only_conditions
= TRUE
;
3628 if (condition_is_negative
) {
3629 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
;
3636 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS
: {
3637 if (condition_length
>= sizeof(u_int16_t
)) {
3638 master_condition_mask
|= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
;
3639 if (condition_is_negative
) {
3640 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
;
3642 memcpy(&cond_packet_filter_tags
, condition_value
, sizeof(cond_packet_filter_tags
));
3643 socket_ip_conditions
= TRUE
;
3647 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK
: {
3648 master_condition_mask
|= NECP_KERNEL_CONDITION_IS_LOOPBACK
;
3649 if (condition_is_negative
) {
3650 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_IS_LOOPBACK
;
3652 socket_only_conditions
= TRUE
;
3655 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY
: {
3656 master_condition_mask
|= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
;
3657 if (condition_is_negative
) {
3658 master_condition_negated_mask
|= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
;
3660 socket_only_conditions
= TRUE
;
3668 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
3672 ultimate_result
= necp_policy_get_result_type(policy
);
3673 switch (ultimate_result
) {
3674 case NECP_POLICY_RESULT_PASS
: {
3675 u_int32_t pass_flags
= 0;
3676 if (necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) > 0) {
3677 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&pass_flags
, sizeof(pass_flags
))) {
3678 ultimate_result_parameter
.pass_flags
= pass_flags
;
3681 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3682 socket_layer_non_id_conditions
= TRUE
;
3683 ip_output_layer_id_condition
= TRUE
;
3684 } else if (socket_ip_conditions
) {
3685 socket_layer_non_id_conditions
= TRUE
;
3686 ip_output_layer_id_condition
= TRUE
;
3687 ip_output_layer_non_id_conditions
= TRUE
;
3691 case NECP_POLICY_RESULT_DROP
: {
3692 u_int32_t drop_flags
= 0;
3693 if (necp_policy_result_get_parameter_length_from_buffer(policy
->result
, policy
->result_size
) > 0) {
3694 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&drop_flags
, sizeof(drop_flags
))) {
3695 ultimate_result_parameter
.drop_flags
= drop_flags
;
3698 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3699 socket_layer_non_id_conditions
= TRUE
;
3700 } else if (socket_ip_conditions
) {
3701 socket_layer_non_id_conditions
= TRUE
;
3702 ip_output_layer_non_id_conditions
= TRUE
;
3703 ip_output_layer_non_id_only
= TRUE
; // Only apply drop to packets that didn't go through socket layer
3707 case NECP_POLICY_RESULT_SKIP
: {
3708 u_int32_t skip_policy_order
= 0;
3709 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&skip_policy_order
, sizeof(skip_policy_order
))) {
3710 ultimate_result_parameter
.skip_policy_order
= skip_policy_order
;
3713 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3714 socket_layer_non_id_conditions
= TRUE
;
3715 ip_output_layer_id_condition
= TRUE
;
3716 } else if (socket_ip_conditions
) {
3717 socket_layer_non_id_conditions
= TRUE
;
3718 ip_output_layer_non_id_conditions
= TRUE
;
3722 case NECP_POLICY_RESULT_SOCKET_DIVERT
:
3723 case NECP_POLICY_RESULT_SOCKET_FILTER
: {
3724 u_int32_t control_unit
= 0;
3725 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&control_unit
, sizeof(control_unit
))) {
3726 ultimate_result_parameter
.flow_divert_control_unit
= control_unit
;
3728 socket_layer_non_id_conditions
= TRUE
;
3731 case NECP_POLICY_RESULT_IP_TUNNEL
: {
3732 struct necp_policy_result_ip_tunnel tunnel_parameters
;
3733 u_int32_t tunnel_parameters_length
= necp_policy_get_result_parameter_length(policy
);
3734 if (tunnel_parameters_length
> sizeof(u_int32_t
) &&
3735 tunnel_parameters_length
<= sizeof(struct necp_policy_result_ip_tunnel
) &&
3736 necp_policy_get_result_parameter(policy
, (u_int8_t
*)&tunnel_parameters
, sizeof(tunnel_parameters
))) {
3737 ifnet_t tunnel_interface
= NULL
;
3738 tunnel_parameters
.interface_name
[tunnel_parameters_length
- sizeof(u_int32_t
) - 1] = 0; // Make sure the string is NULL terminated
3739 if (ifnet_find_by_name(tunnel_parameters
.interface_name
, &tunnel_interface
) == 0) {
3740 ultimate_result_parameter
.tunnel_interface_index
= tunnel_interface
->if_index
;
3741 ifnet_release(tunnel_interface
);
3744 secondary_result
= tunnel_parameters
.secondary_result
;
3745 if (secondary_result
) {
3746 cond_last_interface_index
= ultimate_result_parameter
.tunnel_interface_index
;
3750 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3751 socket_layer_non_id_conditions
= TRUE
;
3752 ip_output_layer_id_condition
= TRUE
;
3753 if (secondary_result
) {
3754 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3756 } else if (socket_ip_conditions
) {
3757 socket_layer_non_id_conditions
= TRUE
;
3758 ip_output_layer_id_condition
= TRUE
;
3759 ip_output_layer_non_id_conditions
= TRUE
;
3760 if (secondary_result
) {
3761 ip_output_layer_tunnel_condition_from_id
= TRUE
;
3762 ip_output_layer_tunnel_condition_from_non_id
= TRUE
;
3767 case NECP_POLICY_RESULT_TRIGGER
:
3768 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
:
3769 case NECP_POLICY_RESULT_TRIGGER_SCOPED
:
3770 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
3771 struct necp_policy_result_service service_parameters
;
3772 u_int32_t service_result_length
= necp_policy_get_result_parameter_length(policy
);
3773 bool has_extra_service_data
= FALSE
;
3774 if (service_result_length
>= (sizeof(service_parameters
))) {
3775 has_extra_service_data
= TRUE
;
3777 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&service_parameters
, sizeof(service_parameters
))) {
3778 ultimate_result_parameter
.service
.identifier
= necp_create_uuid_service_id_mapping(service_parameters
.identifier
);
3779 if (ultimate_result_parameter
.service
.identifier
!= 0) {
3780 uuid_copy(policy
->applied_result_uuid
, service_parameters
.identifier
);
3781 socket_layer_non_id_conditions
= TRUE
;
3782 if (has_extra_service_data
) {
3783 ultimate_result_parameter
.service
.data
= service_parameters
.data
;
3785 ultimate_result_parameter
.service
.data
= 0;
3791 case NECP_POLICY_RESULT_USE_NETAGENT
:
3792 case NECP_POLICY_RESULT_NETAGENT_SCOPED
: {
3793 uuid_t netagent_uuid
;
3794 if (necp_policy_get_result_parameter(policy
, (u_int8_t
*)&netagent_uuid
, sizeof(netagent_uuid
))) {
3795 ultimate_result_parameter
.netagent_id
= necp_create_uuid_service_id_mapping(netagent_uuid
);
3796 if (ultimate_result_parameter
.netagent_id
!= 0) {
3797 uuid_copy(policy
->applied_result_uuid
, netagent_uuid
);
3798 socket_layer_non_id_conditions
= TRUE
;
3803 case NECP_POLICY_RESULT_SOCKET_SCOPED
: {
3804 u_int32_t interface_name_length
= necp_policy_get_result_parameter_length(policy
);
3805 if (interface_name_length
<= IFXNAMSIZ
&& interface_name_length
> 0) {
3806 char interface_name
[IFXNAMSIZ
];
3807 ifnet_t scope_interface
= NULL
;
3808 necp_policy_get_result_parameter(policy
, (u_int8_t
*)interface_name
, interface_name_length
);
3809 interface_name
[interface_name_length
- 1] = 0; // Make sure the string is NULL terminated
3810 if (ifnet_find_by_name(interface_name
, &scope_interface
) == 0) {
3811 ultimate_result_parameter
.scoped_interface_index
= scope_interface
->if_index
;
3812 socket_layer_non_id_conditions
= TRUE
;
3813 ifnet_release(scope_interface
);
3818 case NECP_POLICY_RESULT_SCOPED_DIRECT
: {
3819 socket_layer_non_id_conditions
= TRUE
;
3822 case NECP_POLICY_RESULT_ALLOW_UNENTITLED
: {
3823 socket_layer_non_id_conditions
= TRUE
;
3826 case NECP_POLICY_RESULT_ROUTE_RULES
: {
3827 if (policy
->route_rules
!= NULL
&& policy
->route_rules_size
> 0) {
3828 u_int32_t route_rule_id
= necp_create_route_rule(&necp_route_rules
, policy
->route_rules
, policy
->route_rules_size
);
3829 if (route_rule_id
> 0) {
3830 policy
->applied_route_rules_id
= route_rule_id
;
3831 ultimate_result_parameter
.route_rule_id
= route_rule_id
;
3832 if (socket_only_conditions
) { // socket_ip_conditions can be TRUE or FALSE
3833 socket_layer_non_id_conditions
= TRUE
;
3834 } else if (socket_ip_conditions
) {
3835 socket_layer_non_id_conditions
= TRUE
;
3836 ip_output_layer_non_id_conditions
= TRUE
;
3837 ip_output_layer_non_id_only
= TRUE
; // Only apply route rules to packets that didn't go through socket layer
3848 if (socket_layer_non_id_conditions
) {
3849 necp_kernel_policy_id policy_id
= necp_kernel_socket_policy_add(policy
->order
, session
->session_order
, session
->proc_pid
, master_condition_mask
, master_condition_negated_mask
, cond_app_id
, cond_real_app_id
, cond_custom_entitlement
, cond_account_id
, cond_domain
, cond_pid
, cond_pid_version
, cond_uid
, cond_bound_interface
, cond_traffic_class
, cond_protocol
, &cond_local_start
, &cond_local_end
, cond_local_prefix
, &cond_remote_start
, &cond_remote_end
, cond_remote_prefix
, &cond_agent_type
, &cond_sdk_version
, cond_client_flags
, cond_signing_identifier
, cond_packet_filter_tags
, ultimate_result
, ultimate_result_parameter
);
3851 if (policy_id
== 0) {
3852 NECPLOG0(LOG_DEBUG
, "Error applying socket kernel policy");
3856 cond_ip_output_layer_id
= policy_id
;
3857 policy
->kernel_socket_policies
[0] = policy_id
;
3860 if (ip_output_layer_non_id_conditions
) {
3861 u_int32_t condition_mask
= master_condition_mask
;
3862 if (ip_output_layer_non_id_only
) {
3863 condition_mask
|= NECP_KERNEL_CONDITION_POLICY_ID
;
3866 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
, session
->session_order
, session
->proc_pid
, condition_mask
, master_condition_negated_mask
, NECP_KERNEL_POLICY_ID_NONE
, cond_bound_interface
, 0, cond_protocol
, &cond_local_start
, &cond_local_end
, cond_local_prefix
, &cond_remote_start
, &cond_remote_end
, cond_remote_prefix
, cond_packet_filter_tags
, ultimate_result
, ultimate_result_parameter
);
3868 if (policy_id
== 0) {
3869 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3873 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
] = policy_id
;
3876 if (ip_output_layer_id_condition
) {
3877 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
, session
->session_order
, session
->proc_pid
, NECP_KERNEL_CONDITION_POLICY_ID
| NECP_KERNEL_CONDITION_ALL_INTERFACES
, 0, cond_ip_output_layer_id
, NULL
, 0, 0, NULL
, NULL
, 0, NULL
, NULL
, 0, 0, ultimate_result
, ultimate_result_parameter
);
3879 if (policy_id
== 0) {
3880 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3884 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
] = policy_id
;
3887 // Extra policies for IP Output tunnels for when packets loop back
3888 if (ip_output_layer_tunnel_condition_from_id
) {
3889 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
, session
->session_order
, session
->proc_pid
, NECP_KERNEL_CONDITION_POLICY_ID
| NECP_KERNEL_CONDITION_LAST_INTERFACE
| NECP_KERNEL_CONDITION_ALL_INTERFACES
, 0, policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS
], NULL
, cond_last_interface_index
, 0, NULL
, NULL
, 0, NULL
, NULL
, 0, 0, secondary_result
, secondary_result_parameter
);
3891 if (policy_id
== 0) {
3892 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3896 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION
] = policy_id
;
3899 if (ip_output_layer_tunnel_condition_from_id
) {
3900 necp_kernel_policy_id policy_id
= necp_kernel_ip_output_policy_add(policy
->order
, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
, session
->session_order
, session
->proc_pid
, NECP_KERNEL_CONDITION_POLICY_ID
| NECP_KERNEL_CONDITION_LAST_INTERFACE
| NECP_KERNEL_CONDITION_ALL_INTERFACES
, 0, policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION
], NULL
, cond_last_interface_index
, 0, NULL
, NULL
, 0, NULL
, NULL
, 0, 0, secondary_result
, secondary_result_parameter
);
3902 if (policy_id
== 0) {
3903 NECPLOG0(LOG_DEBUG
, "Error applying IP output kernel policy");
3907 policy
->kernel_ip_output_policies
[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION
] = policy_id
;
3910 policy
->applied
= TRUE
;
3911 policy
->pending_update
= FALSE
;
3919 necp_policy_apply_all(struct necp_session
*session
)
3921 struct necp_session_policy
*policy
= NULL
;
3922 struct necp_session_policy
*temp_policy
= NULL
;
3923 struct kev_necp_policies_changed_data kev_data
;
3924 kev_data
.changed_count
= 0;
3926 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
3928 // Remove exisiting applied policies
3929 if (session
->dirty
) {
3930 LIST_FOREACH_SAFE(policy
, &session
->policies
, chain
, temp_policy
) {
3931 if (policy
->pending_deletion
) {
3932 if (policy
->applied
) {
3933 necp_policy_unapply(policy
);
3935 // Delete the policy
3936 necp_policy_delete(session
, policy
);
3937 } else if (!policy
->applied
) {
3938 necp_policy_apply(session
, policy
);
3939 } else if (policy
->pending_update
) {
3940 // Must have been applied, but needs an update. Remove and re-add.
3941 necp_policy_unapply(policy
);
3942 necp_policy_apply(session
, policy
);
3946 necp_kernel_socket_policies_update_uuid_table();
3947 necp_kernel_socket_policies_reprocess();
3948 necp_kernel_ip_output_policies_reprocess();
3950 // Clear dirty bit flags
3951 session
->dirty
= FALSE
;
3954 lck_rw_done(&necp_kernel_policy_lock
);
3956 necp_update_all_clients();
3957 necp_post_change_event(&kev_data
);
3960 NECPLOG0(LOG_DEBUG
, "Applied NECP policies");
3964 // Kernel Policy Management
3965 // ---------------------
3966 // Kernel policies are derived from session policies
3967 static necp_kernel_policy_id
3968 necp_kernel_policy_get_new_id(bool socket_level
)
3970 static necp_kernel_policy_id necp_last_kernel_socket_policy_id
= 0;
3971 static necp_kernel_policy_id necp_last_kernel_ip_policy_id
= 0;
3973 necp_kernel_policy_id newid
= NECP_KERNEL_POLICY_ID_NONE
;
3975 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
3978 bool wrapped
= FALSE
;
3980 necp_last_kernel_socket_policy_id
++;
3981 if (necp_last_kernel_socket_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET
||
3982 necp_last_kernel_socket_policy_id
>= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
) {
3984 // Already wrapped, give up
3985 NECPLOG0(LOG_ERR
, "Failed to find a free socket kernel policy ID.\n");
3986 return NECP_KERNEL_POLICY_ID_NONE
;
3988 necp_last_kernel_socket_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET
;
3991 newid
= necp_last_kernel_socket_policy_id
;
3992 } while (necp_kernel_socket_policy_find(newid
) != NULL
); // If already used, keep trying
3994 bool wrapped
= FALSE
;
3996 necp_last_kernel_ip_policy_id
++;
3997 if (necp_last_kernel_ip_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
) {
3999 // Already wrapped, give up
4000 NECPLOG0(LOG_ERR
, "Failed to find a free IP kernel policy ID.\n");
4001 return NECP_KERNEL_POLICY_ID_NONE
;
4003 necp_last_kernel_ip_policy_id
= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
;
4006 newid
= necp_last_kernel_ip_policy_id
;
4007 } while (necp_kernel_ip_output_policy_find(newid
) != NULL
); // If already used, keep trying
4010 if (newid
== NECP_KERNEL_POLICY_ID_NONE
) {
4011 NECPLOG0(LOG_ERR
, "Allocate kernel policy id failed.\n");
4012 return NECP_KERNEL_POLICY_ID_NONE
;
4018 #define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SDK_VERSION | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS | NECP_KERNEL_CONDITION_IS_LOOPBACK | NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)
4020 static necp_kernel_policy_id
4021 necp_kernel_socket_policy_add(necp_policy_order order
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_app_id cond_app_id
, necp_app_id cond_real_app_id
, char *cond_custom_entitlement
, u_int32_t cond_account_id
, char *cond_domain
, pid_t cond_pid
, int32_t cond_pid_version
, uid_t cond_uid
, ifnet_t cond_bound_interface
, struct necp_policy_condition_tc_range cond_traffic_class
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, struct necp_policy_condition_agent_type
*cond_agent_type
, struct necp_policy_condition_sdk_version
*cond_sdk_version
, u_int32_t cond_client_flags
, char *cond_signing_identifier
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
4023 struct necp_kernel_socket_policy
*new_kernel_policy
= NULL
;
4024 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
4026 new_kernel_policy
= zalloc_flags(necp_socket_policy_zone
, Z_WAITOK
| Z_ZERO
);
4028 new_kernel_policy
->id
= necp_kernel_policy_get_new_id(true);
4029 new_kernel_policy
->order
= order
;
4030 new_kernel_policy
->session_order
= session_order
;
4031 new_kernel_policy
->session_pid
= session_pid
;
4033 // Sanitize condition mask
4034 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_SOCKET_CONDITIONS
);
4035 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
4036 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
4038 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
4039 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REAL_APP_ID
;
4041 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) && !(new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
)) {
4042 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
;
4044 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
4045 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
4047 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
4048 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
4050 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
4051 new_kernel_policy
->condition_mask
&= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX
| NECP_KERNEL_CONDITION_LOCAL_END
);
4053 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
)) {
4054 new_kernel_policy
->condition_mask
&= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX
| NECP_KERNEL_CONDITION_REMOTE_END
);
4056 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
4058 // Set condition values
4059 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
4060 new_kernel_policy
->cond_app_id
= cond_app_id
;
4062 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
4063 new_kernel_policy
->cond_real_app_id
= cond_real_app_id
;
4065 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
4066 new_kernel_policy
->cond_custom_entitlement
= cond_custom_entitlement
;
4067 new_kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_unknown
;
4069 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
4070 new_kernel_policy
->cond_account_id
= cond_account_id
;
4072 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
4073 new_kernel_policy
->cond_domain
= cond_domain
;
4074 new_kernel_policy
->cond_domain_dot_count
= necp_count_dots(cond_domain
, strlen(cond_domain
));
4076 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
4077 new_kernel_policy
->cond_pid
= cond_pid
;
4078 new_kernel_policy
->cond_pid_version
= cond_pid_version
;
4080 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
4081 new_kernel_policy
->cond_uid
= cond_uid
;
4083 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
4084 if (cond_bound_interface
) {
4085 ifnet_reference(cond_bound_interface
);
4087 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
4089 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
4090 new_kernel_policy
->cond_traffic_class
= cond_traffic_class
;
4092 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
4093 new_kernel_policy
->cond_protocol
= cond_protocol
;
4095 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4096 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
4098 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4099 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
4101 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4102 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
4104 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4105 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
4107 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4108 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
4110 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4111 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
4113 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
4114 memcpy(&new_kernel_policy
->cond_agent_type
, cond_agent_type
, sizeof(*cond_agent_type
));
4116 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
4117 memcpy(&new_kernel_policy
->cond_sdk_version
, cond_sdk_version
, sizeof(*cond_sdk_version
));
4119 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
4120 new_kernel_policy
->cond_client_flags
= cond_client_flags
;
4122 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
4123 new_kernel_policy
->cond_signing_identifier
= cond_signing_identifier
;
4125 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
4126 new_kernel_policy
->cond_packet_filter_tags
= cond_packet_filter_tags
;
4129 new_kernel_policy
->result
= result
;
4130 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
4133 NECPLOG(LOG_DEBUG
, "Added kernel policy: socket, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
4135 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies
, new_kernel_policy
, chain
, session_order
, order
, tmp_kernel_policy
);
4137 return new_kernel_policy
? new_kernel_policy
->id
: 0;
4140 static struct necp_kernel_socket_policy
*
4141 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id
)
4143 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
4144 struct necp_kernel_socket_policy
*tmp_kernel_policy
= NULL
;
4146 if (policy_id
== 0) {
4150 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_socket_policies
, chain
, tmp_kernel_policy
) {
4151 if (kernel_policy
->id
== policy_id
) {
4152 return kernel_policy
;
4160 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id
)
4162 struct necp_kernel_socket_policy
*policy
= NULL
;
4164 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4166 policy
= necp_kernel_socket_policy_find(policy_id
);
4168 LIST_REMOVE(policy
, chain
);
4170 if (policy
->cond_bound_interface
) {
4171 ifnet_release(policy
->cond_bound_interface
);
4172 policy
->cond_bound_interface
= NULL
;
4175 if (policy
->cond_domain
) {
4176 FREE(policy
->cond_domain
, M_NECP
);
4177 policy
->cond_domain
= NULL
;
4180 if (policy
->cond_custom_entitlement
) {
4181 FREE(policy
->cond_custom_entitlement
, M_NECP
);
4182 policy
->cond_custom_entitlement
= NULL
;
4185 if (policy
->cond_signing_identifier
) {
4186 FREE(policy
->cond_signing_identifier
, M_NECP
);
4187 policy
->cond_signing_identifier
= NULL
;
4190 zfree(necp_socket_policy_zone
, policy
);
4197 static inline const char *
4198 necp_get_result_description(char *result_string
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
4200 uuid_string_t uuid_string
;
4202 case NECP_KERNEL_POLICY_RESULT_NONE
: {
4203 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "None");
4206 case NECP_KERNEL_POLICY_RESULT_PASS
: {
4207 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Pass (%X)", result_parameter
.pass_flags
);
4210 case NECP_KERNEL_POLICY_RESULT_SKIP
: {
4211 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Skip (%u)", result_parameter
.skip_policy_order
);
4214 case NECP_KERNEL_POLICY_RESULT_DROP
: {
4215 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Drop (%X)", result_parameter
.drop_flags
);
4218 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
: {
4219 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketDivert (%d)", result_parameter
.flow_divert_control_unit
);
4222 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
: {
4223 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketFilter (%d)", result_parameter
.filter_control_unit
);
4226 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
: {
4227 ifnet_t interface
= ifindex2ifnet
[result_parameter
.tunnel_interface_index
];
4228 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPTunnel (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
4231 case NECP_KERNEL_POLICY_RESULT_IP_FILTER
: {
4232 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "IPFilter");
4235 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
: {
4236 ifnet_t interface
= ifindex2ifnet
[result_parameter
.scoped_interface_index
];
4237 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "SocketScoped (%s%d)", ifnet_name(interface
), ifnet_unit(interface
));
4240 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
: {
4241 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "ScopedDirect");
4244 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
: {
4245 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "AllowUnentitled");
4248 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
: {
4250 char interface_names
[MAX_ROUTE_RULE_INTERFACES
][IFXNAMSIZ
];
4251 struct necp_route_rule
*route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, result_parameter
.route_rule_id
);
4252 if (route_rule
!= NULL
) {
4253 for (index
= 0; index
< MAX_ROUTE_RULE_INTERFACES
; index
++) {
4254 if (route_rule
->exception_if_indices
[index
] != 0) {
4255 ifnet_t interface
= ifindex2ifnet
[route_rule
->exception_if_indices
[index
]];
4256 snprintf(interface_names
[index
], IFXNAMSIZ
, "%s%d", ifnet_name(interface
), ifnet_unit(interface
));
4258 memset(interface_names
[index
], 0, IFXNAMSIZ
);
4261 switch (route_rule
->default_action
) {
4262 case NECP_ROUTE_RULE_DENY_INTERFACE
:
4263 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Only %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4264 (route_rule
->cellular_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Cell " : "",
4265 (route_rule
->wifi_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "WiFi " : "",
4266 (route_rule
->wired_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Wired " : "",
4267 (route_rule
->expensive_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Exp " : "",
4268 (route_rule
->constrained_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? "Constrained " : "",
4269 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[0] : "",
4270 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4271 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[1] : "",
4272 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4273 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[2] : "",
4274 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4275 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[3] : "",
4276 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4277 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[4] : "",
4278 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4279 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[5] : "",
4280 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4281 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[6] : "",
4282 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4283 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[7] : "",
4284 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4285 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[8] : "",
4286 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? " " : "",
4287 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE
) ? interface_names
[9] : "");
4289 case NECP_ROUTE_RULE_ALLOW_INTERFACE
:
4290 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4291 (route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Cell " : "",
4292 (route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!WiFi " : "",
4293 (route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Wired " : "",
4294 (route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Exp " : "",
4295 (route_rule
->constrained_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!Constrained " : "",
4296 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4297 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[0] : "",
4298 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4299 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[1] : "",
4300 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4301 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[2] : "",
4302 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4303 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[3] : "",
4304 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4305 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[4] : "",
4306 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4307 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[5] : "",
4308 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4309 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[6] : "",
4310 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4311 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[7] : "",
4312 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4313 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[8] : "",
4314 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? "!" : "",
4315 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? interface_names
[9] : "");
4317 case NECP_ROUTE_RULE_QOS_MARKING
:
4318 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (QoSMarking %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4319 (route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Cell " : "",
4320 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "WiFi " : "",
4321 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Wired " : "",
4322 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Exp " : "",
4323 (route_rule
->constrained_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? "Constrained " : "",
4324 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[0] : "",
4325 (route_rule
->exception_if_actions
[0] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4326 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[1] : "",
4327 (route_rule
->exception_if_actions
[1] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4328 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[2] : "",
4329 (route_rule
->exception_if_actions
[2] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4330 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[3] : "",
4331 (route_rule
->exception_if_actions
[3] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4332 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[4] : "",
4333 (route_rule
->exception_if_actions
[4] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4334 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[5] : "",
4335 (route_rule
->exception_if_actions
[5] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4336 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[6] : "",
4337 (route_rule
->exception_if_actions
[6] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4338 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[7] : "",
4339 (route_rule
->exception_if_actions
[7] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4340 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[8] : "",
4341 (route_rule
->exception_if_actions
[8] == NECP_ROUTE_RULE_QOS_MARKING
) ? " " : "",
4342 (route_rule
->exception_if_actions
[9] == NECP_ROUTE_RULE_QOS_MARKING
) ? interface_names
[9] : "");
4345 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "RouteRules (Unknown)");
4351 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
: {
4352 bool found_mapping
= FALSE
;
4353 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
);
4354 if (mapping
!= NULL
) {
4355 uuid_unparse(mapping
->uuid
, uuid_string
);
4356 found_mapping
= TRUE
;
4358 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "UseNetAgent (%s)", found_mapping
? uuid_string
: "Unknown");
4361 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
: {
4362 bool found_mapping
= FALSE
;
4363 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.netagent_id
);
4364 if (mapping
!= NULL
) {
4365 uuid_unparse(mapping
->uuid
, uuid_string
);
4366 found_mapping
= TRUE
;
4368 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NetAgentScoped (%s)", found_mapping
? uuid_string
: "Unknown");
4371 case NECP_POLICY_RESULT_TRIGGER
: {
4372 bool found_mapping
= FALSE
;
4373 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4374 if (mapping
!= NULL
) {
4375 uuid_unparse(mapping
->uuid
, uuid_string
);
4376 found_mapping
= TRUE
;
4378 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Trigger (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4381 case NECP_POLICY_RESULT_TRIGGER_IF_NEEDED
: {
4382 bool found_mapping
= FALSE
;
4383 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4384 if (mapping
!= NULL
) {
4385 uuid_unparse(mapping
->uuid
, uuid_string
);
4386 found_mapping
= TRUE
;
4388 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerIfNeeded (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4391 case NECP_POLICY_RESULT_TRIGGER_SCOPED
: {
4392 bool found_mapping
= FALSE
;
4393 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4394 if (mapping
!= NULL
) {
4395 uuid_unparse(mapping
->uuid
, uuid_string
);
4396 found_mapping
= TRUE
;
4398 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "TriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4401 case NECP_POLICY_RESULT_NO_TRIGGER_SCOPED
: {
4402 bool found_mapping
= FALSE
;
4403 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(result_parameter
.service
.identifier
);
4404 if (mapping
!= NULL
) {
4405 uuid_unparse(mapping
->uuid
, uuid_string
);
4406 found_mapping
= TRUE
;
4408 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "NoTriggerScoped (%s.%d)", found_mapping
? uuid_string
: "Unknown", result_parameter
.service
.data
);
4412 snprintf(result_string
, MAX_RESULT_STRING_LEN
, "Unknown %d (%d)", result
, result_parameter
.tunnel_interface_index
);
4416 return result_string
;
4420 necp_kernel_socket_policies_dump_all(void)
4423 struct necp_kernel_socket_policy
*policy
= NULL
;
4426 char result_string
[MAX_RESULT_STRING_LEN
];
4427 char proc_name_string
[MAXCOMLEN
+ 1];
4428 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
4429 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
4431 NECPLOG0(LOG_DEBUG
, "NECP Application Policies:\n");
4432 NECPLOG0(LOG_DEBUG
, "-----------\n");
4433 for (policy_i
= 0; necp_kernel_socket_policies_app_layer_map
!= NULL
&& necp_kernel_socket_policies_app_layer_map
[policy_i
] != NULL
; policy_i
++) {
4434 policy
= necp_kernel_socket_policies_app_layer_map
[policy_i
];
4435 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
4436 NECPLOG(LOG_DEBUG
, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %5x\tResult: %s\n", policy_i
, policy
->id
, proc_name_string
, policy
->session_order
, policy
->order
, policy
->condition_mask
, necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
));
4438 if (necp_kernel_socket_policies_app_layer_map
[0] != NULL
) {
4439 NECPLOG0(LOG_DEBUG
, "-----------\n");
4442 NECPLOG0(LOG_DEBUG
, "NECP Socket Policies:\n");
4443 NECPLOG0(LOG_DEBUG
, "-----------\n");
4444 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4445 NECPLOG(LOG_DEBUG
, "\tApp Bucket: %d\n", app_i
);
4446 for (policy_i
= 0; necp_kernel_socket_policies_map
[app_i
] != NULL
&& (necp_kernel_socket_policies_map
[app_i
])[policy_i
] != NULL
; policy_i
++) {
4447 policy
= (necp_kernel_socket_policies_map
[app_i
])[policy_i
];
4448 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
4449 NECPLOG(LOG_DEBUG
, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %5x\tResult: %s\n", policy_i
, policy
->id
, proc_name_string
, policy
->session_order
, policy
->order
, policy
->condition_mask
, necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
));
4451 NECPLOG0(LOG_DEBUG
, "-----------\n");
4457 necp_kernel_socket_result_is_trigger_service_type(struct necp_kernel_socket_policy
*kernel_policy
)
4459 return kernel_policy
->result
>= NECP_KERNEL_POLICY_RESULT_TRIGGER
&& kernel_policy
->result
<= NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
;
4463 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy
*upper_policy
, struct necp_kernel_socket_policy
*lower_policy
)
4465 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
4466 // Drop always cancels out lower policies
4468 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
||
4469 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
||
4470 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
||
4471 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
||
4472 upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
) {
4473 // Filters and route rules never cancel out lower policies
4475 } else if (necp_kernel_socket_result_is_trigger_service_type(upper_policy
)) {
4476 // Trigger/Scoping policies can overlap one another, but not other results
4477 return necp_kernel_socket_result_is_trigger_service_type(lower_policy
);
4478 } else if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4479 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
4480 // A skip cannot override a policy of a different session
4483 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
4484 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
4485 // This policy is beyond the skip
4488 // This policy is inside the skip
4494 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
4499 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy
*policy
, struct necp_kernel_socket_policy
**policy_array
, int valid_indices
)
4501 bool can_skip
= FALSE
;
4502 u_int32_t highest_skip_session_order
= 0;
4503 u_int32_t highest_skip_order
= 0;
4505 for (i
= 0; i
< valid_indices
; i
++) {
4506 struct necp_kernel_socket_policy
*compared_policy
= policy_array
[i
];
4508 // For policies in a skip window, we can't mark conflicting policies as unnecessary
4510 if (highest_skip_session_order
!= compared_policy
->session_order
||
4511 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
4512 // If we've moved on to the next session, or passed the skip window
4513 highest_skip_session_order
= 0;
4514 highest_skip_order
= 0;
4517 // If this policy is also a skip, in can increase the skip window
4518 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4519 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
4520 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4527 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
4528 // This policy is a skip. Set the skip window accordingly
4530 highest_skip_session_order
= compared_policy
->session_order
;
4531 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
4534 // The result of the compared policy must be able to block out this policy result
4535 if (!necp_kernel_socket_policy_results_overlap(compared_policy
, policy
)) {
4539 // If new policy matches All Interfaces, compared policy must also
4540 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
4544 // If new policy matches Local Networks, compared policy must also
4545 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
)) {
4549 // Default makes lower policies unecessary always
4550 if (compared_policy
->condition_mask
== 0) {
4554 // Compared must be more general than policy, and include only conditions within policy
4555 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
4559 // Negative conditions must match for the overlapping conditions
4560 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
4564 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
&&
4565 strcmp(compared_policy
->cond_domain
, policy
->cond_domain
) != 0) {
4569 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
&&
4570 strcmp(compared_policy
->cond_custom_entitlement
, policy
->cond_custom_entitlement
) != 0) {
4574 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&&
4575 compared_policy
->cond_account_id
!= policy
->cond_account_id
) {
4579 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
4580 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
4584 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&&
4585 compared_policy
->cond_app_id
!= policy
->cond_app_id
) {
4589 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&&
4590 compared_policy
->cond_real_app_id
!= policy
->cond_real_app_id
) {
4594 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
&&
4595 (compared_policy
->cond_pid
!= policy
->cond_pid
|| compared_policy
->cond_pid_version
!= policy
->cond_pid_version
)) {
4599 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
&&
4600 compared_policy
->cond_uid
!= policy
->cond_uid
) {
4604 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
4605 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
4609 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
4610 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
4614 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
&&
4615 compared_policy
->cond_client_flags
!= policy
->cond_client_flags
) {
4619 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
&&
4620 !(compared_policy
->cond_traffic_class
.start_tc
<= policy
->cond_traffic_class
.start_tc
&&
4621 compared_policy
->cond_traffic_class
.end_tc
>= policy
->cond_traffic_class
.end_tc
)) {
4625 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
4626 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
4627 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&policy
->cond_local_end
, (struct sockaddr
*)&compared_policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_end
)) {
4630 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
4631 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
4632 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
4638 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
4639 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
4640 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&policy
->cond_remote_end
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_end
)) {
4643 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
4644 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
4645 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
4651 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
&&
4652 memcmp(&compared_policy
->cond_agent_type
, &policy
->cond_agent_type
, sizeof(policy
->cond_agent_type
)) == 0) {
4656 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
&&
4657 memcmp(&compared_policy
->cond_sdk_version
, &policy
->cond_sdk_version
, sizeof(policy
->cond_sdk_version
)) == 0) {
4661 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
&&
4662 memcmp(&compared_policy
->cond_packet_filter_tags
, &policy
->cond_packet_filter_tags
, sizeof(policy
->cond_packet_filter_tags
)) == 0) {
4673 necp_kernel_socket_policies_reprocess(void)
4676 int bucket_allocation_counts
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
4677 int bucket_current_free_index
[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
];
4678 int app_layer_allocation_count
= 0;
4679 int app_layer_current_free_index
= 0;
4680 struct necp_kernel_socket_policy
*kernel_policy
= NULL
;
4682 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4685 necp_kernel_application_policies_condition_mask
= 0;
4686 necp_kernel_socket_policies_condition_mask
= 0;
4687 necp_kernel_application_policies_count
= 0;
4688 necp_kernel_socket_policies_count
= 0;
4689 necp_kernel_socket_policies_non_app_count
= 0;
4691 // Reset all maps to NULL
4692 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4693 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
4694 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
4695 necp_kernel_socket_policies_map
[app_i
] = NULL
;
4699 bucket_allocation_counts
[app_i
] = 0;
4701 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
4702 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
4703 necp_kernel_socket_policies_app_layer_map
= NULL
;
4706 // Create masks and counts
4707 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
4708 // App layer mask/count
4709 necp_kernel_application_policies_condition_mask
|= kernel_policy
->condition_mask
;
4710 necp_kernel_application_policies_count
++;
4711 app_layer_allocation_count
++;
4713 if ((kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
)) {
4714 // Agent type conditions only apply to app layer
4718 // Update socket layer bucket mask/counts
4719 necp_kernel_socket_policies_condition_mask
|= kernel_policy
->condition_mask
;
4720 necp_kernel_socket_policies_count
++;
4722 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
4723 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
4724 necp_kernel_socket_policies_non_app_count
++;
4725 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4726 bucket_allocation_counts
[app_i
]++;
4729 bucket_allocation_counts
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
)]++;
4734 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4735 if (bucket_allocation_counts
[app_i
] > 0) {
4736 // Allocate a NULL-terminated array of policy pointers for each bucket
4737 MALLOC(necp_kernel_socket_policies_map
[app_i
], struct necp_kernel_socket_policy
**, sizeof(struct necp_kernel_socket_policy
*) * (bucket_allocation_counts
[app_i
] + 1), M_NECP
, M_WAITOK
);
4738 if (necp_kernel_socket_policies_map
[app_i
] == NULL
) {
4742 // Initialize the first entry to NULL
4743 (necp_kernel_socket_policies_map
[app_i
])[0] = NULL
;
4745 bucket_current_free_index
[app_i
] = 0;
4747 MALLOC(necp_kernel_socket_policies_app_layer_map
, struct necp_kernel_socket_policy
**, sizeof(struct necp_kernel_socket_policy
*) * (app_layer_allocation_count
+ 1), M_NECP
, M_WAITOK
);
4748 if (necp_kernel_socket_policies_app_layer_map
== NULL
) {
4751 necp_kernel_socket_policies_app_layer_map
[0] = NULL
;
4754 LIST_FOREACH(kernel_policy
, &necp_kernel_socket_policies
, chain
) {
4755 // Add app layer policies
4756 if (!necp_dedup_policies
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_app_layer_map
, app_layer_current_free_index
)) {
4757 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = kernel_policy
;
4758 app_layer_current_free_index
++;
4759 necp_kernel_socket_policies_app_layer_map
[app_layer_current_free_index
] = NULL
;
4762 if ((kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
)) {
4763 // Agent type conditions only apply to app layer
4767 // Add socket policies
4768 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) ||
4769 kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
4770 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4771 if (!necp_dedup_policies
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
4772 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
4773 bucket_current_free_index
[app_i
]++;
4774 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
4778 app_i
= NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy
->cond_app_id
);
4779 if (!necp_dedup_policies
|| !necp_kernel_socket_policy_is_unnecessary(kernel_policy
, necp_kernel_socket_policies_map
[app_i
], bucket_current_free_index
[app_i
])) {
4780 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = kernel_policy
;
4781 bucket_current_free_index
[app_i
]++;
4782 (necp_kernel_socket_policies_map
[app_i
])[(bucket_current_free_index
[app_i
])] = NULL
;
4786 necp_kernel_socket_policies_dump_all();
4787 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
4791 // Free memory, reset masks to 0
4792 necp_kernel_application_policies_condition_mask
= 0;
4793 necp_kernel_socket_policies_condition_mask
= 0;
4794 necp_kernel_application_policies_count
= 0;
4795 necp_kernel_socket_policies_count
= 0;
4796 necp_kernel_socket_policies_non_app_count
= 0;
4797 for (app_i
= 0; app_i
< NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS
; app_i
++) {
4798 if (necp_kernel_socket_policies_map
[app_i
] != NULL
) {
4799 FREE(necp_kernel_socket_policies_map
[app_i
], M_NECP
);
4800 necp_kernel_socket_policies_map
[app_i
] = NULL
;
4803 if (necp_kernel_socket_policies_app_layer_map
!= NULL
) {
4804 FREE(necp_kernel_socket_policies_app_layer_map
, M_NECP
);
4805 necp_kernel_socket_policies_app_layer_map
= NULL
;
4811 necp_get_new_string_id(void)
4813 static u_int32_t necp_last_string_id
= 0;
4815 u_int32_t newid
= 0;
4817 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4819 bool wrapped
= FALSE
;
4821 necp_last_string_id
++;
4822 if (necp_last_string_id
< 1) {
4824 // Already wrapped, give up
4825 NECPLOG0(LOG_ERR
, "Failed to find a free app UUID.\n");
4828 necp_last_string_id
= 1;
4831 newid
= necp_last_string_id
;
4832 } while (necp_lookup_string_with_id_locked(&necp_account_id_list
, newid
) != NULL
); // If already used, keep trying
4835 NECPLOG0(LOG_ERR
, "Allocate string id failed.\n");
4842 static struct necp_string_id_mapping
*
4843 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list
*list
, char *string
)
4845 struct necp_string_id_mapping
*searchentry
= NULL
;
4846 struct necp_string_id_mapping
*foundentry
= NULL
;
4848 LIST_FOREACH(searchentry
, list
, chain
) {
4849 if (strcmp(searchentry
->string
, string
) == 0) {
4850 foundentry
= searchentry
;
4858 static struct necp_string_id_mapping
*
4859 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list
*list
, u_int32_t local_id
)
4861 struct necp_string_id_mapping
*searchentry
= NULL
;
4862 struct necp_string_id_mapping
*foundentry
= NULL
;
4864 LIST_FOREACH(searchentry
, list
, chain
) {
4865 if (searchentry
->id
== local_id
) {
4866 foundentry
= searchentry
;
4875 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4877 u_int32_t string_id
= 0;
4878 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4880 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4882 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4883 if (existing_mapping
!= NULL
) {
4884 string_id
= existing_mapping
->id
;
4885 os_ref_retain_locked(&existing_mapping
->refcount
);
4887 struct necp_string_id_mapping
*new_mapping
= NULL
;
4888 MALLOC(new_mapping
, struct necp_string_id_mapping
*, sizeof(struct necp_string_id_mapping
), M_NECP
, M_WAITOK
);
4889 if (new_mapping
!= NULL
) {
4890 memset(new_mapping
, 0, sizeof(struct necp_string_id_mapping
));
4892 size_t length
= strlen(string
) + 1;
4893 MALLOC(new_mapping
->string
, char *, length
, M_NECP
, M_WAITOK
);
4894 if (new_mapping
->string
!= NULL
) {
4895 memcpy(new_mapping
->string
, string
, length
);
4896 new_mapping
->id
= necp_get_new_string_id();
4897 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
);
4898 LIST_INSERT_HEAD(list
, new_mapping
, chain
);
4899 string_id
= new_mapping
->id
;
4901 FREE(new_mapping
, M_NECP
);
4910 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list
*list
, char *string
)
4912 struct necp_string_id_mapping
*existing_mapping
= NULL
;
4914 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4916 existing_mapping
= necp_lookup_string_to_id_locked(list
, string
);
4917 if (existing_mapping
!= NULL
) {
4918 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
4919 LIST_REMOVE(existing_mapping
, chain
);
4920 FREE(existing_mapping
->string
, M_NECP
);
4921 FREE(existing_mapping
, M_NECP
);
4929 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
4930 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
4932 necp_get_new_route_rule_id(bool aggregate
)
4934 static u_int32_t necp_last_route_rule_id
= 0;
4935 static u_int32_t necp_last_aggregate_route_rule_id
= 0;
4937 u_int32_t newid
= 0;
4940 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
4941 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4943 bool wrapped
= FALSE
;
4945 necp_last_route_rule_id
++;
4946 if (necp_last_route_rule_id
< NECP_FIRST_VALID_ROUTE_RULE_ID
||
4947 necp_last_route_rule_id
>= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
) {
4949 // Already wrapped, give up
4950 NECPLOG0(LOG_ERR
, "Failed to find a free route rule id.\n");
4953 necp_last_route_rule_id
= NECP_FIRST_VALID_ROUTE_RULE_ID
;
4956 newid
= necp_last_route_rule_id
;
4957 } while (necp_lookup_route_rule_locked(&necp_route_rules
, newid
) != NULL
); // If already used, keep trying
4959 // necp_route_rule_lock protects aggregate rule IDs
4960 LCK_RW_ASSERT(&necp_route_rule_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
4962 bool wrapped
= FALSE
;
4964 necp_last_aggregate_route_rule_id
++;
4965 if (necp_last_aggregate_route_rule_id
< NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
) {
4967 // Already wrapped, give up
4968 NECPLOG0(LOG_ERR
, "Failed to find a free aggregate route rule id.\n");
4971 necp_last_aggregate_route_rule_id
= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID
;
4974 newid
= necp_last_aggregate_route_rule_id
;
4975 } while (necp_lookup_route_rule_locked(&necp_route_rules
, newid
) != NULL
); // If already used, keep trying
4979 NECPLOG0(LOG_ERR
, "Allocate route rule ID failed.\n");
4986 static struct necp_route_rule
*
4987 necp_lookup_route_rule_locked(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
4989 struct necp_route_rule
*searchentry
= NULL
;
4990 struct necp_route_rule
*foundentry
= NULL
;
4992 LIST_FOREACH(searchentry
, list
, chain
) {
4993 if (searchentry
->id
== route_rule_id
) {
4994 foundentry
= searchentry
;
5002 static struct necp_route_rule
*
5003 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list
*list
, u_int8_t default_action
, u_int8_t cellular_action
, u_int8_t wifi_action
, u_int8_t wired_action
, u_int8_t expensive_action
, u_int8_t constrained_action
, u_int32_t
*if_indices
, u_int8_t
*if_actions
, uuid_t netagent_uuid
)
5005 struct necp_route_rule
*searchentry
= NULL
;
5006 struct necp_route_rule
*foundentry
= NULL
;
5008 LIST_FOREACH(searchentry
, list
, chain
) {
5009 if (searchentry
->default_action
== default_action
&&
5010 searchentry
->cellular_action
== cellular_action
&&
5011 searchentry
->wifi_action
== wifi_action
&&
5012 searchentry
->wired_action
== wired_action
&&
5013 searchentry
->expensive_action
== expensive_action
&&
5014 searchentry
->constrained_action
== constrained_action
) {
5015 bool match_failed
= FALSE
;
5020 for (index_a
= 0; index_a
< MAX_ROUTE_RULE_INTERFACES
; index_a
++) {
5021 bool found_index
= FALSE
;
5022 if (searchentry
->exception_if_indices
[index_a
] == 0) {
5026 for (index_b
= 0; index_b
< MAX_ROUTE_RULE_INTERFACES
; index_b
++) {
5027 if (if_indices
[index_b
] == 0) {
5030 if (index_b
>= count_b
) {
5031 count_b
= index_b
+ 1;
5033 if (searchentry
->exception_if_indices
[index_a
] == if_indices
[index_b
] &&
5034 searchentry
->exception_if_actions
[index_a
] == if_actions
[index_b
]) {
5040 match_failed
= TRUE
;
5045 if (match_failed
|| count_a
!= count_b
) {
5049 bool has_agent_a
= uuid_is_null(netagent_uuid
);
5050 bool has_agent_b
= (searchentry
->netagent_id
!= 0);
5051 if (has_agent_a
!= has_agent_b
) {
5056 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(searchentry
->netagent_id
);
5057 if (mapping
== NULL
) {
5058 // Bad mapping, doesn't match
5061 if (uuid_compare(mapping
->uuid
, netagent_uuid
) != 0) {
5062 // UUIDs don't match
5068 foundentry
= searchentry
;
5077 necp_create_route_rule(struct necp_route_rule_list
*list
, u_int8_t
*route_rules_array
, u_int32_t route_rules_array_size
)
5080 u_int32_t route_rule_id
= 0;
5081 struct necp_route_rule
*existing_rule
= NULL
;
5082 u_int8_t default_action
= NECP_ROUTE_RULE_ALLOW_INTERFACE
;
5083 u_int8_t cellular_action
= NECP_ROUTE_RULE_NONE
;
5084 u_int8_t wifi_action
= NECP_ROUTE_RULE_NONE
;
5085 u_int8_t wired_action
= NECP_ROUTE_RULE_NONE
;
5086 u_int8_t expensive_action
= NECP_ROUTE_RULE_NONE
;
5087 u_int8_t constrained_action
= NECP_ROUTE_RULE_NONE
;
5088 u_int32_t if_indices
[MAX_ROUTE_RULE_INTERFACES
];
5089 size_t num_valid_indices
= 0;
5090 memset(&if_indices
, 0, sizeof(if_indices
));
5091 u_int8_t if_actions
[MAX_ROUTE_RULE_INTERFACES
];
5092 memset(&if_actions
, 0, sizeof(if_actions
));
5094 uuid_t netagent_uuid
= {};
5096 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5098 if (route_rules_array
== NULL
|| route_rules_array_size
== 0) {
5103 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) < route_rules_array_size
) {
5104 ifnet_t rule_interface
= NULL
;
5105 char interface_name
[IFXNAMSIZ
];
5106 u_int32_t length
= 0;
5107 u_int8_t
*value
= necp_buffer_get_tlv_value(route_rules_array
, offset
, &length
);
5109 if (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
> route_rules_array_size
) {
5110 // Invalid TLV goes beyond end of the rules array
5114 // Increment offset for the next time through the loop
5115 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
5117 u_int8_t rule_type
= necp_policy_condition_get_type_from_buffer(value
, length
);
5118 u_int8_t rule_flags
= necp_policy_condition_get_flags_from_buffer(value
, length
);
5119 u_int32_t rule_length
= necp_policy_condition_get_value_length_from_buffer(value
, length
);
5120 u_int8_t
*rule_value
= necp_policy_condition_get_value_pointer_from_buffer(value
, length
);
5122 if (rule_type
== NECP_ROUTE_RULE_NONE
) {
5123 // Don't allow an explicit rule to be None action
5127 if (rule_type
== NECP_ROUTE_RULE_USE_NETAGENT
) {
5128 if (rule_length
< sizeof(uuid_t
)) {
5133 if (!uuid_is_null(netagent_uuid
)) {
5134 if (uuid_compare(netagent_uuid
, rule_value
) != 0) {
5135 // UUIDs don't match, skip
5139 // Copy out agent UUID
5140 memcpy(netagent_uuid
, rule_value
, sizeof(netagent_uuid
));
5143 // Adjust remaining length
5144 rule_value
+= sizeof(netagent_uuid
);
5145 rule_length
-= sizeof(netagent_uuid
);
5148 if (rule_length
== 0) {
5149 if (rule_flags
& NECP_ROUTE_RULE_FLAG_CELLULAR
) {
5150 cellular_action
= rule_type
;
5152 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIFI
) {
5153 wifi_action
= rule_type
;
5155 if (rule_flags
& NECP_ROUTE_RULE_FLAG_WIRED
) {
5156 wired_action
= rule_type
;
5158 if (rule_flags
& NECP_ROUTE_RULE_FLAG_EXPENSIVE
) {
5159 expensive_action
= rule_type
;
5161 if (rule_flags
& NECP_ROUTE_RULE_FLAG_CONSTRAINED
) {
5162 constrained_action
= rule_type
;
5164 if (rule_flags
== 0) {
5165 default_action
= rule_type
;
5170 if (num_valid_indices
>= MAX_ROUTE_RULE_INTERFACES
) {
5174 if (rule_length
<= IFXNAMSIZ
) {
5175 memcpy(interface_name
, rule_value
, rule_length
);
5176 interface_name
[rule_length
- 1] = 0; // Make sure the string is NULL terminated
5177 if (ifnet_find_by_name(interface_name
, &rule_interface
) == 0) {
5178 if_actions
[num_valid_indices
] = rule_type
;
5179 if_indices
[num_valid_indices
++] = rule_interface
->if_index
;
5180 ifnet_release(rule_interface
);
5185 existing_rule
= necp_lookup_route_rule_by_contents_locked(list
, default_action
, cellular_action
, wifi_action
, wired_action
, expensive_action
, constrained_action
, if_indices
, if_actions
, netagent_uuid
);
5186 if (existing_rule
!= NULL
) {
5187 route_rule_id
= existing_rule
->id
;
5188 os_ref_retain_locked(&existing_rule
->refcount
);
5190 struct necp_route_rule
*new_rule
= NULL
;
5191 MALLOC(new_rule
, struct necp_route_rule
*, sizeof(struct necp_route_rule
), M_NECP
, M_WAITOK
);
5192 if (new_rule
!= NULL
) {
5193 memset(new_rule
, 0, sizeof(struct necp_route_rule
));
5194 route_rule_id
= new_rule
->id
= necp_get_new_route_rule_id(false);
5195 if (!uuid_is_null(netagent_uuid
)) {
5196 new_rule
->netagent_id
= necp_create_uuid_service_id_mapping(netagent_uuid
);
5198 new_rule
->default_action
= default_action
;
5199 new_rule
->cellular_action
= cellular_action
;
5200 new_rule
->wifi_action
= wifi_action
;
5201 new_rule
->wired_action
= wired_action
;
5202 new_rule
->expensive_action
= expensive_action
;
5203 new_rule
->constrained_action
= constrained_action
;
5204 memcpy(&new_rule
->exception_if_indices
, &if_indices
, sizeof(if_indices
));
5205 memcpy(&new_rule
->exception_if_actions
, &if_actions
, sizeof(if_actions
));
5206 os_ref_init(&new_rule
->refcount
, &necp_refgrp
);
5207 LIST_INSERT_HEAD(list
, new_rule
, chain
);
5210 return route_rule_id
;
5214 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id
)
5217 lck_rw_lock_exclusive(&necp_route_rule_lock
);
5219 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
5220 struct necp_aggregate_route_rule
*tmp_rule
= NULL
;
5222 LIST_FOREACH_SAFE(existing_rule
, &necp_aggregate_route_rules
, chain
, tmp_rule
) {
5224 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
5225 u_int32_t route_rule_id
= existing_rule
->rule_ids
[index
];
5226 if (route_rule_id
== rule_id
) {
5227 LIST_REMOVE(existing_rule
, chain
);
5228 FREE(existing_rule
, M_NECP
);
5234 lck_rw_done(&necp_route_rule_lock
);
5239 necp_remove_route_rule(struct necp_route_rule_list
*list
, u_int32_t route_rule_id
)
5241 struct necp_route_rule
*existing_rule
= NULL
;
5243 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5245 existing_rule
= necp_lookup_route_rule_locked(list
, route_rule_id
);
5246 if (existing_rule
!= NULL
) {
5247 if (os_ref_release_locked(&existing_rule
->refcount
) == 0) {
5248 necp_remove_aggregate_route_rule_for_id(existing_rule
->id
);
5249 necp_remove_uuid_service_id_mapping_with_service_id(existing_rule
->netagent_id
);
5250 LIST_REMOVE(existing_rule
, chain
);
5251 FREE(existing_rule
, M_NECP
);
5259 static struct necp_aggregate_route_rule
*
5260 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id
)
5262 struct necp_aggregate_route_rule
*searchentry
= NULL
;
5263 struct necp_aggregate_route_rule
*foundentry
= NULL
;
5265 lck_rw_lock_shared(&necp_route_rule_lock
);
5267 LIST_FOREACH(searchentry
, &necp_aggregate_route_rules
, chain
) {
5268 if (searchentry
->id
== route_rule_id
) {
5269 foundentry
= searchentry
;
5274 lck_rw_done(&necp_route_rule_lock
);
5280 necp_create_aggregate_route_rule(u_int32_t
*rule_ids
)
5282 u_int32_t aggregate_route_rule_id
= 0;
5283 struct necp_aggregate_route_rule
*new_rule
= NULL
;
5284 struct necp_aggregate_route_rule
*existing_rule
= NULL
;
5286 lck_rw_lock_exclusive(&necp_route_rule_lock
);
5288 // Check if the rule already exists
5289 LIST_FOREACH(existing_rule
, &necp_aggregate_route_rules
, chain
) {
5290 if (memcmp(existing_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
)) == 0) {
5291 lck_rw_done(&necp_route_rule_lock
);
5292 return existing_rule
->id
;
5296 MALLOC(new_rule
, struct necp_aggregate_route_rule
*, sizeof(struct necp_aggregate_route_rule
), M_NECP
, M_WAITOK
);
5297 if (new_rule
!= NULL
) {
5298 memset(new_rule
, 0, sizeof(struct necp_aggregate_route_rule
));
5299 aggregate_route_rule_id
= new_rule
->id
= necp_get_new_route_rule_id(true);
5300 new_rule
->id
= aggregate_route_rule_id
;
5301 memcpy(new_rule
->rule_ids
, rule_ids
, (sizeof(u_int32_t
) * MAX_AGGREGATE_ROUTE_RULES
));
5302 LIST_INSERT_HEAD(&necp_aggregate_route_rules
, new_rule
, chain
);
5304 lck_rw_done(&necp_route_rule_lock
);
5306 return aggregate_route_rule_id
;
5309 #define NECP_NULL_SERVICE_ID 1
5310 #define NECP_FIRST_VALID_SERVICE_ID 2
5311 #define NECP_FIRST_VALID_APP_ID UINT16_MAX
5313 necp_get_new_uuid_id(bool service
)
5315 static u_int32_t necp_last_service_uuid_id
= 0;
5316 static u_int32_t necp_last_app_uuid_id
= 0;
5318 u_int32_t newid
= 0;
5320 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5323 bool wrapped
= FALSE
;
5325 necp_last_service_uuid_id
++;
5326 if (necp_last_service_uuid_id
< NECP_FIRST_VALID_SERVICE_ID
||
5327 necp_last_service_uuid_id
>= NECP_FIRST_VALID_APP_ID
) {
5329 // Already wrapped, give up
5330 NECPLOG0(LOG_ERR
, "Failed to find a free service UUID.\n");
5331 return NECP_NULL_SERVICE_ID
;
5333 necp_last_service_uuid_id
= NECP_FIRST_VALID_SERVICE_ID
;
5336 newid
= necp_last_service_uuid_id
;
5337 } while (necp_uuid_lookup_uuid_with_service_id_locked(newid
) != NULL
); // If already used, keep trying
5339 bool wrapped
= FALSE
;
5341 necp_last_app_uuid_id
++;
5342 if (necp_last_app_uuid_id
< NECP_FIRST_VALID_APP_ID
) {
5344 // Already wrapped, give up
5345 NECPLOG0(LOG_ERR
, "Failed to find a free app UUID.\n");
5346 return NECP_NULL_SERVICE_ID
;
5348 necp_last_app_uuid_id
= NECP_FIRST_VALID_APP_ID
;
5351 newid
= necp_last_app_uuid_id
;
5352 } while (necp_uuid_lookup_uuid_with_app_id_locked(newid
) != NULL
); // If already used, keep trying
5355 if (newid
== NECP_NULL_SERVICE_ID
) {
5356 NECPLOG0(LOG_ERR
, "Allocate uuid ID failed.\n");
5357 return NECP_NULL_SERVICE_ID
;
5363 static struct necp_uuid_id_mapping
*
5364 necp_uuid_lookup_app_id_locked(uuid_t uuid
)
5366 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5367 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5369 LIST_FOREACH(searchentry
, APPUUIDHASH(uuid
), chain
) {
5370 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
5371 foundentry
= searchentry
;
5379 static struct necp_uuid_id_mapping
*
5380 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id
)
5382 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5383 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5385 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
5386 for (uuid_list_head
= &necp_uuid_app_id_hashtbl
[necp_uuid_app_id_hash_num_buckets
- 1]; uuid_list_head
>= necp_uuid_app_id_hashtbl
; uuid_list_head
--) {
5387 LIST_FOREACH(searchentry
, uuid_list_head
, chain
) {
5388 if (searchentry
->id
== local_id
) {
5389 foundentry
= searchentry
;
5399 necp_create_uuid_app_id_mapping(uuid_t uuid
, bool *allocated_mapping
, bool uuid_policy_table
)
5401 u_int32_t local_id
= 0;
5402 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5404 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5406 if (allocated_mapping
) {
5407 *allocated_mapping
= FALSE
;
5410 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
5411 if (existing_mapping
!= NULL
) {
5412 local_id
= existing_mapping
->id
;
5413 os_ref_retain_locked(&existing_mapping
->refcount
);
5414 if (uuid_policy_table
) {
5415 existing_mapping
->table_usecount
++;
5418 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
5419 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
5420 if (new_mapping
!= NULL
) {
5421 uuid_copy(new_mapping
->uuid
, uuid
);
5422 new_mapping
->id
= necp_get_new_uuid_id(false);
5423 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
);
5424 if (uuid_policy_table
) {
5425 new_mapping
->table_usecount
= 1;
5427 new_mapping
->table_usecount
= 0;
5430 LIST_INSERT_HEAD(APPUUIDHASH(uuid
), new_mapping
, chain
);
5432 if (allocated_mapping
) {
5433 *allocated_mapping
= TRUE
;
5436 local_id
= new_mapping
->id
;
5444 necp_remove_uuid_app_id_mapping(uuid_t uuid
, bool *removed_mapping
, bool uuid_policy_table
)
5446 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5448 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5450 if (removed_mapping
) {
5451 *removed_mapping
= FALSE
;
5454 existing_mapping
= necp_uuid_lookup_app_id_locked(uuid
);
5455 if (existing_mapping
!= NULL
) {
5456 if (uuid_policy_table
) {
5457 existing_mapping
->table_usecount
--;
5459 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
5460 LIST_REMOVE(existing_mapping
, chain
);
5461 FREE(existing_mapping
, M_NECP
);
5462 if (removed_mapping
) {
5463 *removed_mapping
= TRUE
;
5472 static struct necp_uuid_id_mapping
*
5473 necp_uuid_get_null_service_id_mapping(void)
5475 static struct necp_uuid_id_mapping null_mapping
;
5476 uuid_clear(null_mapping
.uuid
);
5477 null_mapping
.id
= NECP_NULL_SERVICE_ID
;
5479 return &null_mapping
;
5482 static struct necp_uuid_id_mapping
*
5483 necp_uuid_lookup_service_id_locked(uuid_t uuid
)
5485 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5486 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5488 if (uuid_is_null(uuid
)) {
5489 return necp_uuid_get_null_service_id_mapping();
5492 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
5493 if (uuid_compare(searchentry
->uuid
, uuid
) == 0) {
5494 foundentry
= searchentry
;
5502 static struct necp_uuid_id_mapping
*
5503 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id
)
5505 struct necp_uuid_id_mapping
*searchentry
= NULL
;
5506 struct necp_uuid_id_mapping
*foundentry
= NULL
;
5508 if (local_id
== NECP_NULL_SERVICE_ID
) {
5509 return necp_uuid_get_null_service_id_mapping();
5512 LIST_FOREACH(searchentry
, &necp_uuid_service_id_list
, chain
) {
5513 if (searchentry
->id
== local_id
) {
5514 foundentry
= searchentry
;
5523 necp_create_uuid_service_id_mapping(uuid_t uuid
)
5525 u_int32_t local_id
= 0;
5526 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5528 if (uuid_is_null(uuid
)) {
5529 return NECP_NULL_SERVICE_ID
;
5532 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5534 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
5535 if (existing_mapping
!= NULL
) {
5536 local_id
= existing_mapping
->id
;
5537 os_ref_retain_locked(&existing_mapping
->refcount
);
5539 struct necp_uuid_id_mapping
*new_mapping
= NULL
;
5540 MALLOC(new_mapping
, struct necp_uuid_id_mapping
*, sizeof(*new_mapping
), M_NECP
, M_WAITOK
);
5541 if (new_mapping
!= NULL
) {
5542 uuid_copy(new_mapping
->uuid
, uuid
);
5543 new_mapping
->id
= necp_get_new_uuid_id(true);
5544 os_ref_init(&new_mapping
->refcount
, &necp_refgrp
);
5546 LIST_INSERT_HEAD(&necp_uuid_service_id_list
, new_mapping
, chain
);
5548 local_id
= new_mapping
->id
;
5556 necp_remove_uuid_service_id_mapping(uuid_t uuid
)
5558 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5560 if (uuid_is_null(uuid
)) {
5564 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5566 existing_mapping
= necp_uuid_lookup_service_id_locked(uuid
);
5567 if (existing_mapping
!= NULL
) {
5568 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
5569 LIST_REMOVE(existing_mapping
, chain
);
5570 FREE(existing_mapping
, M_NECP
);
5579 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id
)
5581 struct necp_uuid_id_mapping
*existing_mapping
= NULL
;
5583 if (service_id
== 0) {
5587 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5589 existing_mapping
= necp_uuid_lookup_uuid_with_service_id_locked(service_id
);
5590 if (existing_mapping
!= NULL
) {
5591 if (os_ref_release_locked(&existing_mapping
->refcount
) == 0) {
5592 LIST_REMOVE(existing_mapping
, chain
);
5593 FREE(existing_mapping
, M_NECP
);
5602 necp_kernel_socket_policies_update_uuid_table(void)
5604 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5606 if (necp_uuid_app_id_mappings_dirty
) {
5607 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR
, NULL
, PROC_UUID_NECP_APP_POLICY
) < 0) {
5608 NECPLOG0(LOG_DEBUG
, "Error clearing uuids from policy table\n");
5612 if (necp_num_uuid_app_id_mappings
> 0) {
5613 struct necp_uuid_id_mapping_head
*uuid_list_head
= NULL
;
5614 for (uuid_list_head
= &necp_uuid_app_id_hashtbl
[necp_uuid_app_id_hash_num_buckets
- 1]; uuid_list_head
>= necp_uuid_app_id_hashtbl
; uuid_list_head
--) {
5615 struct necp_uuid_id_mapping
*mapping
= NULL
;
5616 LIST_FOREACH(mapping
, uuid_list_head
, chain
) {
5617 if (mapping
->table_usecount
> 0 &&
5618 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD
, mapping
->uuid
, PROC_UUID_NECP_APP_POLICY
) < 0) {
5619 NECPLOG0(LOG_DEBUG
, "Error adding uuid to policy table\n");
5625 necp_uuid_app_id_mappings_dirty
= FALSE
;
5631 #define NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS (NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS)
5632 static necp_kernel_policy_id
5633 necp_kernel_ip_output_policy_add(necp_policy_order order
, necp_policy_order suborder
, u_int32_t session_order
, int session_pid
, u_int32_t condition_mask
, u_int32_t condition_negated_mask
, necp_kernel_policy_id cond_policy_id
, ifnet_t cond_bound_interface
, u_int32_t cond_last_interface_index
, u_int16_t cond_protocol
, union necp_sockaddr_union
*cond_local_start
, union necp_sockaddr_union
*cond_local_end
, u_int8_t cond_local_prefix
, union necp_sockaddr_union
*cond_remote_start
, union necp_sockaddr_union
*cond_remote_end
, u_int8_t cond_remote_prefix
, u_int16_t cond_packet_filter_tags
, necp_kernel_policy_result result
, necp_kernel_policy_result_parameter result_parameter
)
5635 struct necp_kernel_ip_output_policy
*new_kernel_policy
= NULL
;
5636 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
5638 new_kernel_policy
= zalloc_flags(necp_ip_policy_zone
, Z_WAITOK
| Z_ZERO
);
5639 new_kernel_policy
->id
= necp_kernel_policy_get_new_id(false);
5640 new_kernel_policy
->suborder
= suborder
;
5641 new_kernel_policy
->order
= order
;
5642 new_kernel_policy
->session_order
= session_order
;
5643 new_kernel_policy
->session_pid
= session_pid
;
5645 // Sanitize condition mask
5646 new_kernel_policy
->condition_mask
= (condition_mask
& NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS
);
5647 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
)) {
5648 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE
;
5650 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
)) {
5651 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX
;
5653 if ((new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) && (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
)) {
5654 new_kernel_policy
->condition_mask
&= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX
;
5656 new_kernel_policy
->condition_negated_mask
= condition_negated_mask
& new_kernel_policy
->condition_mask
;
5658 // Set condition values
5659 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
5660 new_kernel_policy
->cond_policy_id
= cond_policy_id
;
5662 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
5663 if (cond_bound_interface
) {
5664 ifnet_reference(cond_bound_interface
);
5666 new_kernel_policy
->cond_bound_interface
= cond_bound_interface
;
5668 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
5669 new_kernel_policy
->cond_last_interface_index
= cond_last_interface_index
;
5671 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
5672 new_kernel_policy
->cond_protocol
= cond_protocol
;
5674 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
5675 memcpy(&new_kernel_policy
->cond_local_start
, cond_local_start
, cond_local_start
->sa
.sa_len
);
5677 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5678 memcpy(&new_kernel_policy
->cond_local_end
, cond_local_end
, cond_local_end
->sa
.sa_len
);
5680 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5681 new_kernel_policy
->cond_local_prefix
= cond_local_prefix
;
5683 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
5684 memcpy(&new_kernel_policy
->cond_remote_start
, cond_remote_start
, cond_remote_start
->sa
.sa_len
);
5686 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5687 memcpy(&new_kernel_policy
->cond_remote_end
, cond_remote_end
, cond_remote_end
->sa
.sa_len
);
5689 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5690 new_kernel_policy
->cond_remote_prefix
= cond_remote_prefix
;
5692 if (new_kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
5693 new_kernel_policy
->cond_packet_filter_tags
= cond_packet_filter_tags
;
5696 new_kernel_policy
->result
= result
;
5697 memcpy(&new_kernel_policy
->result_parameter
, &result_parameter
, sizeof(result_parameter
));
5700 NECPLOG(LOG_DEBUG
, "Added kernel policy: ip output, id=%d, mask=%x\n", new_kernel_policy
->id
, new_kernel_policy
->condition_mask
);
5702 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies
, new_kernel_policy
, chain
, session_order
, order
, suborder
, tmp_kernel_policy
);
5704 return new_kernel_policy
? new_kernel_policy
->id
: 0;
5707 static struct necp_kernel_ip_output_policy
*
5708 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id
)
5710 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
5711 struct necp_kernel_ip_output_policy
*tmp_kernel_policy
= NULL
;
5713 if (policy_id
== 0) {
5717 LIST_FOREACH_SAFE(kernel_policy
, &necp_kernel_ip_output_policies
, chain
, tmp_kernel_policy
) {
5718 if (kernel_policy
->id
== policy_id
) {
5719 return kernel_policy
;
5727 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id
)
5729 struct necp_kernel_ip_output_policy
*policy
= NULL
;
5731 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5733 policy
= necp_kernel_ip_output_policy_find(policy_id
);
5735 LIST_REMOVE(policy
, chain
);
5737 if (policy
->cond_bound_interface
) {
5738 ifnet_release(policy
->cond_bound_interface
);
5739 policy
->cond_bound_interface
= NULL
;
5742 zfree(necp_ip_policy_zone
, policy
);
5750 necp_kernel_ip_output_policies_dump_all(void)
5753 struct necp_kernel_ip_output_policy
*policy
= NULL
;
5756 char result_string
[MAX_RESULT_STRING_LEN
];
5757 char proc_name_string
[MAXCOMLEN
+ 1];
5758 memset(result_string
, 0, MAX_RESULT_STRING_LEN
);
5759 memset(proc_name_string
, 0, MAXCOMLEN
+ 1);
5761 NECPLOG0(LOG_DEBUG
, "NECP IP Output Policies:\n");
5762 NECPLOG0(LOG_DEBUG
, "-----------\n");
5763 for (id_i
= 0; id_i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; id_i
++) {
5764 NECPLOG(LOG_DEBUG
, " ID Bucket: %d\n", id_i
);
5765 for (policy_i
= 0; necp_kernel_ip_output_policies_map
[id_i
] != NULL
&& (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
] != NULL
; policy_i
++) {
5766 policy
= (necp_kernel_ip_output_policies_map
[id_i
])[policy_i
];
5767 proc_name(policy
->session_pid
, proc_name_string
, MAXCOMLEN
);
5768 NECPLOG(LOG_DEBUG
, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d.%d\tMask: %5x\tResult: %s\n", policy_i
, policy
->id
, proc_name_string
, policy
->session_order
, policy
->order
, policy
->suborder
, policy
->condition_mask
, necp_get_result_description(result_string
, policy
->result
, policy
->result_parameter
));
5770 NECPLOG0(LOG_DEBUG
, "-----------\n");
5776 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy
*upper_policy
, struct necp_kernel_ip_output_policy
*lower_policy
)
5778 if (upper_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5779 if (upper_policy
->session_order
!= lower_policy
->session_order
) {
5780 // A skip cannot override a policy of a different session
5783 if (upper_policy
->result_parameter
.skip_policy_order
== 0 ||
5784 lower_policy
->order
>= upper_policy
->result_parameter
.skip_policy_order
) {
5785 // This policy is beyond the skip
5788 // This policy is inside the skip
5794 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
5799 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy
*policy
, struct necp_kernel_ip_output_policy
**policy_array
, int valid_indices
)
5801 bool can_skip
= FALSE
;
5802 u_int32_t highest_skip_session_order
= 0;
5803 u_int32_t highest_skip_order
= 0;
5805 for (i
= 0; i
< valid_indices
; i
++) {
5806 struct necp_kernel_ip_output_policy
*compared_policy
= policy_array
[i
];
5808 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5810 if (highest_skip_session_order
!= compared_policy
->session_order
||
5811 (highest_skip_order
!= 0 && compared_policy
->order
>= highest_skip_order
)) {
5812 // If we've moved on to the next session, or passed the skip window
5813 highest_skip_session_order
= 0;
5814 highest_skip_order
= 0;
5817 // If this policy is also a skip, in can increase the skip window
5818 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5819 if (compared_policy
->result_parameter
.skip_policy_order
> highest_skip_order
) {
5820 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
5827 if (compared_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5828 // This policy is a skip. Set the skip window accordingly
5830 highest_skip_session_order
= compared_policy
->session_order
;
5831 highest_skip_order
= compared_policy
->result_parameter
.skip_policy_order
;
5834 // The result of the compared policy must be able to block out this policy result
5835 if (!necp_kernel_ip_output_policy_results_overlap(compared_policy
, policy
)) {
5839 // If new policy matches All Interfaces, compared policy must also
5840 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
5844 // If new policy matches Local Networks, compared policy must also
5845 if ((policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) && !(compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
)) {
5849 // Default makes lower policies unecessary always
5850 if (compared_policy
->condition_mask
== 0) {
5854 // Compared must be more general than policy, and include only conditions within policy
5855 if ((policy
->condition_mask
& compared_policy
->condition_mask
) != compared_policy
->condition_mask
) {
5859 // Negative conditions must match for the overlapping conditions
5860 if ((policy
->condition_negated_mask
& compared_policy
->condition_mask
) != (compared_policy
->condition_negated_mask
& compared_policy
->condition_mask
)) {
5864 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
&&
5865 compared_policy
->cond_policy_id
!= policy
->cond_policy_id
) {
5869 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
&&
5870 compared_policy
->cond_bound_interface
!= policy
->cond_bound_interface
) {
5874 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
&&
5875 compared_policy
->cond_protocol
!= policy
->cond_protocol
) {
5879 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
5880 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
5881 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&policy
->cond_local_end
, (struct sockaddr
*)&compared_policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_end
)) {
5884 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
5885 if (compared_policy
->cond_local_prefix
> policy
->cond_local_prefix
||
5886 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_local_start
, (struct sockaddr
*)&compared_policy
->cond_local_start
, compared_policy
->cond_local_prefix
)) {
5892 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
5893 if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
5894 if (!necp_is_range_in_range((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&policy
->cond_remote_end
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_end
)) {
5897 } else if (compared_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
5898 if (compared_policy
->cond_remote_prefix
> policy
->cond_remote_prefix
||
5899 !necp_is_addr_in_subnet((struct sockaddr
*)&policy
->cond_remote_start
, (struct sockaddr
*)&compared_policy
->cond_remote_start
, compared_policy
->cond_remote_prefix
)) {
5912 necp_kernel_ip_output_policies_reprocess(void)
5915 int bucket_allocation_counts
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
5916 int bucket_current_free_index
[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
];
5917 struct necp_kernel_ip_output_policy
*kernel_policy
= NULL
;
5919 LCK_RW_ASSERT(&necp_kernel_policy_lock
, LCK_RW_ASSERT_EXCLUSIVE
);
5922 necp_kernel_ip_output_policies_condition_mask
= 0;
5923 necp_kernel_ip_output_policies_count
= 0;
5924 necp_kernel_ip_output_policies_non_id_count
= 0;
5926 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5927 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
5928 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
5929 necp_kernel_ip_output_policies_map
[i
] = NULL
;
5933 bucket_allocation_counts
[i
] = 0;
5936 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
5938 necp_kernel_ip_output_policies_condition_mask
|= kernel_policy
->condition_mask
;
5939 necp_kernel_ip_output_policies_count
++;
5941 /* Update bucket counts:
5942 * Non-id and SKIP policies will be added to all buckets
5943 * Add local networks policy to all buckets for incoming IP
5945 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) ||
5946 (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) ||
5947 kernel_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5948 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5949 bucket_allocation_counts
[i
]++;
5952 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
)) {
5953 necp_kernel_ip_output_policies_non_id_count
++;
5955 bucket_allocation_counts
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
)]++;
5959 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5960 if (bucket_allocation_counts
[i
] > 0) {
5961 // Allocate a NULL-terminated array of policy pointers for each bucket
5962 MALLOC(necp_kernel_ip_output_policies_map
[i
], struct necp_kernel_ip_output_policy
**, sizeof(struct necp_kernel_ip_output_policy
*) * (bucket_allocation_counts
[i
] + 1), M_NECP
, M_WAITOK
);
5963 if (necp_kernel_ip_output_policies_map
[i
] == NULL
) {
5967 // Initialize the first entry to NULL
5968 (necp_kernel_ip_output_policies_map
[i
])[0] = NULL
;
5970 bucket_current_free_index
[i
] = 0;
5973 LIST_FOREACH(kernel_policy
, &necp_kernel_ip_output_policies
, chain
) {
5974 // Insert pointers into map
5975 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) ||
5976 (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) ||
5977 kernel_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
5978 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
5979 if (!necp_dedup_policies
|| !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5980 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5981 bucket_current_free_index
[i
]++;
5982 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5986 i
= NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy
->cond_policy_id
);
5987 if (!necp_dedup_policies
|| !necp_kernel_ip_output_policy_is_unnecessary(kernel_policy
, necp_kernel_ip_output_policies_map
[i
], bucket_current_free_index
[i
])) {
5988 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = kernel_policy
;
5989 bucket_current_free_index
[i
]++;
5990 (necp_kernel_ip_output_policies_map
[i
])[(bucket_current_free_index
[i
])] = NULL
;
5994 necp_kernel_ip_output_policies_dump_all();
5998 // Free memory, reset mask to 0
5999 necp_kernel_ip_output_policies_condition_mask
= 0;
6000 necp_kernel_ip_output_policies_count
= 0;
6001 necp_kernel_ip_output_policies_non_id_count
= 0;
6002 for (i
= 0; i
< NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS
; i
++) {
6003 if (necp_kernel_ip_output_policies_map
[i
] != NULL
) {
6004 FREE(necp_kernel_ip_output_policies_map
[i
], M_NECP
);
6005 necp_kernel_ip_output_policies_map
[i
] = NULL
;
6011 // Outbound Policy Matching
6012 // ---------------------
6018 static struct substring
6019 necp_trim_dots_and_stars(char *string
, size_t length
)
6021 struct substring sub
;
6022 sub
.string
= string
;
6023 sub
.length
= string
? length
: 0;
6025 while (sub
.length
&& (sub
.string
[0] == '.' || sub
.string
[0] == '*')) {
6030 while (sub
.length
&& (sub
.string
[sub
.length
- 1] == '.' || sub
.string
[sub
.length
- 1] == '*')) {
6038 necp_create_trimmed_domain(char *string
, size_t length
)
6040 char *trimmed_domain
= NULL
;
6041 struct substring sub
= necp_trim_dots_and_stars(string
, length
);
6043 MALLOC(trimmed_domain
, char *, sub
.length
+ 1, M_NECP
, M_WAITOK
);
6044 if (trimmed_domain
== NULL
) {
6048 memcpy(trimmed_domain
, sub
.string
, sub
.length
);
6049 trimmed_domain
[sub
.length
] = 0;
6051 return trimmed_domain
;
6055 necp_count_dots(char *string
, size_t length
)
6060 for (i
= 0; i
< length
; i
++) {
6061 if (string
[i
] == '.') {
6070 necp_check_suffix(struct substring parent
, struct substring suffix
, bool require_dot_before_suffix
)
6072 if (parent
.length
<= suffix
.length
) {
6076 size_t length_difference
= (parent
.length
- suffix
.length
);
6078 if (require_dot_before_suffix
) {
6079 if (((char *)(parent
.string
+ length_difference
- 1))[0] != '.') {
6084 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6085 return strncasecmp(parent
.string
+ length_difference
, suffix
.string
, suffix
.length
) == 0;
6089 necp_hostname_matches_domain(struct substring hostname_substring
, u_int8_t hostname_dot_count
, char *domain
, u_int8_t domain_dot_count
)
6091 if (hostname_substring
.string
== NULL
|| domain
== NULL
) {
6092 return hostname_substring
.string
== domain
;
6095 struct substring domain_substring
;
6096 domain_substring
.string
= domain
;
6097 domain_substring
.length
= strlen(domain
);
6099 if (hostname_dot_count
== domain_dot_count
) {
6100 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6101 if (hostname_substring
.length
== domain_substring
.length
&&
6102 strncasecmp(hostname_substring
.string
, domain_substring
.string
, hostname_substring
.length
) == 0) {
6105 } else if (domain_dot_count
< hostname_dot_count
) {
6106 if (necp_check_suffix(hostname_substring
, domain_substring
, TRUE
)) {
6115 net_domain_contains_hostname(char *hostname_string
, char *domain_string
)
6117 if (hostname_string
== NULL
||
6118 domain_string
== NULL
) {
6122 struct substring hostname_substring
;
6123 hostname_substring
.string
= hostname_string
;
6124 hostname_substring
.length
= strlen(hostname_string
);
6126 return necp_hostname_matches_domain(hostname_substring
,
6127 necp_count_dots(hostname_string
, hostname_substring
.length
),
6129 necp_count_dots(domain_string
, strlen(domain_string
)));
6132 #define NECP_MAX_STRING_LEN 1024
6135 necp_copy_string(char *string
, size_t length
)
6137 char *copied_string
= NULL
;
6139 if (length
> NECP_MAX_STRING_LEN
) {
6143 MALLOC(copied_string
, char *, length
+ 1, M_NECP
, M_WAITOK
);
6144 if (copied_string
== NULL
) {
6148 memcpy(copied_string
, string
, length
);
6149 copied_string
[length
] = 0;
6151 return copied_string
;
6155 necp_get_primary_direct_interface_index(void)
6157 u_int32_t interface_index
= IFSCOPE_NONE
;
6159 ifnet_head_lock_shared();
6160 struct ifnet
*ordered_interface
= NULL
;
6161 TAILQ_FOREACH(ordered_interface
, &ifnet_ordered_head
, if_ordered_link
) {
6162 const u_int8_t functional_type
= if_functional_type(ordered_interface
, TRUE
);
6163 if (functional_type
!= IFRTYPE_FUNCTIONAL_UNKNOWN
&&
6164 functional_type
!= IFRTYPE_FUNCTIONAL_LOOPBACK
) {
6165 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
6166 interface_index
= ordered_interface
->if_index
;
6172 return interface_index
;
6176 necp_get_parent_cred_result(proc_t proc
, struct necp_socket_info
*info
)
6178 task_t task
= proc_task(proc
? proc
: current_proc());
6179 coalition_t coal
= task_get_coalition(task
, COALITION_TYPE_JETSAM
);
6181 if (coal
== COALITION_NULL
|| coalition_is_leader(task
, coal
)) {
6182 // No parent, nothing to do
6186 task_t lead_task
= coalition_get_leader(coal
);
6187 if (lead_task
!= NULL
) {
6188 proc_t lead_proc
= get_bsdtask_info(lead_task
);
6189 if (lead_proc
!= NULL
) {
6190 kauth_cred_t lead_cred
= kauth_cred_proc_ref(lead_proc
);
6191 if (lead_cred
!= NULL
) {
6192 errno_t cred_result
= priv_check_cred(lead_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
6193 kauth_cred_unref(&lead_cred
);
6194 info
->cred_result
= cred_result
;
6197 task_deallocate(lead_task
);
6201 // Some processes, due to particular entitlements, require using an NECP client to
6202 // access networking. Returns true if the result should be a Drop.
6204 necp_check_missing_client_drop(proc_t proc
, struct necp_socket_info
*info
)
6206 task_t task
= proc_task(proc
? proc
: current_proc());
6208 if (!info
->has_client
&&
6210 IOTaskHasEntitlement(task
, "com.apple.developer.on-demand-install-capable")) {
6211 // Drop connections that don't use NECP clients and have the
6212 // com.apple.developer.on-demand-install-capable entitlement.
6213 // This effectively restricts those processes to only using
6214 // an NECP-aware path for networking.
6222 necp_check_restricted_multicast_drop(proc_t proc
, struct necp_socket_info
*info
, bool check_minor_version
)
6224 if (!necp_restrict_multicast
|| proc
== NULL
) {
6228 // Check for multicast/broadcast here
6229 if (info
->remote_addr
.sa
.sa_family
== AF_INET
) {
6230 if (!IN_MULTICAST(ntohl(info
->remote_addr
.sin
.sin_addr
.s_addr
)) &&
6231 info
->remote_addr
.sin
.sin_addr
.s_addr
!= INADDR_BROADCAST
) {
6234 } else if (info
->remote_addr
.sa
.sa_family
== AF_INET6
) {
6235 if (!IN6_IS_ADDR_MULTICAST(&info
->remote_addr
.sin6
.sin6_addr
)) {
6243 if (necp_is_platform_binary(proc
)) {
6247 const uint32_t platform
= proc_platform(proc
);
6248 const uint32_t sdk
= proc_sdk(proc
);
6250 // Enforce for iOS, linked on or after version 14
6251 // If the caller set `check_minor_version`, only enforce starting at 14.5
6252 if (platform
!= PLATFORM_IOS
||
6255 (check_minor_version
&& (sdk
>> 16) == 14 && ((sdk
>> 8) & 0xff) < 5)) {
6259 // Allow entitled processes to use multicast
6260 task_t task
= proc_task(proc
);
6262 IOTaskHasEntitlement(task
, "com.apple.developer.networking.multicast")) {
6266 const uint32_t min_sdk
= proc_min_sdk(proc
);
6267 NECPLOG(LOG_INFO
, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk
, min_sdk
);
6272 #define NECP_KERNEL_ADDRESS_TYPE_CONDITIONS (NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_LOCAL_NETWORKS)
6274 necp_application_fillout_info_locked(uuid_t application_uuid
, uuid_t real_application_uuid
, uuid_t responsible_application_uuid
, char *account
, char *domain
, pid_t pid
, int32_t pid_version
, uid_t uid
, u_int16_t protocol
, u_int32_t bound_interface_index
, u_int32_t traffic_class
, union necp_sockaddr_union
*local_addr
, union necp_sockaddr_union
*remote_addr
, u_int16_t local_port
, u_int16_t remote_port
, bool has_client
, proc_t real_proc
, proc_t proc
, proc_t responsible_proc
, u_int32_t drop_order
, u_int32_t client_flags
, struct necp_socket_info
*info
, bool is_loopback
, bool is_delegated
)
6276 memset(info
, 0, sizeof(struct necp_socket_info
));
6279 info
->pid_version
= pid_version
;
6281 info
->protocol
= protocol
;
6282 info
->bound_interface_index
= bound_interface_index
;
6283 info
->traffic_class
= traffic_class
;
6284 info
->has_client
= has_client
;
6285 info
->drop_order
= drop_order
;
6286 info
->client_flags
= client_flags
;
6287 info
->is_loopback
= is_loopback
;
6288 info
->is_delegated
= is_delegated
;
6290 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(application_uuid
)) {
6291 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(application_uuid
);
6292 if (existing_mapping
) {
6293 info
->application_id
= existing_mapping
->id
;
6297 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
&& !uuid_is_null(real_application_uuid
)) {
6298 if (uuid_compare(application_uuid
, real_application_uuid
) == 0) {
6299 info
->real_application_id
= info
->application_id
;
6301 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(real_application_uuid
);
6302 if (existing_mapping
) {
6303 info
->real_application_id
= existing_mapping
->id
;
6308 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
&& !uuid_is_null(responsible_application_uuid
)) {
6309 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(responsible_application_uuid
);
6310 if (existing_mapping
!= NULL
) {
6311 info
->real_application_id
= info
->application_id
;
6312 info
->application_id
= existing_mapping
->id
;
6313 info
->used_responsible_pid
= true;
6317 if (info
->used_responsible_pid
) {
6318 proc
= responsible_proc
;
6321 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
&& proc
!= NULL
) {
6322 info
->cred_result
= priv_check_cred(proc_ucred(proc
), PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
6323 if (info
->cred_result
!= 0) {
6324 // Process does not have entitlement, check the parent process
6325 necp_get_parent_cred_result(proc
, info
);
6329 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
&& proc
!= NULL
) {
6330 info
->is_platform_binary
= necp_is_platform_binary(proc
) ? true : false;
6333 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
&& real_proc
!= NULL
) {
6334 info
->real_is_platform_binary
= (necp_is_platform_binary(real_proc
) ? true : false);
6337 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& account
!= NULL
) {
6338 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, account
);
6339 if (existing_mapping
) {
6340 info
->account_id
= existing_mapping
->id
;
6344 if (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
6345 info
->domain
= domain
;
6348 if (necp_restrict_multicast
||
6349 (necp_kernel_application_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
)) {
6350 if (local_addr
&& local_addr
->sa
.sa_len
> 0) {
6351 memcpy(&info
->local_addr
, local_addr
, local_addr
->sa
.sa_len
);
6352 if (local_port
!= 0) {
6353 info
->local_addr
.sin6
.sin6_port
= local_port
;
6356 if (remote_addr
&& remote_addr
->sa
.sa_len
> 0) {
6357 info
->local_addr
.sa
.sa_family
= remote_addr
->sa
.sa_family
;
6358 info
->local_addr
.sa
.sa_len
= remote_addr
->sa
.sa_len
;
6360 info
->local_addr
.sin6
.sin6_family
= AF_INET6
;
6361 info
->local_addr
.sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
6363 if (local_port
!= 0) {
6364 info
->local_addr
.sin6
.sin6_port
= local_port
;
6367 if (remote_addr
&& remote_addr
->sa
.sa_len
> 0) {
6368 memcpy(&info
->remote_addr
, remote_addr
, remote_addr
->sa
.sa_len
);
6369 if (remote_port
!= 0) {
6370 info
->remote_addr
.sin6
.sin6_port
= remote_port
;
6372 } else if (remote_port
!= 0) {
6373 info
->remote_addr
.sin6
.sin6_len
= sizeof(struct sockaddr_in6
);
6374 info
->remote_addr
.sin6
.sin6_family
= AF_INET6
;
6375 info
->remote_addr
.sin6
.sin6_port
= remote_port
;
6381 necp_send_application_interface_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t if_functional_type
)
6383 struct kev_netpolicy_ifdenied ev_ifdenied
;
6385 bzero(&ev_ifdenied
, sizeof(ev_ifdenied
));
6387 ev_ifdenied
.ev_data
.epid
= pid
;
6388 uuid_copy(ev_ifdenied
.ev_data
.euuid
, proc_uuid
);
6389 ev_ifdenied
.ev_if_functional_type
= if_functional_type
;
6391 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED
, &ev_ifdenied
.ev_data
, sizeof(ev_ifdenied
));
6395 necp_send_network_denied_event(pid_t pid
, uuid_t proc_uuid
, u_int32_t network_type
)
6397 struct kev_netpolicy_netdenied ev_netdenied
= {};
6399 bzero(&ev_netdenied
, sizeof(ev_netdenied
));
6401 ev_netdenied
.ev_data
.epid
= pid
;
6402 uuid_copy(ev_netdenied
.ev_data
.euuid
, proc_uuid
);
6403 ev_netdenied
.ev_network_type
= network_type
;
6405 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED
, &ev_netdenied
.ev_data
, sizeof(ev_netdenied
));
6408 extern char *proc_name_address(void *p
);
6410 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _d) \
6411 if (!has_checked_delegation_entitlement) { \
6412 has_delegation_entitlement = (priv_check_cred(proc_ucred(_p), PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
6413 has_checked_delegation_entitlement = TRUE; \
6415 if (!has_delegation_entitlement) { \
6416 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
6417 proc_name_address(_p), proc_pid(_p), _d); \
6422 necp_application_find_policy_match_internal(proc_t proc
,
6423 u_int8_t
*parameters
,
6424 u_int32_t parameters_size
,
6425 struct necp_aggregate_result
*returned_result
,
6428 u_int required_interface_index
,
6429 const union necp_sockaddr_union
*override_local_addr
,
6430 const union necp_sockaddr_union
*override_remote_addr
,
6431 struct necp_client_endpoint
*returned_v4_gateway
,
6432 struct necp_client_endpoint
*returned_v6_gateway
,
6433 struct rtentry
**returned_route
, bool ignore_address
,
6435 uuid_t
*returned_override_euuid
)
6440 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
6441 struct necp_socket_info info
;
6442 necp_kernel_policy_filter filter_control_unit
= 0;
6443 necp_kernel_policy_result service_action
= 0;
6444 necp_kernel_policy_service service
= { 0, 0 };
6446 u_int16_t protocol
= 0;
6447 u_int32_t bound_interface_index
= required_interface_index
;
6448 u_int32_t traffic_class
= 0;
6449 u_int32_t client_flags
= 0;
6450 union necp_sockaddr_union local_addr
;
6451 union necp_sockaddr_union remote_addr
;
6452 bool no_remote_addr
= FALSE
;
6453 u_int8_t remote_family
= 0;
6454 bool no_local_addr
= FALSE
;
6455 u_int16_t local_port
= 0;
6456 u_int16_t remote_port
= 0;
6457 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
6458 bool is_delegated
= false;
6460 if (override_local_addr
) {
6461 memcpy(&local_addr
, override_local_addr
, sizeof(local_addr
));
6463 memset(&local_addr
, 0, sizeof(local_addr
));
6465 if (override_remote_addr
) {
6466 memcpy(&remote_addr
, override_remote_addr
, sizeof(remote_addr
));
6468 memset(&remote_addr
, 0, sizeof(remote_addr
));
6471 // Initialize UID, PID, and UUIDs to the current process
6472 uid_t uid
= kauth_cred_getuid(proc_ucred(proc
));
6473 pid_t pid
= proc_pid(proc
);
6474 int32_t pid_version
= proc_pidversion(proc
);
6475 uuid_t application_uuid
;
6476 uuid_clear(application_uuid
);
6477 uuid_t real_application_uuid
;
6478 uuid_clear(real_application_uuid
);
6479 proc_getexecutableuuid(proc
, real_application_uuid
, sizeof(real_application_uuid
));
6480 uuid_copy(application_uuid
, real_application_uuid
);
6481 uuid_t responsible_application_uuid
;
6482 uuid_clear(responsible_application_uuid
);
6484 char *domain
= NULL
;
6485 char *account
= NULL
;
6487 #define NECP_MAX_REQUIRED_AGENTS 16
6488 u_int32_t num_required_agent_types
= 0;
6489 struct necp_client_parameter_netagent_type required_agent_types
[NECP_MAX_REQUIRED_AGENTS
];
6490 memset(&required_agent_types
, 0, sizeof(required_agent_types
));
6492 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
6493 u_int32_t netagent_use_flags
[NECP_MAX_NETAGENTS
];
6494 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
6495 memset(&netagent_use_flags
, 0, sizeof(netagent_use_flags
));
6496 int netagent_cursor
;
6498 bool has_checked_delegation_entitlement
= FALSE
;
6499 bool has_delegation_entitlement
= FALSE
;
6501 proc_t responsible_proc
= PROC_NULL
;
6502 proc_t effective_proc
= proc
;
6503 bool release_eproc
= false;
6504 necp_socket_bypass_type_t bypass_type
= NECP_BYPASS_TYPE_NONE
;
6506 u_int32_t flow_divert_aggregate_unit
= 0;
6508 if (returned_result
== NULL
) {
6512 if (returned_v4_gateway
!= NULL
) {
6513 memset(returned_v4_gateway
, 0, sizeof(struct necp_client_endpoint
));
6516 if (returned_v6_gateway
!= NULL
) {
6517 memset(returned_v6_gateway
, 0, sizeof(struct necp_client_endpoint
));
6520 if (returned_override_euuid
!= NULL
) {
6521 uuid_clear(*returned_override_euuid
);
6524 memset(returned_result
, 0, sizeof(struct necp_aggregate_result
));
6526 u_int32_t drop_order
= necp_process_drop_order(proc_ucred(proc
));
6528 necp_kernel_policy_result drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
6530 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6531 if (necp_kernel_application_policies_count
== 0) {
6532 if (necp_drop_all_order
> 0 || drop_order
> 0) {
6533 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6534 lck_rw_done(&necp_kernel_policy_lock
);
6538 lck_rw_done(&necp_kernel_policy_lock
);
6540 while ((offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)) <= parameters_size
) {
6541 u_int8_t type
= necp_buffer_get_tlv_type(parameters
, offset
);
6542 u_int32_t length
= necp_buffer_get_tlv_length(parameters
, offset
);
6544 if (length
> (parameters_size
- (offset
+ sizeof(u_int8_t
) + sizeof(u_int32_t
)))) {
6545 // If the length is larger than what can fit in the remaining parameters size, bail
6546 NECPLOG(LOG_ERR
, "Invalid TLV length (%u)", length
);
6551 u_int8_t
*value
= necp_buffer_get_tlv_value(parameters
, offset
, NULL
);
6552 if (value
!= NULL
) {
6554 case NECP_CLIENT_PARAMETER_APPLICATION
: {
6555 if (length
>= sizeof(uuid_t
)) {
6556 if (uuid_compare(application_uuid
, value
) == 0) {
6561 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "euuid");
6563 is_delegated
= true;
6564 uuid_copy(application_uuid
, value
);
6568 case NECP_CLIENT_PARAMETER_REAL_APPLICATION
: {
6569 if (length
>= sizeof(uuid_t
)) {
6570 if (uuid_compare(real_application_uuid
, value
) == 0) {
6575 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uuid");
6577 is_delegated
= true;
6578 uuid_copy(real_application_uuid
, value
);
6582 case NECP_CLIENT_PARAMETER_PID
: {
6583 if (length
>= sizeof(pid_t
)) {
6584 if (memcmp(&pid
, value
, sizeof(pid_t
)) == 0) {
6589 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "pid");
6591 is_delegated
= true;
6592 memcpy(&pid
, value
, sizeof(pid_t
));
6596 case NECP_CLIENT_PARAMETER_UID
: {
6597 if (length
>= sizeof(uid_t
)) {
6598 if (memcmp(&uid
, value
, sizeof(uid_t
)) == 0) {
6603 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc
, "uid");
6605 is_delegated
= true;
6606 memcpy(&uid
, value
, sizeof(uid_t
));
6610 case NECP_CLIENT_PARAMETER_DOMAIN
: {
6611 domain
= (char *)value
;
6612 domain
[length
- 1] = 0;
6615 case NECP_CLIENT_PARAMETER_ACCOUNT
: {
6616 account
= (char *)value
;
6617 account
[length
- 1] = 0;
6620 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS
: {
6621 if (length
>= sizeof(u_int32_t
)) {
6622 memcpy(&traffic_class
, value
, sizeof(u_int32_t
));
6626 case NECP_CLIENT_PARAMETER_IP_PROTOCOL
: {
6627 if (length
>= sizeof(u_int16_t
)) {
6628 memcpy(&protocol
, value
, sizeof(u_int16_t
));
6629 } else if (length
>= sizeof(u_int8_t
)) {
6630 memcpy(&protocol
, value
, sizeof(u_int8_t
));
6634 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE
: {
6635 if (length
<= IFXNAMSIZ
&& length
> 0) {
6636 ifnet_t bound_interface
= NULL
;
6637 char interface_name
[IFXNAMSIZ
];
6638 memcpy(interface_name
, value
, length
);
6639 interface_name
[length
- 1] = 0; // Make sure the string is NULL terminated
6640 if (ifnet_find_by_name(interface_name
, &bound_interface
) == 0) {
6641 bound_interface_index
= bound_interface
->if_index
;
6642 ifnet_release(bound_interface
);
6647 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS
: {
6648 if (ignore_address
|| override_local_addr
) {
6652 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
6653 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
6654 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
6655 memcpy(&local_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
6660 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS
: {
6661 if (ignore_address
|| override_remote_addr
) {
6665 if (length
>= sizeof(struct necp_policy_condition_addr
)) {
6666 struct necp_policy_condition_addr
*address_struct
= (struct necp_policy_condition_addr
*)(void *)value
;
6667 if (necp_address_is_valid(&address_struct
->address
.sa
)) {
6668 memcpy(&remote_addr
, &address_struct
->address
, sizeof(address_struct
->address
));
6673 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT
: {
6674 if (ignore_address
|| override_local_addr
) {
6678 if (length
>= sizeof(struct necp_client_endpoint
)) {
6679 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
6680 if (endpoint
->u
.endpoint
.endpoint_family
== AF_UNSPEC
&&
6681 endpoint
->u
.endpoint
.endpoint_port
!= 0) {
6683 local_port
= endpoint
->u
.endpoint
.endpoint_port
;
6688 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT
: {
6689 if (ignore_address
|| override_remote_addr
) {
6693 if (length
>= sizeof(struct necp_client_endpoint
)) {
6694 struct necp_client_endpoint
*endpoint
= (struct necp_client_endpoint
*)(void *)value
;
6695 if (endpoint
->u
.endpoint
.endpoint_family
== AF_UNSPEC
&&
6696 endpoint
->u
.endpoint
.endpoint_port
!= 0) {
6698 remote_port
= endpoint
->u
.endpoint
.endpoint_port
;
6703 case NECP_CLIENT_PARAMETER_FLAGS
: {
6704 if (length
>= sizeof(client_flags
)) {
6705 memcpy(&client_flags
, value
, sizeof(client_flags
));
6709 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE
:
6710 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE
: {
6711 if (num_required_agent_types
>= NECP_MAX_REQUIRED_AGENTS
) {
6714 if (length
>= sizeof(struct necp_client_parameter_netagent_type
)) {
6715 memcpy(&required_agent_types
[num_required_agent_types
], value
, sizeof(struct necp_client_parameter_netagent_type
));
6716 num_required_agent_types
++;
6727 offset
+= sizeof(u_int8_t
) + sizeof(u_int32_t
) + length
;
6730 // Check for loopback exception
6731 if (necp_pass_loopback
> 0 && necp_is_loopback(&local_addr
.sa
, &remote_addr
.sa
, NULL
, NULL
, bound_interface_index
)) {
6732 bypass_type
= NECP_BYPASS_TYPE_LOOPBACK
;
6735 if (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
&& necp_pass_loopback
== NECP_LOOPBACK_PASS_ALL
) {
6736 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6737 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6738 returned_result
->routed_interface_index
= lo_ifp
->if_index
;
6739 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
6743 if (proc_pid(effective_proc
) != pid
) {
6744 proc_t found_proc
= proc_find(pid
);
6745 if (found_proc
!= PROC_NULL
) {
6746 effective_proc
= found_proc
;
6747 pid_version
= proc_pidversion(effective_proc
);
6748 release_eproc
= true;
6751 #if defined(XNU_TARGET_OS_OSX)
6752 if (effective_proc
->p_responsible_pid
> 0 && effective_proc
->p_responsible_pid
!= pid
) {
6753 responsible_proc
= proc_find(effective_proc
->p_responsible_pid
);
6754 if (responsible_proc
!= PROC_NULL
) {
6755 proc_getexecutableuuid(responsible_proc
, responsible_application_uuid
, sizeof(responsible_application_uuid
));
6758 #endif /* defined(XNU_TARGET_OS_OSX) */
6761 lck_rw_lock_shared(&necp_kernel_policy_lock
);
6763 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
6764 size_t route_rule_id_array_count
= 0;
6765 necp_application_fillout_info_locked(application_uuid
, real_application_uuid
, responsible_application_uuid
, account
, domain
, pid
, pid_version
, uid
, protocol
, bound_interface_index
, traffic_class
, &local_addr
, &remote_addr
, local_port
, remote_port
, has_client
, proc
, effective_proc
, responsible_proc
, drop_order
, client_flags
, &info
, (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
), is_delegated
);
6766 matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map
, &info
, &filter_control_unit
, route_rule_id_array
, &route_rule_id_array_count
, MAX_AGGREGATE_ROUTE_RULES
, &service_action
, &service
, netagent_ids
, netagent_use_flags
, NECP_MAX_NETAGENTS
, required_agent_types
, num_required_agent_types
, info
.used_responsible_pid
? responsible_proc
: effective_proc
, 0, NULL
, NULL
, &drop_dest_policy_result
, &drop_all_bypass
, &flow_divert_aggregate_unit
);
6768 // Check for loopback exception again after the policy match
6769 if (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
&&
6770 necp_pass_loopback
== NECP_LOOPBACK_PASS_WITH_FILTER
&&
6771 (matched_policy
== NULL
|| matched_policy
->result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
)) {
6772 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
6773 returned_result
->filter_control_unit
= 0;
6775 returned_result
->filter_control_unit
= filter_control_unit
;
6778 if (flow_divert_aggregate_unit
> 0) {
6779 returned_result
->flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
6782 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6783 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_PASS
;
6784 returned_result
->routed_interface_index
= lo_ifp
->if_index
;
6785 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
6790 if (matched_policy
) {
6791 returned_result
->policy_id
= matched_policy
->id
;
6792 returned_result
->routing_result
= matched_policy
->result
;
6793 memcpy(&returned_result
->routing_result_parameter
, &matched_policy
->result_parameter
, sizeof(returned_result
->routing_result_parameter
));
6794 if (returned_override_euuid
!= NULL
&& info
.used_responsible_pid
&& !(matched_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
)) {
6795 uuid_copy(*returned_override_euuid
, responsible_application_uuid
);
6798 bool drop_all
= false;
6799 if (necp_drop_all_order
> 0 || info
.drop_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
6800 // Mark socket as a drop if drop_all is set
6802 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
6803 drop_all_bypass
= necp_check_drop_all_bypass_result(proc
);
6806 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
6807 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6808 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6810 returned_result
->policy_id
= 0;
6811 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
6814 if (necp_check_missing_client_drop(proc
, &info
) ||
6815 necp_check_restricted_multicast_drop(proc
, &info
, false)) {
6817 returned_result
->policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
6818 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6820 if (filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
6821 returned_result
->filter_control_unit
= 0;
6823 returned_result
->filter_control_unit
= filter_control_unit
;
6826 if (flow_divert_aggregate_unit
> 0) {
6827 returned_result
->flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
6830 returned_result
->service_action
= service_action
;
6832 // Handle trigger service
6833 if (service
.identifier
!= 0) {
6834 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(service
.identifier
);
6835 if (mapping
!= NULL
) {
6836 struct necp_service_registration
*service_registration
= NULL
;
6837 uuid_copy(returned_result
->service_uuid
, mapping
->uuid
);
6838 returned_result
->service_data
= service
.data
;
6839 if (service
.identifier
== NECP_NULL_SERVICE_ID
) {
6840 // NULL service is always 'registered'
6841 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
6843 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
6844 if (service
.identifier
== service_registration
->service_id
) {
6845 returned_result
->service_flags
|= NECP_SERVICE_FLAGS_REGISTERED
;
6854 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
6855 struct necp_uuid_id_mapping
*mapping
= NULL
;
6856 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
6857 if (netagent_id
== 0) {
6860 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
6861 if (mapping
!= NULL
) {
6862 uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
);
6863 returned_result
->netagent_use_flags
[netagent_cursor
] = netagent_use_flags
[netagent_cursor
];
6867 // Do routing evaluation
6868 u_int output_bound_interface
= bound_interface_index
;
6869 if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
6870 output_bound_interface
= returned_result
->routing_result_parameter
.scoped_interface_index
;
6871 } else if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
6872 output_bound_interface
= returned_result
->routing_result_parameter
.tunnel_interface_index
;
6873 } else if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
) {
6874 output_bound_interface
= necp_get_primary_direct_interface_index();
6875 if (output_bound_interface
== IFSCOPE_NONE
) {
6876 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
6878 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
;
6879 returned_result
->routing_result_parameter
.scoped_interface_index
= output_bound_interface
;
6883 if (returned_result
->routing_result
== NECP_KERNEL_POLICY_RESULT_DROP
&&
6884 returned_result
->routing_result_parameter
.drop_flags
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) {
6885 // Trigger the event that we dropped due to a local network policy
6886 necp_send_network_denied_event(pid
, application_uuid
, NETPOLICY_NETWORKTYPE_LOCAL
);
6887 if (reason
!= NULL
) {
6888 *reason
= NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED
;
6892 if (local_addr
.sa
.sa_len
== 0 ||
6893 (local_addr
.sa
.sa_family
== AF_INET
&& local_addr
.sin
.sin_addr
.s_addr
== 0) ||
6894 (local_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&local_addr
.sin6
.sin6_addr
))) {
6895 no_local_addr
= TRUE
;
6898 if (remote_addr
.sa
.sa_len
== 0 ||
6899 (remote_addr
.sa
.sa_family
== AF_INET
&& remote_addr
.sin
.sin_addr
.s_addr
== 0) ||
6900 (remote_addr
.sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
.sin6
.sin6_addr
))) {
6901 no_remote_addr
= TRUE
;
6902 remote_family
= remote_addr
.sa
.sa_family
;
6905 returned_result
->routed_interface_index
= 0;
6906 struct rtentry
*rt
= NULL
;
6907 if (!no_local_addr
&& (client_flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) != 0) {
6908 // Treat the output bound interface as the routed interface for local address
6909 // validation later.
6910 returned_result
->routed_interface_index
= output_bound_interface
;
6912 if (no_remote_addr
) {
6913 memset(&remote_addr
, 0, sizeof(remote_addr
));
6914 if (remote_family
== AF_INET6
) {
6915 // Reset address to ::
6916 remote_addr
.sa
.sa_family
= AF_INET6
;
6917 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
6919 // Reset address to 0.0.0.0
6920 remote_addr
.sa
.sa_family
= AF_INET
;
6921 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in
);
6925 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
6926 output_bound_interface
);
6928 if (remote_addr
.sa
.sa_family
== AF_INET
&& rt
!= NULL
&&
6929 IS_INTF_CLAT46(rt
->rt_ifp
)) {
6932 returned_result
->routed_interface_index
= 0;
6935 if (no_remote_addr
&& remote_family
== AF_UNSPEC
&&
6936 (rt
== NULL
|| rt
->rt_ifp
== NULL
)) {
6937 // Route lookup for default IPv4 failed, try IPv6
6939 // Cleanup old route if necessary
6945 // Reset address to ::
6946 memset(&remote_addr
, 0, sizeof(remote_addr
));
6947 remote_addr
.sa
.sa_family
= AF_INET6
;
6948 remote_addr
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
6951 rt
= rtalloc1_scoped((struct sockaddr
*)&remote_addr
, 0, 0,
6952 output_bound_interface
);
6956 rt
->rt_ifp
!= NULL
) {
6957 returned_result
->routed_interface_index
= rt
->rt_ifp
->if_index
;
6959 * For local addresses, we allow the interface scope to be
6960 * either the loopback interface or the interface hosting the
6963 if (bound_interface_index
!= IFSCOPE_NONE
&&
6964 rt
->rt_ifa
!= NULL
&& rt
->rt_ifa
->ifa_ifp
&&
6965 (output_bound_interface
== lo_ifp
->if_index
||
6966 rt
->rt_ifp
->if_index
== lo_ifp
->if_index
||
6967 rt
->rt_ifa
->ifa_ifp
->if_index
== bound_interface_index
)) {
6968 struct sockaddr_storage dst
;
6969 unsigned int ifscope
= bound_interface_index
;
6972 * Transform dst into the internal routing table form
6974 (void) sa_copy((struct sockaddr
*)&remote_addr
,
6977 if ((rt
->rt_ifp
->if_index
== lo_ifp
->if_index
) ||
6978 rt_ifa_is_dst((struct sockaddr
*)&dst
, rt
->rt_ifa
)) {
6979 returned_result
->routed_interface_index
=
6980 bound_interface_index
;
6986 if (returned_result
->routed_interface_index
!= 0 &&
6987 returned_result
->routed_interface_index
!= lo_ifp
->if_index
&& // Loopback can accept any local address
6989 // Transform local_addr into the ifaddr form
6990 // IPv6 Scope IDs are always embedded in the ifaddr list
6991 struct sockaddr_storage local_address_sanitized
;
6992 u_int ifscope
= IFSCOPE_NONE
;
6993 (void)sa_copy(&local_addr
.sa
, &local_address_sanitized
, &ifscope
);
6994 SIN(&local_address_sanitized
)->sin_port
= 0;
6995 if (local_address_sanitized
.ss_family
== AF_INET6
) {
6996 SIN6(&local_address_sanitized
)->sin6_scope_id
= 0;
6999 // Validate local address on routed interface
7000 struct ifaddr
*ifa
= ifa_ifwithaddr_scoped((struct sockaddr
*)&local_address_sanitized
, returned_result
->routed_interface_index
);
7002 // Interface address not found, reject route
7003 returned_result
->routed_interface_index
= 0;
7009 ifaddr_release(ifa
);
7014 if (flags
!= NULL
) {
7015 if ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_LISTENER
) == 0) {
7016 // Check for local/direct
7017 bool is_local
= FALSE
;
7018 if (rt
!= NULL
&& (rt
->rt_flags
& RTF_LOCAL
)) {
7020 } else if (returned_result
->routed_interface_index
!= 0 &&
7022 // Clean up the address before comparison with interface addresses
7024 // Transform remote_addr into the ifaddr form
7025 // IPv6 Scope IDs are always embedded in the ifaddr list
7026 struct sockaddr_storage remote_address_sanitized
;
7027 u_int ifscope
= IFSCOPE_NONE
;
7028 (void)sa_copy(&remote_addr
.sa
, &remote_address_sanitized
, &ifscope
);
7029 SIN(&remote_address_sanitized
)->sin_port
= 0;
7030 if (remote_address_sanitized
.ss_family
== AF_INET6
) {
7031 SIN6(&remote_address_sanitized
)->sin6_scope_id
= 0;
7034 // Check if remote address is an interface address
7035 struct ifaddr
*ifa
= ifa_ifwithaddr((struct sockaddr
*)&remote_address_sanitized
);
7036 if (ifa
!= NULL
&& ifa
->ifa_ifp
!= NULL
) {
7037 u_int if_index_for_remote_addr
= ifa
->ifa_ifp
->if_index
;
7038 if (if_index_for_remote_addr
== returned_result
->routed_interface_index
||
7039 if_index_for_remote_addr
== lo_ifp
->if_index
) {
7044 ifaddr_release(ifa
);
7050 *flags
|= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL
| NECP_CLIENT_RESULT_FLAG_IS_DIRECT
);
7053 !(rt
->rt_flags
& RTF_GATEWAY
) &&
7054 (rt
->rt_ifa
&& rt
->rt_ifa
->ifa_ifp
&& !(rt
->rt_ifa
->ifa_ifp
->if_flags
& IFF_POINTOPOINT
))) {
7055 // Route is directly accessible
7056 *flags
|= NECP_CLIENT_RESULT_FLAG_IS_DIRECT
;
7061 rt
->rt_ifp
!= NULL
) {
7062 // Check probe status
7063 if (rt
->rt_ifp
->if_eflags
& IFEF_PROBE_CONNECTIVITY
) {
7064 *flags
|= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY
;
7067 if (rt
->rt_ifp
->if_type
== IFT_CELLULAR
) {
7068 struct if_cellular_status_v1
*ifsr
;
7070 ifnet_lock_shared(rt
->rt_ifp
);
7071 lck_rw_lock_exclusive(&rt
->rt_ifp
->if_link_status_lock
);
7073 if (rt
->rt_ifp
->if_link_status
!= NULL
) {
7074 ifsr
= &rt
->rt_ifp
->if_link_status
->ifsr_u
.ifsr_cell
.if_cell_u
.if_status_v1
;
7076 if (ifsr
->valid_bitmask
& IF_CELL_UL_MSS_RECOMMENDED_VALID
) {
7077 if (ifsr
->mss_recommended
== IF_CELL_UL_MSS_RECOMMENDED_NONE
) {
7078 returned_result
->mss_recommended
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE
;
7079 } else if (ifsr
->mss_recommended
== IF_CELL_UL_MSS_RECOMMENDED_MEDIUM
) {
7080 returned_result
->mss_recommended
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM
;
7081 } else if (ifsr
->mss_recommended
== IF_CELL_UL_MSS_RECOMMENDED_LOW
) {
7082 returned_result
->mss_recommended
= NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW
;
7086 lck_rw_done(&rt
->rt_ifp
->if_link_status_lock
);
7087 ifnet_lock_done(rt
->rt_ifp
);
7090 // Check link quality
7091 if ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY
) &&
7092 (rt
->rt_ifp
->if_interface_state
.valid_bitmask
& IF_INTERFACE_STATE_LQM_STATE_VALID
) &&
7093 rt
->rt_ifp
->if_interface_state
.lqm_state
== IFNET_LQM_THRESH_ABORT
) {
7094 *flags
|= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT
;
7097 // Check QoS marking (fastlane)
7098 for (size_t route_rule_index
= 0; route_rule_index
< route_rule_id_array_count
; route_rule_index
++) {
7099 if (necp_update_qos_marking(rt
->rt_ifp
, route_rule_id_array
[route_rule_index
])) {
7100 *flags
|= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING
;
7101 // If the route can use QoS markings, stop iterating route rules
7106 if (IFNET_IS_LOW_POWER(rt
->rt_ifp
)) {
7107 *flags
|= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER
;
7110 if (traffic_class
== SO_TC_BK_SYS
) {
7111 // Block BK_SYS traffic if interface is throttled
7112 u_int32_t throttle_level
= 0;
7113 if (ifnet_get_throttle(rt
->rt_ifp
, &throttle_level
) == 0) {
7114 if (throttle_level
== IFNET_THROTTLE_OPPORTUNISTIC
) {
7115 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
7116 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
7123 if (returned_result
->routed_interface_index
!= 0) {
7124 union necp_sockaddr_union default_address
;
7125 struct rtentry
*v4Route
= NULL
;
7126 struct rtentry
*v6Route
= NULL
;
7128 memset(&default_address
, 0, sizeof(default_address
));
7130 // Reset address to 0.0.0.0
7131 default_address
.sa
.sa_family
= AF_INET
;
7132 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in
);
7133 v4Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
7134 returned_result
->routed_interface_index
);
7136 // Reset address to ::
7137 default_address
.sa
.sa_family
= AF_INET6
;
7138 default_address
.sa
.sa_len
= sizeof(struct sockaddr_in6
);
7139 v6Route
= rtalloc1_scoped((struct sockaddr
*)&default_address
, 0, 0,
7140 returned_result
->routed_interface_index
);
7142 if (v4Route
!= NULL
) {
7143 if (v4Route
->rt_ifp
!= NULL
&& !IS_INTF_CLAT46(v4Route
->rt_ifp
)) {
7144 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV4
;
7146 if (returned_v4_gateway
!= NULL
&&
7147 v4Route
->rt_gateway
!= NULL
&&
7148 v4Route
->rt_gateway
->sa_len
== sizeof(returned_v4_gateway
->u
.sin
)) {
7149 memcpy(&returned_v4_gateway
->u
.sin
, v4Route
->rt_gateway
, sizeof(returned_v4_gateway
->u
.sin
));
7150 memset(&returned_v4_gateway
->u
.sin
.sin_zero
, 0, sizeof(returned_v4_gateway
->u
.sin
.sin_zero
));
7156 if (v6Route
!= NULL
) {
7157 if (v6Route
->rt_ifp
!= NULL
) {
7158 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_IPV6
;
7160 if (ifnet_get_nat64prefix(v6Route
->rt_ifp
, returned_result
->nat64_prefixes
) == 0) {
7161 *flags
|= NECP_CLIENT_RESULT_FLAG_HAS_NAT64
;
7164 if (returned_v6_gateway
!= NULL
&&
7165 v6Route
->rt_gateway
!= NULL
&&
7166 v6Route
->rt_gateway
->sa_len
== sizeof(returned_v6_gateway
->u
.sin6
)) {
7167 memcpy(&returned_v6_gateway
->u
.sin6
, v6Route
->rt_gateway
, sizeof(returned_v6_gateway
->u
.sin6
));
7175 for (size_t route_rule_index
= 0; route_rule_index
< route_rule_id_array_count
; route_rule_index
++) {
7176 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
7177 bool route_is_allowed
= necp_route_is_allowed(rt
, NULL
, route_rule_id_array
[route_rule_index
], &interface_type_denied
);
7178 if (!route_is_allowed
) {
7179 // If the route is blocked, treat the lookup as a drop
7180 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
7181 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
7183 if (interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
7184 if (reason
!= NULL
) {
7185 if (interface_type_denied
== IFRTYPE_FUNCTIONAL_CELLULAR
) {
7186 *reason
= NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED
;
7187 } else if (interface_type_denied
== IFRTYPE_FUNCTIONAL_WIFI_INFRA
) {
7188 *reason
= NECP_CLIENT_RESULT_REASON_WIFI_DENIED
;
7191 necp_send_application_interface_denied_event(pid
, application_uuid
, interface_type_denied
);
7193 // If the route gets denied, stop matching rules
7197 // Check if there is a route rule that adds an agent
7198 u_int32_t netagent_id
= necp_route_get_netagent(rt
, route_rule_id_array
[route_rule_index
]);
7199 if (netagent_id
!= 0) {
7200 struct necp_uuid_id_mapping
*mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
7201 if (mapping
!= NULL
) {
7202 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
7203 if (uuid_is_null(returned_result
->netagents
[netagent_cursor
])) {
7205 uuid_copy(returned_result
->netagents
[netagent_cursor
], mapping
->uuid
);
7206 returned_result
->netagent_use_flags
[netagent_cursor
] = 0;
7214 if (rt
!= NULL
&& rt
->rt_ifp
!= NULL
) {
7215 const bool expensive_prohibited
= ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
) &&
7216 IFNET_IS_EXPENSIVE(rt
->rt_ifp
));
7217 const bool constrained_prohibited
= ((client_flags
& NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED
) &&
7218 IFNET_IS_CONSTRAINED(rt
->rt_ifp
));
7219 if (reason
!= NULL
) {
7220 if (expensive_prohibited
) {
7221 *reason
= NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED
;
7222 } else if (constrained_prohibited
) {
7223 *reason
= NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED
;
7226 if (expensive_prohibited
|| constrained_prohibited
) {
7227 // If the client flags prohibited a property of the interface, treat it as a drop
7228 returned_result
->routing_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
7229 memset(&returned_result
->routing_result_parameter
, 0, sizeof(returned_result
->routing_result_parameter
));
7234 if (returned_route
!= NULL
) {
7235 *returned_route
= rt
;
7244 lck_rw_done(&necp_kernel_policy_lock
);
7246 if (release_eproc
&& effective_proc
!= PROC_NULL
) {
7247 proc_rele(effective_proc
);
7249 #if defined(XNU_TARGET_OS_OSX)
7250 if (responsible_proc
!= PROC_NULL
) {
7251 proc_rele(responsible_proc
);
7259 necp_is_route_local(union necp_sockaddr_union
*remote_addr
)
7261 bool no_remote_addr
= FALSE
;
7262 u_int8_t remote_family
= 0;
7263 struct rtentry
*rt
= NULL
;
7264 bool is_local
= FALSE
;
7266 if (remote_addr
== NULL
) {
7270 if (remote_addr
->sa
.sa_len
== 0 ||
7271 (remote_addr
->sa
.sa_family
== AF_INET
&& remote_addr
->sin
.sin_addr
.s_addr
== 0) ||
7272 (remote_addr
->sa
.sa_family
== AF_INET6
&& IN6_IS_ADDR_UNSPECIFIED(&remote_addr
->sin6
.sin6_addr
))) {
7273 no_remote_addr
= TRUE
;
7274 remote_family
= remote_addr
->sa
.sa_family
;
7277 if (no_remote_addr
) {
7278 memset(remote_addr
, 0, sizeof(union necp_sockaddr_union
));
7279 if (remote_family
== AF_INET6
) {
7280 // Reset address to ::
7281 remote_addr
->sa
.sa_family
= AF_INET6
;
7282 remote_addr
->sa
.sa_len
= sizeof(struct sockaddr_in6
);
7284 // Reset address to 0.0.0.0
7285 remote_addr
->sa
.sa_family
= AF_INET
;
7286 remote_addr
->sa
.sa_len
= sizeof(struct sockaddr_in
);
7290 // Lookup route regardless of the scoped interface to check if
7291 // remote address is in a local network.
7292 rt
= rtalloc1_scoped((struct sockaddr
*)remote_addr
, 0, 0, 0);
7297 if (remote_addr
->sa
.sa_family
== AF_INET
&& IS_INTF_CLAT46(rt
->rt_ifp
)) {
7300 is_local
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
);
7310 necp_socket_check_policy(struct necp_kernel_socket_policy
*kernel_policy
, necp_app_id app_id
, necp_app_id real_app_id
, errno_t cred_result
, u_int32_t account_id
, struct substring domain
, u_int8_t domain_dot_count
, pid_t pid
, int32_t pid_version
, uid_t uid
, u_int32_t bound_interface_index
, u_int32_t traffic_class
, u_int16_t protocol
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
, struct necp_client_parameter_netagent_type
*required_agent_types
, u_int32_t num_required_agent_types
, bool has_client
, uint32_t client_flags
, int is_platform_binary
, proc_t proc
, u_int16_t pf_tag
, struct rtentry
*rt
, bool is_loopback
, bool real_is_platform_binary
, bool is_delegated
)
7312 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
7313 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
7314 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
7315 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
7316 if (bound_interface_index
== cond_bound_interface_index
) {
7317 // No match, matches forbidden interface
7321 if (bound_interface_index
!= cond_bound_interface_index
) {
7322 // No match, does not match required interface
7327 if (bound_interface_index
!= 0) {
7328 // No match, requires a non-bound packet
7334 if (kernel_policy
->condition_mask
== 0) {
7338 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
7339 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
7340 if (app_id
== kernel_policy
->cond_app_id
) {
7341 // No match, matches forbidden application
7345 if (app_id
!= kernel_policy
->cond_app_id
) {
7346 // No match, does not match required application
7351 // Check signing identifier only after APP ID matched
7352 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
||
7353 kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
7354 u_int8_t matched
= necp_boolean_state_false
;
7355 const char *signing_id
= cs_identity_get(proc
? proc
: current_proc());
7357 if (signing_id
!= NULL
) {
7358 size_t signing_id_size
= strlen(signing_id
) + 1;
7359 if (memcmp(signing_id
, kernel_policy
->cond_signing_identifier
, signing_id_size
) == 0) {
7360 matched
= necp_boolean_state_true
;
7364 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER
) {
7365 if (matched
== necp_boolean_state_true
) {
7369 if (matched
!= necp_boolean_state_true
) {
7376 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
7377 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
7378 if (real_app_id
== kernel_policy
->cond_real_app_id
) {
7379 // No match, matches forbidden application
7383 if (real_app_id
!= kernel_policy
->cond_real_app_id
) {
7384 // No match, does not match required application
7390 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
7396 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
7397 if (cred_result
!= 0) {
7398 // Process is missing entitlement
7403 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
7404 if (is_platform_binary
== 0) {
7405 // Process is not platform binary
7410 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_SDK_VERSION
) {
7412 if (kernel_policy
->cond_sdk_version
.platform
!= 0) {
7413 if (kernel_policy
->cond_sdk_version
.platform
!= proc_platform(proc
)) {
7414 // Process does not match platform
7419 if (kernel_policy
->cond_sdk_version
.min_version
!= 0) {
7420 if (kernel_policy
->cond_sdk_version
.min_version
> proc_min_sdk(proc
)) {
7421 // Process min version is older than required min version
7426 if (kernel_policy
->cond_sdk_version
.version
!= 0) {
7427 if (kernel_policy
->cond_sdk_version
.version
> proc_sdk(proc
)) {
7428 // Process SDK version is older than required version
7435 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT
) {
7436 if (kernel_policy
->cond_custom_entitlement_matched
== necp_boolean_state_false
) {
7437 // Process is missing entitlement based on previous check
7439 } else if (kernel_policy
->cond_custom_entitlement_matched
== necp_boolean_state_unknown
) {
7440 if (kernel_policy
->cond_custom_entitlement
!= NULL
) {
7442 // No process found, cannot check entitlement
7445 task_t task
= proc_task(proc
);
7447 !IOTaskHasEntitlement(task
, kernel_policy
->cond_custom_entitlement
)) {
7448 // Process is missing custom entitlement
7449 kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_false
;
7452 kernel_policy
->cond_custom_entitlement_matched
= necp_boolean_state_true
;
7458 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
7459 bool domain_matches
= necp_hostname_matches_domain(domain
, domain_dot_count
, kernel_policy
->cond_domain
, kernel_policy
->cond_domain_dot_count
);
7460 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
7461 if (domain_matches
) {
7462 // No match, matches forbidden domain
7466 if (!domain_matches
) {
7467 // No match, does not match required domain
7473 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
7474 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
) {
7475 if (account_id
== kernel_policy
->cond_account_id
) {
7476 // No match, matches forbidden account
7480 if (account_id
!= kernel_policy
->cond_account_id
) {
7481 // No match, does not match required account
7487 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PID
) {
7488 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PID
) {
7489 if (pid
== kernel_policy
->cond_pid
) {
7490 // No match, matches forbidden pid
7493 if (kernel_policy
->cond_pid_version
!= 0 && pid_version
== kernel_policy
->cond_pid_version
) {
7497 if (pid
!= kernel_policy
->cond_pid
) {
7498 // No match, does not match required pid
7501 if (kernel_policy
->cond_pid_version
!= 0 && pid_version
!= kernel_policy
->cond_pid_version
) {
7507 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_UID
) {
7508 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_UID
) {
7509 if (uid
== kernel_policy
->cond_uid
) {
7510 // No match, matches forbidden uid
7514 if (uid
!= kernel_policy
->cond_uid
) {
7515 // No match, does not match required uid
7521 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
7522 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
7523 if (traffic_class
>= kernel_policy
->cond_traffic_class
.start_tc
&&
7524 traffic_class
<= kernel_policy
->cond_traffic_class
.end_tc
) {
7525 // No match, matches forbidden traffic class
7529 if (traffic_class
< kernel_policy
->cond_traffic_class
.start_tc
||
7530 traffic_class
> kernel_policy
->cond_traffic_class
.end_tc
) {
7531 // No match, does not match required traffic class
7537 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
7538 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
7539 if (protocol
== kernel_policy
->cond_protocol
) {
7540 // No match, matches forbidden protocol
7544 if (protocol
!= kernel_policy
->cond_protocol
) {
7545 // No match, does not match required protocol
7551 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_AGENT_TYPE
) {
7552 bool matches_agent_type
= FALSE
;
7553 for (u_int32_t i
= 0; i
< num_required_agent_types
; i
++) {
7554 struct necp_client_parameter_netagent_type
*required_agent_type
= &required_agent_types
[i
];
7555 if ((strlen(kernel_policy
->cond_agent_type
.agent_domain
) == 0 ||
7556 strncmp(required_agent_type
->netagent_domain
, kernel_policy
->cond_agent_type
.agent_domain
, NETAGENT_DOMAINSIZE
) == 0) &&
7557 (strlen(kernel_policy
->cond_agent_type
.agent_type
) == 0 ||
7558 strncmp(required_agent_type
->netagent_type
, kernel_policy
->cond_agent_type
.agent_type
, NETAGENT_TYPESIZE
) == 0)) {
7559 // Found a required agent that matches
7560 matches_agent_type
= TRUE
;
7564 if (!matches_agent_type
) {
7569 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
7570 bool is_local
= FALSE
;
7573 is_local
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
);
7575 is_local
= necp_is_route_local(remote
);
7579 // Either no route to validate or no match for local networks
7584 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
7585 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
7586 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
7587 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
7596 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
7597 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
7598 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
7610 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
7611 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
7612 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
7613 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
7622 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
7623 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
7624 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
7636 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
7637 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
7638 if ((client_flags
& kernel_policy
->cond_client_flags
) == kernel_policy
->cond_client_flags
) {
7639 // Flags do match, and condition is negative, fail.
7643 if ((client_flags
& kernel_policy
->cond_client_flags
) != kernel_policy
->cond_client_flags
) {
7644 // Flags do not match, fail.
7650 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
7651 bool isEmpty
= necp_addr_is_empty((struct sockaddr
*)local
);
7652 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_EMPTY
) {
7663 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
7664 bool isEmpty
= necp_addr_is_empty((struct sockaddr
*)remote
);
7665 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_EMPTY
) {
7676 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
7677 bool tags_matched
= false;
7678 if (kernel_policy
->cond_packet_filter_tags
& NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP
) {
7679 if (pf_tag
== PF_TAG_ID_STACK_DROP
) {
7680 tags_matched
= true;
7684 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
7689 if (!tags_matched
) {
7695 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) {
7696 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_IS_LOOPBACK
) {
7707 if (is_delegated
&& (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
)) {
7708 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) {
7709 if (real_is_platform_binary
) {
7713 if (!real_is_platform_binary
) {
7722 static inline u_int32_t
7723 necp_socket_calc_flowhash_locked(struct necp_socket_info
*info
)
7725 return net_flowhash(info
, sizeof(*info
), necp_kernel_socket_policies_gencount
);
7729 necp_socket_fillout_info_locked(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
, bool override_is_inbound
, u_int32_t drop_order
, proc_t
*socket_proc
, struct necp_socket_info
*info
, bool is_loopback
)
7731 struct socket
*so
= NULL
;
7732 proc_t sock_proc
= NULL
;
7733 proc_t curr_proc
= current_proc();
7735 memset(info
, 0, sizeof(struct necp_socket_info
));
7737 so
= inp
->inp_socket
;
7739 info
->drop_order
= drop_order
;
7740 info
->is_loopback
= is_loopback
;
7741 info
->is_delegated
= ((so
->so_flags
& SOF_DELEGATED
) ? true : false);
7743 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_UID
) {
7744 info
->uid
= kauth_cred_getuid(so
->so_cred
);
7747 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_TRAFFIC_CLASS
) {
7748 info
->traffic_class
= so
->so_traffic_class
;
7751 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_HAS_CLIENT
) {
7752 info
->has_client
= !uuid_is_null(inp
->necp_client_uuid
);
7755 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_CLIENT_FLAGS
) {
7756 info
->client_flags
= 0;
7757 if (INP_NO_CONSTRAINED(inp
)) {
7758 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED
;
7760 if (INP_NO_EXPENSIVE(inp
)) {
7761 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE
;
7763 if (inp
->inp_socket
->so_flags1
& SOF1_CELLFALLBACK
) {
7764 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC
;
7766 if (inp
->inp_socket
->so_flags1
& SOF1_INBOUND
|| override_is_inbound
) {
7767 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_INBOUND
;
7769 if (inp
->inp_socket
->so_options
& SO_ACCEPTCONN
||
7770 inp
->inp_flags2
& INP2_EXTERNAL_PORT
) {
7771 info
->client_flags
|= NECP_CLIENT_PARAMETER_FLAG_LISTENER
;
7775 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
7776 if (inp
->inp_ip_p
) {
7777 info
->protocol
= inp
->inp_ip_p
;
7779 info
->protocol
= SOCK_PROTO(so
);
7783 if (inp
->inp_flags2
& INP2_WANT_APP_POLICY
&& necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_APP_ID
) {
7784 u_int32_t responsible_application_id
= 0;
7786 struct necp_uuid_id_mapping
*existing_mapping
= necp_uuid_lookup_app_id_locked(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
));
7787 if (existing_mapping
) {
7788 info
->application_id
= existing_mapping
->id
;
7791 #if defined(XNU_TARGET_OS_OSX)
7792 if (so
->so_rpid
> 0) {
7793 existing_mapping
= necp_uuid_lookup_app_id_locked(so
->so_ruuid
);
7794 if (existing_mapping
!= NULL
) {
7795 responsible_application_id
= existing_mapping
->id
;
7800 if (responsible_application_id
> 0) {
7801 info
->real_application_id
= info
->application_id
;
7802 info
->application_id
= responsible_application_id
;
7803 info
->used_responsible_pid
= true;
7804 } else if (!(so
->so_flags
& SOF_DELEGATED
)) {
7805 info
->real_application_id
= info
->application_id
;
7806 } else if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
) {
7807 struct necp_uuid_id_mapping
*real_existing_mapping
= necp_uuid_lookup_app_id_locked(so
->last_uuid
);
7808 if (real_existing_mapping
) {
7809 info
->real_application_id
= real_existing_mapping
->id
;
7813 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ENTITLEMENT
) {
7814 info
->cred_result
= priv_check_cred(so
->so_cred
, PRIV_NET_PRIVILEGED_NECP_MATCH
, 0);
7815 if (info
->cred_result
!= 0) {
7816 // Process does not have entitlement, check the parent process
7817 necp_get_parent_cred_result(NULL
, info
);
7823 #if defined(XNU_TARGET_OS_OSX)
7824 info
->used_responsible_pid
? so
->so_rpid
:
7826 ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
);
7827 if (socket_pid
&& (socket_pid
!= proc_pid(curr_proc
))) {
7828 sock_proc
= proc_find(socket_pid
);
7830 *socket_proc
= sock_proc
;
7834 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PID
) {
7835 info
->pid
= socket_pid
;
7836 info
->pid_version
= proc_pidversion(sock_proc
!= NULL
? sock_proc
: curr_proc
);
7839 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_PLATFORM_BINARY
) {
7840 info
->is_platform_binary
= necp_is_platform_binary(sock_proc
? sock_proc
: curr_proc
) ? true : false;
7843 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY
) {
7844 proc_t real_proc
= curr_proc
;
7845 bool release_real_proc
= false;
7846 if (so
->last_pid
!= proc_pid(real_proc
)) {
7847 if (so
->last_pid
== socket_pid
&& sock_proc
!= NULL
) {
7848 real_proc
= sock_proc
;
7850 proc_t last_proc
= proc_find(so
->last_pid
);
7851 if (last_proc
!= NULL
) {
7852 real_proc
= last_proc
;
7853 release_real_proc
= true;
7857 if (real_proc
!= NULL
) {
7858 info
->real_is_platform_binary
= (necp_is_platform_binary(real_proc
) ? true : false);
7859 if (release_real_proc
) {
7860 proc_rele(real_proc
);
7865 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_ACCOUNT_ID
&& inp
->inp_necp_attributes
.inp_account
!= NULL
) {
7866 struct necp_string_id_mapping
*existing_mapping
= necp_lookup_string_to_id_locked(&necp_account_id_list
, inp
->inp_necp_attributes
.inp_account
);
7867 if (existing_mapping
) {
7868 info
->account_id
= existing_mapping
->id
;
7872 if (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_CONDITION_DOMAIN
) {
7873 info
->domain
= inp
->inp_necp_attributes
.inp_domain
;
7876 if (override_bound_interface
) {
7877 info
->bound_interface_index
= override_bound_interface
;
7879 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
) {
7880 info
->bound_interface_index
= inp
->inp_boundifp
->if_index
;
7884 if (necp_restrict_multicast
||
7885 (necp_kernel_socket_policies_condition_mask
& NECP_KERNEL_ADDRESS_TYPE_CONDITIONS
)) {
7886 if (override_local_addr
!= NULL
) {
7887 if (override_local_addr
->sa_family
== AF_INET6
&& override_local_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
7888 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
7889 if (IN6_IS_ADDR_V4MAPPED(&(info
->local_addr
.sin6
.sin6_addr
))) {
7890 struct sockaddr_in sin
;
7891 in6_sin6_2_sin(&sin
, &(info
->local_addr
.sin6
));
7892 memset(&info
->local_addr
, 0, sizeof(union necp_sockaddr_union
));
7893 memcpy(&info
->local_addr
, &sin
, sin
.sin_len
);
7895 } else if (override_local_addr
->sa_family
== AF_INET
&& override_local_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
7896 memcpy(&info
->local_addr
, override_local_addr
, override_local_addr
->sa_len
);
7899 if (inp
->inp_vflag
& INP_IPV4
) {
7900 ((struct sockaddr_in
*)&info
->local_addr
)->sin_family
= AF_INET
;
7901 ((struct sockaddr_in
*)&info
->local_addr
)->sin_len
= sizeof(struct sockaddr_in
);
7902 ((struct sockaddr_in
*)&info
->local_addr
)->sin_port
= inp
->inp_lport
;
7903 memcpy(&((struct sockaddr_in
*)&info
->local_addr
)->sin_addr
, &inp
->inp_laddr
, sizeof(struct in_addr
));
7904 } else if (inp
->inp_vflag
& INP_IPV6
) {
7905 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_family
= AF_INET6
;
7906 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
7907 ((struct sockaddr_in6
*)&info
->local_addr
)->sin6_port
= inp
->inp_lport
;
7908 memcpy(&((struct sockaddr_in6
*)&info
->local_addr
)->sin6_addr
, &inp
->in6p_laddr
, sizeof(struct in6_addr
));
7912 if (override_remote_addr
!= NULL
) {
7913 if (override_remote_addr
->sa_family
== AF_INET6
&& override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in6
)) {
7914 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
7915 if (IN6_IS_ADDR_V4MAPPED(&(info
->remote_addr
.sin6
.sin6_addr
))) {
7916 struct sockaddr_in sin
;
7917 in6_sin6_2_sin(&sin
, &(info
->remote_addr
.sin6
));
7918 memset(&info
->remote_addr
, 0, sizeof(union necp_sockaddr_union
));
7919 memcpy(&info
->remote_addr
, &sin
, sin
.sin_len
);
7921 } else if (override_remote_addr
->sa_family
== AF_INET
&& override_remote_addr
->sa_len
<= sizeof(struct sockaddr_in
)) {
7922 memcpy(&info
->remote_addr
, override_remote_addr
, override_remote_addr
->sa_len
);
7925 if (inp
->inp_vflag
& INP_IPV4
) {
7926 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_family
= AF_INET
;
7927 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_len
= sizeof(struct sockaddr_in
);
7928 ((struct sockaddr_in
*)&info
->remote_addr
)->sin_port
= inp
->inp_fport
;
7929 memcpy(&((struct sockaddr_in
*)&info
->remote_addr
)->sin_addr
, &inp
->inp_faddr
, sizeof(struct in_addr
));
7930 } else if (inp
->inp_vflag
& INP_IPV6
) {
7931 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_family
= AF_INET6
;
7932 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
7933 ((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_port
= inp
->inp_fport
;
7934 memcpy(&((struct sockaddr_in6
*)&info
->remote_addr
)->sin6_addr
, &inp
->in6p_faddr
, sizeof(struct in6_addr
));
7940 static inline struct necp_kernel_socket_policy
*
7941 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy
**policy_search_array
, struct necp_socket_info
*info
,
7942 necp_kernel_policy_filter
*return_filter
,
7943 u_int32_t
*return_route_rule_id_array
, size_t *return_route_rule_id_array_count
, size_t route_rule_id_array_count
,
7944 necp_kernel_policy_result
*return_service_action
, necp_kernel_policy_service
*return_service
,
7945 u_int32_t
*return_netagent_array
, u_int32_t
*return_netagent_use_flags_array
, size_t netagent_array_count
,
7946 struct necp_client_parameter_netagent_type
*required_agent_types
,
7947 u_int32_t num_required_agent_types
, proc_t proc
, u_int16_t pf_tag
, necp_kernel_policy_id
*skip_policy_id
, struct rtentry
*rt
,
7948 necp_kernel_policy_result
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t
*return_drop_all_bypass
,
7949 u_int32_t
*return_flow_divert_aggregate_unit
)
7951 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
7952 u_int32_t skip_order
= 0;
7953 u_int32_t skip_session_order
= 0;
7954 size_t route_rule_id_count
= 0;
7956 size_t netagent_cursor
= 0;
7957 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
7958 if (return_drop_all_bypass
!= NULL
) {
7959 *return_drop_all_bypass
= drop_all_bypass
;
7962 // Pre-process domain for quick matching
7963 struct substring domain_substring
= necp_trim_dots_and_stars(info
->domain
, info
->domain
? strlen(info
->domain
) : 0);
7964 u_int8_t domain_dot_count
= necp_count_dots(domain_substring
.string
, domain_substring
.length
);
7966 if (return_filter
!= NULL
) {
7970 if (return_route_rule_id_array_count
!= NULL
) {
7971 *return_route_rule_id_array_count
= 0;
7974 if (return_service_action
!= NULL
) {
7975 *return_service_action
= 0;
7978 if (return_service
!= NULL
) {
7979 return_service
->identifier
= 0;
7980 return_service
->data
= 0;
7983 // Do not subject layer-2 filter to NECP policies, return a PASS policy
7984 if (necp_pass_interpose
> 0 && info
->client_flags
& NECP_CLIENT_PARAMETER_FLAG_INTERPOSE
) {
7985 return &pass_policy
;
7988 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
7990 if (policy_search_array
!= NULL
) {
7991 for (i
= 0; policy_search_array
[i
] != NULL
; i
++) {
7992 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
7993 // We've hit a drop all rule
7994 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
7995 drop_all_bypass
= necp_check_drop_all_bypass_result(proc
);
7996 if (return_drop_all_bypass
!= NULL
) {
7997 *return_drop_all_bypass
= drop_all_bypass
;
8000 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8004 if (necp_drop_dest_policy
.entry_count
!= 0 &&
8005 necp_address_matches_drop_dest_policy(&info
->remote_addr
, policy_search_array
[i
]->session_order
)) {
8006 // We've hit a drop by destination address rule
8007 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8010 if (info
->drop_order
!= 0 && policy_search_array
[i
]->session_order
>= info
->drop_order
) {
8011 // We've hit a drop order for this socket
8014 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
8017 skip_session_order
= 0;
8020 if (policy_search_array
[i
]->order
< skip_order
) {
8026 skip_session_order
= 0;
8028 } else if (skip_session_order
) {
8033 if (necp_socket_check_policy(policy_search_array
[i
], info
->application_id
, info
->real_application_id
, info
->cred_result
, info
->account_id
, domain_substring
, domain_dot_count
, info
->pid
, info
->pid_version
, info
->uid
, info
->bound_interface_index
, info
->traffic_class
, info
->protocol
, &info
->local_addr
, &info
->remote_addr
, required_agent_types
, num_required_agent_types
, info
->has_client
, info
->client_flags
, info
->is_platform_binary
, proc
, pf_tag
, rt
, info
->is_loopback
, info
->real_is_platform_binary
, info
->is_delegated
)) {
8034 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER
) {
8035 if (return_filter
&& *return_filter
!= NECP_FILTER_UNIT_NO_FILTER
) {
8036 necp_kernel_policy_filter control_unit
= policy_search_array
[i
]->result_parameter
.filter_control_unit
;
8037 if (control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
8038 *return_filter
= control_unit
;
8040 *return_filter
|= control_unit
;
8042 if (necp_debug
> 1) {
8043 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.filter_control_unit
);
8047 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) {
8048 if (return_route_rule_id_array
&& route_rule_id_count
< route_rule_id_array_count
) {
8049 return_route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
;
8050 if (necp_debug
> 1) {
8051 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.route_rule_id
);
8055 } else if (necp_kernel_socket_result_is_trigger_service_type(policy_search_array
[i
])) {
8056 if (return_service_action
&& *return_service_action
== 0) {
8057 *return_service_action
= policy_search_array
[i
]->result
;
8058 if (necp_debug
> 1) {
8059 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Service Action %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result
);
8062 if (return_service
&& return_service
->identifier
== 0) {
8063 return_service
->identifier
= policy_search_array
[i
]->result_parameter
.service
.identifier
;
8064 return_service
->data
= policy_search_array
[i
]->result_parameter
.service
.data
;
8065 if (necp_debug
> 1) {
8066 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Service ID %d Data %d", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, policy_search_array
[i
]->result_parameter
.service
.identifier
, policy_search_array
[i
]->result_parameter
.service
.data
);
8070 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
||
8071 policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
) {
8072 if (return_netagent_array
!= NULL
&&
8073 netagent_cursor
< netagent_array_count
) {
8074 return_netagent_array
[netagent_cursor
] = policy_search_array
[i
]->result_parameter
.netagent_id
;
8075 if (return_netagent_use_flags_array
!= NULL
&&
8076 policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED
) {
8077 return_netagent_use_flags_array
[netagent_cursor
] |= NECP_AGENT_USE_FLAG_SCOPE
;
8080 if (necp_debug
> 1) {
8081 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
8082 info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
,
8083 policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_USE_NETAGENT
? "Use" : "Scope",
8084 policy_search_array
[i
]->result_parameter
.netagent_id
);
8088 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
8089 u_int32_t control_unit
= policy_search_array
[i
]->result_parameter
.flow_divert_control_unit
;
8090 if (control_unit
& FLOW_DIVERT_IS_TRANSPARENT
) {
8091 /* For transparent proxies, accumulate the control unit and continue to the next policy */
8092 if (return_flow_divert_aggregate_unit
!= NULL
) {
8093 *return_flow_divert_aggregate_unit
|= (control_unit
& ~FLOW_DIVERT_IS_TRANSPARENT
);
8094 if (necp_debug
> 1) {
8095 NECPLOG(LOG_DEBUG
, "Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", info
->application_id
, info
->real_application_id
, info
->bound_interface_index
, info
->protocol
, control_unit
);
8102 // Matched policy is a skip. Do skip and continue.
8103 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
8104 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
8105 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
8106 if (skip_policy_id
&& *skip_policy_id
== NECP_KERNEL_POLICY_ID_NONE
) {
8107 *skip_policy_id
= policy_search_array
[i
]->id
;
8112 // Matched an allow unentitled, which clears any drop order
8113 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED
) {
8114 info
->drop_order
= 0;
8118 // Passed all tests, found a match
8119 matched_policy
= policy_search_array
[i
];
8125 if (return_route_rule_id_array_count
!= NULL
) {
8126 *return_route_rule_id_array_count
= route_rule_id_count
;
8128 return matched_policy
;
8132 necp_socket_uses_interface(struct inpcb
*inp
, u_int32_t interface_index
)
8134 bool found_match
= FALSE
;
8136 ifaddr_t
*addresses
= NULL
;
8137 union necp_sockaddr_union address_storage
;
8139 int family
= AF_INET
;
8140 ifnet_t interface
= ifindex2ifnet
[interface_index
];
8142 if (inp
== NULL
|| interface
== NULL
) {
8146 if (inp
->inp_vflag
& INP_IPV4
) {
8148 } else if (inp
->inp_vflag
& INP_IPV6
) {
8152 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
8154 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
8158 for (i
= 0; addresses
[i
] != NULL
; i
++) {
8159 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
8160 if (family
== AF_INET
) {
8161 if (memcmp(&address_storage
.sin
.sin_addr
, &inp
->inp_laddr
, sizeof(inp
->inp_laddr
)) == 0) {
8165 } else if (family
== AF_INET6
) {
8166 if (memcmp(&address_storage
.sin6
.sin6_addr
, &inp
->in6p_laddr
, sizeof(inp
->in6p_laddr
)) == 0) {
8175 ifnet_free_address_list(addresses
);
8181 necp_socket_is_connected(struct inpcb
*inp
)
8183 return inp
->inp_socket
->so_state
& (SS_ISCONNECTING
| SS_ISCONNECTED
| SS_ISDISCONNECTING
);
8186 static inline necp_socket_bypass_type_t
8187 necp_socket_bypass(struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, struct inpcb
*inp
)
8189 if (necp_pass_loopback
> 0 && necp_is_loopback(override_local_addr
, override_remote_addr
, inp
, NULL
, IFSCOPE_NONE
)) {
8190 return NECP_BYPASS_TYPE_LOOPBACK
;
8191 } else if (necp_is_intcoproc(inp
, NULL
)) {
8192 return NECP_BYPASS_TYPE_INTCOPROC
;
8195 return NECP_BYPASS_TYPE_NONE
;
8199 necp_socket_ip_tunnel_tso(struct inpcb
*inp
)
8201 u_int tunnel_interface_index
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
;
8202 ifnet_t tunnel_interface
= NULL
;
8204 ifnet_head_lock_shared();
8205 tunnel_interface
= ifindex2ifnet
[tunnel_interface_index
];
8208 if (tunnel_interface
!= NULL
) {
8209 tcp_set_tso(intotcpcb(inp
), tunnel_interface
);
8213 necp_kernel_policy_id
8214 necp_socket_find_policy_match(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, u_int32_t override_bound_interface
)
8216 struct socket
*so
= NULL
;
8217 necp_kernel_policy_filter filter_control_unit
= 0;
8218 struct necp_kernel_socket_policy
*matched_policy
= NULL
;
8219 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8220 necp_kernel_policy_result service_action
= 0;
8221 necp_kernel_policy_service service
= { 0, 0 };
8222 u_int32_t drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8223 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8224 proc_t socket_proc
= NULL
;
8225 necp_socket_bypass_type_t bypass_type
= NECP_BYPASS_TYPE_NONE
;
8227 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
8228 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
8229 int netagent_cursor
;
8231 struct necp_socket_info info
;
8233 u_int32_t flow_divert_aggregate_unit
= 0;
8236 return NECP_KERNEL_POLICY_ID_NONE
;
8239 // Ignore invalid addresses
8240 if (override_local_addr
!= NULL
&&
8241 !necp_address_is_valid(override_local_addr
)) {
8242 override_local_addr
= NULL
;
8244 if (override_remote_addr
!= NULL
&&
8245 !necp_address_is_valid(override_remote_addr
)) {
8246 override_remote_addr
= NULL
;
8249 so
= inp
->inp_socket
;
8251 u_int32_t drop_order
= necp_process_drop_order(so
->so_cred
);
8253 // Don't lock. Possible race condition, but we don't want the performance hit.
8254 if (necp_kernel_socket_policies_count
== 0 ||
8255 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
8256 if (necp_drop_all_order
> 0 || drop_order
> 0) {
8257 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8258 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8259 inp
->inp_policyresult
.policy_gencount
= 0;
8260 inp
->inp_policyresult
.app_id
= 0;
8261 inp
->inp_policyresult
.flowhash
= 0;
8262 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8263 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8264 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8265 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
) != NECP_BYPASS_TYPE_NONE
) {
8266 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8268 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8271 return NECP_KERNEL_POLICY_ID_NONE
;
8274 // Check for loopback exception
8275 bypass_type
= necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
);
8276 if (bypass_type
== NECP_BYPASS_TYPE_INTCOPROC
|| (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
&& necp_pass_loopback
== NECP_LOOPBACK_PASS_ALL
)) {
8277 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
8278 // If the previous policy result was "socket scoped", un-scope the socket.
8279 inp
->inp_flags
&= ~INP_BOUND_IF
;
8280 inp
->inp_boundifp
= NULL
;
8282 // Mark socket as a pass
8283 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8284 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8285 inp
->inp_policyresult
.policy_gencount
= 0;
8286 inp
->inp_policyresult
.app_id
= 0;
8287 inp
->inp_policyresult
.flowhash
= 0;
8288 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8289 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8290 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8291 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8292 return NECP_KERNEL_POLICY_ID_NONE
;
8296 lck_rw_lock_shared(&necp_kernel_policy_lock
);
8297 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, override_bound_interface
, false, drop_order
, &socket_proc
, &info
, (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
));
8300 u_int32_t flowhash
= necp_socket_calc_flowhash_locked(&info
);
8301 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
8302 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
8303 inp
->inp_policyresult
.flowhash
== flowhash
) {
8304 // If already matched this socket on this generation of table, skip
8307 lck_rw_done(&necp_kernel_policy_lock
);
8310 proc_rele(socket_proc
);
8313 return inp
->inp_policyresult
.policy_id
;
8316 inp
->inp_policyresult
.app_id
= info
.application_id
;
8318 // Match socket to policy
8319 necp_kernel_policy_id skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8320 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
8321 size_t route_rule_id_array_count
= 0;
8322 matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info
.application_id
)], &info
, &filter_control_unit
, route_rule_id_array
, &route_rule_id_array_count
, MAX_AGGREGATE_ROUTE_RULES
, &service_action
, &service
, netagent_ids
, NULL
, NECP_MAX_NETAGENTS
, NULL
, 0, socket_proc
? socket_proc
: current_proc(), 0, &skip_policy_id
, inp
->inp_route
.ro_rt
, &drop_dest_policy_result
, &drop_all_bypass
, &flow_divert_aggregate_unit
);
8324 // Check for loopback exception again after the policy match
8325 if (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
&&
8326 necp_pass_loopback
== NECP_LOOPBACK_PASS_WITH_FILTER
&&
8327 (matched_policy
== NULL
|| matched_policy
->result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
)) {
8328 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
8329 // If the previous policy result was "socket scoped", un-scope the socket.
8330 inp
->inp_flags
&= ~INP_BOUND_IF
;
8331 inp
->inp_boundifp
= NULL
;
8333 // Mark socket as a pass
8334 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8335 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8336 inp
->inp_policyresult
.policy_gencount
= 0;
8337 inp
->inp_policyresult
.app_id
= 0;
8338 inp
->inp_policyresult
.flowhash
= 0;
8339 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
8340 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
8341 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8342 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8345 lck_rw_done(&necp_kernel_policy_lock
);
8348 proc_rele(socket_proc
);
8351 return NECP_KERNEL_POLICY_ID_NONE
;
8354 // If the socket matched a scoped service policy, mark as Drop if not registered.
8355 // This covers the cases in which a service is required (on demand) but hasn't started yet.
8356 if ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
8357 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
8358 service
.identifier
!= 0 &&
8359 service
.identifier
!= NECP_NULL_SERVICE_ID
) {
8360 bool service_is_registered
= FALSE
;
8361 struct necp_service_registration
*service_registration
= NULL
;
8362 LIST_FOREACH(service_registration
, &necp_registered_service_list
, kernel_chain
) {
8363 if (service
.identifier
== service_registration
->service_id
) {
8364 service_is_registered
= TRUE
;
8368 if (!service_is_registered
) {
8369 // Mark socket as a drop if service is not registered
8370 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8371 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8372 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8373 inp
->inp_policyresult
.flowhash
= flowhash
;
8374 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8375 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8376 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8377 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8379 if (necp_debug
> 1) {
8380 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because service is not registered", info
.bound_interface_index
, info
.protocol
);
8384 lck_rw_done(&necp_kernel_policy_lock
);
8387 proc_rele(socket_proc
);
8390 return NECP_KERNEL_POLICY_ID_NONE
;
8394 for (netagent_cursor
= 0; netagent_cursor
< NECP_MAX_NETAGENTS
; netagent_cursor
++) {
8395 struct necp_uuid_id_mapping
*mapping
= NULL
;
8396 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
8397 if (netagent_id
== 0) {
8400 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
8401 if (mapping
!= NULL
) {
8402 u_int32_t agent_flags
= 0;
8403 agent_flags
= netagent_get_flags(mapping
->uuid
);
8404 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
8405 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
8407 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
8408 if (agent_flags
& NETAGENT_FLAG_KERNEL_ACTIVATED
) {
8409 int trigger_error
= 0;
8410 trigger_error
= netagent_kernel_trigger(mapping
->uuid
);
8411 if (necp_debug
> 1) {
8412 NECPLOG(LOG_DEBUG
, "Socket Policy: Triggering inactive agent, error %d", trigger_error
);
8416 // Mark socket as a drop if required agent is not active
8417 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8418 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8419 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8420 inp
->inp_policyresult
.flowhash
= flowhash
;
8421 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8422 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8423 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8424 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8426 if (necp_debug
> 1) {
8427 NECPLOG(LOG_DEBUG
, "Socket Policy: (BoundInterface %d Proto %d) Dropping packet because agent is not active", info
.bound_interface_index
, info
.protocol
);
8431 lck_rw_done(&necp_kernel_policy_lock
);
8434 proc_rele(socket_proc
);
8437 return NECP_KERNEL_POLICY_ID_NONE
;
8443 u_int32_t route_rule_id
= 0;
8444 if (route_rule_id_array_count
== 1) {
8445 route_rule_id
= route_rule_id_array
[0];
8446 } else if (route_rule_id_array_count
> 1) {
8447 route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
8450 bool reset_tcp_tunnel_interface
= false;
8451 bool send_local_network_denied_event
= false;
8452 if (matched_policy
) {
8453 matched_policy_id
= matched_policy
->id
;
8454 inp
->inp_policyresult
.policy_id
= matched_policy
->id
;
8455 inp
->inp_policyresult
.skip_policy_id
= skip_policy_id
;
8456 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8457 inp
->inp_policyresult
.flowhash
= flowhash
;
8458 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
8459 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
8460 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
;
8461 inp
->inp_policyresult
.results
.result
= matched_policy
->result
;
8462 memcpy(&inp
->inp_policyresult
.results
.result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
8464 if (info
.used_responsible_pid
&& (matched_policy
->condition_mask
& NECP_KERNEL_CONDITION_REAL_APP_ID
)) {
8465 inp
->inp_policyresult
.app_id
= info
.real_application_id
;
8468 if (necp_socket_is_connected(inp
) &&
8469 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
8470 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& !necp_socket_uses_interface(inp
, matched_policy
->result_parameter
.tunnel_interface_index
)))) {
8472 NECPLOG(LOG_DEBUG
, "Marking socket in state %d as defunct", so
->so_state
);
8474 sosetdefunct(current_proc(), so
, SHUTDOWN_SOCKET_LEVEL_NECP
| SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL
, TRUE
);
8475 } else if (necp_socket_is_connected(inp
) &&
8476 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
8477 info
.protocol
== IPPROTO_TCP
) {
8478 // Reset TCP socket interface based parameters if tunnel policy changes
8479 reset_tcp_tunnel_interface
= true;
8482 if (necp_debug
> 1) {
8483 NECPLOG(LOG_DEBUG
, "Socket Policy: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d", inp
->inp_socket
, info
.bound_interface_index
, info
.protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
);
8486 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
&&
8487 matched_policy
->result_parameter
.drop_flags
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) {
8488 // Trigger the event that we dropped due to a local network policy
8489 send_local_network_denied_event
= true;
8492 bool drop_all
= false;
8493 if (necp_drop_all_order
> 0 || info
.drop_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
8494 // Mark socket as a drop if set
8496 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8497 drop_all_bypass
= necp_check_drop_all_bypass_result(socket_proc
? socket_proc
: current_proc());
8500 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8501 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8502 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8503 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8504 inp
->inp_policyresult
.flowhash
= flowhash
;
8505 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8506 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8507 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8508 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8510 // Mark non-matching socket so we don't re-check it
8511 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8512 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8513 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8514 inp
->inp_policyresult
.flowhash
= flowhash
;
8515 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
; // We may have matched a filter, so mark it!
8516 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
8517 inp
->inp_policyresult
.results
.route_rule_id
= route_rule_id
; // We may have matched a route rule, so mark it!
8518 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8522 if (necp_check_missing_client_drop(socket_proc
? socket_proc
: current_proc(), &info
) ||
8523 necp_check_restricted_multicast_drop(socket_proc
? socket_proc
: current_proc(), &info
, false)) {
8525 inp
->inp_policyresult
.policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8526 inp
->inp_policyresult
.skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8527 inp
->inp_policyresult
.policy_gencount
= necp_kernel_socket_policies_gencount
;
8528 inp
->inp_policyresult
.flowhash
= flowhash
;
8529 inp
->inp_policyresult
.results
.filter_control_unit
= 0;
8530 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= 0;
8531 inp
->inp_policyresult
.results
.route_rule_id
= 0;
8532 inp
->inp_policyresult
.results
.result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8536 lck_rw_done(&necp_kernel_policy_lock
);
8538 if (reset_tcp_tunnel_interface
) {
8539 // Update MSS when not holding the policy lock to avoid recursive locking
8540 tcp_mtudisc(inp
, 0);
8542 // Update TSO flag based on the tunnel interface
8543 necp_socket_ip_tunnel_tso(inp
);
8546 if (send_local_network_denied_event
&& inp
->inp_policyresult
.network_denied_notifies
== 0) {
8547 inp
->inp_policyresult
.network_denied_notifies
++;
8548 necp_send_network_denied_event(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
),
8549 ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
),
8550 NETPOLICY_NETWORKTYPE_LOCAL
);
8554 proc_rele(socket_proc
);
8557 return matched_policy_id
;
8561 necp_ip_output_check_policy(struct necp_kernel_ip_output_policy
*kernel_policy
, necp_kernel_policy_id socket_policy_id
, necp_kernel_policy_id socket_skip_policy_id
, u_int32_t bound_interface_index
, u_int32_t last_interface_index
, u_int16_t protocol
, union necp_sockaddr_union
*local
, union necp_sockaddr_union
*remote
, struct rtentry
*rt
, u_int16_t pf_tag
)
8563 if (!(kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_ALL_INTERFACES
)) {
8564 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
8565 u_int32_t cond_bound_interface_index
= kernel_policy
->cond_bound_interface
? kernel_policy
->cond_bound_interface
->if_index
: 0;
8566 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_BOUND_INTERFACE
) {
8567 if (bound_interface_index
== cond_bound_interface_index
) {
8568 // No match, matches forbidden interface
8572 if (bound_interface_index
!= cond_bound_interface_index
) {
8573 // No match, does not match required interface
8578 if (bound_interface_index
!= 0) {
8579 // No match, requires a non-bound packet
8585 if (kernel_policy
->condition_mask
== 0) {
8589 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_POLICY_ID
) {
8590 necp_kernel_policy_id matched_policy_id
=
8591 kernel_policy
->result
== NECP_KERNEL_POLICY_RESULT_SKIP
? socket_skip_policy_id
: socket_policy_id
;
8592 if (matched_policy_id
!= kernel_policy
->cond_policy_id
) {
8593 // No match, does not match required id
8598 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LAST_INTERFACE
) {
8599 if (last_interface_index
!= kernel_policy
->cond_last_interface_index
) {
8604 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
8605 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PROTOCOL
) {
8606 if (protocol
== kernel_policy
->cond_protocol
) {
8607 // No match, matches forbidden protocol
8611 if (protocol
!= kernel_policy
->cond_protocol
) {
8612 // No match, does not match required protocol
8618 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_NETWORKS
) {
8619 bool is_local
= FALSE
;
8622 is_local
= IS_NECP_DEST_IN_LOCAL_NETWORKS(rt
);
8624 is_local
= necp_is_route_local(remote
);
8628 // Either no route to validate or no match for local networks
8633 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_START
) {
8634 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
8635 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, (struct sockaddr
*)&kernel_policy
->cond_local_end
);
8636 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_END
) {
8645 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
8646 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)local
, (struct sockaddr
*)&kernel_policy
->cond_local_start
, kernel_policy
->cond_local_prefix
);
8647 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_LOCAL_PREFIX
) {
8659 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_START
) {
8660 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
8661 bool inRange
= necp_is_addr_in_range((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, (struct sockaddr
*)&kernel_policy
->cond_remote_end
);
8662 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_END
) {
8671 } else if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
8672 bool inSubnet
= necp_is_addr_in_subnet((struct sockaddr
*)remote
, (struct sockaddr
*)&kernel_policy
->cond_remote_start
, kernel_policy
->cond_remote_prefix
);
8673 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_REMOTE_PREFIX
) {
8685 if (kernel_policy
->condition_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
8686 bool tags_matched
= false;
8688 if (kernel_policy
->cond_packet_filter_tags
& NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP
) {
8689 if ((pf_tag
& PF_TAG_ID_STACK_DROP
) == PF_TAG_ID_STACK_DROP
) {
8690 tags_matched
= true;
8693 if (kernel_policy
->condition_negated_mask
& NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS
) {
8698 if (!tags_matched
) {
8708 static inline struct necp_kernel_ip_output_policy
*
8709 necp_ip_output_find_policy_match_locked(necp_kernel_policy_id socket_policy_id
, necp_kernel_policy_id socket_skip_policy_id
, u_int32_t bound_interface_index
, u_int32_t last_interface_index
, u_int16_t protocol
, union necp_sockaddr_union
*local_addr
, union necp_sockaddr_union
*remote_addr
, struct rtentry
*rt
, u_int16_t pf_tag
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_result
*return_drop_dest_policy_result
, necp_drop_all_bypass_check_result_t
*return_drop_all_bypass
)
8711 u_int32_t skip_order
= 0;
8712 u_int32_t skip_session_order
= 0;
8713 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
8714 struct necp_kernel_ip_output_policy
**policy_search_array
= necp_kernel_ip_output_policies_map
[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(socket_policy_id
)];
8715 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
8716 size_t route_rule_id_count
= 0;
8717 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8718 if (return_drop_all_bypass
!= NULL
) {
8719 *return_drop_all_bypass
= drop_all_bypass
;
8722 if (return_route_rule_id
!= NULL
) {
8723 *return_route_rule_id
= 0;
8726 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8728 if (policy_search_array
!= NULL
) {
8729 for (int i
= 0; policy_search_array
[i
] != NULL
; i
++) {
8730 if (necp_drop_all_order
!= 0 && policy_search_array
[i
]->session_order
>= necp_drop_all_order
) {
8731 // We've hit a drop all rule
8732 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8733 drop_all_bypass
= necp_check_drop_all_bypass_result(NULL
);
8734 if (return_drop_all_bypass
!= NULL
) {
8735 *return_drop_all_bypass
= drop_all_bypass
;
8738 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8742 if (necp_drop_dest_policy
.entry_count
> 0 &&
8743 necp_address_matches_drop_dest_policy(remote_addr
, policy_search_array
[i
]->session_order
)) {
8744 // We've hit a drop by destination address rule
8745 *return_drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8748 if (skip_session_order
&& policy_search_array
[i
]->session_order
>= skip_session_order
) {
8751 skip_session_order
= 0;
8754 if (policy_search_array
[i
]->order
< skip_order
) {
8760 skip_session_order
= 0;
8762 } else if (skip_session_order
) {
8767 if (necp_ip_output_check_policy(policy_search_array
[i
], socket_policy_id
, socket_skip_policy_id
, bound_interface_index
, last_interface_index
, protocol
, local_addr
, remote_addr
, rt
, pf_tag
)) {
8768 if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_ROUTE_RULES
) {
8769 if (return_route_rule_id
!= NULL
&& route_rule_id_count
< MAX_AGGREGATE_ROUTE_RULES
) {
8770 route_rule_id_array
[route_rule_id_count
++] = policy_search_array
[i
]->result_parameter
.route_rule_id
;
8773 } else if (policy_search_array
[i
]->result
== NECP_KERNEL_POLICY_RESULT_SKIP
) {
8774 skip_order
= policy_search_array
[i
]->result_parameter
.skip_policy_order
;
8775 skip_session_order
= policy_search_array
[i
]->session_order
+ 1;
8779 // Passed all tests, found a match
8780 matched_policy
= policy_search_array
[i
];
8786 if (route_rule_id_count
== 1) {
8787 *return_route_rule_id
= route_rule_id_array
[0];
8788 } else if (route_rule_id_count
> 1) {
8789 *return_route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
8792 return matched_policy
;
8796 necp_output_bypass(struct mbuf
*packet
)
8798 if (necp_pass_loopback
> 0 && necp_is_loopback(NULL
, NULL
, NULL
, packet
, IFSCOPE_NONE
)) {
8801 if (necp_pass_keepalives
> 0 && necp_get_is_keepalive_from_packet(packet
)) {
8804 if (necp_is_intcoproc(NULL
, packet
)) {
8810 necp_kernel_policy_id
8811 necp_ip_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip_out_args
*ipoa
, struct rtentry
*rt
,
8812 necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
8814 struct ip
*ip
= NULL
;
8815 int hlen
= sizeof(struct ip
);
8816 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8817 necp_kernel_policy_id socket_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8818 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8819 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
8820 u_int16_t protocol
= 0;
8821 u_int32_t bound_interface_index
= 0;
8822 u_int32_t last_interface_index
= 0;
8823 union necp_sockaddr_union local_addr
;
8824 union necp_sockaddr_union remote_addr
;
8825 u_int32_t drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8826 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8827 u_int16_t pf_tag
= 0;
8833 if (result_parameter
) {
8834 memset(result_parameter
, 0, sizeof(*result_parameter
));
8837 if (packet
== NULL
) {
8838 return NECP_KERNEL_POLICY_ID_NONE
;
8841 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
8842 socket_skip_policy_id
= necp_get_skip_policy_id_from_packet(packet
);
8843 pf_tag
= necp_get_packet_filter_tags_from_packet(packet
);
8845 // Exit early for an empty list
8846 // Don't lock. Possible race condition, but we don't want the performance hit.
8847 if (necp_kernel_ip_output_policies_count
== 0 ||
8848 (socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
&& necp_kernel_ip_output_policies_non_id_count
== 0 && necp_drop_dest_policy
.entry_count
== 0)) {
8849 if (necp_drop_all_order
> 0) {
8850 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8852 if (necp_output_bypass(packet
)) {
8853 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8855 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8860 return matched_policy_id
;
8863 // Check for loopback exception
8864 if (necp_output_bypass(packet
)) {
8865 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8867 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
8869 return matched_policy_id
;
8872 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
8874 // Process packet to get relevant fields
8875 ip
= mtod(packet
, struct ip
*);
8877 hlen
= _IP_VHL_HL(ip
->ip_vhl
) << 2;
8879 hlen
= ip
->ip_hl
<< 2;
8882 protocol
= ip
->ip_p
;
8884 if ((flags
& IP_OUTARGS
) && (ipoa
!= NULL
) &&
8885 (ipoa
->ipoa_flags
& IPOAF_BOUND_IF
) &&
8886 ipoa
->ipoa_boundif
!= IFSCOPE_NONE
) {
8887 bound_interface_index
= ipoa
->ipoa_boundif
;
8890 local_addr
.sin
.sin_family
= AF_INET
;
8891 local_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
8892 memcpy(&local_addr
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
));
8894 remote_addr
.sin
.sin_family
= AF_INET
;
8895 remote_addr
.sin
.sin_len
= sizeof(struct sockaddr_in
);
8896 memcpy(&((struct sockaddr_in
*)&remote_addr
)->sin_addr
, &ip
->ip_dst
, sizeof(ip
->ip_dst
));
8901 if ((int)(hlen
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
8902 m_copydata(packet
, hlen
, sizeof(th
), (u_int8_t
*)&th
);
8903 ((struct sockaddr_in
*)&local_addr
)->sin_port
= th
.th_sport
;
8904 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= th
.th_dport
;
8910 if ((int)(hlen
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
8911 m_copydata(packet
, hlen
, sizeof(uh
), (u_int8_t
*)&uh
);
8912 ((struct sockaddr_in
*)&local_addr
)->sin_port
= uh
.uh_sport
;
8913 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= uh
.uh_dport
;
8918 ((struct sockaddr_in
*)&local_addr
)->sin_port
= 0;
8919 ((struct sockaddr_in
*)&remote_addr
)->sin_port
= 0;
8924 // Match packet to policy
8925 lck_rw_lock_shared(&necp_kernel_policy_lock
);
8926 u_int32_t route_rule_id
= 0;
8927 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, socket_skip_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
, rt
, pf_tag
, &route_rule_id
, &drop_dest_policy_result
, &drop_all_bypass
);
8928 if (matched_policy
) {
8929 matched_policy_id
= matched_policy
->id
;
8931 *result
= matched_policy
->result
;
8934 if (result_parameter
) {
8935 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
8938 if (route_rule_id
!= 0 &&
8939 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
8940 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
8943 if (necp_debug
> 1) {
8944 NECPLOG(LOG_DEBUG
, "IP Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d Route Rule %u", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
, route_rule_id
);
8947 bool drop_all
= false;
8949 * Apply drop-all only to packets which have never matched a primary policy (check
8950 * if the packet saved policy id is none or falls within the socket policy id range).
8952 if (socket_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
&&
8953 (necp_drop_all_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
)) {
8955 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
8956 drop_all_bypass
= necp_check_drop_all_bypass_result(NULL
);
8959 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
8960 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
8962 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
8964 } else if (route_rule_id
!= 0 &&
8965 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
8966 // If we matched a route rule, mark it
8967 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
8971 lck_rw_done(&necp_kernel_policy_lock
);
8973 return matched_policy_id
;
8976 necp_kernel_policy_id
8977 necp_ip6_output_find_policy_match(struct mbuf
*packet
, int flags
, struct ip6_out_args
*ip6oa
, struct rtentry
*rt
,
8978 necp_kernel_policy_result
*result
, necp_kernel_policy_result_parameter
*result_parameter
)
8980 struct ip6_hdr
*ip6
= NULL
;
8983 necp_kernel_policy_id socket_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8984 necp_kernel_policy_id socket_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8985 necp_kernel_policy_id matched_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
8986 struct necp_kernel_ip_output_policy
*matched_policy
= NULL
;
8987 u_int16_t protocol
= 0;
8988 u_int32_t bound_interface_index
= 0;
8989 u_int32_t last_interface_index
= 0;
8990 union necp_sockaddr_union local_addr
;
8991 union necp_sockaddr_union remote_addr
;
8992 u_int32_t drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
8993 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
8994 u_int16_t pf_tag
= 0;
9000 if (result_parameter
) {
9001 memset(result_parameter
, 0, sizeof(*result_parameter
));
9004 if (packet
== NULL
) {
9005 return NECP_KERNEL_POLICY_ID_NONE
;
9008 socket_policy_id
= necp_get_policy_id_from_packet(packet
);
9009 socket_skip_policy_id
= necp_get_skip_policy_id_from_packet(packet
);
9010 pf_tag
= necp_get_packet_filter_tags_from_packet(packet
);
9012 // Exit early for an empty list
9013 // Don't lock. Possible race condition, but we don't want the performance hit.
9014 if (necp_kernel_ip_output_policies_count
== 0 ||
9015 (socket_policy_id
== NECP_KERNEL_POLICY_ID_NONE
&& necp_kernel_ip_output_policies_non_id_count
== 0 && necp_drop_dest_policy
.entry_count
== 0)) {
9016 if (necp_drop_all_order
> 0) {
9017 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
9019 if (necp_output_bypass(packet
)) {
9020 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
9022 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
9027 return matched_policy_id
;
9030 // Check for loopback exception
9031 if (necp_output_bypass(packet
)) {
9032 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
9034 *result
= NECP_KERNEL_POLICY_RESULT_PASS
;
9036 return matched_policy_id
;
9039 last_interface_index
= necp_get_last_interface_index_from_packet(packet
);
9041 // Process packet to get relevant fields
9042 ip6
= mtod(packet
, struct ip6_hdr
*);
9044 if ((flags
& IPV6_OUTARGS
) && (ip6oa
!= NULL
) &&
9045 (ip6oa
->ip6oa_flags
& IP6OAF_BOUND_IF
) &&
9046 ip6oa
->ip6oa_boundif
!= IFSCOPE_NONE
) {
9047 bound_interface_index
= ip6oa
->ip6oa_boundif
;
9050 ((struct sockaddr_in6
*)&local_addr
)->sin6_family
= AF_INET6
;
9051 ((struct sockaddr_in6
*)&local_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
9052 memcpy(&((struct sockaddr_in6
*)&local_addr
)->sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
));
9054 ((struct sockaddr_in6
*)&remote_addr
)->sin6_family
= AF_INET6
;
9055 ((struct sockaddr_in6
*)&remote_addr
)->sin6_len
= sizeof(struct sockaddr_in6
);
9056 memcpy(&((struct sockaddr_in6
*)&remote_addr
)->sin6_addr
, &ip6
->ip6_dst
, sizeof(ip6
->ip6_dst
));
9058 offset
= ip6_lasthdr(packet
, 0, IPPROTO_IPV6
, &next
);
9059 if (offset
>= 0 && packet
->m_pkthdr
.len
>= offset
) {
9064 if ((int)(offset
+ sizeof(th
)) <= packet
->m_pkthdr
.len
) {
9065 m_copydata(packet
, offset
, sizeof(th
), (u_int8_t
*)&th
);
9066 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= th
.th_sport
;
9067 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= th
.th_dport
;
9073 if ((int)(offset
+ sizeof(uh
)) <= packet
->m_pkthdr
.len
) {
9074 m_copydata(packet
, offset
, sizeof(uh
), (u_int8_t
*)&uh
);
9075 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= uh
.uh_sport
;
9076 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= uh
.uh_dport
;
9081 ((struct sockaddr_in6
*)&local_addr
)->sin6_port
= 0;
9082 ((struct sockaddr_in6
*)&remote_addr
)->sin6_port
= 0;
9088 // Match packet to policy
9089 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9090 u_int32_t route_rule_id
= 0;
9091 matched_policy
= necp_ip_output_find_policy_match_locked(socket_policy_id
, socket_skip_policy_id
, bound_interface_index
, last_interface_index
, protocol
, &local_addr
, &remote_addr
, rt
, pf_tag
, &route_rule_id
, &drop_dest_policy_result
, &drop_all_bypass
);
9092 if (matched_policy
) {
9093 matched_policy_id
= matched_policy
->id
;
9095 *result
= matched_policy
->result
;
9098 if (result_parameter
) {
9099 memcpy(result_parameter
, &matched_policy
->result_parameter
, sizeof(matched_policy
->result_parameter
));
9102 if (route_rule_id
!= 0 &&
9103 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
9104 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
9107 if (necp_debug
> 1) {
9108 NECPLOG(LOG_DEBUG
, "IP6 Output: (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d Route Rule %u", socket_policy_id
, bound_interface_index
, last_interface_index
, protocol
, matched_policy
->id
, matched_policy
->result
, matched_policy
->result_parameter
.tunnel_interface_index
, route_rule_id
);
9111 bool drop_all
= false;
9113 * Apply drop-all only to packets which have never matched a primary policy (check
9114 * if the packet saved policy id is none or falls within the socket policy id range).
9116 if (socket_policy_id
< NECP_KERNEL_POLICY_ID_FIRST_VALID_IP
&&
9117 (necp_drop_all_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
)) {
9119 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
9120 drop_all_bypass
= necp_check_drop_all_bypass_result(NULL
);
9123 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
9124 matched_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
9126 *result
= NECP_KERNEL_POLICY_RESULT_DROP
;
9128 } else if (route_rule_id
!= 0 &&
9129 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
== 0) {
9130 // If we matched a route rule, mark it
9131 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
9135 lck_rw_done(&necp_kernel_policy_lock
);
9137 return matched_policy_id
;
9142 necp_is_addr_in_range(struct sockaddr
*addr
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
9146 if (addr
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
9150 /* Must be greater than or equal to start */
9151 cmp
= necp_addr_compare(addr
, range_start
, 1);
9152 if (cmp
!= 0 && cmp
!= 1) {
9156 /* Must be less than or equal to end */
9157 cmp
= necp_addr_compare(addr
, range_end
, 1);
9158 if (cmp
!= 0 && cmp
!= -1) {
9166 necp_is_range_in_range(struct sockaddr
*inner_range_start
, struct sockaddr
*inner_range_end
, struct sockaddr
*range_start
, struct sockaddr
*range_end
)
9170 if (inner_range_start
== NULL
|| inner_range_end
== NULL
|| range_start
== NULL
|| range_end
== NULL
) {
9174 /* Must be greater than or equal to start */
9175 cmp
= necp_addr_compare(inner_range_start
, range_start
, 1);
9176 if (cmp
!= 0 && cmp
!= 1) {
9180 /* Must be less than or equal to end */
9181 cmp
= necp_addr_compare(inner_range_end
, range_end
, 1);
9182 if (cmp
!= 0 && cmp
!= -1) {
9190 necp_is_addr_in_subnet(struct sockaddr
*addr
, struct sockaddr
*subnet_addr
, u_int8_t subnet_prefix
)
9192 if (addr
== NULL
|| subnet_addr
== NULL
) {
9196 if (addr
->sa_family
!= subnet_addr
->sa_family
|| addr
->sa_len
!= subnet_addr
->sa_len
) {
9200 switch (addr
->sa_family
) {
9202 if (satosin(subnet_addr
)->sin_port
!= 0 &&
9203 satosin(addr
)->sin_port
!= satosin(subnet_addr
)->sin_port
) {
9206 return necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin(addr
)->sin_addr
, (u_int8_t
*)&satosin(subnet_addr
)->sin_addr
, subnet_prefix
);
9209 if (satosin6(subnet_addr
)->sin6_port
!= 0 &&
9210 satosin6(addr
)->sin6_port
!= satosin6(subnet_addr
)->sin6_port
) {
9213 if (satosin6(addr
)->sin6_scope_id
&&
9214 satosin6(subnet_addr
)->sin6_scope_id
&&
9215 satosin6(addr
)->sin6_scope_id
!= satosin6(subnet_addr
)->sin6_scope_id
) {
9218 return necp_buffer_compare_with_bit_prefix((u_int8_t
*)&satosin6(addr
)->sin6_addr
, (u_int8_t
*)&satosin6(subnet_addr
)->sin6_addr
, subnet_prefix
);
9233 * 2: Not comparable or error
9236 necp_addr_compare(struct sockaddr
*sa1
, struct sockaddr
*sa2
, int check_port
)
9239 int port_result
= 0;
9241 if (sa1
->sa_family
!= sa2
->sa_family
|| sa1
->sa_len
!= sa2
->sa_len
) {
9245 if (sa1
->sa_len
== 0) {
9249 switch (sa1
->sa_family
) {
9251 if (sa1
->sa_len
!= sizeof(struct sockaddr_in
)) {
9255 result
= memcmp(&satosin(sa1
)->sin_addr
.s_addr
, &satosin(sa2
)->sin_addr
.s_addr
, sizeof(satosin(sa1
)->sin_addr
.s_addr
));
9258 if (satosin(sa1
)->sin_port
< satosin(sa2
)->sin_port
) {
9260 } else if (satosin(sa1
)->sin_port
> satosin(sa2
)->sin_port
) {
9265 result
= port_result
;
9266 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
9274 if (sa1
->sa_len
!= sizeof(struct sockaddr_in6
)) {
9278 if (satosin6(sa1
)->sin6_scope_id
!= satosin6(sa2
)->sin6_scope_id
) {
9282 result
= memcmp(&satosin6(sa1
)->sin6_addr
.s6_addr
[0], &satosin6(sa2
)->sin6_addr
.s6_addr
[0], sizeof(struct in6_addr
));
9285 if (satosin6(sa1
)->sin6_port
< satosin6(sa2
)->sin6_port
) {
9287 } else if (satosin6(sa1
)->sin6_port
> satosin6(sa2
)->sin6_port
) {
9292 result
= port_result
;
9293 } else if ((result
> 0 && port_result
< 0) || (result
< 0 && port_result
> 0)) {
9301 result
= memcmp(sa1
, sa2
, sa1
->sa_len
);
9308 } else if (result
> 0) {
9316 necp_buffer_compare_with_bit_prefix(u_int8_t
*p1
, u_int8_t
*p2
, u_int32_t bits
)
9320 /* Handle null pointers */
9321 if (p1
== NULL
|| p2
== NULL
) {
9326 if (*p1
++ != *p2
++) {
9333 mask
= ~((1 << (8 - bits
)) - 1);
9334 if ((*p1
& mask
) != (*p2
& mask
)) {
9342 necp_addr_is_empty(struct sockaddr
*addr
)
9348 if (addr
->sa_len
== 0) {
9352 switch (addr
->sa_family
) {
9354 static struct sockaddr_in ipv4_empty_address
= {
9355 .sin_len
= sizeof(struct sockaddr_in
),
9356 .sin_family
= AF_INET
,
9358 .sin_addr
= { .s_addr
= 0 }, // 0.0.0.0
9361 if (necp_addr_compare(addr
, (struct sockaddr
*)&ipv4_empty_address
, 0) == 0) {
9368 static struct sockaddr_in6 ipv6_empty_address
= {
9369 .sin6_len
= sizeof(struct sockaddr_in6
),
9370 .sin6_family
= AF_INET6
,
9373 .sin6_addr
= IN6ADDR_ANY_INIT
, // ::
9376 if (necp_addr_compare(addr
, (struct sockaddr
*)&ipv6_empty_address
, 0) == 0) {
9390 necp_update_qos_marking(struct ifnet
*ifp
, u_int32_t route_rule_id
)
9392 bool qos_marking
= FALSE
;
9393 int exception_index
= 0;
9394 struct necp_route_rule
*route_rule
= NULL
;
9396 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
9397 if (route_rule
== NULL
) {
9398 qos_marking
= FALSE
;
9402 qos_marking
= (route_rule
->default_action
== NECP_ROUTE_RULE_QOS_MARKING
) ? TRUE
: FALSE
;
9408 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
9409 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
9412 if (route_rule
->exception_if_actions
[exception_index
] != NECP_ROUTE_RULE_QOS_MARKING
) {
9415 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
) {
9417 if (necp_debug
> 2) {
9418 NECPLOG(LOG_DEBUG
, "QoS Marking : Interface match %d for Rule %d Allowed %d",
9419 route_rule
->exception_if_indices
[exception_index
], route_rule_id
, qos_marking
);
9425 if ((route_rule
->cellular_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_CELLULAR(ifp
)) ||
9426 (route_rule
->wifi_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIFI(ifp
)) ||
9427 (route_rule
->wired_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_WIRED(ifp
)) ||
9428 (route_rule
->expensive_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_EXPENSIVE(ifp
)) ||
9429 (route_rule
->constrained_action
== NECP_ROUTE_RULE_QOS_MARKING
&& IFNET_IS_CONSTRAINED(ifp
))) {
9431 if (necp_debug
> 2) {
9432 NECPLOG(LOG_DEBUG
, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d for Rule %d Allowed %d",
9433 route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
,
9434 route_rule
->expensive_action
, route_rule
->constrained_action
, route_rule_id
, qos_marking
);
9439 if (necp_debug
> 1) {
9440 NECPLOG(LOG_DEBUG
, "QoS Marking: Rule %d ifp %s Allowed %d",
9441 route_rule_id
, ifp
? ifp
->if_xname
: "", qos_marking
);
9447 necp_lookup_current_qos_marking(int32_t *qos_marking_gencount
, struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
, bool old_qos_marking
)
9449 bool new_qos_marking
= old_qos_marking
;
9450 struct ifnet
*ifp
= interface
;
9452 if (net_qos_policy_restricted
== 0) {
9453 return new_qos_marking
;
9457 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
9459 if (*qos_marking_gencount
== necp_kernel_socket_policies_gencount
) {
9460 return new_qos_marking
;
9463 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9465 if (ifp
== NULL
&& route
!= NULL
) {
9466 ifp
= route
->rt_ifp
;
9469 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
9471 if (ifp
== NULL
|| route_rule_id
== 0) {
9472 new_qos_marking
= FALSE
;
9476 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
9477 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
9478 if (aggregate_route_rule
!= NULL
) {
9480 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
9481 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
9482 if (sub_route_rule_id
== 0) {
9485 new_qos_marking
= necp_update_qos_marking(ifp
, sub_route_rule_id
);
9486 if (new_qos_marking
== TRUE
) {
9492 new_qos_marking
= necp_update_qos_marking(ifp
, route_rule_id
);
9495 * Now that we have an interface we remember the gencount
9497 *qos_marking_gencount
= necp_kernel_socket_policies_gencount
;
9500 lck_rw_done(&necp_kernel_policy_lock
);
9501 return new_qos_marking
;
9505 necp_socket_update_qos_marking(struct inpcb
*inp
, struct rtentry
*route
, u_int32_t route_rule_id
)
9507 bool qos_marking
= inp
->inp_socket
->so_flags1
& SOF1_QOSMARKING_ALLOWED
? TRUE
: FALSE
;
9509 if (net_qos_policy_restricted
== 0) {
9512 if (inp
->inp_socket
== NULL
) {
9515 if ((inp
->inp_socket
->so_flags1
& SOF1_QOSMARKING_POLICY_OVERRIDE
)) {
9519 qos_marking
= necp_lookup_current_qos_marking(&(inp
->inp_policyresult
.results
.qos_marking_gencount
), route
, NULL
, route_rule_id
, qos_marking
);
9521 if (qos_marking
== TRUE
) {
9522 inp
->inp_socket
->so_flags1
|= SOF1_QOSMARKING_ALLOWED
;
9524 inp
->inp_socket
->so_flags1
&= ~SOF1_QOSMARKING_ALLOWED
;
9529 necp_route_is_lqm_abort(struct ifnet
*ifp
, struct ifnet
*delegated_ifp
)
9532 (ifp
->if_interface_state
.valid_bitmask
& IF_INTERFACE_STATE_LQM_STATE_VALID
) &&
9533 ifp
->if_interface_state
.lqm_state
== IFNET_LQM_THRESH_ABORT
) {
9536 if (delegated_ifp
!= NULL
&&
9537 (delegated_ifp
->if_interface_state
.valid_bitmask
& IF_INTERFACE_STATE_LQM_STATE_VALID
) &&
9538 delegated_ifp
->if_interface_state
.lqm_state
== IFNET_LQM_THRESH_ABORT
) {
9545 necp_route_is_allowed_inner(struct rtentry
*route
, struct ifnet
*ifp
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
9547 bool default_is_allowed
= TRUE
;
9548 u_int8_t type_aggregate_action
= NECP_ROUTE_RULE_NONE
;
9549 int exception_index
= 0;
9550 struct ifnet
*delegated_ifp
= NULL
;
9551 struct necp_route_rule
*route_rule
= NULL
;
9553 route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
9554 if (route_rule
== NULL
) {
9558 default_is_allowed
= (route_rule
->default_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
9560 ifp
= route
->rt_ifp
;
9563 if (necp_debug
> 1 && !default_is_allowed
) {
9564 NECPLOG(LOG_DEBUG
, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
9566 return default_is_allowed
;
9569 delegated_ifp
= ifp
->if_delegated
.ifp
;
9570 for (exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
9571 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
9574 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
||
9575 (delegated_ifp
!= NULL
&& route_rule
->exception_if_indices
[exception_index
] == delegated_ifp
->if_index
)) {
9576 if (route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9577 const bool lqm_abort
= necp_route_is_lqm_abort(ifp
, delegated_ifp
);
9578 if (necp_debug
> 1 && lqm_abort
) {
9579 NECPLOG(LOG_DEBUG
, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
9580 route_rule
->exception_if_indices
[exception_index
], route_rule_id
);
9583 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->exception_if_actions
[exception_index
])) {
9584 if (necp_debug
> 1) {
9585 NECPLOG(LOG_DEBUG
, "Route Allowed: Interface match %d for Rule %d Allowed %d", route_rule
->exception_if_indices
[exception_index
], route_rule_id
, ((route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
));
9587 return (route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
9592 if (IFNET_IS_CELLULAR(ifp
)) {
9593 if (route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9594 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9595 if (interface_type_denied
!= NULL
) {
9596 *interface_type_denied
= IFRTYPE_FUNCTIONAL_CELLULAR
;
9598 // Mark aggregate action as deny
9599 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9601 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->cellular_action
)) {
9602 if (interface_type_denied
!= NULL
) {
9603 *interface_type_denied
= IFRTYPE_FUNCTIONAL_CELLULAR
;
9605 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9606 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9607 route_rule
->cellular_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9608 // Deny wins if there is a conflict
9609 type_aggregate_action
= route_rule
->cellular_action
;
9614 if (IFNET_IS_WIFI(ifp
)) {
9615 if (route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9616 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9617 if (interface_type_denied
!= NULL
) {
9618 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
;
9620 // Mark aggregate action as deny
9621 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9623 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wifi_action
)) {
9624 if (interface_type_denied
!= NULL
) {
9625 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIFI_INFRA
;
9627 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9628 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9629 route_rule
->wifi_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9630 // Deny wins if there is a conflict
9631 type_aggregate_action
= route_rule
->wifi_action
;
9636 if (IFNET_IS_WIRED(ifp
)) {
9637 if (route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9638 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9639 if (interface_type_denied
!= NULL
) {
9640 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIRED
;
9642 // Mark aggregate action as deny
9643 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9645 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->wired_action
)) {
9646 if (interface_type_denied
!= NULL
) {
9647 *interface_type_denied
= IFRTYPE_FUNCTIONAL_WIRED
;
9649 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9650 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9651 route_rule
->wired_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9652 // Deny wins if there is a conflict
9653 type_aggregate_action
= route_rule
->wired_action
;
9658 if (IFNET_IS_EXPENSIVE(ifp
)) {
9659 if (route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9660 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9661 // Mark aggregate action as deny
9662 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9664 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->expensive_action
)) {
9665 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9666 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9667 route_rule
->expensive_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9668 // Deny wins if there is a conflict
9669 type_aggregate_action
= route_rule
->expensive_action
;
9674 if (IFNET_IS_CONSTRAINED(ifp
)) {
9675 if (route_rule
->constrained_action
== NECP_ROUTE_RULE_DENY_LQM_ABORT
) {
9676 if (necp_route_is_lqm_abort(ifp
, delegated_ifp
)) {
9677 // Mark aggregate action as deny
9678 type_aggregate_action
= NECP_ROUTE_RULE_DENY_INTERFACE
;
9680 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule
->constrained_action
)) {
9681 if (type_aggregate_action
== NECP_ROUTE_RULE_NONE
||
9682 (type_aggregate_action
== NECP_ROUTE_RULE_ALLOW_INTERFACE
&&
9683 route_rule
->constrained_action
== NECP_ROUTE_RULE_DENY_INTERFACE
)) {
9684 // Deny wins if there is a conflict
9685 type_aggregate_action
= route_rule
->constrained_action
;
9690 if (type_aggregate_action
!= NECP_ROUTE_RULE_NONE
) {
9691 if (necp_debug
> 1) {
9692 NECPLOG(LOG_DEBUG
, "Route Allowed: C:%d WF:%d W:%d E:%d for Rule %d Allowed %d", route_rule
->cellular_action
, route_rule
->wifi_action
, route_rule
->wired_action
, route_rule
->expensive_action
, route_rule_id
, ((type_aggregate_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
));
9694 return (type_aggregate_action
== NECP_ROUTE_RULE_DENY_INTERFACE
) ? FALSE
: TRUE
;
9697 if (necp_debug
> 1 && !default_is_allowed
) {
9698 NECPLOG(LOG_DEBUG
, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id
, default_is_allowed
);
9700 return default_is_allowed
;
9704 necp_route_is_allowed(struct rtentry
*route
, struct ifnet
*interface
, u_int32_t route_rule_id
, u_int32_t
*interface_type_denied
)
9706 if ((route
== NULL
&& interface
== NULL
) || route_rule_id
== 0) {
9707 if (necp_debug
> 1) {
9708 NECPLOG(LOG_DEBUG
, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id
, TRUE
);
9713 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id
)) {
9714 struct necp_aggregate_route_rule
*aggregate_route_rule
= necp_lookup_aggregate_route_rule_locked(route_rule_id
);
9715 if (aggregate_route_rule
!= NULL
) {
9717 for (index
= 0; index
< MAX_AGGREGATE_ROUTE_RULES
; index
++) {
9718 u_int32_t sub_route_rule_id
= aggregate_route_rule
->rule_ids
[index
];
9719 if (sub_route_rule_id
== 0) {
9722 if (!necp_route_is_allowed_inner(route
, interface
, sub_route_rule_id
, interface_type_denied
)) {
9728 return necp_route_is_allowed_inner(route
, interface
, route_rule_id
, interface_type_denied
);
9735 necp_route_get_netagent(struct rtentry
*route
, u_int32_t route_rule_id
)
9737 if (route
== NULL
) {
9741 struct ifnet
*ifp
= route
->rt_ifp
;
9746 struct necp_route_rule
*route_rule
= necp_lookup_route_rule_locked(&necp_route_rules
, route_rule_id
);
9747 if (route_rule
== NULL
) {
9751 // No netagent, skip
9752 if (route_rule
->netagent_id
== 0) {
9756 if (route_rule
->default_action
== NECP_ROUTE_RULE_USE_NETAGENT
) {
9757 return route_rule
->netagent_id
;
9760 for (int exception_index
= 0; exception_index
< MAX_ROUTE_RULE_INTERFACES
; exception_index
++) {
9761 if (route_rule
->exception_if_indices
[exception_index
] == 0) {
9764 if (route_rule
->exception_if_indices
[exception_index
] == ifp
->if_index
&&
9765 route_rule
->exception_if_actions
[exception_index
] == NECP_ROUTE_RULE_USE_NETAGENT
) {
9766 return route_rule
->netagent_id
;
9770 if (route_rule
->cellular_action
== NECP_ROUTE_RULE_USE_NETAGENT
&&
9771 ifp
->if_type
== IFT_CELLULAR
) {
9772 return route_rule
->netagent_id
;
9775 if (route_rule
->wifi_action
== NECP_ROUTE_RULE_USE_NETAGENT
&&
9776 ifp
->if_family
== IFNET_FAMILY_ETHERNET
&& ifp
->if_subfamily
== IFNET_SUBFAMILY_WIFI
) {
9777 return route_rule
->netagent_id
;
9780 if (route_rule
->wired_action
== NECP_ROUTE_RULE_USE_NETAGENT
&&
9781 (ifp
->if_family
== IFNET_FAMILY_ETHERNET
|| ifp
->if_family
== IFNET_FAMILY_FIREWIRE
)) {
9782 return route_rule
->netagent_id
;
9785 if (route_rule
->expensive_action
== NECP_ROUTE_RULE_USE_NETAGENT
&&
9786 ifp
->if_eflags
& IFEF_EXPENSIVE
) {
9787 return route_rule
->netagent_id
;
9790 if (route_rule
->constrained_action
== NECP_ROUTE_RULE_USE_NETAGENT
&&
9791 ifp
->if_xflags
& IFXF_CONSTRAINED
) {
9792 return route_rule
->netagent_id
;
9799 necp_packet_is_allowed_over_interface(struct mbuf
*packet
, struct ifnet
*interface
)
9801 bool is_allowed
= TRUE
;
9802 u_int32_t route_rule_id
= necp_get_route_rule_id_from_packet(packet
);
9803 if (route_rule_id
!= 0 &&
9804 interface
!= NULL
) {
9805 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9806 is_allowed
= necp_route_is_allowed(NULL
, interface
, necp_get_route_rule_id_from_packet(packet
), NULL
);
9807 lck_rw_done(&necp_kernel_policy_lock
);
9813 necp_netagents_allow_traffic(u_int32_t
*netagent_ids
, size_t netagent_id_count
)
9815 size_t netagent_cursor
;
9816 for (netagent_cursor
= 0; netagent_cursor
< netagent_id_count
; netagent_cursor
++) {
9817 struct necp_uuid_id_mapping
*mapping
= NULL
;
9818 u_int32_t netagent_id
= netagent_ids
[netagent_cursor
];
9819 if (netagent_id
== 0) {
9822 mapping
= necp_uuid_lookup_uuid_with_service_id_locked(netagent_id
);
9823 if (mapping
!= NULL
) {
9824 u_int32_t agent_flags
= 0;
9825 agent_flags
= netagent_get_flags(mapping
->uuid
);
9826 if (agent_flags
& NETAGENT_FLAG_REGISTERED
) {
9827 if (agent_flags
& NETAGENT_FLAG_ACTIVE
) {
9829 } else if ((agent_flags
& NETAGENT_FLAG_VOLUNTARY
) == 0) {
9839 necp_packet_filter_tags_receive(u_int16_t pf_tag
, u_int32_t pass_flags
)
9841 bool allowed_to_receive
= TRUE
;
9843 if (pf_tag
== PF_TAG_ID_STACK_DROP
&&
9844 (pass_flags
& NECP_KERNEL_POLICY_PASS_PF_TAG
) != NECP_KERNEL_POLICY_PASS_PF_TAG
) {
9845 allowed_to_receive
= FALSE
;
9848 return allowed_to_receive
;
9852 necp_socket_is_allowed_to_send_recv_internal(struct inpcb
*inp
, struct sockaddr
*override_local_addr
, struct sockaddr
*override_remote_addr
, ifnet_t input_interface
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
9854 u_int32_t verifyifindex
= input_interface
? input_interface
->if_index
: 0;
9855 bool allowed_to_receive
= TRUE
;
9856 struct necp_socket_info info
;
9857 u_int32_t flowhash
= 0;
9858 necp_kernel_policy_result service_action
= 0;
9859 necp_kernel_policy_service service
= { 0, 0 };
9860 u_int32_t route_rule_id
= 0;
9861 struct rtentry
*route
= NULL
;
9862 u_int32_t interface_type_denied
= IFRTYPE_FUNCTIONAL_UNKNOWN
;
9863 necp_kernel_policy_result drop_dest_policy_result
= NECP_KERNEL_POLICY_RESULT_NONE
;
9864 necp_drop_all_bypass_check_result_t drop_all_bypass
= NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
;
9865 u_int32_t netagent_ids
[NECP_MAX_NETAGENTS
];
9866 proc_t socket_proc
= NULL
;
9867 necp_kernel_policy_filter filter_control_unit
= 0;
9868 u_int32_t pass_flags
= 0;
9869 u_int32_t flow_divert_aggregate_unit
= 0;
9870 necp_socket_bypass_type_t bypass_type
= NECP_BYPASS_TYPE_NONE
;
9872 memset(&netagent_ids
, 0, sizeof(netagent_ids
));
9874 if (return_policy_id
) {
9875 *return_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9877 if (return_skip_policy_id
) {
9878 *return_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
9880 if (return_route_rule_id
) {
9881 *return_route_rule_id
= 0;
9883 if (return_pass_flags
) {
9884 *return_pass_flags
= 0;
9891 route
= inp
->inp_route
.ro_rt
;
9893 struct socket
*so
= inp
->inp_socket
;
9895 u_int32_t drop_order
= necp_process_drop_order(so
->so_cred
);
9897 // Don't lock. Possible race condition, but we don't want the performance hit.
9898 if (necp_kernel_socket_policies_count
== 0 ||
9899 (!(inp
->inp_flags2
& INP2_WANT_APP_POLICY
) && necp_kernel_socket_policies_non_app_count
== 0)) {
9900 if (necp_drop_all_order
> 0 || drop_order
> 0) {
9901 if (necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
) != NECP_BYPASS_TYPE_NONE
) {
9902 allowed_to_receive
= TRUE
;
9904 allowed_to_receive
= FALSE
;
9910 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
9911 if ((necp_socket_is_connected(inp
) || (override_local_addr
== NULL
&& override_remote_addr
== NULL
)) && inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
9912 bool policies_have_changed
= FALSE
;
9913 bool route_allowed
= TRUE
;
9915 if (inp
->inp_policyresult
.policy_gencount
!= necp_kernel_socket_policies_gencount
) {
9916 policies_have_changed
= TRUE
;
9918 if (inp
->inp_policyresult
.results
.route_rule_id
!= 0) {
9919 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9920 if (!necp_route_is_allowed(route
, input_interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
)) {
9921 route_allowed
= FALSE
;
9923 lck_rw_done(&necp_kernel_policy_lock
);
9927 if (!policies_have_changed
) {
9928 if (!route_allowed
||
9929 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
9930 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
9931 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& input_interface
&&
9932 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
)) {
9933 allowed_to_receive
= FALSE
;
9935 if (return_policy_id
) {
9936 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
9938 if (return_skip_policy_id
) {
9939 *return_skip_policy_id
= inp
->inp_policyresult
.skip_policy_id
;
9941 if (return_route_rule_id
) {
9942 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
9944 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
) {
9945 pass_flags
= inp
->inp_policyresult
.results
.result_parameter
.pass_flags
;
9952 // Check for loopback exception
9953 bypass_type
= necp_socket_bypass(override_local_addr
, override_remote_addr
, inp
);
9954 if (bypass_type
== NECP_BYPASS_TYPE_INTCOPROC
|| (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
&& necp_pass_loopback
== NECP_LOOPBACK_PASS_ALL
)) {
9955 allowed_to_receive
= TRUE
;
9959 // Actually calculate policy result
9960 lck_rw_lock_shared(&necp_kernel_policy_lock
);
9961 necp_socket_fillout_info_locked(inp
, override_local_addr
, override_remote_addr
, 0, input_interface
!= NULL
? true : false, drop_order
, &socket_proc
, &info
, (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
));
9963 flowhash
= necp_socket_calc_flowhash_locked(&info
);
9964 if (inp
->inp_policyresult
.policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
9965 inp
->inp_policyresult
.policy_gencount
== necp_kernel_socket_policies_gencount
&&
9966 inp
->inp_policyresult
.flowhash
== flowhash
) {
9967 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_DROP
||
9968 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
9969 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& input_interface
&&
9970 inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
9971 (inp
->inp_policyresult
.results
.route_rule_id
!= 0 &&
9972 !necp_route_is_allowed(route
, input_interface
, inp
->inp_policyresult
.results
.route_rule_id
, &interface_type_denied
))) {
9973 allowed_to_receive
= FALSE
;
9975 if (return_policy_id
) {
9976 *return_policy_id
= inp
->inp_policyresult
.policy_id
;
9978 if (return_route_rule_id
) {
9979 *return_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
9981 if (return_skip_policy_id
) {
9982 *return_skip_policy_id
= inp
->inp_policyresult
.skip_policy_id
;
9984 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
) {
9985 pass_flags
= inp
->inp_policyresult
.results
.result_parameter
.pass_flags
;
9988 lck_rw_done(&necp_kernel_policy_lock
);
9992 u_int32_t route_rule_id_array
[MAX_AGGREGATE_ROUTE_RULES
];
9993 size_t route_rule_id_array_count
= 0;
9994 struct necp_kernel_socket_policy
*matched_policy
= necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map
[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info
.application_id
)], &info
, &filter_control_unit
, route_rule_id_array
, &route_rule_id_array_count
, MAX_AGGREGATE_ROUTE_RULES
, &service_action
, &service
, netagent_ids
, NULL
, NECP_MAX_NETAGENTS
, NULL
, 0, socket_proc
? socket_proc
: current_proc(), pf_tag
, return_skip_policy_id
, inp
->inp_route
.ro_rt
, &drop_dest_policy_result
, &drop_all_bypass
, &flow_divert_aggregate_unit
);
9996 // Check for loopback exception again after the policy match
9997 if (bypass_type
== NECP_BYPASS_TYPE_LOOPBACK
&&
9998 necp_pass_loopback
== NECP_LOOPBACK_PASS_WITH_FILTER
&&
9999 (matched_policy
== NULL
|| matched_policy
->result
!= NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
)) {
10000 // Polices have changed since last evaluation, update inp result with new filter state
10001 if (inp
->inp_policyresult
.results
.filter_control_unit
!= filter_control_unit
) {
10002 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
10004 if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= flow_divert_aggregate_unit
) {
10005 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
10007 allowed_to_receive
= TRUE
;
10008 lck_rw_done(&necp_kernel_policy_lock
);
10012 if (route_rule_id_array_count
== 1) {
10013 route_rule_id
= route_rule_id_array
[0];
10014 } else if (route_rule_id_array_count
> 1) {
10015 route_rule_id
= necp_create_aggregate_route_rule(route_rule_id_array
);
10018 bool send_local_network_denied_event
= false;
10019 if (matched_policy
!= NULL
) {
10020 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
&&
10021 matched_policy
->result_parameter
.drop_flags
& NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK
) {
10022 // Trigger the event that we dropped due to a local network policy
10023 send_local_network_denied_event
= true;
10026 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_DROP
||
10027 matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
10028 (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&& input_interface
&&
10029 matched_policy
->result_parameter
.tunnel_interface_index
!= verifyifindex
) ||
10030 ((service_action
== NECP_KERNEL_POLICY_RESULT_TRIGGER_SCOPED
||
10031 service_action
== NECP_KERNEL_POLICY_RESULT_NO_TRIGGER_SCOPED
) &&
10032 service
.identifier
!= 0 && service
.identifier
!= NECP_NULL_SERVICE_ID
) ||
10033 (route_rule_id
!= 0 &&
10034 !necp_route_is_allowed(route
, input_interface
, route_rule_id
, &interface_type_denied
)) ||
10035 !necp_netagents_allow_traffic(netagent_ids
, NECP_MAX_NETAGENTS
)) {
10036 allowed_to_receive
= FALSE
;
10038 if (return_policy_id
) {
10039 *return_policy_id
= matched_policy
->id
;
10041 if (return_route_rule_id
) {
10042 *return_route_rule_id
= route_rule_id
;
10044 if (matched_policy
->result
== NECP_KERNEL_POLICY_RESULT_PASS
) {
10045 pass_flags
= matched_policy
->result_parameter
.pass_flags
;
10047 // Polices has changed since last evaluation, update inp result with new filter state
10048 if (inp
->inp_policyresult
.results
.filter_control_unit
!= filter_control_unit
) {
10049 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
10051 if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= flow_divert_aggregate_unit
) {
10052 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
10056 if (necp_debug
> 1 && matched_policy
->id
!= inp
->inp_policyresult
.policy_id
) {
10057 NECPLOG(LOG_DEBUG
, "Socket Send/Recv Policy: Policy %d Allowed %d", return_policy_id
? *return_policy_id
: 0, allowed_to_receive
);
10060 bool drop_all
= false;
10061 if (necp_drop_all_order
> 0 || info
.drop_order
> 0 || drop_dest_policy_result
== NECP_KERNEL_POLICY_RESULT_DROP
) {
10063 if (drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE
) {
10064 drop_all_bypass
= necp_check_drop_all_bypass_result(socket_proc
? socket_proc
: current_proc());
10067 if (drop_all
&& drop_all_bypass
== NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE
) {
10068 allowed_to_receive
= FALSE
;
10070 if (return_policy_id
) {
10071 *return_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
10073 if (return_route_rule_id
) {
10074 *return_route_rule_id
= route_rule_id
;
10077 // Polices has changed since last evaluation, update inp result with new filter state
10078 if (inp
->inp_policyresult
.results
.filter_control_unit
!= filter_control_unit
) {
10079 inp
->inp_policyresult
.results
.filter_control_unit
= filter_control_unit
;
10081 if (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= flow_divert_aggregate_unit
) {
10082 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
= flow_divert_aggregate_unit
;
10087 if (necp_check_restricted_multicast_drop(socket_proc
? socket_proc
: current_proc(), &info
, true)) {
10088 allowed_to_receive
= FALSE
;
10091 lck_rw_done(&necp_kernel_policy_lock
);
10093 if (send_local_network_denied_event
&& inp
->inp_policyresult
.network_denied_notifies
== 0) {
10094 inp
->inp_policyresult
.network_denied_notifies
++;
10095 necp_send_network_denied_event(((so
->so_flags
& SOF_DELEGATED
) ? so
->e_pid
: so
->last_pid
),
10096 ((so
->so_flags
& SOF_DELEGATED
) ? so
->e_uuid
: so
->last_uuid
),
10097 NETPOLICY_NETWORKTYPE_LOCAL
);
10101 if (return_pass_flags
!= NULL
) {
10102 *return_pass_flags
= pass_flags
;
10105 if (pf_tag
!= 0 && allowed_to_receive
) {
10106 allowed_to_receive
= necp_packet_filter_tags_receive(pf_tag
, pass_flags
);
10109 if (!allowed_to_receive
&& interface_type_denied
!= IFRTYPE_FUNCTIONAL_UNKNOWN
) {
10110 soevent(inp
->inp_socket
, (SO_FILT_HINT_LOCKED
| SO_FILT_HINT_IFDENIED
));
10114 proc_rele(socket_proc
);
10117 return allowed_to_receive
;
10121 necp_socket_is_allowed_to_send_recv_v4(struct inpcb
*inp
, u_int16_t local_port
, u_int16_t remote_port
, struct in_addr
*local_addr
, struct in_addr
*remote_addr
, ifnet_t input_interface
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
10123 struct sockaddr_in local
= {};
10124 struct sockaddr_in remote
= {};
10125 local
.sin_family
= remote
.sin_family
= AF_INET
;
10126 local
.sin_len
= remote
.sin_len
= sizeof(struct sockaddr_in
);
10127 local
.sin_port
= local_port
;
10128 remote
.sin_port
= remote_port
;
10129 memcpy(&local
.sin_addr
, local_addr
, sizeof(local
.sin_addr
));
10130 memcpy(&remote
.sin_addr
, remote_addr
, sizeof(remote
.sin_addr
));
10132 return necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, input_interface
,
10133 pf_tag
, return_policy_id
, return_route_rule_id
, return_skip_policy_id
, return_pass_flags
);
10137 necp_socket_is_allowed_to_send_recv_v6(struct inpcb
*inp
, u_int16_t local_port
, u_int16_t remote_port
, struct in6_addr
*local_addr
, struct in6_addr
*remote_addr
, ifnet_t input_interface
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
, u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
10139 struct sockaddr_in6 local
= {};
10140 struct sockaddr_in6 remote
= {};
10141 local
.sin6_family
= remote
.sin6_family
= AF_INET6
;
10142 local
.sin6_len
= remote
.sin6_len
= sizeof(struct sockaddr_in6
);
10143 local
.sin6_port
= local_port
;
10144 remote
.sin6_port
= remote_port
;
10145 memcpy(&local
.sin6_addr
, local_addr
, sizeof(local
.sin6_addr
));
10146 memcpy(&remote
.sin6_addr
, remote_addr
, sizeof(remote
.sin6_addr
));
10148 return necp_socket_is_allowed_to_send_recv_internal(inp
, (struct sockaddr
*)&local
, (struct sockaddr
*)&remote
, input_interface
,
10149 pf_tag
, return_policy_id
, return_route_rule_id
, return_skip_policy_id
, return_pass_flags
);
10153 necp_socket_is_allowed_to_send_recv(struct inpcb
*inp
, ifnet_t input_interface
, u_int16_t pf_tag
, necp_kernel_policy_id
*return_policy_id
,
10154 u_int32_t
*return_route_rule_id
, necp_kernel_policy_id
*return_skip_policy_id
, u_int32_t
*return_pass_flags
)
10156 return necp_socket_is_allowed_to_send_recv_internal(inp
, NULL
, NULL
, input_interface
, pf_tag
,
10157 return_policy_id
, return_route_rule_id
,
10158 return_skip_policy_id
, return_pass_flags
);
10162 necp_mark_packet_from_socket(struct mbuf
*packet
, struct inpcb
*inp
, necp_kernel_policy_id policy_id
, u_int32_t route_rule_id
,
10163 necp_kernel_policy_id skip_policy_id
, u_int32_t pass_flags
)
10165 if (packet
== NULL
|| inp
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10169 // Mark ID for Pass and IP Tunnel
10170 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
10171 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
10172 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_PASS
||
10173 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
) {
10174 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= inp
->inp_policyresult
.policy_id
;
10176 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
10178 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= 0;
10179 if (route_rule_id
!= 0) {
10180 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= route_rule_id
;
10182 packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
= inp
->inp_policyresult
.results
.route_rule_id
;
10184 packet
->m_pkthdr
.necp_mtag
.necp_app_id
= (inp
->inp_policyresult
.app_id
> UINT16_MAX
? (inp
->inp_policyresult
.app_id
- UINT16_MAX
) : inp
->inp_policyresult
.app_id
);
10186 if (skip_policy_id
!= NECP_KERNEL_POLICY_ID_NONE
&&
10187 skip_policy_id
!= NECP_KERNEL_POLICY_ID_NO_MATCH
) {
10188 // Only mark the skip policy if it is a valid policy ID
10189 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
= skip_policy_id
;
10190 } else if (inp
->inp_policyresult
.results
.filter_control_unit
== NECP_FILTER_UNIT_NO_FILTER
) {
10191 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
10192 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
10193 // See necp_get_skip_policy_id_from_packet() and
10194 // necp_packet_should_skip_filters().
10195 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
= NECP_KERNEL_POLICY_ID_NO_MATCH
;
10197 packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
10200 if (((pass_flags
& NECP_KERNEL_POLICY_PASS_PF_TAG
) == NECP_KERNEL_POLICY_PASS_PF_TAG
) ||
10201 ((inp
->inp_policyresult
.results
.result_parameter
.pass_flags
& NECP_KERNEL_POLICY_PASS_PF_TAG
) == NECP_KERNEL_POLICY_PASS_PF_TAG
)) {
10202 m_pftag(packet
)->pftag_tag
= PF_TAG_ID_SYSTEM_SERVICE
;
10209 necp_mark_packet_from_ip(struct mbuf
*packet
, necp_kernel_policy_id policy_id
)
10211 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10215 // Mark ID for Pass and IP Tunnel
10216 if (policy_id
!= NECP_KERNEL_POLICY_ID_NONE
) {
10217 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= policy_id
;
10219 packet
->m_pkthdr
.necp_mtag
.necp_policy_id
= NECP_KERNEL_POLICY_ID_NONE
;
10226 necp_mark_packet_from_interface(struct mbuf
*packet
, ifnet_t interface
)
10228 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10232 // Mark ID for Pass and IP Tunnel
10233 if (interface
!= NULL
) {
10234 packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
= interface
->if_index
;
10241 necp_mark_packet_as_keepalive(struct mbuf
*packet
, bool is_keepalive
)
10243 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10247 if (is_keepalive
) {
10248 packet
->m_pkthdr
.pkt_flags
|= PKTF_KEEPALIVE
;
10250 packet
->m_pkthdr
.pkt_flags
&= ~PKTF_KEEPALIVE
;
10256 necp_kernel_policy_id
10257 necp_get_policy_id_from_packet(struct mbuf
*packet
)
10259 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10260 return NECP_KERNEL_POLICY_ID_NONE
;
10263 return packet
->m_pkthdr
.necp_mtag
.necp_policy_id
;
10266 necp_kernel_policy_id
10267 necp_get_skip_policy_id_from_packet(struct mbuf
*packet
)
10269 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10270 return NECP_KERNEL_POLICY_ID_NONE
;
10273 // Check for overloaded value. See necp_mark_packet_from_socket().
10274 if (packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
== NECP_KERNEL_POLICY_ID_NO_MATCH
) {
10275 return NECP_KERNEL_POLICY_ID_NONE
;
10278 return packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
;
10282 necp_get_packet_filter_tags_from_packet(struct mbuf
*packet
)
10284 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10288 return m_pftag(packet
)->pftag_tag
;
10292 necp_packet_should_skip_filters(struct mbuf
*packet
)
10294 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10298 // Check for overloaded value. See necp_mark_packet_from_socket().
10299 return packet
->m_pkthdr
.necp_mtag
.necp_skip_policy_id
== NECP_KERNEL_POLICY_ID_NO_MATCH
;
10303 necp_get_last_interface_index_from_packet(struct mbuf
*packet
)
10305 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10309 return packet
->m_pkthdr
.necp_mtag
.necp_last_interface_index
;
10313 necp_get_route_rule_id_from_packet(struct mbuf
*packet
)
10315 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10319 return packet
->m_pkthdr
.necp_mtag
.necp_route_rule_id
;
10323 necp_get_app_uuid_from_packet(struct mbuf
*packet
,
10326 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10330 bool found_mapping
= FALSE
;
10331 if (packet
->m_pkthdr
.necp_mtag
.necp_app_id
!= 0) {
10332 lck_rw_lock_shared(&necp_kernel_policy_lock
);
10333 necp_app_id app_id
= (packet
->m_pkthdr
.necp_mtag
.necp_app_id
< UINT16_MAX
? (packet
->m_pkthdr
.necp_mtag
.necp_app_id
+ UINT16_MAX
) : packet
->m_pkthdr
.necp_mtag
.necp_app_id
);
10334 struct necp_uuid_id_mapping
*entry
= necp_uuid_lookup_uuid_with_app_id_locked(app_id
);
10335 if (entry
!= NULL
) {
10336 uuid_copy(app_uuid
, entry
->uuid
);
10337 found_mapping
= true;
10339 lck_rw_done(&necp_kernel_policy_lock
);
10341 if (!found_mapping
) {
10342 uuid_clear(app_uuid
);
10348 necp_get_is_keepalive_from_packet(struct mbuf
*packet
)
10350 if (packet
== NULL
|| !(packet
->m_flags
& M_PKTHDR
)) {
10354 return packet
->m_pkthdr
.pkt_flags
& PKTF_KEEPALIVE
;
10358 necp_socket_get_content_filter_control_unit(struct socket
*so
)
10360 struct inpcb
*inp
= sotoinpcb(so
);
10365 return inp
->inp_policyresult
.results
.filter_control_unit
;
10369 necp_socket_should_use_flow_divert(struct inpcb
*inp
)
10375 return !(inp
->inp_socket
->so_flags1
& SOF1_FLOW_DIVERT_SKIP
) &&
10376 (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
||
10377 (inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= 0));
10381 necp_socket_get_flow_divert_control_unit(struct inpcb
*inp
, uint32_t *aggregate_unit
)
10387 if (inp
->inp_socket
->so_flags1
& SOF1_FLOW_DIVERT_SKIP
) {
10391 if (aggregate_unit
!= NULL
&&
10392 inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
!= 0) {
10393 *aggregate_unit
= inp
->inp_policyresult
.results
.flow_divert_aggregate_unit
;
10396 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT
) {
10397 return inp
->inp_policyresult
.results
.result_parameter
.flow_divert_control_unit
;
10404 necp_socket_should_rescope(struct inpcb
*inp
)
10410 return inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
||
10411 inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
;
10415 necp_socket_get_rescope_if_index(struct inpcb
*inp
)
10421 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED
) {
10422 return inp
->inp_policyresult
.results
.result_parameter
.scoped_interface_index
;
10423 } else if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT
) {
10424 return necp_get_primary_direct_interface_index();
10431 necp_socket_get_effective_mtu(struct inpcb
*inp
, u_int32_t current_mtu
)
10434 return current_mtu
;
10437 if (inp
->inp_policyresult
.results
.result
== NECP_KERNEL_POLICY_RESULT_IP_TUNNEL
&&
10438 (inp
->inp_flags
& INP_BOUND_IF
) &&
10439 inp
->inp_boundifp
) {
10440 u_int bound_interface_index
= inp
->inp_boundifp
->if_index
;
10441 u_int tunnel_interface_index
= inp
->inp_policyresult
.results
.result_parameter
.tunnel_interface_index
;
10443 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
10444 if (bound_interface_index
!= tunnel_interface_index
) {
10445 ifnet_t tunnel_interface
= NULL
;
10447 ifnet_head_lock_shared();
10448 tunnel_interface
= ifindex2ifnet
[tunnel_interface_index
];
10451 if (tunnel_interface
!= NULL
) {
10452 u_int32_t direct_tunnel_mtu
= tunnel_interface
->if_mtu
;
10453 u_int32_t delegate_tunnel_mtu
= (tunnel_interface
->if_delegated
.ifp
!= NULL
) ? tunnel_interface
->if_delegated
.ifp
->if_mtu
: 0;
10454 if (delegate_tunnel_mtu
!= 0 &&
10455 strncmp(tunnel_interface
->if_name
, "ipsec", strlen("ipsec")) == 0) {
10456 // For ipsec interfaces, calculate the overhead from the delegate interface
10457 u_int32_t tunnel_overhead
= (u_int32_t
)(esp_hdrsiz(NULL
) + sizeof(struct ip6_hdr
));
10458 if (delegate_tunnel_mtu
> tunnel_overhead
) {
10459 delegate_tunnel_mtu
-= tunnel_overhead
;
10462 if (delegate_tunnel_mtu
< direct_tunnel_mtu
) {
10463 // If the (delegate - overhead) < direct, return (delegate - overhead)
10464 return delegate_tunnel_mtu
;
10466 // Otherwise return direct
10467 return direct_tunnel_mtu
;
10470 // For non-ipsec interfaces, just return the tunnel MTU
10471 return direct_tunnel_mtu
;
10477 // By default, just return the MTU passed in
10478 return current_mtu
;
10482 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter
*result_parameter
)
10484 if (result_parameter
== NULL
) {
10488 return ifindex2ifnet
[result_parameter
->tunnel_interface_index
];
10492 necp_packet_can_rebind_to_ifnet(struct mbuf
*packet
, struct ifnet
*interface
, struct route
*new_route
, int family
)
10494 bool found_match
= FALSE
;
10495 errno_t result
= 0;
10496 ifaddr_t
*addresses
= NULL
;
10497 union necp_sockaddr_union address_storage
;
10500 if (packet
== NULL
|| interface
== NULL
|| new_route
== NULL
|| (family
!= AF_INET
&& family
!= AF_INET6
)) {
10504 result
= ifnet_get_address_list_family(interface
, &addresses
, family
);
10506 NECPLOG(LOG_ERR
, "Failed to get address list for %s%d", ifnet_name(interface
), ifnet_unit(interface
));
10510 for (i
= 0; addresses
[i
] != NULL
; i
++) {
10511 ROUTE_RELEASE(new_route
);
10512 if (ifaddr_address(addresses
[i
], &address_storage
.sa
, sizeof(address_storage
)) == 0) {
10513 if (family
== AF_INET
) {
10514 struct ip
*ip
= mtod(packet
, struct ip
*);
10515 if (memcmp(&address_storage
.sin
.sin_addr
, &ip
->ip_src
, sizeof(ip
->ip_src
)) == 0) {
10516 struct sockaddr_in
*dst4
= (struct sockaddr_in
*)(void *)&new_route
->ro_dst
;
10517 dst4
->sin_family
= AF_INET
;
10518 dst4
->sin_len
= sizeof(struct sockaddr_in
);
10519 dst4
->sin_addr
= ip
->ip_dst
;
10520 rtalloc_scoped(new_route
, interface
->if_index
);
10521 if (!ROUTE_UNUSABLE(new_route
)) {
10522 found_match
= TRUE
;
10526 } else if (family
== AF_INET6
) {
10527 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
10528 if (memcmp(&address_storage
.sin6
.sin6_addr
, &ip6
->ip6_src
, sizeof(ip6
->ip6_src
)) == 0) {
10529 struct sockaddr_in6
*dst6
= (struct sockaddr_in6
*)(void *)&new_route
->ro_dst
;
10530 dst6
->sin6_family
= AF_INET6
;
10531 dst6
->sin6_len
= sizeof(struct sockaddr_in6
);
10532 dst6
->sin6_addr
= ip6
->ip6_dst
;
10533 rtalloc_scoped(new_route
, interface
->if_index
);
10534 if (!ROUTE_UNUSABLE(new_route
)) {
10535 found_match
= TRUE
;
10544 ifnet_free_address_list(addresses
);
10546 return found_match
;
10550 necp_addr_is_loopback(struct sockaddr
*address
)
10552 if (address
== NULL
) {
10556 if (address
->sa_family
== AF_INET
) {
10557 return ntohl(((struct sockaddr_in
*)(void *)address
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
;
10558 } else if (address
->sa_family
== AF_INET6
) {
10559 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)address
)->sin6_addr
);
10566 necp_is_loopback(struct sockaddr
*local_addr
, struct sockaddr
*remote_addr
, struct inpcb
*inp
, struct mbuf
*packet
, u_int32_t bound_interface_index
)
10568 // Note: This function only checks for the loopback addresses.
10569 // In the future, we may want to expand to also allow any traffic
10570 // going through the loopback interface, but until then, this
10571 // check is cheaper.
10573 if (local_addr
!= NULL
&& necp_addr_is_loopback(local_addr
)) {
10577 if (remote_addr
!= NULL
&& necp_addr_is_loopback(remote_addr
)) {
10582 if ((inp
->inp_flags
& INP_BOUND_IF
) && inp
->inp_boundifp
&& (inp
->inp_boundifp
->if_flags
& IFF_LOOPBACK
)) {
10585 if (inp
->inp_vflag
& INP_IPV4
) {
10586 if (ntohl(inp
->inp_laddr
.s_addr
) == INADDR_LOOPBACK
||
10587 ntohl(inp
->inp_faddr
.s_addr
) == INADDR_LOOPBACK
) {
10590 } else if (inp
->inp_vflag
& INP_IPV6
) {
10591 if (IN6_IS_ADDR_LOOPBACK(&inp
->in6p_laddr
) ||
10592 IN6_IS_ADDR_LOOPBACK(&inp
->in6p_faddr
)) {
10596 } else if (bound_interface_index
!= IFSCOPE_NONE
&& lo_ifp
->if_index
== bound_interface_index
) {
10600 if (packet
!= NULL
) {
10601 struct ip
*ip
= mtod(packet
, struct ip
*);
10602 if (ip
->ip_v
== 4) {
10603 if (ntohl(ip
->ip_src
.s_addr
) == INADDR_LOOPBACK
) {
10606 if (ntohl(ip
->ip_dst
.s_addr
) == INADDR_LOOPBACK
) {
10609 } else if (ip
->ip_v
== 6) {
10610 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
10611 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_src
)) {
10614 if (IN6_IS_ADDR_LOOPBACK(&ip6
->ip6_dst
)) {
10624 necp_is_intcoproc(struct inpcb
*inp
, struct mbuf
*packet
)
10627 if (!(inp
->inp_vflag
& INP_IPV6
)) {
10630 if (INP_INTCOPROC_ALLOWED(inp
)) {
10633 if ((inp
->inp_flags
& INP_BOUND_IF
) &&
10634 IFNET_IS_INTCOPROC(inp
->inp_boundifp
)) {
10639 if (packet
!= NULL
) {
10640 struct ip6_hdr
*ip6
= mtod(packet
, struct ip6_hdr
*);
10641 if ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
) == IPV6_VERSION
&&
10642 IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_dst
) &&
10643 ip6
->ip6_dst
.s6_addr32
[2] == ntohl(0xaede48ff) &&
10644 ip6
->ip6_dst
.s6_addr32
[3] == ntohl(0xfe334455)) {
10653 necp_address_matches_drop_dest_policy(union necp_sockaddr_union
*sau
, u_int32_t session_order
)
10655 char dest_str
[MAX_IPv6_STR_LEN
];
10657 if (necp_drop_dest_debug
> 0) {
10658 if (sau
->sa
.sa_family
== AF_INET
) {
10659 (void) inet_ntop(AF_INET
, &sau
->sin
.sin_addr
, dest_str
, sizeof(dest_str
));
10660 } else if (sau
->sa
.sa_family
== AF_INET6
) {
10661 (void) inet_ntop(AF_INET6
, &sau
->sin6
.sin6_addr
, dest_str
, sizeof(dest_str
));
10666 for (u_int32_t i
= 0; i
< necp_drop_dest_policy
.entry_count
; i
++) {
10667 struct necp_drop_dest_entry
*necp_drop_dest_entry
= &necp_drop_dest_policy
.entries
[i
];
10668 struct necp_policy_condition_addr
*npca
= &necp_drop_dest_entry
->cond_addr
;
10670 if (session_order
>= necp_drop_dest_entry
->order
&& necp_is_addr_in_subnet(&sau
->sa
, &npca
->address
.sa
, npca
->prefix
)) {
10671 if (necp_drop_dest_debug
> 0) {
10672 char subnet_str
[MAX_IPv6_STR_LEN
];
10673 struct proc
*p
= current_proc();
10674 pid_t pid
= proc_pid(p
);
10676 if (sau
->sa
.sa_family
== AF_INET
) {
10677 (void) inet_ntop(AF_INET
, &npca
->address
.sin
, subnet_str
, sizeof(subnet_str
));
10678 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s matches %s/%u", __func__
, proc_best_name(p
), pid
, dest_str
, subnet_str
, npca
->prefix
);
10679 } else if (sau
->sa
.sa_family
== AF_INET6
) {
10680 (void) inet_ntop(AF_INET6
, &npca
->address
.sin6
, subnet_str
, sizeof(subnet_str
));
10681 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s matches %s/%u", __func__
, proc_best_name(p
), pid
, dest_str
, subnet_str
, npca
->prefix
);
10687 if (necp_drop_dest_debug
> 1) {
10688 struct proc
*p
= current_proc();
10689 pid_t pid
= proc_pid(p
);
10691 os_log(OS_LOG_DEFAULT
, "%s (process %s:%u) %s no match", __func__
, proc_best_name(p
), pid
, dest_str
);
10697 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
10699 #pragma unused(arg1, arg2, oidp)
10702 struct necp_drop_dest_policy tmp_drop_dest_policy
;
10703 struct proc
*p
= current_proc();
10704 pid_t pid
= proc_pid(p
);
10706 if (req
->newptr
!= USER_ADDR_NULL
&& proc_suser(current_proc()) != 0 &&
10707 priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES
, 0) != 0) {
10708 NECPLOG(LOG_ERR
, "%s (process %s:%u) not permitted", __func__
, proc_best_name(p
), pid
);
10711 if (req
->newptr
!= USER_ADDR_NULL
&& req
->newlen
!= sizeof(struct necp_drop_dest_policy
)) {
10712 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad newlen %lu", __func__
, proc_best_name(p
), pid
, req
->newlen
);
10716 memcpy(&tmp_drop_dest_policy
, &necp_drop_dest_policy
, sizeof(struct necp_drop_dest_policy
));
10717 error
= sysctl_io_opaque(req
, &tmp_drop_dest_policy
, sizeof(struct necp_drop_dest_policy
), &changed
);
10719 NECPLOG(LOG_ERR
, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__
, proc_best_name(p
), pid
, error
);
10722 if (changed
== 0 || req
->newptr
== USER_ADDR_NULL
) {
10727 // Validate the passed parameters
10729 if (tmp_drop_dest_policy
.entry_count
>= MAX_NECP_DROP_DEST_LEVEL_ADDRS
) {
10730 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad entry_count %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_policy
.entry_count
);
10733 for (u_int32_t i
= 0; i
< tmp_drop_dest_policy
.entry_count
; i
++) {
10734 struct necp_drop_dest_entry
*tmp_drop_dest_entry
= &tmp_drop_dest_policy
.entries
[i
];
10735 struct necp_policy_condition_addr
*npca
= &tmp_drop_dest_entry
->cond_addr
;
10737 switch (tmp_drop_dest_entry
->level
) {
10738 case NECP_SESSION_PRIORITY_UNKNOWN
:
10739 if (tmp_drop_dest_policy
.entry_count
!= 0) {
10740 NECPLOG(LOG_ERR
, "%s (process %s:%u) NECP_SESSION_PRIORITY_UNKNOWN bad entry_count %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_policy
.entry_count
);
10744 case NECP_SESSION_PRIORITY_CONTROL
:
10745 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL
:
10746 case NECP_SESSION_PRIORITY_HIGH
:
10747 case NECP_SESSION_PRIORITY_HIGH_1
:
10748 case NECP_SESSION_PRIORITY_HIGH_2
:
10749 case NECP_SESSION_PRIORITY_HIGH_3
:
10750 case NECP_SESSION_PRIORITY_HIGH_4
:
10751 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED
:
10752 case NECP_SESSION_PRIORITY_DEFAULT
:
10753 case NECP_SESSION_PRIORITY_LOW
:
10754 if (tmp_drop_dest_policy
.entry_count
== 0) {
10755 NECPLOG(LOG_ERR
, "%s (process %s:%u) priority %u entry_count 0", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_entry
->level
);
10760 NECPLOG(LOG_ERR
, "%s (process %s:%u) bad level %u", __func__
, proc_best_name(p
), pid
, tmp_drop_dest_entry
->level
);
10765 switch (npca
->address
.sa
.sa_family
) {
10767 if (npca
->prefix
> 32) {
10768 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad prefix %u", __func__
, proc_best_name(p
), pid
, npca
->prefix
);
10771 if (npca
->address
.sin
.sin_len
!= sizeof(struct sockaddr_in
)) {
10772 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad sin_len %u", __func__
, proc_best_name(p
), pid
, npca
->address
.sin
.sin_len
);
10775 if (npca
->address
.sin
.sin_port
!= 0) {
10776 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET bad sin_port %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin
.sin_port
);
10782 if (npca
->prefix
> 128) {
10783 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__
, proc_best_name(p
), pid
, npca
->prefix
);
10786 if (npca
->address
.sin6
.sin6_len
!= sizeof(struct sockaddr_in6
)) {
10787 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_len
);
10790 if (npca
->address
.sin6
.sin6_port
!= 0) {
10791 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_port %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_port
);
10794 if (npca
->address
.sin6
.sin6_flowinfo
!= 0) {
10795 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_flowinfo %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_flowinfo
);
10798 if (npca
->address
.sin6
.sin6_scope_id
!= 0) {
10799 NECPLOG(LOG_ERR
, "%s (process %s:%u) AF_INET6 bad sin6_scope_id %u, not zero", __func__
, proc_best_name(p
), pid
, npca
->address
.sin6
.sin6_scope_id
);
10811 // Commit the changed policy
10813 lck_rw_lock_exclusive(&necp_kernel_policy_lock
);
10814 memset(&necp_drop_dest_policy
, 0, sizeof(struct necp_drop_dest_policy
));
10816 necp_drop_dest_policy
.entry_count
= tmp_drop_dest_policy
.entry_count
;
10817 for (u_int32_t i
= 0; i
< tmp_drop_dest_policy
.entry_count
; i
++) {
10818 struct necp_drop_dest_entry
*tmp_drop_dest_entry
= &tmp_drop_dest_policy
.entries
[i
];
10819 struct necp_drop_dest_entry
*necp_drop_dest_entry
= &necp_drop_dest_policy
.entries
[i
];
10821 memcpy(necp_drop_dest_entry
, tmp_drop_dest_entry
, sizeof(struct necp_drop_dest_entry
));
10823 necp_drop_dest_entry
->order
= necp_get_first_order_for_priority(necp_drop_dest_entry
->level
);
10825 lck_rw_done(&necp_kernel_policy_lock
);