xref: /xnu-11417.140.69/bsd/net/necp.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 /*
2  * Copyright (c) 2013-2025 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <string.h>
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>
36 #include <sys/mbuf.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/proc_uuid_policy.h>
39 #include <net/if.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>
45 #include <sys/ubc.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/bloom_filter.h>
59 #include <net/if_var.h>
60 #include <net/pfvar.h>
61 #if SKYWALK
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) */
64 #include <sys/kauth.h>
65 #include <sys/sysctl.h>
66 #include <sys/sysproto.h>
67 #include <sys/priv.h>
68 #include <sys/kern_event.h>
69 #include <sys/file_internal.h>
70 #include <IOKit/IOBSD.h>
71 #include <libkern/crypto/rand.h>
72 #include <corecrypto/cchmac.h>
73 #include <corecrypto/ccsha2.h>
74 #include <os/refcnt.h>
75 #include <mach-o/loader.h>
76 #include <net/network_agent.h>
77 #include <net/necp.h>
78 #include <netinet/flow_divert_proto.h>
79 #include <kern/socket_flows.h>
80 
81 #include <net/sockaddr_utils.h>
82 #include <net/trie_utility.h>
83 
84 /*
85  * NECP - Network Extension Control Policy database
86  * ------------------------------------------------
87  * The goal of this module is to allow clients connecting via a
88  * policy file descriptor to create high-level policy sessions, which
89  * are ingested into low-level kernel policies that control and tag
90  * traffic at the application, socket, and IP layers.
91  *
92  * ------------------------------------------------
93  * Sessions
94  * ------------------------------------------------
95  * Each session owns a list of session policies, each of which can
96  * specify any combination of conditions and a single result. Each
97  * session also has a priority level (such as High, Default, or Low)
98  * which is requested by the client. Based on the requested level,
99  * a session order value is assigned to the session, which will be used
100  * to sort kernel policies generated by the session. The session client
101  * can specify the sub-order for each policy it creates which will be
102  * used to further sort the kernel policies.
103  *
104  *  Policy fd --> 1 necp_session --> list of necp_session_policy structs
105  *
106  * ------------------------------------------------
107  * Kernel Policies
108  * ------------------------------------------------
109  * Whenever a session send the Apply command, its policies are ingested
110  * and generate kernel policies. There are two phases of kernel policy
111  * ingestion.
112  *
113  * 1. The session policy is parsed to create kernel policies at the socket
114  *	  and IP layers, when applicable. For example, a policy that requires
115  *    all traffic from App1 to Pass will generate a socket kernel policy to
116  *    match App1 and mark packets with ID1, and also an IP policy to match
117  *    ID1 and let the packet pass. This is handled in necp_apply_policy. The
118  *    resulting kernel policies are added to the global socket and IP layer
119  *    policy lists.
120  *  necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
121  *                                      ||                             ||
122  *                                      \/                             \/
123  *                          necp_kernel_socket_policies   necp_kernel_ip_output_policies
124  *
125  * 2. Once the global lists of kernel policies have been filled out, each
126  *    list is traversed to create optimized sub-lists ("Maps") which are used during
127  *    data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
128  *    which hashes incoming packets based on marked socket-layer policies, and removes
129  *    duplicate or overlapping policies. Socket policies are sent into two maps,
130  *    necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
131  *    The app layer map is used for policy checks coming in from user space, and is one
132  *    list with duplicate and overlapping policies removed. The socket map hashes based
133  *    on app UUID, and removes duplicate and overlapping policies.
134  *  necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
135  *                            |-> necp_kernel_socket_policies_map
136  *
137  *  necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
138  *
139  * ------------------------------------------------
140  * Drop All Level
141  * ------------------------------------------------
142  * The Drop All Level is a sysctl that controls the level at which policies are allowed
143  * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
144  * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
145  * by a session with a priority level better than (numerically less than) the
146  * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
147  * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
148  * session orders to be dropped.
149  */
150 
151 u_int32_t necp_drop_all_order = 0;
152 u_int32_t necp_drop_all_level = 0;
153 
154 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
155 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
156 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
157 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
158 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
159 
160 u_int32_t necp_drop_unentitled_order = 0;
161 #ifdef XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
163 #else // XNU_TARGET_OS_WATCH
164 u_int32_t necp_drop_unentitled_level = 0;
165 #endif // XNU_TARGET_OS_WATCH
166 
167 u_int32_t necp_drop_management_order = 0;
168 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
169 
170 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
171 
172 os_log_t necp_log_handle = NULL;
173 os_log_t necp_data_trace_log_handle = NULL;
174 
175 u_int32_t necp_session_count = 0;
176 u_int32_t necp_trie_count = 0;
177 
178 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
179     struct necp_session_policy, NET_KT_DEFAULT);
180 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
181     struct necp_kernel_socket_policy, NET_KT_DEFAULT);
182 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
183     struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
184 
185 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do {          \
186 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) {  \
187 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
188 	} else {                                                                                                                                                \
189 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
190 	                if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) {      \
191 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
192 	                        break;                                                                                                                          \
193 	                }                                                                                                                                               \
194 	        }                                                                                                                                                       \
195 	}                                                                                                                                                               \
196 } while (0)
197 
198 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do {      \
199 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) {                                                                                                               \
200 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
201 	} else {                                                                                                                                                \
202 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
203 	                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))) {         \
204 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
205 	                        break;                                                                                                                          \
206 	                }                                                                                                                                               \
207 	        }                                                                                                                                                       \
208 	}                                                                                                                                                               \
209 } while (0)
210 
211 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
212 	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))) {                                                                                                                      \
213 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
214 	} else {                                                                                                                                                \
215 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
216 	                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)))	{ \
217 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
218 	                        break;                                                                                                                          \
219 	                }                                                                                                                                               \
220 	        }                                                                                                                                                       \
221 	}                                                                                                                                                               \
222 } while (0)
223 
224 #define IS_NECP_ROUTE_RULE_DENY(x)     ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
225 
226 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x)     (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
227 
228 #define NECP_KERNEL_CONDITION_ALL_INTERFACES            0x000001
229 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE           0x000002
230 #define NECP_KERNEL_CONDITION_PROTOCOL                          0x000004
231 #define NECP_KERNEL_CONDITION_LOCAL_START                       0x000008
232 #define NECP_KERNEL_CONDITION_LOCAL_END                         0x000010
233 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX                      0x000020
234 #define NECP_KERNEL_CONDITION_REMOTE_START                      0x000040
235 #define NECP_KERNEL_CONDITION_REMOTE_END                        0x000080
236 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX                     0x000100
237 #define NECP_KERNEL_CONDITION_APP_ID                            0x000200
238 #define NECP_KERNEL_CONDITION_REAL_APP_ID                       0x000400
239 #define NECP_KERNEL_CONDITION_DOMAIN                            0x000800
240 #define NECP_KERNEL_CONDITION_ACCOUNT_ID                        0x001000
241 #define NECP_KERNEL_CONDITION_POLICY_ID                         0x002000
242 #define NECP_KERNEL_CONDITION_PID                                       0x004000
243 #define NECP_KERNEL_CONDITION_UID                                       0x008000
244 #define NECP_KERNEL_CONDITION_LAST_INTERFACE            0x010000                        // Only set from packets looping between interfaces
245 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS                     0x020000
246 #define NECP_KERNEL_CONDITION_ENTITLEMENT                       0x040000
247 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT        0x080000
248 #define NECP_KERNEL_CONDITION_AGENT_TYPE                        0x100000
249 #define NECP_KERNEL_CONDITION_HAS_CLIENT                        0x200000
250 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS                    0x400000
251 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS                      0x800000
252 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY                       0x1000000
253 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY                      0x2000000
254 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY                   0x4000000
255 #define NECP_KERNEL_CONDITION_SDK_VERSION                       0x8000000
256 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER                0x10000000
257 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS                0x20000000
258 #define NECP_KERNEL_CONDITION_IS_LOOPBACK                       0x40000000
259 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY       0x80000000
260 #define NECP_KERNEL_CONDITION_SCHEME_PORT                       0x100000000
261 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER                     0x200000000
262 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT              0x400000000
263 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN                      0x800000000
264 #define NECP_KERNEL_CONDITION_REAL_UID                          0x1000000000
265 #define NECP_KERNEL_CONDITION_URL                               0x2000000000
266 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS             0x4000000000
267 
268 #define NECP_MAX_POLICY_RESULT_SIZE                                     512
269 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE                         1024
270 #define NECP_MAX_CONDITIONS_ARRAY_SIZE                          4096
271 #define NECP_MAX_POLICY_LIST_COUNT                                      1024
272 
273 #define NECP_MAX_DOMAIN_FILTER_SIZE                             65536 // Allows room for 100K domains
274 #define NECP_MAX_DOMAIN_TRIE_SIZE                               (1024 * 512) // Allows 5000+ domains
275 
276 typedef enum {
277 	NECP_BYPASS_TYPE_NONE = 0,
278 	NECP_BYPASS_TYPE_INTCOPROC = 1,
279 	NECP_BYPASS_TYPE_LOOPBACK = 2,
280 	NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
281 } necp_socket_bypass_type_t;
282 
283 // Cap the policy size at the max result + conditions size, with room for extra TLVs
284 #define NECP_MAX_POLICY_SIZE                                            (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
285 
286 struct necp_service_registration {
287 	LIST_ENTRY(necp_service_registration)   session_chain;
288 	LIST_ENTRY(necp_service_registration)   kernel_chain;
289 	u_int32_t                                                               service_id;
290 };
291 
292 struct necp_domain_filter {
293 	LIST_ENTRY(necp_domain_filter) owner_chain;
294 	LIST_ENTRY(necp_domain_filter) chain;
295 	u_int32_t       id;
296 	struct net_bloom_filter *filter;
297 	os_refcnt_t     refcount;
298 };
299 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
300 
301 /*
302  * Filter id space is split between domain bloom filter id and domain trie filter id.
303  * id <= 10000 - bloom filter ids
304  * id > 10000 - trie filter ids
305  */
306 #define NECP_DOMAIN_FILTER_ID_MAX           10000
307 #define NECP_DOMAIN_TRIE_ID_START           NECP_DOMAIN_FILTER_ID_MAX
308 #define NECP_IS_DOMAIN_FILTER_ID(id)        (id <= NECP_DOMAIN_FILTER_ID_MAX)
309 
310 struct necp_domain_trie {
311 	LIST_ENTRY(necp_domain_trie) owner_chain;
312 	LIST_ENTRY(necp_domain_trie) chain;
313 	u_int32_t       id;
314 	struct necp_domain_trie_request *trie_request;
315 	size_t trie_request_size;
316 	struct net_trie trie;
317 	os_refcnt_t     refcount;
318 };
319 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
320 
321 struct necp_session {
322 	u_int8_t                                        necp_fd_type;
323 	u_int32_t                                       control_unit;
324 	u_int32_t                                       session_priority; // Descriptive priority rating
325 	u_int32_t                                       session_order;
326 
327 	necp_policy_id                          last_policy_id;
328 
329 	decl_lck_mtx_data(, lock);
330 
331 	bool                                            proc_locked; // Messages must come from proc_uuid
332 	uuid_t                                          proc_uuid;
333 	int                                                     proc_pid;
334 
335 	bool                                            dirty;
336 	LIST_HEAD(_policies, necp_session_policy) policies;
337 
338 	LIST_HEAD(_services, necp_service_registration) services;
339 	struct necp_domain_filter_list domain_filters;
340 	struct necp_domain_trie_list domain_tries;
341 
342 	TAILQ_ENTRY(necp_session) chain;
343 };
344 
345 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
346 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
347 
348 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
349 
350 struct necp_socket_info {
351 	pid_t pid;
352 	int32_t pid_version;
353 	uid_t uid;
354 	uid_t real_uid;
355 	union necp_sockaddr_union local_addr;
356 	union necp_sockaddr_union remote_addr;
357 	u_int32_t bound_interface_index;
358 	u_int32_t bound_interface_flags;
359 	u_int32_t bound_interface_eflags;
360 	u_int32_t bound_interface_xflags;
361 	u_int32_t traffic_class;
362 	u_int16_t protocol;
363 	u_int16_t scheme_port;
364 	u_int32_t application_id;
365 	u_int32_t real_application_id;
366 	u_int32_t account_id;
367 	u_int32_t drop_order;
368 	u_int32_t client_flags;
369 	char *domain __null_terminated;
370 	char *url __null_terminated;
371 	struct soflow_hash_entry *soflow_entry;
372 	unsigned is_entitled : 1;
373 	unsigned has_client : 1;
374 	unsigned has_system_signed_result : 1;
375 	unsigned is_platform_binary : 1;
376 	unsigned used_responsible_pid : 1;
377 	unsigned is_loopback : 1;
378 	unsigned real_is_platform_binary : 1;
379 	unsigned is_delegated : 1;
380 	unsigned is_local : 1;
381 	unsigned __pad_bits : 7;
382 };
383 
384 static  LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
385 static  LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
386 static  LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
387     &necp_kernel_policy_mtx_attr);
388 
389 static  LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
390 static  LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
391 
392 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
393 
394 /*
395  * On modification, invalidate cached lookups by bumping the generation count.
396  * Other calls will need to take the slowpath of taking
397  * the subsystem lock.
398  */
399 static volatile int32_t necp_kernel_socket_policies_gencount;
400 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do {                                                     \
401 	if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) {      \
402 	        necp_kernel_socket_policies_gencount = 1;                                                                               \
403 	}                                                                                                                                                               \
404 } while (0)
405 
406 /*
407  * Drop-all Bypass:
408  * Allow priviledged processes to bypass the default drop-all
409  * via entitlement check.  For OSX, since entitlement check is
410  * not supported for configd, configd signing identity is checked
411  * instead.
412  */
413 #define SIGNING_ID_CONFIGD "com.apple.configd"
414 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
415 
416 typedef enum {
417 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
418 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
419 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
420 } necp_drop_all_bypass_check_result_t;
421 
422 static u_int64_t necp_kernel_application_policies_condition_mask;
423 static size_t necp_kernel_application_policies_count;
424 static u_int64_t necp_kernel_socket_policies_condition_mask;
425 static size_t necp_kernel_socket_policies_count;
426 static size_t necp_kernel_socket_policies_non_app_count;
427 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
428 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
429 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
430 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
431 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
432 static size_t necp_kernel_socket_policies_app_layer_map_count;
433 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
434 /*
435  * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
436  * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
437  * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
438  *
439  * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
440  */
441 
442 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
443 static size_t necp_kernel_ip_output_policies_count;
444 static size_t necp_kernel_ip_output_policies_non_id_count;
445 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
446 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
447 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
448 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
449 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
450 static struct necp_kernel_socket_policy pass_policy =
451 {
452 	.id = NECP_KERNEL_POLICY_ID_NO_MATCH,
453 	.result = NECP_KERNEL_POLICY_RESULT_PASS,
454 };
455 
456 static struct necp_session *necp_create_session(void);
457 static void necp_delete_session(struct necp_session *session);
458 
459 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
460     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
461 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
462 
463 #define MAX_RESULT_STRING_LEN 64
464 static inline const char * __sized_by(MAX_RESULT_STRING_LEN) necp_get_result_description(char * __sized_by(MAX_RESULT_STRING_LEN) result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
465 
466 static struct necp_session_policy *necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *__sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t * __sized_by(result_size)result, u_int32_t result_size);
467 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
468 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
469 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
470 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
471 static void necp_policy_apply_all(struct necp_session *session);
472 
473 static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union * __single 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 __null_terminated, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
474 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
475 static bool necp_kernel_socket_policies_reprocess(void);
476 static bool necp_kernel_socket_policies_update_uuid_table(void);
477 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
478     struct necp_socket_info *info,
479     necp_kernel_policy_filter *return_filter,
480     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
481     size_t *return_route_rule_id_array_count,
482     size_t route_rule_id_array_count,
483     necp_kernel_policy_result *return_service_action,
484     necp_kernel_policy_service *return_service,
485     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
486     size_t netagent_array_count,
487     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
488     size_t netagent_use_flags_array_count,
489     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
490     u_int32_t num_required_agent_types,
491     proc_t proc,
492     u_int16_t pf_tag,
493     necp_kernel_policy_id *skip_policy_id,
494     struct rtentry *rt,
495     necp_kernel_policy_result *return_drop_dest_policy_result,
496     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
497     u_int32_t *return_flow_divert_aggregate_unit,
498     struct socket *so,
499     int debug);
500 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_int64_t condition_mask, u_int64_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, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
501 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
502 static bool necp_kernel_ip_output_policies_reprocess(void);
503 
504 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
505 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);
506 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
507 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
508 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
509 static bool necp_addr_is_empty(struct sockaddr *addr);
510 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);
511 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
512 
513 struct necp_uuid_id_mapping {
514 	LIST_ENTRY(necp_uuid_id_mapping) chain;
515 	uuid_t          uuid;
516 	u_int32_t       id;
517 	os_refcnt_t     refcount;
518 	u_int32_t       table_usecount; // Add to UUID policy table count
519 };
520 static size_t necp_num_uuid_app_id_mappings;
521 static bool necp_uuid_app_id_mappings_dirty;
522 #define NECP_UUID_APP_ID_HASH_SIZE 64
523 static u_long necp_uuid_app_id_hash_mask;
524 static u_long necp_uuid_app_id_hash_num_buckets;
525 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * __counted_by(necp_uuid_app_id_hash_num_buckets) necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
526 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
527 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
528 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
529 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
530 
531 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
532 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
533 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
534 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
535 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
536 
537 struct necp_string_id_mapping {
538 	LIST_ENTRY(necp_string_id_mapping) chain;
539 	char            *string __null_terminated;
540 	necp_app_id     id;
541 	os_refcnt_t     refcount;
542 };
543 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
544 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
545 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
546 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
547 
548 static u_int32_t necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter);
549 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
550 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
551 
552 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
553     struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
554 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
555 static void necp_free_domain_trie(struct necp_domain_trie *trie);
556 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
557 static Boolean necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length);
558 
559 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
560 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
561 
562 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
563 
564 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
565 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
566 
567 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
568 static bool necp_update_qos_marking(struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
569 
570 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
571 
572 #define MAX_ROUTE_RULE_INTERFACES 10
573 struct necp_route_rule {
574 	LIST_ENTRY(necp_route_rule) chain;
575 	u_int32_t       id;
576 	u_int32_t       netagent_id;
577 	u_int32_t       control_unit;
578 	u_int32_t       match_netagent_id;
579 	u_int32_t       effective_type;
580 	u_int8_t        default_action;
581 	u_int8_t        cellular_action;
582 	u_int8_t        wifi_action;
583 	u_int8_t        wired_action;
584 	u_int8_t        expensive_action;
585 	u_int8_t        constrained_action;
586 	u_int8_t        companion_action;
587 	u_int8_t        vpn_action;
588 	u_int           exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
589 	u_int8_t        exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
590 	os_refcnt_t     refcount;
591 };
592 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
593 static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, bool *has_socket_only_actions);
594 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
595 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
596 static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
597     u_int32_t route_rule_id, u_int32_t *interface_type_denied);
598 static uint32_t necp_route_get_netagent(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove);
599 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
600 static uint32_t necp_route_get_flow_divert(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, u_int32_t *flow_divert_aggregate_unit);
601 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
602 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
603 
604 #define MAX_AGGREGATE_ROUTE_RULES 16
605 struct necp_aggregate_route_rule {
606 	LIST_ENTRY(necp_aggregate_route_rule) chain;
607 	u_int32_t       id;
608 	u_int32_t       rule_ids[MAX_AGGREGATE_ROUTE_RULES];
609 };
610 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
611 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
612 
613 // Sysctl definitions
614 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
615 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
616 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
617 
618 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
619 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
620 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
621 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
624 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
625 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", "");
626 SYSCTL_PROC(_net_necp, NECPCTL_DROP_MANAGEMENT_LEVEL, drop_management_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_management_level, 0, &sysctl_handle_necp_management_level, "IU", "");
627 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", "");
628 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
629 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, "");
630 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
631 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
632 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
633 
634 static struct necp_drop_dest_policy necp_drop_dest_policy;
635 static int necp_drop_dest_debug = 0;    // 0: off, 1: match, >1: every evaluation
636 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
637 
638 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
639 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
640     0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
641 
642 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
643 
644 /*
645  * data tracing control -
646  *
647  * necp_data_tracing_level    : 1 for brief trace, 2 for policy details, 3 for condition details
648  * necp_data_tracing_port     : match traffic with specified port
649  * necp_data_tracing_proto    : match traffic with specified protocol
650  * necp_data_tracing_pid      : match traffic with specified pid (only applied at socket level)
651  * necp_data_tracing_ifindex  : match traffic on specified ifindex
652  * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched.  Default is 0 to trace traffic if any specified attributes matched.
653  * data_tracing_session_order     : match policies in the specified session - log traffic that hit these policies
654  * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
655  */
656 static int necp_data_tracing_level = 0;
657 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
658 
659 static int necp_data_tracing_port = 0;
660 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
661 
662 static int necp_data_tracing_proto = 0;
663 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
664 
665 static int necp_data_tracing_pid = 0;
666 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
667 
668 static int necp_data_tracing_ifindex = 0;
669 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
670 
671 static int necp_data_tracing_match_all = 0;
672 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
673 
674 static int necp_data_tracing_session_order = 0;
675 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
676 
677 static int necp_data_tracing_policy_order = 0;
678 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
679 
680 #define NECP_DATA_TRACE_LEVEL_BRIEF     1
681 #define NECP_DATA_TRACE_LEVEL_POLICY    2
682 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
683 #define NECP_DATA_TRACE_LEVEL_DP        4
684 
685 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
686     (pid == necp_data_tracing_pid)
687 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
688     (protocol == necp_data_tracing_proto)
689 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
690     (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
691 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
692     (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
693 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
694 	(ifindex == necp_data_tracing_ifindex)
695 
696 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
697     ((necp_data_tracing_level && \
698 	((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
699 	(necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
700 	(necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
701 	(necp_data_tracing_port && (NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) || NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr))))) ? necp_data_tracing_level : 0)
702 
703 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
704     ((necp_data_tracing_level && \
705 	((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
706 	(!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
707 	(!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
708 	(!necp_data_tracing_port || (NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) || NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr))))) ? necp_data_tracing_level : 0)
709 
710 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
711     (necp_data_tracing_match_all ? \
712 	NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
713 	NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
714 
715 #define NECP_DATA_TRACE_ON(debug) (debug)
716 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
717 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
718 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
719 
720 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
721 
722 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
723     if (NECP_DATA_TRACE_ON(debug)) { \
724     char laddr_str[MAX_IPv6_STR_LEN]; \
725     char raddr_str[MAX_IPv6_STR_LEN]; \
726     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d>", \
727 	caller, log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id); \
728     }
729 
730 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
731     if (NECP_DATA_TRACE_ON(debug)) { \
732     char laddr_str[MAX_IPv6_STR_LEN]; \
733     char raddr_str[MAX_IPv6_STR_LEN]; \
734     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d result %d>", \
735 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id, inp ? inp->inp_policyresult.results.result : 0); \
736     }
737 
738 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
739     if (NECP_DATA_TRACE_ON(debug)) { \
740     char laddr_str[MAX_IPv6_STR_LEN]; \
741     char raddr_str[MAX_IPv6_STR_LEN]; \
742     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d result %d> <input ifindex %d> <allowed_to_receive %d><pf_tag %X pass_flags %X>", \
743 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id, inp ? inp->inp_policyresult.results.result : 0, verifyifindex, allowed_to_receive, pf_tag, pass_flags); \
744     }
745 
746 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
747     if (NECP_DATA_TRACE_ON(debug)) { \
748     char laddr_str[MAX_IPv6_STR_LEN]; \
749     char raddr_str[MAX_IPv6_STR_LEN]; \
750     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
751 	caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, info->local_addr.sin.sin_family, info->protocol, ntohs(info->local_addr.sin.sin_port), ntohs(info->local_addr.sin6.sin6_port), ntohs(info->remote_addr.sin.sin_port), ntohs(info->remote_addr.sin6.sin6_port), necp_get_address_string(&info->local_addr, laddr_str), necp_get_address_string(&info->remote_addr, raddr_str), necp_drop_all_order, info->pid, info->application_id, info->real_application_id, info->bound_interface_index, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result]); \
752     }
753 
754 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
755     if (NECP_DATA_TRACE_ON(debug)) { \
756     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
757 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
758     }
759 
760 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
761     if (NECP_DATA_TRACE_ON(debug)) { \
762     char laddr_str[MAX_IPv6_STR_LEN]; \
763     char raddr_str[MAX_IPv6_STR_LEN]; \
764     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d>", \
765 	        caller, log_msg, local_addr.sin.sin_family, protocol, ntohs(local_addr.sin.sin_port), ntohs(local_addr.sin6.sin6_port), ntohs(remote_addr.sin.sin_port), ntohs(remote_addr.sin6.sin6_port), necp_get_address_string(&local_addr, laddr_str), necp_get_address_string(&remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id, (unsigned int)packet, ip->ip_len, ntohs(ip->ip_len)); \
766     }
767 
768 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
769     if (NECP_DATA_TRACE_ON(debug)) { \
770     char laddr_str[MAX_IPv6_STR_LEN]; \
771     char raddr_str[MAX_IPv6_STR_LEN]; \
772     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d %d>", \
773 caller, log_msg, local_addr.sin.sin_family, protocol, ntohs(local_addr.sin.sin_port), ntohs(local_addr.sin6.sin6_port), ntohs(remote_addr.sin.sin_port), ntohs(remote_addr.sin6.sin6_port), necp_get_address_string(&local_addr, laddr_str), necp_get_address_string(&remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id, (unsigned int)packet, ip6->ip6_plen, ntohs(ip6->ip6_plen), packet ? packet->m_pkthdr.len : 0); \
774     }
775 
776 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
777     if (NECP_DATA_TRACE_ON(debug)) { \
778     char laddr_str[MAX_IPv6_STR_LEN]; \
779     char raddr_str[MAX_IPv6_STR_LEN]; \
780     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
781 	    caller, log_msg, local_addr->sin.sin_family, protocol, ntohs(local_addr->sin.sin_port), ntohs(local_addr->sin6.sin6_port), ntohs(remote_addr->sin.sin_port), ntohs(remote_addr->sin6.sin6_port), necp_get_address_string(local_addr, laddr_str), necp_get_address_string(remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result]); \
782     }
783 
784 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
785     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
786     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - policy id=%d session_order=%d policy_order=%d result=%s (cond_policy_id %d) (skip_session_order %d skip_order %d)", \
787 	    caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result], policy_search_array[i]->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID ? policy_search_array[i]->cond_policy_id : 0, skip_session_order, skip_order); \
788     }
789 
790 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
791     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
792     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - policy id=%d session_order=%d policy_order=%d result=%s (cond_policy_id %d) (skip_session_order %d skip_order %d)", \
793 	        caller, log_msg, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result], policy_search_array[i]->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID ? policy_search_array[i]->cond_policy_id : 0, skip_session_order, skip_order); \
794     }
795 
796 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
797     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
798     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value (%d / 0x%X) (%d / 0x%X) (%d / 0x%X) input (%d / 0x%X) (%d / 0x%X) (%d / 0x%X)>", \
799 	        caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
800     }
801 
802 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
803     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
804     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
805 	    caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
806 	    input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
807     }
808 
809 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
810     NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
811 
812 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
813     NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
814 
815 
816 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
817     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
818     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value (%d / 0x%X) (%d / 0x%X) (%d / 0x%X) input (%d / 0x%X) (%d / 0x%X) (%d / 0x%X)>", \
819 	    caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
820     }
821 
822 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
823     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
824     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
825 	caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
826 	input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
827     }
828 
829 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
830     NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
831 
832 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
833     NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
834 
835 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
836     (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
837      addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
838 
839 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
840 	"INVALID",
841 	"PASS",
842 	"SKIP",
843 	"DROP",
844 	"SOCKET_DIVERT",
845 	"SOCKET_FILTER",
846 	"IP_TUNNEL",
847 	"IP_FILTER",
848 	"TRIGGER",
849 	"TRIGGER_IF_NEEDED",
850 	"TRIGGER_SCOPED",
851 	"NO_TRIGGER_SCOPED",
852 	"SOCKET_SCOPED",
853 	"ROUTE_RULES",
854 	"USE_NETAGENT",
855 	"NETAGENT_SCOPED",
856 	"SCOPED_DIRECT",
857 	"ALLOW_UNENTITLED",
858 	"REMOVE_NETAGENT"
859 };
860 
861 
862 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
863 
864 static int necp_drop_loopback_count = 0;
865 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
866 
867 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)868 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
869 {
870 	bool is_interface_address = false;
871 	if (addr == NULL) {
872 		return false;
873 	}
874 
875 	// Clean up the address before comparison with interface addresses
876 	// Transform remote_addr into the ifaddr form
877 	// IPv6 Scope IDs are always embedded in the ifaddr list
878 	struct sockaddr_storage remote_address_sanitized;
879 	u_int ifscope = IFSCOPE_NONE;
880 	(void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
881 	SIN(&remote_address_sanitized)->sin_port = 0;
882 	if (remote_address_sanitized.ss_family == AF_INET6) {
883 		if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
884 			SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
885 		}
886 	}
887 
888 	// Check if remote address is an interface address
889 	struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
890 	if (ifa != NULL && ifa->ifa_ifp != NULL) {
891 		is_interface_address = true;
892 	}
893 	if (ifa != NULL) {
894 		ifaddr_release(ifa);
895 		ifa = NULL;
896 	}
897 
898 	return is_interface_address;
899 }
900 
901 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
902     ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && (include_local_addresses || !((rt)->rt_flags & RTF_LOCAL)) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT) && !((rt)->rt_ifa->ifa_ifp->if_eflags & IFEF_DIRECTLINK)) && (include_local_addresses || addr == NULL || !necp_address_is_local_interface_address(addr)))
903 
904 // Session order allocation
905 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)906 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
907 {
908 	u_int32_t new_order = 0;
909 
910 	// For now, just allocate 1000 orders for each priority
911 	if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
912 		priority = NECP_SESSION_PRIORITY_DEFAULT;
913 	}
914 
915 	// Use the control unit to decide the offset into the priority list
916 	new_order = (control_unit) + ((priority - 1) * 1000);
917 
918 	return new_order;
919 }
920 
921 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)922 necp_get_first_order_for_priority(u_int32_t priority)
923 {
924 	if (priority == 0) {
925 		return 0;
926 	}
927 	return ((priority - 1) * 1000) + 1;
928 }
929 
930 // Sysctl handler
931 static int
932 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
933 {
934 #pragma unused(arg1, arg2)
935 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
936 	necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
937 	return error;
938 }
939 
940 static int
941 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
942 {
943 #pragma unused(arg1, arg2)
944 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
945 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
946 	return error;
947 }
948 
949 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
950 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)951 _necp_process_drop_order_inner(kauth_cred_t cred)
952 {
953 	if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
954 	    priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
955 		return necp_drop_unentitled_order;
956 	} else {
957 		return 0;
958 	}
959 }
960 
961 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
962 #pragma GCC poison _necp_process_drop_order_inner
963 
964 static int
965 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
966 {
967 #pragma unused(arg1, arg2)
968 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
969 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
970 	return error;
971 }
972 
973 static inline bool
necp_socket_is_connected(struct inpcb * inp)974 necp_socket_is_connected(struct inpcb *inp)
975 {
976 	return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
977 }
978 
979 
980 // Session fd
981 
982 static int necp_session_op_close(struct fileglob *, vfs_context_t);
983 
984 static const struct fileops necp_session_fd_ops = {
985 	.fo_type     = DTYPE_NETPOLICY,
986 	.fo_read     = fo_no_read,
987 	.fo_write    = fo_no_write,
988 	.fo_ioctl    = fo_no_ioctl,
989 	.fo_select   = fo_no_select,
990 	.fo_close    = necp_session_op_close,
991 	.fo_drain    = fo_no_drain,
992 	.fo_kqfilter = fo_no_kqfilter,
993 };
994 
995 static inline int
necp_is_platform_binary(proc_t proc)996 necp_is_platform_binary(proc_t proc)
997 {
998 	return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
999 }
1000 
1001 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1002 necp_check_drop_all_bypass_result(proc_t proc)
1003 {
1004 	if (proc == NULL) {
1005 		proc = current_proc();
1006 		if (proc == NULL) {
1007 			return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1008 		}
1009 	}
1010 
1011 #if defined(XNU_TARGET_OS_OSX)
1012 	const char *signing_id __null_terminated = NULL;
1013 	const bool isConfigd = (necp_is_platform_binary(proc) &&
1014 	    (signing_id = cs_identity_get(proc)) &&
1015 	    (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1016 	    (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1017 	if (isConfigd) {
1018 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1019 	}
1020 #endif
1021 
1022 	const task_t __single task = proc_task(proc);
1023 	if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1024 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1025 	} else {
1026 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1027 	}
1028 }
1029 
1030 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1031 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1032 {
1033 #pragma unused(uap)
1034 	int error = 0;
1035 	struct necp_session *session = NULL;
1036 	struct fileproc * __single fp = NULL;
1037 	int fd = -1;
1038 	uid_t uid = kauth_cred_getuid(kauth_cred_get());
1039 
1040 	if (!necp_is_platform_binary(p)) {
1041 		NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1042 		error = EACCES;
1043 		goto done;
1044 	}
1045 
1046 	if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1047 		NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1048 		error = EACCES;
1049 		goto done;
1050 	}
1051 
1052 	error = falloc(p, &fp, &fd);
1053 	if (error != 0) {
1054 		goto done;
1055 	}
1056 
1057 	session = necp_create_session();
1058 	if (session == NULL) {
1059 		error = ENOMEM;
1060 		goto done;
1061 	}
1062 
1063 	fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1064 	fp->fp_glob->fg_flag = 0;
1065 	fp->fp_glob->fg_ops = &necp_session_fd_ops;
1066 	fp_set_data(fp, session);
1067 
1068 	proc_fdlock(p);
1069 	procfdtbl_releasefd(p, fd, NULL);
1070 	fp_drop(p, fd, fp, 1);
1071 	proc_fdunlock(p);
1072 
1073 	*retval = fd;
1074 done:
1075 	if (error != 0) {
1076 		if (fp != NULL) {
1077 			fp_free(p, fd, fp);
1078 			fp = NULL;
1079 		}
1080 	}
1081 
1082 	return error;
1083 }
1084 
1085 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1086 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1087 {
1088 #pragma unused(ctx)
1089 	struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1090 	fg_set_data(fg, NULL);
1091 
1092 	if (session != NULL) {
1093 		necp_policy_mark_all_for_deletion(session);
1094 		necp_policy_apply_all(session);
1095 		necp_delete_session(session);
1096 		return 0;
1097 	} else {
1098 		return ENOENT;
1099 	}
1100 }
1101 
1102 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1103 necp_session_find_from_fd(struct proc *p, int fd,
1104     struct fileproc **fpp, struct necp_session **session)
1105 {
1106 	struct fileproc * __single fp = NULL;
1107 	int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1108 
1109 	if (error == 0) {
1110 		*fpp = fp;
1111 		*session = (struct necp_session *)fp_get_data(fp);
1112 		if ((*session)->necp_fd_type != necp_fd_type_session) {
1113 			// Not a client fd, ignore
1114 			fp_drop(p, fd, fp, 0);
1115 			error = EINVAL;
1116 		}
1117 	}
1118 
1119 	return error;
1120 }
1121 
1122 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1123 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1124 {
1125 	int error = 0;
1126 	u_int8_t * __indexable tlv_buffer = NULL;
1127 
1128 	if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1129 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1130 		error = EINVAL;
1131 		goto done;
1132 	}
1133 
1134 	if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1135 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1136 		error = EINVAL;
1137 		goto done;
1138 	}
1139 
1140 	if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1141 		error = ENOMEM;
1142 		goto done;
1143 	}
1144 
1145 	error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1146 	if (error != 0) {
1147 		NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1148 		goto done;
1149 	}
1150 
1151 	necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1152 	if (error != 0) {
1153 		NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1154 		goto done;
1155 	}
1156 
1157 	error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1158 	if (error != 0) {
1159 		NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1160 		goto done;
1161 	}
1162 
1163 done:
1164 	if (tlv_buffer != NULL) {
1165 		kfree_data(tlv_buffer, uap->in_buffer_length);
1166 		tlv_buffer = NULL;
1167 	}
1168 	*retval = error;
1169 
1170 	return error;
1171 }
1172 
1173 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1174 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1175 {
1176 	int error = 0;
1177 	u_int8_t * __indexable response = NULL;
1178 
1179 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1180 		NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1181 		error = EINVAL;
1182 		goto done;
1183 	}
1184 
1185 	necp_policy_id policy_id = 0;
1186 	error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1187 	if (error != 0) {
1188 		NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1189 		goto done;
1190 	}
1191 
1192 	struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1193 	if (policy == NULL || policy->pending_deletion) {
1194 		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1195 		error = ENOENT;
1196 		goto done;
1197 	}
1198 
1199 	u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1200 	u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1201 	u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1202 
1203 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1204 		NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1205 		error = EINVAL;
1206 		goto done;
1207 	}
1208 
1209 	if (response_size > NECP_MAX_POLICY_SIZE) {
1210 		NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1211 		error = EINVAL;
1212 		goto done;
1213 	}
1214 
1215 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1216 	if (response == NULL) {
1217 		error = ENOMEM;
1218 		goto done;
1219 	}
1220 
1221 	u_int8_t *cursor = response;
1222 	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1223 	if (result_tlv_size) {
1224 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1225 	}
1226 	if (policy->conditions_size) {
1227 		memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1228 	}
1229 
1230 	error = copyout(response, uap->out_buffer, response_size);
1231 	if (error != 0) {
1232 		NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1233 		goto done;
1234 	}
1235 
1236 done:
1237 	if (response != NULL) {
1238 		kfree_data(response, response_size);
1239 		response = NULL;
1240 	}
1241 	*retval = error;
1242 
1243 	return error;
1244 }
1245 
1246 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1247 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1248 {
1249 	int error = 0;
1250 
1251 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1252 		NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1253 		error = EINVAL;
1254 		goto done;
1255 	}
1256 
1257 	necp_policy_id delete_policy_id = 0;
1258 	error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1259 	if (error != 0) {
1260 		NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1261 		goto done;
1262 	}
1263 
1264 	struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1265 	if (policy == NULL || policy->pending_deletion) {
1266 		NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1267 		error = ENOENT;
1268 		goto done;
1269 	}
1270 
1271 	necp_policy_mark_for_deletion(session, policy);
1272 done:
1273 	*retval = error;
1274 	return error;
1275 }
1276 
1277 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1278 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1279 {
1280 #pragma unused(uap)
1281 	necp_policy_apply_all(session);
1282 	*retval = 0;
1283 	return 0;
1284 }
1285 
1286 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1287 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1288 {
1289 	u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1290 	u_int32_t response_size = 0;
1291 	u_int8_t * __indexable response = NULL;
1292 	int num_policies = 0;
1293 	int cur_policy_index = 0;
1294 	int error = 0;
1295 	struct necp_session_policy *policy;
1296 
1297 	LIST_FOREACH(policy, &session->policies, chain) {
1298 		if (!policy->pending_deletion) {
1299 			num_policies++;
1300 		}
1301 	}
1302 
1303 	if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1304 		NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1305 		error = EINVAL;
1306 		goto done;
1307 	}
1308 
1309 	response_size = num_policies * tlv_size;
1310 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1311 		NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1312 		error = EINVAL;
1313 		goto done;
1314 	}
1315 
1316 	// Create a response with one Policy ID TLV for each policy
1317 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1318 	if (response == NULL) {
1319 		error = ENOMEM;
1320 		goto done;
1321 	}
1322 
1323 	u_int8_t *cursor = response;
1324 	LIST_FOREACH(policy, &session->policies, chain) {
1325 		if (!policy->pending_deletion && cur_policy_index < num_policies) {
1326 			cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1327 			cur_policy_index++;
1328 		}
1329 	}
1330 
1331 	error = copyout(response, uap->out_buffer, response_size);
1332 	if (error != 0) {
1333 		NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1334 		goto done;
1335 	}
1336 
1337 done:
1338 	if (response != NULL) {
1339 		kfree_data(response, response_size);
1340 		response = NULL;
1341 	}
1342 	*retval = error;
1343 
1344 	return error;
1345 }
1346 
1347 
1348 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1349 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1350 {
1351 #pragma unused(uap)
1352 	necp_policy_mark_all_for_deletion(session);
1353 	*retval = 0;
1354 	return 0;
1355 }
1356 
1357 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1358 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1359 {
1360 	int error = 0;
1361 	struct necp_session_policy *policy = NULL;
1362 	struct necp_session_policy *temp_policy = NULL;
1363 
1364 	if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1365 		NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1366 		error = EINVAL;
1367 		goto done;
1368 	}
1369 
1370 	necp_session_priority requested_session_priority = 0;
1371 	error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1372 	if (error != 0) {
1373 		NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1374 		goto done;
1375 	}
1376 
1377 	// Enforce special session priorities with entitlements
1378 	if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1379 	    requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1380 	    requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1381 	    requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1382 		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1383 		if (cred_result != 0) {
1384 			NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1385 			error = EPERM;
1386 			goto done;
1387 		}
1388 	}
1389 
1390 	if (session->session_priority != requested_session_priority) {
1391 		session->session_priority = requested_session_priority;
1392 		session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1393 		session->dirty = TRUE;
1394 
1395 		// Mark all policies as needing updates
1396 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1397 			policy->pending_update = TRUE;
1398 		}
1399 	}
1400 
1401 done:
1402 	*retval = error;
1403 	return error;
1404 }
1405 
1406 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1407 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1408 {
1409 #pragma unused(uap)
1410 	session->proc_locked = TRUE;
1411 	*retval = 0;
1412 	return 0;
1413 }
1414 
1415 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1416 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1417 {
1418 	int error = 0;
1419 	struct necp_service_registration *new_service = NULL;
1420 
1421 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1422 		NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1423 		error = EINVAL;
1424 		goto done;
1425 	}
1426 
1427 	uuid_t service_uuid;
1428 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1429 	if (error != 0) {
1430 		NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1431 		goto done;
1432 	}
1433 
1434 	new_service = kalloc_type(struct necp_service_registration,
1435 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
1436 
1437 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1438 	new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1439 	LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1440 	LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1441 	lck_rw_done(&necp_kernel_policy_lock);
1442 
1443 done:
1444 	*retval = error;
1445 	return error;
1446 }
1447 
1448 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1449 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1450 {
1451 	int error = 0;
1452 	struct necp_service_registration * __single service = NULL;
1453 	struct necp_service_registration *temp_service = NULL;
1454 	struct necp_uuid_id_mapping *mapping = NULL;
1455 
1456 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1457 		NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1458 		error = EINVAL;
1459 		goto done;
1460 	}
1461 
1462 	uuid_t service_uuid;
1463 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1464 	if (error != 0) {
1465 		NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1466 		goto done;
1467 	}
1468 
1469 	// Remove all matching services for this session
1470 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1471 	mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1472 	if (mapping != NULL) {
1473 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1474 			if (service->service_id == mapping->id) {
1475 				LIST_REMOVE(service, session_chain);
1476 				LIST_REMOVE(service, kernel_chain);
1477 				kfree_type(struct necp_service_registration, service);
1478 			}
1479 		}
1480 		necp_remove_uuid_service_id_mapping(service_uuid);
1481 	}
1482 	lck_rw_done(&necp_kernel_policy_lock);
1483 
1484 done:
1485 	*retval = error;
1486 	return error;
1487 }
1488 
1489 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1490 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1491 {
1492 #pragma unused(session)
1493 	int error = 0;
1494 
1495 	if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1496 		NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1497 		error = EINVAL;
1498 		goto done;
1499 	}
1500 
1501 	error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1502 done:
1503 	*retval = error;
1504 	return error;
1505 }
1506 
1507 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1508 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1509 {
1510 	int error = 0;
1511 	struct net_bloom_filter *bloom_filter = NULL;
1512 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1513 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1514 
1515 	if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1516 	    in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1517 	    uap->in_buffer == 0) {
1518 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1519 		error = EINVAL;
1520 		goto done;
1521 	}
1522 
1523 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1524 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1525 		error = EINVAL;
1526 		goto done;
1527 	}
1528 
1529 	bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1530 	if (bloom_filter == NULL) {
1531 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1532 		error = ENOMEM;
1533 		goto done;
1534 	}
1535 
1536 	error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1537 	if (error != 0) {
1538 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1539 		goto done;
1540 	}
1541 
1542 	size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1543 	if (expected_filter_size != in_buffer_length) {
1544 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1545 		error = EINVAL;
1546 		goto done;
1547 	}
1548 
1549 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1550 	u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1551 	lck_rw_done(&necp_kernel_policy_lock);
1552 
1553 	if (filter_id == 0) {
1554 		error = ENOMEM;
1555 	} else {
1556 		// Bloom filter is taken over by the new filter entry, clear the local pointer
1557 		bloom_filter = NULL;
1558 
1559 		error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1560 		if (error != 0) {
1561 			NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1562 			goto done;
1563 		}
1564 	}
1565 
1566 done:
1567 	*retval = error;
1568 	if (error != 0 && bloom_filter != NULL) {
1569 		uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1570 		kfree_data(filter_buffer, in_buffer_length);
1571 		bloom_filter = NULL;
1572 	}
1573 	return error;
1574 }
1575 
1576 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1577 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1578 {
1579 	int error = 0;
1580 
1581 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1582 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1583 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1584 		error = EINVAL;
1585 		goto done;
1586 	}
1587 
1588 	u_int32_t filter_id;
1589 	error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1590 	if (error != 0) {
1591 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1592 		goto done;
1593 	}
1594 
1595 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1596 	bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1597 	if (!removed) {
1598 		error = ENOENT;
1599 	}
1600 	lck_rw_done(&necp_kernel_policy_lock);
1601 
1602 done:
1603 	*retval = error;
1604 	return error;
1605 }
1606 
1607 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1608 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1609 {
1610 #pragma unused(uap)
1611 
1612 	struct necp_domain_filter * __single filter = NULL;
1613 	struct necp_domain_filter *temp_filter = NULL;
1614 	LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1615 		if (os_ref_release_locked(&filter->refcount) == 0) {
1616 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1617 			LIST_REMOVE(filter, chain);
1618 			lck_rw_done(&necp_kernel_policy_lock);
1619 			LIST_REMOVE(filter, owner_chain);
1620 			net_bloom_filter_destroy(filter->filter);
1621 			kfree_type(struct necp_domain_filter, filter);
1622 		}
1623 	}
1624 
1625 	*retval = 0;
1626 	return 0;
1627 }
1628 
1629 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1630 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1631 {
1632 	int error = 0;
1633 
1634 	struct necp_domain_trie_request *domain_trie_request = NULL;
1635 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1636 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1637 
1638 	if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1639 	    in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1640 	    uap->in_buffer == 0) {
1641 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1642 		error = EINVAL;
1643 		goto done;
1644 	}
1645 
1646 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1647 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1648 		error = EINVAL;
1649 		goto done;
1650 	}
1651 
1652 	domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1653 	if (domain_trie_request == NULL) {
1654 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1655 		error = ENOMEM;
1656 		goto done;
1657 	}
1658 
1659 	error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1660 	if (error != 0) {
1661 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1662 		goto done;
1663 	}
1664 
1665 	NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1666 
1667 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1668 	u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1669 	lck_rw_done(&necp_kernel_policy_lock);
1670 
1671 	if (id == 0) {
1672 		error = ENOMEM;
1673 	} else {
1674 		error = copyout(&id, uap->out_buffer, sizeof(id));
1675 		if (error != 0) {
1676 			NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1677 			goto done;
1678 		}
1679 	}
1680 
1681 done:
1682 	*retval = error;
1683 	if (error != 0 && domain_trie_request != NULL) {
1684 		uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1685 		kfree_data(domain_buffer, in_buffer_length);
1686 		domain_trie_request = NULL;
1687 	}
1688 	return error;
1689 }
1690 
1691 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1692 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1693 {
1694 	int error = 0;
1695 
1696 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1697 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1698 		NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1699 		error = EINVAL;
1700 		goto done;
1701 	}
1702 
1703 	u_int32_t id;
1704 	error = copyin(uap->in_buffer, &id, sizeof(id));
1705 	if (error != 0) {
1706 		NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1707 		goto done;
1708 	}
1709 
1710 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1711 	bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1712 	if (!removed) {
1713 		error = ENOENT;
1714 	}
1715 	lck_rw_done(&necp_kernel_policy_lock);
1716 
1717 done:
1718 	*retval = error;
1719 	return error;
1720 }
1721 
1722 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1723 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1724 {
1725 #pragma unused(uap)
1726 	struct necp_domain_trie* __single trie = NULL;
1727 	struct necp_domain_trie* __single temp_trie = NULL;
1728 	LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1729 		if (os_ref_release_locked(&trie->refcount) == 0) {
1730 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1731 			LIST_REMOVE(trie, chain);
1732 			lck_rw_done(&necp_kernel_policy_lock);
1733 			LIST_REMOVE(trie, owner_chain);
1734 			necp_free_domain_trie(trie);
1735 		}
1736 	}
1737 	*retval = 0;
1738 	return 0;
1739 }
1740 
1741 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1742 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1743 {
1744 #pragma unused(session)
1745 
1746 	int error = 0;
1747 
1748 	uint8_t request_buffer[2000] = { 0 };
1749 	uint8_t *ptr = NULL;
1750 	uint32_t count = 0;
1751 	int output_length = 0;
1752 
1753 	lck_rw_lock_shared(&necp_kernel_policy_lock);
1754 	count = necp_trie_count;
1755 	lck_rw_done(&necp_kernel_policy_lock);
1756 
1757 	if (count == 0) {
1758 		error = ENOENT;
1759 		goto done;
1760 	}
1761 
1762 	output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1763 	if (output_length > uap->out_buffer_length) {
1764 		NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1765 		error = EINVAL;
1766 		goto done;
1767 	}
1768 	if (output_length > sizeof(request_buffer)) {
1769 		NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1770 		error = EINVAL;
1771 		goto done;
1772 	}
1773 
1774 	memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1775 	ptr = request_buffer + sizeof(count);
1776 
1777 	lck_rw_lock_shared(&necp_kernel_policy_lock);
1778 	struct necp_domain_trie* __single trie = NULL;
1779 	LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1780 		if (trie->trie_request != NULL) {
1781 			memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1782 			ptr += sizeof(struct necp_domain_trie_request);
1783 		}
1784 	}
1785 	lck_rw_done(&necp_kernel_policy_lock);
1786 
1787 	error = copyout(request_buffer, uap->out_buffer, output_length);
1788 
1789 done:
1790 	*retval = error;
1791 	return error;
1792 }
1793 
1794 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1795 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1796 {
1797 	struct fileproc * __single fp;
1798 	int error = 0;
1799 	int return_value = 0;
1800 	struct necp_session * __single session = NULL;
1801 
1802 	error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1803 	if (error != 0) {
1804 		NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1805 		return error;
1806 	}
1807 
1808 	NECP_SESSION_LOCK(session);
1809 
1810 	if (session->proc_locked) {
1811 		// Verify that the calling process is allowed to do actions
1812 		uuid_t proc_uuid;
1813 		proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1814 		if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1815 			error = EPERM;
1816 			goto done;
1817 		}
1818 	} else {
1819 		// If not locked, update the proc_uuid and proc_pid of the session
1820 		proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1821 		session->proc_pid = proc_pid(current_proc());
1822 	}
1823 
1824 	u_int32_t action = uap->action;
1825 	switch (action) {
1826 	case NECP_SESSION_ACTION_POLICY_ADD: {
1827 		return_value = necp_session_add_policy(session, uap, retval);
1828 		break;
1829 	}
1830 	case NECP_SESSION_ACTION_POLICY_GET: {
1831 		return_value = necp_session_get_policy(session, uap, retval);
1832 		break;
1833 	}
1834 	case NECP_SESSION_ACTION_POLICY_DELETE:  {
1835 		return_value = necp_session_delete_policy(session, uap, retval);
1836 		break;
1837 	}
1838 	case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1839 		return_value = necp_session_apply_all(session, uap, retval);
1840 		break;
1841 	}
1842 	case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1843 		return_value = necp_session_list_all(session, uap, retval);
1844 		break;
1845 	}
1846 	case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1847 		return_value = necp_session_delete_all(session, uap, retval);
1848 		break;
1849 	}
1850 	case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1851 		return_value = necp_session_set_session_priority(session, uap, retval);
1852 		break;
1853 	}
1854 	case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1855 		return_value = necp_session_lock_to_process(session, uap, retval);
1856 		break;
1857 	}
1858 	case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1859 		return_value = necp_session_register_service(session, uap, retval);
1860 		break;
1861 	}
1862 	case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1863 		return_value = necp_session_unregister_service(session, uap, retval);
1864 		break;
1865 	}
1866 	case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1867 		return_value = necp_session_dump_all(session, uap, retval);
1868 		break;
1869 	}
1870 	case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1871 		return_value = necp_session_add_domain_filter(session, uap, retval);
1872 		break;
1873 	}
1874 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1875 		return_value = necp_session_remove_domain_filter(session, uap, retval);
1876 		break;
1877 	}
1878 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1879 		return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1880 		break;
1881 	}
1882 	case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1883 		return_value = necp_session_add_domain_trie(session, uap, retval);
1884 		break;
1885 	}
1886 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1887 		return_value = necp_session_remove_domain_trie(session, uap, retval);
1888 		break;
1889 	}
1890 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1891 		return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1892 		break;
1893 	}
1894 	case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1895 		return_value = necp_session_trie_dump_all(session, uap, retval);
1896 		break;
1897 	}
1898 	default: {
1899 		NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1900 		return_value = EINVAL;
1901 		break;
1902 	}
1903 	}
1904 
1905 done:
1906 	NECP_SESSION_UNLOCK(session);
1907 	fp_drop(p, uap->necp_fd, fp, 0);
1908 	return return_value;
1909 }
1910 
1911 struct necp_resolver_key_state {
1912 	const struct ccdigest_info *digest_info;
1913 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1914 };
1915 static struct necp_resolver_key_state s_necp_resolver_key_state;
1916 
1917 static void
necp_generate_resolver_key(void)1918 necp_generate_resolver_key(void)
1919 {
1920 	s_necp_resolver_key_state.digest_info = ccsha256_di();
1921 	cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1922 }
1923 
1924 static void
necp_sign_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,uuid_t client_id,u_int32_t sign_type,u_int8_t * data,size_t data_length)1925 necp_sign_update_context(const struct ccdigest_info *di,
1926     cchmac_ctx_t ctx,
1927     uuid_t client_id,
1928     u_int32_t sign_type,
1929     u_int8_t *data,
1930     size_t data_length)
1931 {
1932 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1933 	const char * __null_terminated context_string = "NECP Resolver Binder";
1934 	uint8_t separator = 0;
1935 	cchmac_update(di, ctx, sizeof(context), context);
1936 	cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1937 	cchmac_update(di, ctx, sizeof(separator), &separator);
1938 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1939 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1940 	cchmac_update(di, ctx, data_length, data);
1941 }
1942 
1943 int
necp_sign_resolver_answer(uuid_t client_id,u_int32_t sign_type,u_int8_t * data,size_t data_length,u_int8_t * tag,size_t * out_tag_length)1944 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1945     u_int8_t *data, size_t data_length,
1946     u_int8_t *tag, size_t *out_tag_length)
1947 {
1948 	if (s_necp_resolver_key_state.digest_info == NULL) {
1949 		return EINVAL;
1950 	}
1951 
1952 	if (data == NULL ||
1953 	    data_length == 0 ||
1954 	    tag == NULL ||
1955 	    out_tag_length == NULL) {
1956 		return EINVAL;
1957 	}
1958 
1959 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1960 	if (*out_tag_length < required_tag_length) {
1961 		return ERANGE;
1962 	}
1963 
1964 	*out_tag_length = required_tag_length;
1965 
1966 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1967 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1968 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1969 	    sizeof(s_necp_resolver_key_state.key),
1970 	    s_necp_resolver_key_state.key);
1971 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1972 	    ctx, client_id, sign_type, data, data_length);
1973 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1974 
1975 	return 0;
1976 }
1977 
1978 bool
necp_validate_resolver_answer(uuid_t client_id,u_int32_t sign_type,u_int8_t * __sized_by (data_length)data,size_t data_length,u_int8_t * __sized_by (tag_length)tag,size_t tag_length)1979 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1980     u_int8_t * __sized_by(data_length)data, size_t data_length,
1981     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1982 {
1983 	if (s_necp_resolver_key_state.digest_info == NULL) {
1984 		return false;
1985 	}
1986 
1987 	if (data == NULL ||
1988 	    data_length == 0 ||
1989 	    tag == NULL ||
1990 	    tag_length == 0) {
1991 		return false;
1992 	}
1993 
1994 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1995 	if (tag_length != required_tag_length) {
1996 		return false;
1997 	}
1998 
1999 	uint8_t actual_tag[required_tag_length];
2000 
2001 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
2002 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
2003 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
2004 	    sizeof(s_necp_resolver_key_state.key),
2005 	    s_necp_resolver_key_state.key);
2006 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
2007 	    ctx, client_id, sign_type, data, data_length);
2008 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
2009 
2010 	return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
2011 }
2012 
2013 struct necp_application_id_key_state {
2014 	const struct ccdigest_info *digest_info;
2015 	uint8_t key[CCSHA256_OUTPUT_SIZE];
2016 };
2017 static struct necp_application_id_key_state s_necp_application_id_key_state;
2018 
2019 static void
necp_generate_application_id_key(void)2020 necp_generate_application_id_key(void)
2021 {
2022 	s_necp_application_id_key_state.digest_info = ccsha256_di();
2023 	cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
2024 }
2025 
2026 static void
necp_sign_application_id_update_context(const struct ccdigest_info * di,cchmac_ctx_t ctx,uuid_t client_id,u_int32_t sign_type)2027 necp_sign_application_id_update_context(const struct ccdigest_info *di,
2028     cchmac_ctx_t ctx,
2029     uuid_t client_id,
2030     u_int32_t sign_type)
2031 {
2032 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
2033 	const char context_string[] = "NECP Application ID";
2034 	uint8_t separator = 0;
2035 	cchmac_update(di, ctx, sizeof(context), context);
2036 	cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
2037 	cchmac_update(di, ctx, sizeof(separator), &separator);
2038 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
2039 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
2040 }
2041 
2042 int
necp_sign_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * __counted_by (* out_tag_length)tag,size_t * out_tag_length)2043 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
2044     u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
2045 {
2046 	if (s_necp_application_id_key_state.digest_info == NULL) {
2047 		return EINVAL;
2048 	}
2049 
2050 	if (tag == NULL ||
2051 	    out_tag_length == NULL) {
2052 		return EINVAL;
2053 	}
2054 
2055 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2056 	if (*out_tag_length < required_tag_length) {
2057 		return ERANGE;
2058 	}
2059 
2060 	*out_tag_length = required_tag_length;
2061 
2062 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2063 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
2064 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2065 	    sizeof(s_necp_application_id_key_state.key),
2066 	    s_necp_application_id_key_state.key);
2067 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2068 	    ctx, client_id, sign_type);
2069 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
2070 
2071 	return 0;
2072 }
2073 
2074 bool
necp_validate_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * __sized_by (tag_length)tag,size_t tag_length)2075 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2076     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2077 {
2078 	if (s_necp_application_id_key_state.digest_info == NULL) {
2079 		return false;
2080 	}
2081 
2082 	if (tag == NULL ||
2083 	    tag_length == 0) {
2084 		return false;
2085 	}
2086 
2087 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2088 	if (tag_length != required_tag_length) {
2089 		return false;
2090 	}
2091 
2092 	uint8_t actual_tag[required_tag_length];
2093 
2094 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2095 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
2096 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2097 	    sizeof(s_necp_application_id_key_state.key),
2098 	    s_necp_application_id_key_state.key);
2099 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2100 	    ctx, client_id, sign_type);
2101 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2102 
2103 	return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2104 }
2105 
2106 void
necp_init(void)2107 necp_init(void)
2108 {
2109 	necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2110 	necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2111 
2112 	necp_client_init();
2113 
2114 	TAILQ_INIT(&necp_session_list);
2115 
2116 	LIST_INIT(&necp_kernel_socket_policies);
2117 	LIST_INIT(&necp_kernel_ip_output_policies);
2118 
2119 	LIST_INIT(&necp_account_id_list);
2120 
2121 	LIST_INIT(&necp_uuid_service_id_list);
2122 
2123 	LIST_INIT(&necp_registered_service_list);
2124 
2125 	LIST_INIT(&necp_route_rules);
2126 	LIST_INIT(&necp_aggregate_route_rules);
2127 
2128 	LIST_INIT(&necp_global_domain_filter_list);
2129 	LIST_INIT(&necp_global_domain_trie_list);
2130 
2131 	necp_generate_resolver_key();
2132 	necp_generate_application_id_key();
2133 
2134 	necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2135 	    hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2136 	    NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2137 	necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2138 	necp_num_uuid_app_id_mappings = 0;
2139 	necp_uuid_app_id_mappings_dirty = FALSE;
2140 
2141 	necp_kernel_application_policies_condition_mask = 0;
2142 	necp_kernel_socket_policies_condition_mask = 0;
2143 	necp_kernel_ip_output_policies_condition_mask = 0;
2144 
2145 	necp_kernel_application_policies_count = 0;
2146 	necp_kernel_socket_policies_count = 0;
2147 	necp_kernel_socket_policies_non_app_count = 0;
2148 	necp_kernel_ip_output_policies_count = 0;
2149 	necp_kernel_ip_output_policies_non_id_count = 0;
2150 
2151 	necp_kernel_socket_policies_gencount = 1;
2152 
2153 	memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2154 	memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2155 	necp_kernel_socket_policies_app_layer_map = NULL;
2156 
2157 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2158 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2159 }
2160 
2161 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2162 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2163 {
2164 	struct kev_msg ev_msg;
2165 	memset(&ev_msg, 0, sizeof(ev_msg));
2166 
2167 	ev_msg.vendor_code      = KEV_VENDOR_APPLE;
2168 	ev_msg.kev_class        = KEV_NETWORK_CLASS;
2169 	ev_msg.kev_subclass     = KEV_NECP_SUBCLASS;
2170 	ev_msg.event_code       = KEV_NECP_POLICIES_CHANGED;
2171 
2172 	ev_msg.dv[0].data_ptr    = necp_event_data;
2173 	ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2174 	ev_msg.dv[1].data_length = 0;
2175 
2176 	kev_post_msg(&ev_msg);
2177 }
2178 
2179 static inline bool
necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor,u_int8_t type,u_int32_t length,u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length)2180 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2181     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2182 {
2183 	if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2184 		NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2185 		return false;
2186 	}
2187 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2188 	if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2189 	    (uintptr_t)(next_tlv - buffer) > buffer_length) {     // make sure the next TLV has enough room in buffer
2190 		NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2191 		    length, buffer_length);
2192 		return false;
2193 	}
2194 	return true;
2195 }
2196 
2197 u_int8_t * __counted_by(0)
2198 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2199     u_int32_t length, const void * __sized_by(length)value, bool *updated,
2200     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2201 {
2202 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2203 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2204 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2205 		// If we can't fit this TLV, return the current cursor
2206 		return cursor;
2207 	}
2208 	u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2209 	if (*updated || *(u_int8_t *)(cursor) != type) {
2210 		*(u_int8_t *)(cursor) = type;
2211 		*updated = TRUE;
2212 	}
2213 	if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2214 		*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2215 		*updated = TRUE;
2216 	}
2217 	if (length > 0) {
2218 		if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2219 			memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2220 			*updated = TRUE;
2221 		}
2222 	}
2223 	return next_tlv;
2224 }
2225 
2226 u_int8_t * __counted_by(0)
2227 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2228     u_int32_t length, const void * __sized_by(length)value,
2229     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2230 {
2231 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2232 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2233 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2234 		return NULL;
2235 	}
2236 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2237 	*(u_int8_t *)(cursor) = type;
2238 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2239 	if (length > 0) {
2240 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2241 	}
2242 
2243 	return next_tlv;
2244 }
2245 
2246 static u_int8_t * __counted_by(0)
2247 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2248     u_int32_t length, const void * __sized_by(length)value,
2249     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2250 {
2251 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2252 	// Add one extra byte to 'length' to account for the flags byte for validation.
2253 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2254 	if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2255 		return NULL;
2256 	}
2257 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2258 
2259 	// TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2260 	*(u_int8_t *)(cursor) = type;
2261 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2262 	*(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2263 	if (length > 0) {
2264 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2265 	}
2266 
2267 	return next_tlv;
2268 }
2269 
2270 u_int8_t
necp_buffer_get_tlv_type(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset)2271 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2272 {
2273 	u_int8_t * __indexable type = NULL;
2274 	uint64_t end_offset = 0;
2275 
2276 	if (buffer == NULL ||
2277 	    os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2278 		return 0;
2279 	}
2280 
2281 	type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2282 	return type ? *type : 0;
2283 }
2284 
2285 u_int32_t
necp_buffer_get_tlv_length(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset)2286 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2287 {
2288 	u_int32_t * __indexable length = NULL;
2289 	uint64_t end_offset = 0;
2290 
2291 	if (buffer == NULL ||
2292 	    os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2293 		return 0;
2294 	}
2295 
2296 	length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2297 	return length ? *length : 0;
2298 }
2299 
2300 u_int8_t *__sized_by(*value_size)
__necp_buffer_get_tlv_value(u_int8_t * __counted_by (buffer_length)buffer,size_t buffer_length,u_int32_t tlv_offset,u_int32_t * value_size)2301 __necp_buffer_get_tlv_value(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset, u_int32_t * value_size)
2302 {
2303 	u_int8_t * __indexable value = NULL;
2304 	uint64_t end_offset = 0;
2305 
2306 	if (buffer == NULL) {
2307 		return NULL;
2308 	}
2309 
2310 	u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2311 	if (length == 0) {
2312 		return NULL;
2313 	}
2314 
2315 	if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2316 		return NULL;
2317 	}
2318 
2319 	if (value_size) {
2320 		*value_size = length;
2321 	}
2322 
2323 	value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2324 	return value;
2325 }
2326 
2327 int
necp_buffer_find_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2328 necp_buffer_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2329 {
2330 	if (err != NULL) {
2331 		*err = ENOENT;
2332 	}
2333 	if (offset < 0) {
2334 		if (err != NULL) {
2335 			*err = EINVAL;
2336 		}
2337 		return -1;
2338 	}
2339 	int cursor = offset;
2340 	int next_cursor;
2341 	u_int32_t curr_length;
2342 	u_int8_t curr_type;
2343 
2344 	while (TRUE) {
2345 		if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2346 			return -1;
2347 		}
2348 		if (!next) {
2349 			curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2350 		} else {
2351 			next = 0;
2352 			curr_type = NECP_TLV_NIL;
2353 		}
2354 		curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2355 		if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2356 			return -1;
2357 		}
2358 
2359 		next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2360 		if (curr_type == type) {
2361 			// check if entire TLV fits inside buffer
2362 			if (((u_int32_t)next_cursor) <= buffer_length) {
2363 				if (err != NULL) {
2364 					*err = 0;
2365 				}
2366 				return cursor;
2367 			} else {
2368 				return -1;
2369 			}
2370 		}
2371 		cursor = next_cursor;
2372 	}
2373 }
2374 
2375 static int
necp_find_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2376 necp_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2377 {
2378 	int cursor = -1;
2379 	if (buffer != NULL) {
2380 		cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2381 	}
2382 	return cursor;
2383 }
2384 
2385 static int
necp_get_tlv_at_offset(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int tlv_offset,u_int32_t out_buffer_length,void * __indexable out_buffer,u_int32_t * value_size)2386 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2387     int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2388 {
2389 	if (buffer == NULL) {
2390 		NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2391 		return EINVAL;
2392 	}
2393 
2394 	// Handle buffer parsing
2395 
2396 	// Validate that buffer has enough room for any TLV
2397 	if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2398 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2399 		    buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2400 		return EINVAL;
2401 	}
2402 
2403 	// Validate that buffer has enough room for this TLV
2404 	u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2405 	if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2406 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2407 		    tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2408 		return EINVAL;
2409 	}
2410 
2411 	if (out_buffer != NULL && out_buffer_length > 0) {
2412 		// Validate that out buffer is large enough for  value
2413 		if (out_buffer_length < tlv_length) {
2414 			NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2415 			    out_buffer_length, tlv_length);
2416 			return EINVAL;
2417 		}
2418 
2419 		// Get value pointer
2420 		u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2421 		if (tlv_value == NULL) {
2422 			NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2423 			return ENOENT;
2424 		}
2425 
2426 		// Copy value
2427 		memcpy(out_buffer, tlv_value, tlv_length);
2428 	}
2429 
2430 	// Copy out length
2431 	if (value_size != NULL) {
2432 		*value_size = tlv_length;
2433 	}
2434 
2435 	return 0;
2436 }
2437 
2438 static int
necp_get_tlv(u_int8_t * __sized_by (buffer_length)buffer,u_int32_t buffer_length,int offset,u_int8_t type,u_int32_t buff_len,void * __indexable buff,u_int32_t * value_size)2439 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2440     int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2441 {
2442 	int error = 0;
2443 
2444 	int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2445 	if (tlv_offset < 0) {
2446 		return error;
2447 	}
2448 
2449 	return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2450 }
2451 
2452 // Session Management
2453 
2454 static struct necp_session *
necp_create_session(void)2455 necp_create_session(void)
2456 {
2457 	struct necp_session *new_session = NULL;
2458 
2459 	new_session = kalloc_type(struct necp_session,
2460 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2461 
2462 	new_session->necp_fd_type = necp_fd_type_session;
2463 	new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2464 	new_session->dirty = FALSE;
2465 	LIST_INIT(&new_session->policies);
2466 	LIST_INIT(&new_session->services);
2467 	LIST_INIT(&new_session->domain_filters);
2468 	LIST_INIT(&new_session->domain_tries);
2469 	lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2470 
2471 	// Take the lock
2472 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2473 
2474 	// Find the next available control unit
2475 	u_int32_t control_unit = 1;
2476 	struct necp_session *next_session = NULL;
2477 	TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2478 		if (next_session->control_unit > control_unit) {
2479 			// Found a gap, grab this control unit
2480 			break;
2481 		}
2482 
2483 		// Try the next control unit, loop around
2484 		control_unit = next_session->control_unit + 1;
2485 	}
2486 
2487 	new_session->control_unit = control_unit;
2488 	new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2489 
2490 	if (next_session != NULL) {
2491 		TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2492 	} else {
2493 		TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2494 	}
2495 
2496 	necp_session_count++;
2497 	lck_rw_done(&necp_kernel_policy_lock);
2498 
2499 	if (necp_debug) {
2500 		NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2501 	}
2502 
2503 	return new_session;
2504 }
2505 
2506 static void
necp_delete_session(struct necp_session * session)2507 necp_delete_session(struct necp_session *session)
2508 {
2509 	if (session != NULL) {
2510 		struct necp_service_registration * __single service = NULL;
2511 		struct necp_service_registration *temp_service = NULL;
2512 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2513 			LIST_REMOVE(service, session_chain);
2514 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2515 			LIST_REMOVE(service, kernel_chain);
2516 			lck_rw_done(&necp_kernel_policy_lock);
2517 			kfree_type(struct necp_service_registration, service);
2518 		}
2519 		struct necp_domain_filter * __single filter = NULL;
2520 		struct necp_domain_filter *temp_filter = NULL;
2521 		LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2522 			if (os_ref_release_locked(&filter->refcount) == 0) {
2523 				lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2524 				LIST_REMOVE(filter, chain);
2525 				lck_rw_done(&necp_kernel_policy_lock);
2526 				LIST_REMOVE(filter, owner_chain);
2527 				net_bloom_filter_destroy(filter->filter);
2528 				kfree_type(struct necp_domain_filter, filter);
2529 			}
2530 		}
2531 		if (necp_debug) {
2532 			NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2533 		}
2534 
2535 		lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2536 		TAILQ_REMOVE(&necp_session_list, session, chain);
2537 		necp_session_count--;
2538 		lck_rw_done(&necp_kernel_policy_lock);
2539 
2540 		lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2541 		kfree_type(struct necp_session, session);
2542 	}
2543 }
2544 
2545 // Session Policy Management
2546 
2547 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2548 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2549 {
2550 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2551 }
2552 
2553 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2554 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2555 {
2556 	return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2557 }
2558 
2559 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2560 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2561 {
2562 	return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2563 }
2564 
2565 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2566 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2567 {
2568 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2569 	if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2570 		return TRUE;
2571 	}
2572 	return FALSE;
2573 }
2574 
2575 static inline bool
_necp_address_is_valid(struct sockaddr * address)2576 _necp_address_is_valid(struct sockaddr *address)
2577 {
2578 	if (address->sa_family == AF_INET) {
2579 		return address->sa_len == sizeof(struct sockaddr_in);
2580 	} else if (address->sa_family == AF_INET6) {
2581 		return address->sa_len == sizeof(struct sockaddr_in6);
2582 	} else {
2583 		return FALSE;
2584 	}
2585 }
2586 
2587 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2588 
2589 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2590 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2591 {
2592 	bool validated = FALSE;
2593 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2594 	u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2595 	*is_pass_skip = FALSE;
2596 	switch (type) {
2597 	case NECP_POLICY_RESULT_PASS: {
2598 		*is_pass_skip = TRUE;
2599 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2600 			validated = TRUE;
2601 		}
2602 		break;
2603 	}
2604 	case NECP_POLICY_RESULT_DROP: {
2605 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2606 			validated = TRUE;
2607 		}
2608 		break;
2609 	}
2610 	case NECP_POLICY_RESULT_ROUTE_RULES:
2611 	case NECP_POLICY_RESULT_SCOPED_DIRECT:
2612 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2613 		validated = TRUE;
2614 		break;
2615 	}
2616 	case NECP_POLICY_RESULT_SKIP:
2617 		*is_pass_skip = TRUE;
2618 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
2619 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
2620 		if (parameter_length >= sizeof(u_int32_t)) {
2621 			validated = TRUE;
2622 		}
2623 		break;
2624 	}
2625 	case NECP_POLICY_RESULT_IP_TUNNEL: {
2626 		if (parameter_length > sizeof(u_int32_t)) {
2627 			validated = TRUE;
2628 		}
2629 		break;
2630 	}
2631 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2632 		if (parameter_length > 0) {
2633 			validated = TRUE;
2634 		}
2635 		break;
2636 	}
2637 	case NECP_POLICY_RESULT_USE_NETAGENT:
2638 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2639 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2640 		if (parameter_length >= sizeof(uuid_t)) {
2641 			validated = TRUE;
2642 		}
2643 		break;
2644 	}
2645 	default: {
2646 		validated = FALSE;
2647 		break;
2648 	}
2649 	}
2650 
2651 	if (necp_debug) {
2652 		NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2653 	}
2654 
2655 	return validated;
2656 }
2657 
2658 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2659 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2660 {
2661 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2662 }
2663 
2664 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2665 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2666 {
2667 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2668 }
2669 
2670 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2671 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2672 {
2673 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2674 }
2675 
2676 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2677 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2678 {
2679 	return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2680 }
2681 
2682 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2683 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2684 {
2685 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2686 }
2687 
2688 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2689 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2690 {
2691 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2692 }
2693 
2694 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2695 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2696 {
2697 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2698 }
2699 
2700 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2701 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2702 {
2703 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2704 	return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2705 }
2706 
2707 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2708 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2709 {
2710 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2711 	u_int32_t condition_length = 0;
2712 	pid_t *condition_value = NULL;
2713 
2714 	if (type == NECP_POLICY_CONDITION_PID) {
2715 		condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2716 		if (condition_length >= sizeof(pid_t)) {
2717 			condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2718 			return *condition_value == 0;
2719 		}
2720 	}
2721 	return false;
2722 }
2723 
2724 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2725 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2726 {
2727 	bool validated = FALSE;
2728 	bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2729 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2730 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2731 	    policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2732 	    policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2733 	    policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2734 	    policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2735 	    policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2736 	    policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2737 	u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2738 	u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2739 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2740 	u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2741 	switch (type) {
2742 	case NECP_POLICY_CONDITION_APPLICATION:
2743 	case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2744 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2745 		    condition_length >= sizeof(uuid_t) &&
2746 		    condition_value != NULL &&
2747 		    !uuid_is_null(condition_value)) {
2748 			validated = TRUE;
2749 		}
2750 		break;
2751 	}
2752 	case NECP_POLICY_CONDITION_DOMAIN:
2753 	case NECP_POLICY_CONDITION_ACCOUNT:
2754 	case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2755 	case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2756 	case NECP_POLICY_CONDITION_URL: {
2757 		if (condition_length > 0) {
2758 			validated = TRUE;
2759 		}
2760 		break;
2761 	}
2762 	case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2763 		if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2764 			validated = TRUE;
2765 		}
2766 		break;
2767 	}
2768 	case NECP_POLICY_CONDITION_DEFAULT:
2769 	case NECP_POLICY_CONDITION_ALL_INTERFACES:
2770 	case NECP_POLICY_CONDITION_ENTITLEMENT:
2771 	case NECP_POLICY_CONDITION_HAS_CLIENT:
2772 	case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2773 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2774 			validated = TRUE;
2775 		}
2776 		break;
2777 	}
2778 	case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2779 		if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2780 			validated = TRUE;
2781 		}
2782 		break;
2783 	}
2784 	case NECP_POLICY_CONDITION_SDK_VERSION: {
2785 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2786 		    condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2787 			validated = TRUE;
2788 		}
2789 		break;
2790 	}
2791 	case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2792 		if (condition_length >= sizeof(u_int16_t)) {
2793 			validated = TRUE;
2794 		}
2795 		break;
2796 	}
2797 	case NECP_POLICY_CONDITION_PID: {
2798 		if (condition_length >= sizeof(pid_t) &&
2799 		    condition_value != NULL) {
2800 			validated = TRUE;
2801 		}
2802 		break;
2803 	}
2804 	case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2805 		if (condition_length >= sizeof(u_int32_t)) {
2806 			validated = TRUE;
2807 		}
2808 		break;
2809 	}
2810 	case NECP_POLICY_CONDITION_UID:
2811 	case NECP_POLICY_CONDITION_REAL_UID: {
2812 		if (condition_length >= sizeof(uid_t)) {
2813 			validated = TRUE;
2814 		}
2815 		break;
2816 	}
2817 	case NECP_POLICY_CONDITION_LOCAL_ADDR:
2818 	case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2819 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2820 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2821 			validated = TRUE;
2822 		}
2823 		break;
2824 	}
2825 	case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2826 	case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2827 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2828 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2829 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2830 			validated = TRUE;
2831 		}
2832 		break;
2833 	}
2834 	case NECP_POLICY_CONDITION_AGENT_TYPE: {
2835 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2836 		    condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2837 			validated = TRUE;
2838 		}
2839 		break;
2840 	}
2841 	case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2842 		if (condition_length >= sizeof(u_int16_t)) {
2843 			validated = TRUE;
2844 		}
2845 		break;
2846 	}
2847 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2848 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2849 		if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2850 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2851 			validated = TRUE;
2852 		}
2853 		break;
2854 	}
2855 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2856 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2857 		if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2858 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2859 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2860 			validated = TRUE;
2861 		}
2862 		break;
2863 	}
2864 	case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2865 		if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2866 			validated = TRUE;
2867 		}
2868 		break;
2869 	}
2870 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2871 		validated = TRUE;
2872 		break;
2873 	}
2874 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2875 		validated = TRUE;
2876 		break;
2877 	}
2878 	case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2879 		if (condition_length >= sizeof(u_int16_t)) {
2880 			u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2881 			if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2882 				validated = TRUE;
2883 			}
2884 		}
2885 		break;
2886 	}
2887 	case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2888 		validated = TRUE;
2889 		break;
2890 	}
2891 	case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2892 		validated = TRUE;
2893 		break;
2894 	}
2895 	case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2896 		validated = TRUE;
2897 		break;
2898 	}
2899 	case NECP_POLICY_CONDITION_SCHEME_PORT: {
2900 		if (condition_length >= sizeof(u_int16_t)) {
2901 			validated = TRUE;
2902 		}
2903 		break;
2904 	}
2905 	case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2906 		if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2907 			validated = TRUE;
2908 		}
2909 		break;
2910 	}
2911 	default: {
2912 		validated = FALSE;
2913 		break;
2914 	}
2915 	}
2916 
2917 	if (necp_debug) {
2918 		NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2919 	}
2920 
2921 	return validated;
2922 }
2923 
2924 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2925 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2926 {
2927 	return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2928 	       necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2929 }
2930 
2931 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2932 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2933 {
2934 	bool validated = FALSE;
2935 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2936 	switch (type) {
2937 	case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2938 		validated = TRUE;
2939 		break;
2940 	}
2941 	case NECP_ROUTE_RULE_DENY_INTERFACE: {
2942 		validated = TRUE;
2943 		break;
2944 	}
2945 	case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2946 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2947 		validated = (rule_length >= sizeof(u_int32_t));
2948 		break;
2949 	}
2950 	case NECP_ROUTE_RULE_QOS_MARKING: {
2951 		validated = TRUE;
2952 		break;
2953 	}
2954 	case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2955 		validated = TRUE;
2956 		break;
2957 	}
2958 	case NECP_ROUTE_RULE_USE_NETAGENT:
2959 	case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2960 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2961 		validated = (rule_length >= sizeof(uuid_t));
2962 		break;
2963 	}
2964 	case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2965 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2966 		validated = (rule_length >= sizeof(uint32_t));
2967 		break;
2968 	}
2969 	default: {
2970 		validated = FALSE;
2971 		break;
2972 	}
2973 	}
2974 
2975 	if (necp_debug) {
2976 		NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2977 	}
2978 
2979 	return validated;
2980 }
2981 
2982 static int
necp_get_posix_error_for_necp_error(int response_error)2983 necp_get_posix_error_for_necp_error(int response_error)
2984 {
2985 	switch (response_error) {
2986 	case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2987 	case NECP_ERROR_INVALID_TLV:
2988 	case NECP_ERROR_POLICY_RESULT_INVALID:
2989 	case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2990 	case NECP_ERROR_ROUTE_RULES_INVALID: {
2991 		return EINVAL;
2992 	}
2993 	case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2994 		return ENOENT;
2995 	}
2996 	case NECP_ERROR_INVALID_PROCESS: {
2997 		return EPERM;
2998 	}
2999 	case NECP_ERROR_INTERNAL:
3000 	default: {
3001 		return ENOMEM;
3002 	}
3003 	}
3004 }
3005 
3006 static necp_policy_id
necp_handle_policy_add(struct necp_session * session,u_int8_t * __sized_by (tlv_buffer_length)tlv_buffer,size_t tlv_buffer_length,int offset,int * return_error)3007 necp_handle_policy_add(struct necp_session *session,
3008     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
3009 {
3010 	bool has_default_condition = FALSE;
3011 	bool has_non_default_condition = FALSE;
3012 	bool has_application_condition = FALSE;
3013 	bool has_real_application_condition = FALSE;
3014 	bool requires_application_condition = FALSE;
3015 	bool has_kernel_pid = FALSE;
3016 	bool is_pass_skip = FALSE;
3017 	u_int32_t conditions_array_size = 0;
3018 	u_int8_t *conditions_array = NULL;
3019 	int conditions_array_cursor;
3020 
3021 	bool has_default_route_rule = FALSE;
3022 	u_int32_t route_rules_array_size = 0;
3023 	u_int8_t *route_rules_array = NULL;
3024 	int route_rules_array_cursor;
3025 
3026 	int cursor;
3027 	int error = 0;
3028 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3029 
3030 	necp_policy_order order = 0;
3031 	struct necp_session_policy *policy = NULL;
3032 	u_int32_t policy_result_size = 0;
3033 	u_int8_t *policy_result = NULL;
3034 
3035 	// Read policy order
3036 	error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
3037 	if (error) {
3038 		NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
3039 		response_error = NECP_ERROR_INVALID_TLV;
3040 		goto fail;
3041 	}
3042 
3043 	// Read policy result
3044 	cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
3045 	if (error || cursor < 0) {
3046 		NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
3047 		response_error = NECP_ERROR_INVALID_TLV;
3048 		goto fail;
3049 	}
3050 
3051 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
3052 	if (error || policy_result_size == 0) {
3053 		NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
3054 		response_error = NECP_ERROR_INVALID_TLV;
3055 		goto fail;
3056 	}
3057 	if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
3058 		NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
3059 		response_error = NECP_ERROR_INVALID_TLV;
3060 		goto fail;
3061 	}
3062 	policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
3063 	if (policy_result == NULL) {
3064 		NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
3065 		response_error = NECP_ERROR_INTERNAL;
3066 		goto fail;
3067 	}
3068 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
3069 	if (error) {
3070 		NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
3071 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3072 		goto fail;
3073 	}
3074 	if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
3075 		NECPLOG0(LOG_ERR, "Failed to validate policy result");
3076 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3077 		goto fail;
3078 	}
3079 
3080 	if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3081 		// Read route rules conditions
3082 
3083 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3084 		    cursor >= 0;
3085 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3086 			u_int32_t route_rule_size = 0;
3087 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3088 			if (os_add_overflow(route_rules_array_size,
3089 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3090 			    &route_rules_array_size)) {
3091 				NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3092 				response_error = NECP_ERROR_INVALID_TLV;
3093 				goto fail;
3094 			}
3095 		}
3096 
3097 		if (route_rules_array_size == 0) {
3098 			NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3099 			response_error = NECP_ERROR_INVALID_TLV;
3100 			goto fail;
3101 		}
3102 		if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3103 			NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3104 			response_error = NECP_ERROR_INVALID_TLV;
3105 			goto fail;
3106 		}
3107 		route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3108 		if (route_rules_array == NULL) {
3109 			NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3110 			response_error = NECP_ERROR_INTERNAL;
3111 			goto fail;
3112 		}
3113 
3114 		route_rules_array_cursor = 0;
3115 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3116 		    cursor >= 0;
3117 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3118 			u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3119 			u_int32_t route_rule_size = 0;
3120 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3121 			if (route_rule_size > 0 &&
3122 			    (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3123 				// Add type
3124 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3125 				route_rules_array_cursor += sizeof(route_rule_type);
3126 
3127 				// Add length
3128 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3129 				route_rules_array_cursor += sizeof(route_rule_size);
3130 
3131 				// Add value
3132 				necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3133 
3134 				if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3135 					NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3136 					response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3137 					goto fail;
3138 				}
3139 
3140 				if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3141 					if (has_default_route_rule) {
3142 						NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3143 						response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3144 						goto fail;
3145 					}
3146 					has_default_route_rule = TRUE;
3147 				}
3148 
3149 				route_rules_array_cursor += route_rule_size;
3150 			}
3151 		}
3152 	}
3153 
3154 	// Read policy conditions
3155 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3156 	    cursor >= 0;
3157 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3158 		u_int32_t condition_size = 0;
3159 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3160 
3161 		if (condition_size > 0) {
3162 			if (os_add_overflow(conditions_array_size,
3163 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3164 			    &conditions_array_size)) {
3165 				NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3166 				response_error = NECP_ERROR_INVALID_TLV;
3167 				goto fail;
3168 			}
3169 		}
3170 	}
3171 
3172 	if (conditions_array_size == 0) {
3173 		NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3174 		response_error = NECP_ERROR_INVALID_TLV;
3175 		goto fail;
3176 	}
3177 	if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3178 		NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3179 		response_error = NECP_ERROR_INVALID_TLV;
3180 		goto fail;
3181 	}
3182 	conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3183 	if (conditions_array == NULL) {
3184 		NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3185 		response_error = NECP_ERROR_INTERNAL;
3186 		goto fail;
3187 	}
3188 
3189 	conditions_array_cursor = 0;
3190 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3191 	    cursor >= 0;
3192 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3193 		u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3194 		u_int32_t condition_size = 0;
3195 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3196 		if (condition_size > 0 &&
3197 		    (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3198 			// Add type
3199 			memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3200 			conditions_array_cursor += sizeof(condition_type);
3201 
3202 			// Add length
3203 			memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3204 			conditions_array_cursor += sizeof(condition_size);
3205 
3206 			// Add value
3207 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3208 			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))) {
3209 				NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3210 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3211 				goto fail;
3212 			}
3213 
3214 			if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3215 				has_default_condition = TRUE;
3216 			} else {
3217 				has_non_default_condition = TRUE;
3218 			}
3219 			if (has_default_condition && has_non_default_condition) {
3220 				NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3221 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3222 				goto fail;
3223 			}
3224 
3225 			if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3226 				has_application_condition = TRUE;
3227 			}
3228 
3229 			if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3230 				has_real_application_condition = TRUE;
3231 			}
3232 
3233 			if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3234 				requires_application_condition = TRUE;
3235 			}
3236 
3237 			if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3238 				has_kernel_pid = TRUE;
3239 			}
3240 
3241 			conditions_array_cursor += condition_size;
3242 		}
3243 	}
3244 
3245 	if (requires_application_condition && !has_application_condition) {
3246 		NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3247 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3248 		goto fail;
3249 	}
3250 
3251 	if (has_kernel_pid && !is_pass_skip) {
3252 		NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3253 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3254 		goto fail;
3255 	}
3256 
3257 	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) {
3258 		response_error = NECP_ERROR_INTERNAL;
3259 		goto fail;
3260 	}
3261 
3262 	return policy->local_id;
3263 
3264 fail:
3265 	if (policy_result != NULL) {
3266 		kfree_data_sized_by(policy_result, policy_result_size);
3267 	}
3268 	if (conditions_array != NULL) {
3269 		kfree_data_sized_by(conditions_array, conditions_array_size);
3270 	}
3271 	if (route_rules_array != NULL) {
3272 		kfree_data_sized_by(route_rules_array, route_rules_array_size);
3273 	}
3274 
3275 	if (return_error != NULL) {
3276 		*return_error = necp_get_posix_error_for_necp_error(response_error);
3277 	}
3278 	return 0;
3279 }
3280 
3281 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3282 necp_policy_get_new_id(struct necp_session *session)
3283 {
3284 	session->last_policy_id++;
3285 	if (session->last_policy_id < 1) {
3286 		session->last_policy_id = 1;
3287 	}
3288 
3289 	necp_policy_id newid = session->last_policy_id;
3290 
3291 	if (newid == 0) {
3292 		NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3293 		return 0;
3294 	}
3295 
3296 	return newid;
3297 }
3298 
3299 /*
3300  *	For the policy dump response this is the structure:
3301  *
3302  *	<NECP_PACKET_HEADER>
3303  *	{
3304  *		type	:	NECP_TLV_POLICY_DUMP
3305  *		length	:	...
3306  *		value	:
3307  *		{
3308  *			{
3309  *				type	:	NECP_TLV_POLICY_ID
3310  *				len		:	...
3311  *				value	:	...
3312  *			}
3313  *			{
3314  *				type	:	NECP_TLV_POLICY_ORDER
3315  *				len		:	...
3316  *				value	:	...
3317  *			}
3318  *			{
3319  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3320  *				len		:	...
3321  *				value	:	...
3322  *			}
3323  *			{
3324  *				type	:	NECP_TLV_POLICY_OWNER
3325  *				len		:	...
3326  *				value	:	...
3327  *			}
3328  *			{
3329  *				type	:	NECP_TLV_POLICY_CONDITION
3330  *				len		:	...
3331  *				value	:
3332  *				{
3333  *					{
3334  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3335  *						len		:	...
3336  *						value	:	...
3337  *					}
3338  *					{
3339  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3340  *						len		:	...
3341  *						value	:	...
3342  *					}
3343  *					...
3344  *				}
3345  *			}
3346  *		}
3347  *	}
3348  *	{
3349  *		type	:	NECP_TLV_POLICY_DUMP
3350  *		length	:	...
3351  *		value	:
3352  *		{
3353  *			{
3354  *				type	:	NECP_TLV_POLICY_ID
3355  *				len		:	...
3356  *				value	:	...
3357  *			}
3358  *			{
3359  *				type	:	NECP_TLV_POLICY_ORDER
3360  *				len		:	...
3361  *				value	:	...
3362  *			}
3363  *			{
3364  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3365  *				len		:	...
3366  *				value	:	...
3367  *			}
3368  *			{
3369  *				type	:	NECP_TLV_POLICY_OWNER
3370  *				len		:	...
3371  *				value	:	...
3372  *			}
3373  *			{
3374  *				type	:	NECP_TLV_POLICY_CONDITION
3375  *				len		:	...
3376  *				value	:
3377  *				{
3378  *					{
3379  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3380  *						len		:	...
3381  *						value	:	...
3382  *					}
3383  *					{
3384  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3385  *						len		:	...
3386  *						value	:	...
3387  *					}
3388  *					...
3389  *				}
3390  *			}
3391  *		}
3392  *	}
3393  *	...
3394  */
3395 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3396 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3397 {
3398 	struct necp_kernel_socket_policy * __single policy = NULL;
3399 	int policy_i;
3400 	int policy_count = 0;
3401 	u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3402 	u_int32_t * __indexable tlv_buffer_lengths = NULL;
3403 	u_int32_t total_tlv_len = 0;
3404 	u_int8_t * __indexable result_buf = NULL;
3405 	u_int8_t *result_buf_cursor = result_buf;
3406 	char result_string[MAX_RESULT_STRING_LEN];
3407 	char proc_name_string[MAXCOMLEN + 1];
3408 
3409 	int error_code = 0;
3410 	bool error_occured = false;
3411 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3412 
3413 #define REPORT_ERROR(error) error_occured = true;               \
3414 	                                                response_error = error;         \
3415 	                                                goto done
3416 
3417 #define UNLOCK_AND_REPORT_ERROR(lock, error)    lck_rw_done(lock);      \
3418 	                                                                                        REPORT_ERROR(error)
3419 
3420 	errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3421 	if (cred_result != 0) {
3422 		NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3423 		REPORT_ERROR(NECP_ERROR_INTERNAL);
3424 	}
3425 
3426 	// LOCK
3427 	lck_rw_lock_shared(&necp_kernel_policy_lock);
3428 
3429 	if (necp_debug) {
3430 		NECPLOG0(LOG_DEBUG, "Gathering policies");
3431 	}
3432 
3433 	policy_count = necp_kernel_application_policies_count;
3434 
3435 	tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3436 	if (tlv_buffer_pointers == NULL) {
3437 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3438 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3439 	}
3440 
3441 	tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3442 	if (tlv_buffer_lengths == NULL) {
3443 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3444 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3445 	}
3446 
3447 	for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3448 		policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3449 
3450 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
3451 		memset(proc_name_string, 0, MAXCOMLEN + 1);
3452 
3453 		necp_get_result_description(result_string, policy->result, policy->result_parameter);
3454 		proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3455 
3456 		u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3457 		u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3458 
3459 		if (necp_debug) {
3460 			NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3461 		}
3462 
3463 		u_int32_t total_allocated_bytes =       sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) +                                     // NECP_TLV_POLICY_ID
3464 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) +                                                                                              // NECP_TLV_POLICY_ORDER
3465 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) +                                                                              // NECP_TLV_POLICY_SESSION_ORDER
3466 		    sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len +                                                                                                          // NECP_TLV_POLICY_RESULT_STRING
3467 		    sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len +                                                                                                              // NECP_TLV_POLICY_OWNER
3468 		    sizeof(u_int8_t) + sizeof(u_int32_t);                                                                                                                                               // NECP_TLV_POLICY_CONDITION
3469 
3470 		// We now traverse the condition_mask to see how much space we need to allocate
3471 		u_int64_t condition_mask = policy->condition_mask;
3472 		u_int64_t condition_negated_mask = policy->condition_negated_mask;
3473 		u_int8_t num_conditions = 0;
3474 		struct necp_string_id_mapping *account_id_entry = NULL;
3475 		char if_name[IFXNAMSIZ];
3476 		u_int32_t condition_tlv_length = 0;
3477 		memset(if_name, 0, sizeof(if_name));
3478 
3479 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3480 			num_conditions++;
3481 		} else {
3482 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3483 				num_conditions++;
3484 			}
3485 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3486 				num_conditions++;
3487 			}
3488 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3489 				snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3490 				condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3491 				num_conditions++;
3492 			}
3493 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3494 				condition_tlv_length += sizeof(policy->cond_protocol);
3495 				num_conditions++;
3496 			}
3497 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3498 				condition_tlv_length += sizeof(uuid_t);
3499 				num_conditions++;
3500 			}
3501 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3502 				condition_tlv_length += sizeof(uuid_t);
3503 				num_conditions++;
3504 			}
3505 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3506 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3507 				u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3508 				condition_tlv_length += domain_len;
3509 				num_conditions++;
3510 			}
3511 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3512 				condition_tlv_length += sizeof(u_int32_t);
3513 				num_conditions++;
3514 			}
3515 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3516 				u_int32_t url_len = strlen(policy->cond_url) + 1;
3517 				condition_tlv_length += url_len;
3518 				num_conditions++;
3519 			}
3520 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3521 				account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3522 				u_int32_t account_id_len = 0;
3523 				if (account_id_entry) {
3524 					account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3525 				}
3526 				condition_tlv_length += account_id_len;
3527 				num_conditions++;
3528 			}
3529 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3530 				condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3531 				num_conditions++;
3532 			}
3533 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3534 				condition_tlv_length += sizeof(uid_t);
3535 				num_conditions++;
3536 			}
3537 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3538 				condition_tlv_length += sizeof(uid_t);
3539 				num_conditions++;
3540 			}
3541 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3542 				condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3543 				num_conditions++;
3544 			}
3545 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3546 				num_conditions++;
3547 			}
3548 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3549 				u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3550 				condition_tlv_length += entitlement_len;
3551 				num_conditions++;
3552 			}
3553 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3554 				num_conditions++;
3555 			}
3556 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3557 				num_conditions++;
3558 			}
3559 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3560 				condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3561 				num_conditions++;
3562 			}
3563 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3564 				condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3565 				num_conditions++;
3566 			}
3567 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3568 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3569 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3570 				} else {
3571 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3572 				}
3573 				num_conditions++;
3574 			}
3575 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3576 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3577 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3578 				} else {
3579 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3580 				}
3581 				num_conditions++;
3582 			}
3583 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3584 				condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3585 				num_conditions++;
3586 			}
3587 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3588 				condition_tlv_length += sizeof(u_int32_t);
3589 				num_conditions++;
3590 			}
3591 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3592 				num_conditions++;
3593 			}
3594 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3595 				num_conditions++;
3596 			}
3597 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3598 				u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3599 				condition_tlv_length += identifier_len;
3600 				num_conditions++;
3601 			}
3602 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3603 				condition_tlv_length += sizeof(u_int16_t);
3604 				num_conditions++;
3605 			}
3606 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3607 				num_conditions++;
3608 			}
3609 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3610 				num_conditions++;
3611 			}
3612 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3613 				condition_tlv_length += sizeof(u_int16_t);
3614 				num_conditions++;
3615 			}
3616 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3617 				condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3618 				num_conditions++;
3619 			}
3620 		}
3621 
3622 		// These are for the condition TLVs (id, length, flags).  The space for "value" is already accounted for above.
3623 		condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3624 		total_allocated_bytes += condition_tlv_length;
3625 
3626 		u_int8_t * __indexable tlv_buffer;
3627 		tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3628 		if (tlv_buffer == NULL) {
3629 			NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3630 			continue;
3631 		}
3632 
3633 		u_int8_t *cursor = tlv_buffer;
3634 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3635 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3636 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3637 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3638 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3639 
3640 #define N_QUICK 256
3641 		u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3642 
3643 		u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3644 		if (condition_tlv_length <= N_QUICK) {
3645 			cond_buf = q_cond_buf;
3646 		} else {
3647 			cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3648 			if (cond_buf == NULL) {
3649 				NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3650 				kfree_data(tlv_buffer, total_allocated_bytes);
3651 				continue;
3652 			}
3653 		}
3654 
3655 		memset(cond_buf, 0, condition_tlv_length);
3656 		u_int8_t *cond_buf_cursor = cond_buf;
3657 		u_int8_t cond_flags = 0;
3658 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3659 			cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3660 		} else {
3661 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3662 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3663 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ALL_INTERFACES, cond_flags, 0, "", cond_buf, condition_tlv_length);
3664 			}
3665 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3666 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3667 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_HAS_CLIENT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3668 			}
3669 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3670 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3671 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_NETWORKS, cond_flags, sizeof(policy->cond_local_networks_flags), &policy->cond_local_networks_flags, cond_buf, condition_tlv_length);
3672 			}
3673 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3674 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3675 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE, cond_flags, strbuflen(if_name, sizeof(if_name) - 1) + 1,
3676 				    if_name, cond_buf, condition_tlv_length);
3677 			}
3678 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3679 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3680 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_IP_PROTOCOL, cond_flags, sizeof(policy->cond_protocol), &policy->cond_protocol,
3681 				    cond_buf, condition_tlv_length);
3682 			}
3683 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3684 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3685 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3686 				if (entry != NULL) {
3687 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3688 					    cond_buf, condition_tlv_length);
3689 				}
3690 			}
3691 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3692 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3693 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3694 				if (entry != NULL) {
3695 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3696 					    cond_buf, condition_tlv_length);
3697 				}
3698 			}
3699 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3700 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3701 				cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3702 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN, cond_flags, strlen(policy->cond_domain) + 1, __unsafe_null_terminated_to_indexable(policy->cond_domain), cond_buf, condition_tlv_length);
3703 			}
3704 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3705 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3706 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN_FILTER, cond_flags, sizeof(policy->cond_domain_filter), &policy->cond_domain_filter,
3707 				    cond_buf, condition_tlv_length);
3708 			}
3709 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3710 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3711 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_URL, cond_flags, strlen(policy->cond_url) + 1, __unsafe_null_terminated_to_indexable(policy->cond_url), cond_buf, condition_tlv_length);
3712 			}
3713 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3714 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3715 				if (account_id_entry != NULL) {
3716 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ACCOUNT, cond_flags, strlen(account_id_entry->string) + 1, __unsafe_null_terminated_to_indexable(account_id_entry->string), cond_buf, condition_tlv_length);
3717 				}
3718 			}
3719 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3720 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3721 				uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3722 				memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3723 				memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3724 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3725 				    cond_buf, condition_tlv_length);
3726 			}
3727 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3728 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3729 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_UID, cond_flags, sizeof(policy->cond_uid), &policy->cond_uid,
3730 				    cond_buf, condition_tlv_length);
3731 			}
3732 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3733 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3734 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_UID, cond_flags, sizeof(policy->cond_real_uid), &policy->cond_real_uid,
3735 				    cond_buf, condition_tlv_length);
3736 			}
3737 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3738 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3739 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_TRAFFIC_CLASS, cond_flags, sizeof(policy->cond_traffic_class), &policy->cond_traffic_class,
3740 				    cond_buf, condition_tlv_length);
3741 			}
3742 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3743 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3744 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3745 				    cond_buf, condition_tlv_length);
3746 			}
3747 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3748 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3749 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, strlen(policy->cond_custom_entitlement) + 1, __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement), cond_buf, condition_tlv_length);
3750 			}
3751 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3752 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3753 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PLATFORM_BINARY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3754 			}
3755 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3756 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3757 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3758 			}
3759 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3760 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3761 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3762 				    sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3763 				    cond_buf, condition_tlv_length);
3764 			}
3765 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3766 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3767 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3768 					struct necp_policy_condition_addr_range range;
3769 					memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3770 					memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3771 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3772 					    cond_buf, condition_tlv_length);
3773 				} else {
3774 					struct necp_policy_condition_addr addr;
3775 					addr.prefix = policy->cond_local_prefix;
3776 					memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3777 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3778 					    cond_buf, condition_tlv_length);
3779 				}
3780 			}
3781 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3782 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3783 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3784 					struct necp_policy_condition_addr_range range;
3785 					memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3786 					memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3787 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3788 					    cond_buf, condition_tlv_length);
3789 				} else {
3790 					struct necp_policy_condition_addr addr;
3791 					addr.prefix = policy->cond_remote_prefix;
3792 					memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3793 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3794 					    cond_buf, condition_tlv_length);
3795 				}
3796 			}
3797 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3798 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3799 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3800 				    sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3801 				    cond_buf, condition_tlv_length);
3802 			}
3803 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3804 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3805 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_CLIENT_FLAGS, cond_flags, sizeof(policy->cond_client_flags), &policy->cond_client_flags, cond_buf, condition_tlv_length);
3806 			}
3807 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3808 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3809 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3810 			}
3811 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3812 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3813 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3814 			}
3815 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3816 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3817 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, cond_flags, strlen(policy->cond_signing_identifier) + 1, __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier), cond_buf, condition_tlv_length);
3818 			}
3819 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3820 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3821 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS, cond_flags, sizeof(policy->cond_packet_filter_tags), &policy->cond_packet_filter_tags, cond_buf, condition_tlv_length);
3822 			}
3823 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3824 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3825 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, cond_flags, 0, "", cond_buf, condition_tlv_length);
3826 			}
3827 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3828 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3829 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, cond_flags, 0, "", cond_buf, condition_tlv_length);
3830 			}
3831 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3832 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3833 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SCHEME_PORT, cond_flags, sizeof(policy->cond_scheme_port), &policy->cond_scheme_port, cond_buf, condition_tlv_length);
3834 			}
3835 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3836 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3837 				uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3838 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3839 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3840 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3841 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3842 				    cond_buf, condition_tlv_length);
3843 			}
3844 		}
3845 
3846 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3847 		if (cond_buf != q_cond_buf) {
3848 			kfree_data(cond_buf, condition_tlv_length);
3849 		}
3850 
3851 		tlv_buffer_pointers[policy_i] = tlv_buffer;
3852 		tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3853 
3854 		// This is the length of the TLV for NECP_TLV_POLICY_DUMP
3855 		total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3856 	}
3857 
3858 	// UNLOCK
3859 	lck_rw_done(&necp_kernel_policy_lock);
3860 
3861 	// Copy out
3862 	if (out_buffer != 0) {
3863 		if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3864 			NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3865 			REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3866 		}
3867 
3868 		// Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3869 		result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3870 		if (result_buf == NULL) {
3871 			NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3872 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3873 		}
3874 
3875 		// Add four bytes for total length at the start
3876 		memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3877 
3878 		// Copy the TLVs
3879 		result_buf_cursor = result_buf + sizeof(u_int32_t);
3880 		for (int i = 0; i < policy_count; i++) {
3881 			if (tlv_buffer_pointers[i] != NULL) {
3882 				result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3883 				    result_buf, total_tlv_len + sizeof(u_int32_t));
3884 			}
3885 		}
3886 
3887 		int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3888 		if (copy_error) {
3889 			NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3890 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3891 		}
3892 	}
3893 
3894 done:
3895 
3896 	if (error_occured) {
3897 		error_code = necp_get_posix_error_for_necp_error(response_error);
3898 	}
3899 
3900 	if (result_buf != NULL) {
3901 		kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3902 	}
3903 
3904 	if (tlv_buffer_pointers != NULL) {
3905 		for (int i = 0; i < policy_count; i++) {
3906 			if (tlv_buffer_pointers[i] != NULL) {
3907 				kfree_data_addr(tlv_buffer_pointers[i]);
3908 				tlv_buffer_pointers[i] = NULL;
3909 			}
3910 		}
3911 		kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3912 	}
3913 
3914 	if (tlv_buffer_lengths != NULL) {
3915 		kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3916 	}
3917 #undef N_QUICK
3918 #undef RESET_COND_BUF
3919 #undef REPORT_ERROR
3920 #undef UNLOCK_AND_REPORT_ERROR
3921 
3922 	return error_code;
3923 }
3924 
3925 static struct necp_session_policy *
necp_policy_create(struct necp_session * session,necp_policy_order order,u_int8_t * __sized_by (conditions_array_size)conditions_array,u_int32_t conditions_array_size,u_int8_t * __sized_by (route_rules_array_size)route_rules_array,u_int32_t route_rules_array_size,u_int8_t * __sized_by (result_size)result,u_int32_t result_size)3926 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t * __sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t *__sized_by(result_size)result, u_int32_t result_size)
3927 {
3928 	struct necp_session_policy *new_policy = NULL;
3929 	struct necp_session_policy *tmp_policy = NULL;
3930 
3931 	if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3932 		goto done;
3933 	}
3934 
3935 	new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3936 	new_policy->applied = FALSE;
3937 	new_policy->pending_deletion = FALSE;
3938 	new_policy->pending_update = FALSE;
3939 	new_policy->order = order;
3940 	new_policy->conditions = conditions_array;
3941 	new_policy->conditions_size = conditions_array_size;
3942 	new_policy->route_rules = route_rules_array;
3943 	new_policy->route_rules_size = route_rules_array_size;
3944 	new_policy->result = result;
3945 	new_policy->result_size = result_size;
3946 	new_policy->local_id = necp_policy_get_new_id(session);
3947 
3948 	LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3949 
3950 	session->dirty = TRUE;
3951 
3952 	if (necp_debug) {
3953 		NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3954 	}
3955 done:
3956 	return new_policy;
3957 }
3958 
3959 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3960 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3961 {
3962 	struct necp_session_policy *policy = NULL;
3963 	if (policy_id == 0) {
3964 		return NULL;
3965 	}
3966 
3967 	LIST_FOREACH(policy, &session->policies, chain) {
3968 		if (policy->local_id == policy_id) {
3969 			return policy;
3970 		}
3971 	}
3972 
3973 	return NULL;
3974 }
3975 
3976 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3977 necp_policy_get_result_type(struct necp_session_policy *policy)
3978 {
3979 	return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3980 }
3981 
3982 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3983 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3984 {
3985 	return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3986 }
3987 
3988 static bool
necp_policy_get_result_parameter(struct necp_session_policy * policy,u_int8_t * __sized_by (parameter_buffer_length)parameter_buffer,u_int32_t parameter_buffer_length)3989 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t * __sized_by(parameter_buffer_length)parameter_buffer, u_int32_t parameter_buffer_length)
3990 {
3991 	if (policy) {
3992 		u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3993 		if (parameter_buffer_length >= parameter_length) {
3994 			u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3995 			if (parameter && parameter_buffer) {
3996 				memcpy(parameter_buffer, parameter, parameter_length);
3997 				return TRUE;
3998 			}
3999 		}
4000 	}
4001 
4002 	return FALSE;
4003 }
4004 
4005 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)4006 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
4007 {
4008 	if (session == NULL || policy == NULL) {
4009 		return FALSE;
4010 	}
4011 
4012 	policy->pending_deletion = TRUE;
4013 	session->dirty = TRUE;
4014 
4015 	if (necp_debug) {
4016 		NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
4017 	}
4018 	return TRUE;
4019 }
4020 
4021 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)4022 necp_policy_mark_all_for_deletion(struct necp_session *session)
4023 {
4024 	struct necp_session_policy *policy = NULL;
4025 	struct necp_session_policy *temp_policy = NULL;
4026 
4027 	LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4028 		necp_policy_mark_for_deletion(session, policy);
4029 	}
4030 
4031 	return TRUE;
4032 }
4033 
4034 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)4035 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
4036 {
4037 	if (session == NULL || policy == NULL) {
4038 		return FALSE;
4039 	}
4040 
4041 	LIST_REMOVE(policy, chain);
4042 
4043 	if (policy->result) {
4044 		kfree_data_sized_by(policy->result, policy->result_size);
4045 		policy->result = NULL;
4046 		policy->result_size = 0;
4047 	}
4048 
4049 	if (policy->conditions) {
4050 		kfree_data_sized_by(policy->conditions, policy->conditions_size);
4051 		policy->conditions = NULL;
4052 		policy->conditions_size = 0;
4053 	}
4054 
4055 	if (policy->route_rules) {
4056 		kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
4057 		policy->route_rules = NULL;
4058 		policy->route_rules_size = 0;
4059 	}
4060 
4061 	zfree(necp_session_policy_zone, policy);
4062 
4063 	if (necp_debug) {
4064 		NECPLOG0(LOG_DEBUG, "Removed NECP policy");
4065 	}
4066 	return TRUE;
4067 }
4068 
4069 static bool
necp_policy_unapply(struct necp_session_policy * policy)4070 necp_policy_unapply(struct necp_session_policy *policy)
4071 {
4072 	int i = 0;
4073 	if (policy == NULL) {
4074 		return FALSE;
4075 	}
4076 
4077 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4078 
4079 	// Release local uuid mappings
4080 	if (!uuid_is_null(policy->applied_app_uuid)) {
4081 		bool removed_mapping = FALSE;
4082 		if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4083 			necp_uuid_app_id_mappings_dirty = TRUE;
4084 			necp_num_uuid_app_id_mappings--;
4085 		}
4086 		uuid_clear(policy->applied_app_uuid);
4087 	}
4088 	if (!uuid_is_null(policy->applied_real_app_uuid)) {
4089 		necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4090 		uuid_clear(policy->applied_real_app_uuid);
4091 	}
4092 	if (!uuid_is_null(policy->applied_result_uuid)) {
4093 		necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
4094 		uuid_clear(policy->applied_result_uuid);
4095 	}
4096 
4097 	// Release string mappings
4098 	if (policy->applied_account != NULL) {
4099 		necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4100 		kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4101 		policy->applied_account = NULL;
4102 		policy->applied_account_size = 0;
4103 	}
4104 
4105 	// Release route rule
4106 	if (policy->applied_route_rules_id != 0) {
4107 		necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4108 		policy->applied_route_rules_id = 0;
4109 	}
4110 
4111 	// Remove socket policies
4112 	for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4113 		if (policy->kernel_socket_policies[i] != 0) {
4114 			necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4115 			policy->kernel_socket_policies[i] = 0;
4116 		}
4117 	}
4118 
4119 	// Remove IP output policies
4120 	for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4121 		if (policy->kernel_ip_output_policies[i] != 0) {
4122 			necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4123 			policy->kernel_ip_output_policies[i] = 0;
4124 		}
4125 	}
4126 
4127 	policy->applied = FALSE;
4128 
4129 	return TRUE;
4130 }
4131 
4132 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION                 0
4133 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION             1
4134 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION                                2
4135 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS                   3
4136 struct necp_policy_result_ip_tunnel {
4137 	u_int32_t secondary_result;
4138 	char interface_name[IFXNAMSIZ];
4139 } __attribute__((__packed__));
4140 
4141 struct necp_policy_result_service {
4142 	uuid_t identifier;
4143 	u_int32_t data;
4144 } __attribute__((__packed__));
4145 
4146 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)4147 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
4148 {
4149 	bool socket_only_conditions = FALSE;
4150 	bool socket_ip_conditions = FALSE;
4151 
4152 	bool socket_layer_non_id_conditions = FALSE;
4153 	bool ip_output_layer_non_id_conditions = FALSE;
4154 	bool ip_output_layer_non_id_only = FALSE;
4155 	bool ip_output_layer_id_condition = FALSE;
4156 	bool ip_output_layer_tunnel_condition_from_id = FALSE;
4157 	bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4158 	necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4159 
4160 	u_int64_t master_condition_mask = 0;
4161 	u_int64_t master_condition_negated_mask = 0;
4162 	ifnet_t __single cond_bound_interface = NULL;
4163 	u_int32_t cond_account_id = 0;
4164 	char *cond_domain __null_terminated = NULL;
4165 	u_int32_t cond_domain_filter = 0;
4166 	char *cond_url __null_terminated = NULL;
4167 	char *cond_custom_entitlement __null_terminated = NULL;
4168 	char *cond_signing_identifier __null_terminated = NULL;
4169 	pid_t cond_pid = 0;
4170 	int32_t cond_pid_version = 0;
4171 	uid_t cond_uid = 0;
4172 	uid_t cond_real_uid = 0;
4173 	necp_app_id cond_app_id = 0;
4174 	necp_app_id cond_real_app_id = 0;
4175 	struct necp_policy_condition_tc_range cond_traffic_class;
4176 	cond_traffic_class.start_tc = 0;
4177 	cond_traffic_class.end_tc = 0;
4178 	u_int16_t cond_protocol = 0;
4179 	union necp_sockaddr_union cond_local_start;
4180 	union necp_sockaddr_union cond_local_end;
4181 	u_int8_t cond_local_prefix = 0;
4182 	union necp_sockaddr_union cond_remote_start;
4183 	union necp_sockaddr_union cond_remote_end;
4184 	u_int8_t cond_remote_prefix = 0;
4185 	u_int32_t cond_client_flags = 0;
4186 	u_int8_t cond_local_networks_flags = 0;
4187 	u_int32_t offset = 0;
4188 	u_int8_t ultimate_result = 0;
4189 	u_int32_t secondary_result = 0;
4190 	struct necp_policy_condition_agent_type cond_agent_type = {};
4191 	struct necp_policy_condition_sdk_version cond_sdk_version = {};
4192 	u_int16_t cond_packet_filter_tags = 0;
4193 	u_int16_t cond_scheme_port = 0;
4194 	u_int32_t cond_bound_interface_flags = 0;
4195 	u_int32_t cond_bound_interface_eflags = 0;
4196 	u_int32_t cond_bound_interface_xflags = 0;
4197 	necp_kernel_policy_result_parameter secondary_result_parameter;
4198 	memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4199 	u_int32_t cond_last_interface_index = 0;
4200 	necp_kernel_policy_result_parameter ultimate_result_parameter;
4201 	memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4202 
4203 	if (policy == NULL) {
4204 		return FALSE;
4205 	}
4206 
4207 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4208 
4209 	// Process conditions
4210 	while (offset < policy->conditions_size) {
4211 		u_int32_t length = 0;
4212 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4213 
4214 		u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4215 		u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4216 		bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4217 		u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4218 		u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4219 		switch (condition_type) {
4220 		case NECP_POLICY_CONDITION_DEFAULT: {
4221 			socket_ip_conditions = TRUE;
4222 			break;
4223 		}
4224 		case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4225 			master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4226 			socket_ip_conditions = TRUE;
4227 			break;
4228 		}
4229 		case NECP_POLICY_CONDITION_HAS_CLIENT: {
4230 			master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4231 			socket_only_conditions = TRUE;
4232 			break;
4233 		}
4234 		case NECP_POLICY_CONDITION_ENTITLEMENT: {
4235 			if (condition_length > 0) {
4236 				if (cond_custom_entitlement == NULL) {
4237 					cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4238 					if (cond_custom_entitlement != NULL) {
4239 						master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4240 						socket_only_conditions = TRUE;
4241 					}
4242 				}
4243 			} else {
4244 				master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4245 				socket_only_conditions = TRUE;
4246 			}
4247 			break;
4248 		}
4249 		case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4250 			master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4251 			if (condition_is_negative) {
4252 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4253 			}
4254 			socket_only_conditions = TRUE;
4255 			break;
4256 		}
4257 		case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4258 			master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4259 			socket_only_conditions = TRUE;
4260 			break;
4261 		}
4262 		case NECP_POLICY_CONDITION_SDK_VERSION: {
4263 			if (condition_length >= sizeof(cond_sdk_version)) {
4264 				master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4265 				memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4266 				socket_only_conditions = TRUE;
4267 			}
4268 			break;
4269 		}
4270 		case NECP_POLICY_CONDITION_DOMAIN: {
4271 			// Make sure there is only one such rule
4272 			if (condition_length > 0 && cond_domain == NULL) {
4273 				const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4274 
4275 				u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4276 				cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4277 				if (cond_domain != NULL) {
4278 					master_condition_mask |= mask_value;
4279 					if (condition_is_negative) {
4280 						master_condition_negated_mask |= mask_value;
4281 					}
4282 					socket_only_conditions = TRUE;
4283 				}
4284 			}
4285 			break;
4286 		}
4287 		case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4288 			// Make sure there is only one such rule
4289 			if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4290 				memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4291 				if (cond_domain_filter != 0) {
4292 					master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4293 					if (condition_is_negative) {
4294 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4295 					}
4296 					socket_only_conditions = TRUE;
4297 				}
4298 			}
4299 			break;
4300 		}
4301 		case NECP_POLICY_CONDITION_URL: {
4302 			// Make sure there is only one such rule
4303 			if (condition_length > 0 && cond_url == NULL) {
4304 				u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4305 				cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4306 				if (cond_url != NULL) {
4307 					master_condition_mask |= mask_value;
4308 					if (condition_is_negative) {
4309 						master_condition_negated_mask |= mask_value;
4310 					}
4311 					socket_only_conditions = TRUE;
4312 				}
4313 			}
4314 			break;
4315 		}
4316 		case NECP_POLICY_CONDITION_ACCOUNT: {
4317 			// Make sure there is only one such rule
4318 			if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4319 				size_t string_buffer_size = 0;
4320 				char * __sized_by(string_buffer_size) string = NULL;
4321 				string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4322 				string_buffer_size = condition_length + 1;
4323 				if (string != NULL) {
4324 					memcpy(string, condition_value, condition_length);
4325 					string[condition_length] = 0;
4326 					cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4327 					if (cond_account_id != 0) {
4328 						policy->applied_account = string;         // Save the string in parent policy
4329 						policy->applied_account_size = string_buffer_size;
4330 						master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4331 						if (condition_is_negative) {
4332 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4333 						}
4334 						socket_only_conditions = TRUE;
4335 					} else {
4336 						kfree_data_sized_by(string, string_buffer_size);
4337 					}
4338 				}
4339 			}
4340 			break;
4341 		}
4342 		case NECP_POLICY_CONDITION_APPLICATION: {
4343 			// Make sure there is only one such rule, because we save the uuid in the policy
4344 			if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4345 				bool allocated_mapping = FALSE;
4346 				uuid_t application_uuid;
4347 				memcpy(application_uuid, condition_value, sizeof(uuid_t));
4348 				cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4349 				if (cond_app_id != 0) {
4350 					if (allocated_mapping) {
4351 						necp_uuid_app_id_mappings_dirty = TRUE;
4352 						necp_num_uuid_app_id_mappings++;
4353 					}
4354 					uuid_copy(policy->applied_app_uuid, application_uuid);
4355 					master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4356 					if (condition_is_negative) {
4357 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4358 					}
4359 					socket_only_conditions = TRUE;
4360 				}
4361 			}
4362 			break;
4363 		}
4364 		case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4365 			// Make sure there is only one such rule, because we save the uuid in the policy
4366 			if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4367 				uuid_t real_application_uuid;
4368 				memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4369 				cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4370 				if (cond_real_app_id != 0) {
4371 					uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4372 					master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4373 					if (condition_is_negative) {
4374 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4375 					}
4376 					socket_only_conditions = TRUE;
4377 				}
4378 			}
4379 			break;
4380 		}
4381 		case NECP_POLICY_CONDITION_PID: {
4382 			if (condition_length >= sizeof(pid_t)) {
4383 				master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4384 				if (condition_is_negative) {
4385 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4386 				}
4387 				memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4388 				if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4389 					memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4390 				}
4391 				socket_only_conditions = TRUE;
4392 			}
4393 			break;
4394 		}
4395 		case NECP_POLICY_CONDITION_UID: {
4396 			if (condition_length >= sizeof(uid_t)) {
4397 				master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4398 				if (condition_is_negative) {
4399 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4400 				}
4401 				memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4402 				socket_only_conditions = TRUE;
4403 			}
4404 			break;
4405 		}
4406 		case NECP_POLICY_CONDITION_REAL_UID: {
4407 			if (condition_length >= sizeof(uid_t)) {
4408 				master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4409 				if (condition_is_negative) {
4410 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4411 				}
4412 				memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4413 				socket_only_conditions = TRUE;
4414 			}
4415 			break;
4416 		}
4417 		case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4418 			if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4419 				master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4420 				if (condition_is_negative) {
4421 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4422 				}
4423 				memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4424 				socket_only_conditions = TRUE;
4425 			}
4426 			break;
4427 		}
4428 		case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4429 			if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4430 				char interface_name[IFXNAMSIZ];
4431 				memcpy(interface_name, condition_value, condition_length);
4432 				interface_name[condition_length - 1] = 0;         // Make sure the string is NULL terminated
4433 				if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4434 					master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4435 					if (condition_is_negative) {
4436 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4437 					}
4438 				}
4439 				socket_ip_conditions = TRUE;
4440 			}
4441 			break;
4442 		}
4443 		case NECP_POLICY_CONDITION_IP_PROTOCOL:
4444 		case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4445 			if (condition_length >= sizeof(u_int16_t)) {
4446 				master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4447 				if (condition_is_negative) {
4448 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4449 				}
4450 				memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4451 				if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4452 					socket_only_conditions = TRUE;
4453 				} else {
4454 					socket_ip_conditions = TRUE;
4455 				}
4456 			}
4457 			break;
4458 		}
4459 		case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4460 			if (condition_is_negative) {
4461 				master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4462 			}
4463 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4464 			socket_ip_conditions = TRUE;
4465 			if (condition_length >= sizeof(u_int8_t)) {
4466 				memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4467 			}
4468 			break;
4469 		}
4470 		case NECP_POLICY_CONDITION_LOCAL_ADDR:
4471 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4472 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4473 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4474 				break;
4475 			}
4476 
4477 			cond_local_prefix = address_struct->prefix;
4478 			memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4479 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4480 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4481 			if (condition_is_negative) {
4482 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4483 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4484 			}
4485 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4486 				socket_only_conditions = TRUE;
4487 			} else {
4488 				socket_ip_conditions = TRUE;
4489 			}
4490 			break;
4491 		}
4492 		case NECP_POLICY_CONDITION_REMOTE_ADDR:
4493 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4494 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4495 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4496 				break;
4497 			}
4498 
4499 			cond_remote_prefix = address_struct->prefix;
4500 			memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4501 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4502 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4503 			if (condition_is_negative) {
4504 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4505 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4506 			}
4507 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4508 				socket_only_conditions = TRUE;
4509 			} else {
4510 				socket_ip_conditions = TRUE;
4511 			}
4512 			break;
4513 		}
4514 		case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4515 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4516 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4517 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4518 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4519 				break;
4520 			}
4521 
4522 			memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4523 			memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4524 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4525 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4526 			if (condition_is_negative) {
4527 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4528 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4529 			}
4530 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4531 				socket_only_conditions = TRUE;
4532 			} else {
4533 				socket_ip_conditions = TRUE;
4534 			}
4535 			break;
4536 		}
4537 		case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4538 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4539 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4540 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4541 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4542 				break;
4543 			}
4544 
4545 			memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4546 			memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4547 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4548 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4549 			if (condition_is_negative) {
4550 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4551 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4552 			}
4553 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4554 				socket_only_conditions = TRUE;
4555 			} else {
4556 				socket_ip_conditions = TRUE;
4557 			}
4558 			break;
4559 		}
4560 		case NECP_POLICY_CONDITION_AGENT_TYPE: {
4561 			if (condition_length >= sizeof(cond_agent_type)) {
4562 				master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4563 				memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4564 				socket_only_conditions = TRUE;
4565 			}
4566 			break;
4567 		}
4568 		case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4569 			if (condition_is_negative) {
4570 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4571 			}
4572 			master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4573 			socket_only_conditions = TRUE;
4574 			if (condition_length >= sizeof(u_int32_t)) {
4575 				memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4576 			} else {
4577 				// Empty means match on fallback traffic
4578 				cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4579 			}
4580 			break;
4581 		}
4582 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4583 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4584 			if (condition_is_negative) {
4585 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4586 			}
4587 			socket_only_conditions = TRUE;
4588 			break;
4589 		}
4590 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4591 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4592 			if (condition_is_negative) {
4593 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4594 			}
4595 			socket_only_conditions = TRUE;
4596 			break;
4597 		}
4598 		case NECP_POLICY_CONDITION_SCHEME_PORT: {
4599 			master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4600 			if (condition_is_negative) {
4601 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4602 			}
4603 			memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4604 			socket_ip_conditions = TRUE;
4605 			break;
4606 		}
4607 		case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4608 			if (condition_length > 0) {
4609 				if (cond_signing_identifier == NULL) {
4610 					cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4611 					if (cond_signing_identifier != NULL) {
4612 						master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4613 						socket_only_conditions = TRUE;
4614 						if (condition_is_negative) {
4615 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4616 						}
4617 					}
4618 				}
4619 			}
4620 			break;
4621 		}
4622 		case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4623 			if (condition_length >= sizeof(u_int16_t)) {
4624 				master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4625 				if (condition_is_negative) {
4626 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4627 				}
4628 				memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4629 				socket_ip_conditions = TRUE;
4630 			}
4631 			break;
4632 		}
4633 		case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4634 			master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4635 			if (condition_is_negative) {
4636 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4637 			}
4638 			socket_only_conditions = TRUE;
4639 			break;
4640 		}
4641 		case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4642 			master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4643 			if (condition_is_negative) {
4644 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4645 			}
4646 			socket_only_conditions = TRUE;
4647 			break;
4648 		}
4649 		case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4650 			if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4651 				u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4652 				memcpy(&flags, condition_value, sizeof(flags));
4653 				cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4654 				cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4655 				cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4656 				master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4657 				if (condition_is_negative) {
4658 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4659 				}
4660 				socket_ip_conditions = TRUE;
4661 			}
4662 			break;
4663 		}
4664 		default: {
4665 			break;
4666 		}
4667 		}
4668 
4669 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4670 	}
4671 
4672 	// Process result
4673 	ultimate_result = necp_policy_get_result_type(policy);
4674 	switch (ultimate_result) {
4675 	case NECP_POLICY_RESULT_PASS: {
4676 		u_int32_t pass_flags = 0;
4677 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4678 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4679 				ultimate_result_parameter.pass_flags = pass_flags;
4680 			}
4681 		}
4682 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4683 			socket_layer_non_id_conditions = TRUE;
4684 			ip_output_layer_id_condition = TRUE;
4685 		} else if (socket_ip_conditions) {
4686 			socket_layer_non_id_conditions = TRUE;
4687 			ip_output_layer_id_condition = TRUE;
4688 			ip_output_layer_non_id_conditions = TRUE;
4689 		}
4690 		break;
4691 	}
4692 	case NECP_POLICY_RESULT_DROP: {
4693 		u_int32_t drop_flags = 0;
4694 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4695 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4696 				ultimate_result_parameter.drop_flags = drop_flags;
4697 			}
4698 		}
4699 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4700 			socket_layer_non_id_conditions = TRUE;
4701 		} else if (socket_ip_conditions) {
4702 			socket_layer_non_id_conditions = TRUE;
4703 			ip_output_layer_non_id_conditions = TRUE;
4704 			ip_output_layer_non_id_only = TRUE;         // Only apply drop to packets that didn't go through socket layer
4705 		}
4706 		break;
4707 	}
4708 	case NECP_POLICY_RESULT_SKIP: {
4709 		u_int32_t skip_policy_order = 0;
4710 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4711 			ultimate_result_parameter.skip_policy_order = skip_policy_order;
4712 		}
4713 
4714 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4715 			socket_layer_non_id_conditions = TRUE;
4716 			ip_output_layer_id_condition = TRUE;
4717 		} else if (socket_ip_conditions) {
4718 			socket_layer_non_id_conditions = TRUE;
4719 			ip_output_layer_non_id_conditions = TRUE;
4720 		}
4721 		break;
4722 	}
4723 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
4724 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
4725 		u_int32_t control_unit = 0;
4726 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4727 			ultimate_result_parameter.flow_divert_control_unit = control_unit;
4728 		}
4729 		socket_layer_non_id_conditions = TRUE;
4730 		break;
4731 	}
4732 	case NECP_POLICY_RESULT_IP_TUNNEL: {
4733 		struct necp_policy_result_ip_tunnel tunnel_parameters;
4734 		u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4735 		if (tunnel_parameters_length > sizeof(u_int32_t) &&
4736 		    tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4737 		    necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4738 			ifnet_t __single tunnel_interface = NULL;
4739 			tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0;         // Make sure the string is NULL terminated
4740 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4741 				ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4742 				ifnet_release(tunnel_interface);
4743 			}
4744 
4745 			secondary_result = tunnel_parameters.secondary_result;
4746 			if (secondary_result) {
4747 				cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4748 			}
4749 		}
4750 
4751 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4752 			socket_layer_non_id_conditions = TRUE;
4753 			ip_output_layer_id_condition = TRUE;
4754 			if (secondary_result) {
4755 				ip_output_layer_tunnel_condition_from_id = TRUE;
4756 			}
4757 		} else if (socket_ip_conditions) {
4758 			socket_layer_non_id_conditions = TRUE;
4759 			ip_output_layer_id_condition = TRUE;
4760 			ip_output_layer_non_id_conditions = TRUE;
4761 			if (secondary_result) {
4762 				ip_output_layer_tunnel_condition_from_id = TRUE;
4763 				ip_output_layer_tunnel_condition_from_non_id = TRUE;
4764 			}
4765 		}
4766 		break;
4767 	}
4768 	case NECP_POLICY_RESULT_USE_NETAGENT:
4769 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4770 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4771 		uuid_t netagent_uuid;
4772 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4773 			ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4774 			if (ultimate_result_parameter.netagent_id != 0) {
4775 				uuid_copy(policy->applied_result_uuid, netagent_uuid);
4776 				socket_layer_non_id_conditions = TRUE;
4777 			}
4778 		}
4779 		break;
4780 	}
4781 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4782 		u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4783 		if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4784 			char interface_name[IFXNAMSIZ];
4785 			ifnet_t __single scope_interface = NULL;
4786 			necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4787 			interface_name[interface_name_length - 1] = 0;         // Make sure the string is NULL terminated
4788 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4789 				ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4790 				socket_layer_non_id_conditions = TRUE;
4791 				ifnet_release(scope_interface);
4792 			}
4793 		}
4794 		break;
4795 	}
4796 	case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4797 		socket_layer_non_id_conditions = TRUE;
4798 		break;
4799 	}
4800 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4801 		socket_layer_non_id_conditions = TRUE;
4802 		break;
4803 	}
4804 	case NECP_POLICY_RESULT_ROUTE_RULES: {
4805 		if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4806 			bool has_socket_only_actions = FALSE;
4807 			u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4808 			if (route_rule_id > 0) {
4809 				policy->applied_route_rules_id = route_rule_id;
4810 				ultimate_result_parameter.route_rule_id = route_rule_id;
4811 				if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4812 					socket_layer_non_id_conditions = TRUE;
4813 				} else if (socket_ip_conditions) {
4814 					socket_layer_non_id_conditions = TRUE;
4815 					ip_output_layer_non_id_conditions = TRUE;
4816 					ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4817 				}
4818 			}
4819 		}
4820 		break;
4821 	}
4822 	default: {
4823 		break;
4824 	}
4825 	}
4826 
4827 	if (socket_layer_non_id_conditions) {
4828 		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_domain_filter, cond_url, cond_pid, cond_pid_version, cond_uid, cond_real_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, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4829 
4830 		if (policy_id == 0) {
4831 			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4832 			goto fail;
4833 		}
4834 
4835 		cond_ip_output_layer_id = policy_id;
4836 		policy->kernel_socket_policies[0] = policy_id;
4837 	}
4838 
4839 	if (ip_output_layer_non_id_conditions) {
4840 		u_int64_t condition_mask = master_condition_mask;
4841 		if (ip_output_layer_non_id_only) {
4842 			condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4843 		}
4844 
4845 		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, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4846 
4847 		if (policy_id == 0) {
4848 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4849 			goto fail;
4850 		}
4851 
4852 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4853 	}
4854 
4855 	if (ip_output_layer_id_condition) {
4856 		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, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, ultimate_result, ultimate_result_parameter);
4857 
4858 		if (policy_id == 0) {
4859 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4860 			goto fail;
4861 		}
4862 
4863 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4864 	}
4865 
4866 	// Extra policies for IP Output tunnels for when packets loop back
4867 	if (ip_output_layer_tunnel_condition_from_id) {
4868 		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, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, secondary_result, secondary_result_parameter);
4869 
4870 		if (policy_id == 0) {
4871 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4872 			goto fail;
4873 		}
4874 
4875 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4876 	}
4877 
4878 	if (ip_output_layer_tunnel_condition_from_id) {
4879 		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, 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, cond_local_networks_flags, secondary_result, secondary_result_parameter);
4880 
4881 		if (policy_id == 0) {
4882 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4883 			goto fail;
4884 		}
4885 
4886 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4887 	}
4888 
4889 	policy->applied = TRUE;
4890 	policy->pending_update = FALSE;
4891 	return TRUE;
4892 
4893 fail:
4894 	return FALSE;
4895 }
4896 
4897 static void
necp_policy_apply_all(struct necp_session * session)4898 necp_policy_apply_all(struct necp_session *session)
4899 {
4900 	struct necp_session_policy *policy = NULL;
4901 	struct necp_session_policy *temp_policy = NULL;
4902 	struct kev_necp_policies_changed_data kev_data;
4903 	kev_data.changed_count = 0;
4904 
4905 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4906 
4907 	// Remove exisiting applied policies
4908 	if (session->dirty) {
4909 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4910 			if (policy->pending_deletion) {
4911 				if (policy->applied) {
4912 					necp_policy_unapply(policy);
4913 				}
4914 				// Delete the policy
4915 				necp_policy_delete(session, policy);
4916 			} else if (!policy->applied) {
4917 				necp_policy_apply(session, policy);
4918 			} else if (policy->pending_update) {
4919 				// Must have been applied, but needs an update. Remove and re-add.
4920 				necp_policy_unapply(policy);
4921 				necp_policy_apply(session, policy);
4922 			}
4923 		}
4924 
4925 		necp_kernel_socket_policies_update_uuid_table();
4926 		necp_kernel_socket_policies_reprocess();
4927 		necp_kernel_ip_output_policies_reprocess();
4928 
4929 		// Clear dirty bit flags
4930 		session->dirty = FALSE;
4931 	}
4932 
4933 	lck_rw_done(&necp_kernel_policy_lock);
4934 
4935 	necp_update_all_clients();
4936 	necp_post_change_event(&kev_data);
4937 
4938 	if (necp_debug) {
4939 		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4940 	}
4941 }
4942 
4943 // Kernel Policy Management
4944 // ---------------------
4945 // Kernel policies are derived from session policies
4946 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4947 necp_kernel_policy_get_new_id(bool socket_level)
4948 {
4949 	static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4950 	static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4951 
4952 	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4953 
4954 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4955 
4956 	if (socket_level) {
4957 		bool wrapped = FALSE;
4958 		do {
4959 			necp_last_kernel_socket_policy_id++;
4960 			if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4961 			    necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4962 				if (wrapped) {
4963 					// Already wrapped, give up
4964 					NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4965 					return NECP_KERNEL_POLICY_ID_NONE;
4966 				}
4967 				necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4968 				wrapped = TRUE;
4969 			}
4970 			newid = necp_last_kernel_socket_policy_id;
4971 		} while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4972 	} else {
4973 		bool wrapped = FALSE;
4974 		do {
4975 			necp_last_kernel_ip_policy_id++;
4976 			if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4977 				if (wrapped) {
4978 					// Already wrapped, give up
4979 					NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4980 					return NECP_KERNEL_POLICY_ID_NONE;
4981 				}
4982 				necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4983 				wrapped = TRUE;
4984 			}
4985 			newid = necp_last_kernel_ip_policy_id;
4986 		} while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4987 	}
4988 
4989 	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4990 		NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4991 		return NECP_KERNEL_POLICY_ID_NONE;
4992 	}
4993 
4994 	return newid;
4995 }
4996 
4997 #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_REAL_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 | NECP_KERNEL_CONDITION_SCHEME_PORT | NECP_KERNEL_CONDITION_DOMAIN_FILTER | NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT | NECP_KERNEL_CONDITION_EXACT_DOMAIN | NECP_KERNEL_CONDITION_URL | NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)
4998 
4999 static necp_kernel_policy_id
necp_kernel_socket_policy_add(necp_policy_order order,u_int32_t session_order,int session_pid,u_int64_t condition_mask,u_int64_t condition_negated_mask,necp_app_id cond_app_id,necp_app_id cond_real_app_id,char * cond_custom_entitlement __null_terminated,u_int32_t cond_account_id,char * cond_domain __null_terminated,u_int32_t cond_domain_filter,char * cond_url __null_terminated,pid_t cond_pid,int32_t cond_pid_version,uid_t cond_uid,uid_t cond_real_uid,ifnet_t cond_bound_interface,struct necp_policy_condition_tc_range cond_traffic_class,u_int16_t cond_protocol,union necp_sockaddr_union * __single 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 __null_terminated,u_int16_t cond_packet_filter_tags,u_int16_t cond_scheme_port,u_int32_t cond_bound_interface_flags,u_int32_t cond_bound_interface_eflags,u_int32_t cond_bound_interface_xflags,u_int8_t cond_local_networks_flags,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)5000 necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union * __single 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 __null_terminated, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5001 {
5002 	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
5003 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5004 
5005 	new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
5006 
5007 	new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
5008 	new_kernel_policy->order = order;
5009 	new_kernel_policy->session_order = session_order;
5010 	new_kernel_policy->session_pid = session_pid;
5011 
5012 	// Sanitize condition mask
5013 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
5014 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
5015 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
5016 	}
5017 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
5018 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
5019 	}
5020 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
5021 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
5022 	}
5023 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
5024 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
5025 	}
5026 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
5027 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
5028 	}
5029 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
5030 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
5031 	}
5032 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
5033 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
5034 	}
5035 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
5036 
5037 	// Set condition values
5038 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
5039 		new_kernel_policy->cond_app_id = cond_app_id;
5040 	}
5041 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
5042 		new_kernel_policy->cond_real_app_id = cond_real_app_id;
5043 	}
5044 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
5045 		new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
5046 	}
5047 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5048 		new_kernel_policy->cond_account_id = cond_account_id;
5049 	}
5050 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5051 	    (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5052 		new_kernel_policy->cond_domain = cond_domain;
5053 		new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5054 	}
5055 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5056 		new_kernel_policy->cond_domain_filter = cond_domain_filter;
5057 	}
5058 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5059 		new_kernel_policy->cond_url = cond_url;
5060 	}
5061 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5062 		new_kernel_policy->cond_pid = cond_pid;
5063 		new_kernel_policy->cond_pid_version = cond_pid_version;
5064 	}
5065 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5066 		new_kernel_policy->cond_uid = cond_uid;
5067 	}
5068 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5069 		new_kernel_policy->cond_real_uid = cond_real_uid;
5070 	}
5071 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5072 		if (cond_bound_interface) {
5073 			ifnet_reference(cond_bound_interface);
5074 		}
5075 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
5076 	}
5077 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5078 		new_kernel_policy->cond_traffic_class = cond_traffic_class;
5079 	}
5080 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5081 		new_kernel_policy->cond_protocol = cond_protocol;
5082 	}
5083 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5084 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5085 	}
5086 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5087 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5088 	}
5089 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5090 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
5091 	}
5092 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5093 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5094 	}
5095 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5096 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5097 	}
5098 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5099 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5100 	}
5101 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5102 		memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5103 	}
5104 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5105 		memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5106 	}
5107 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5108 		new_kernel_policy->cond_client_flags = cond_client_flags;
5109 	}
5110 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5111 		new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5112 	}
5113 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5114 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5115 	}
5116 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5117 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
5118 	}
5119 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5120 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5121 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5122 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5123 	}
5124 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5125 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5126 	}
5127 
5128 	new_kernel_policy->result = result;
5129 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5130 
5131 	if (necp_debug) {
5132 		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5133 	}
5134 	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5135 
5136 	return new_kernel_policy ? new_kernel_policy->id : 0;
5137 }
5138 
5139 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5140 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5141 {
5142 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5143 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5144 
5145 	if (policy_id == 0) {
5146 		return NULL;
5147 	}
5148 
5149 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5150 		if (kernel_policy->id == policy_id) {
5151 			return kernel_policy;
5152 		}
5153 	}
5154 
5155 	return NULL;
5156 }
5157 
5158 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5159 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5160 {
5161 	struct necp_kernel_socket_policy * __single policy = NULL;
5162 	char * __indexable buffer = NULL;
5163 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5164 
5165 	policy = necp_kernel_socket_policy_find(policy_id);
5166 	if (policy) {
5167 		LIST_REMOVE(policy, chain);
5168 
5169 		if (policy->cond_bound_interface) {
5170 			ifnet_release(policy->cond_bound_interface);
5171 			policy->cond_bound_interface = NULL;
5172 		}
5173 
5174 		if (policy->cond_domain) {
5175 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5176 			kfree_data_addr(buffer);
5177 			policy->cond_domain = NULL;
5178 		}
5179 
5180 		if (policy->cond_url) {
5181 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5182 			kfree_data_addr(buffer);
5183 			policy->cond_url = NULL;
5184 		}
5185 
5186 		if (policy->cond_custom_entitlement) {
5187 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5188 			kfree_data_addr(buffer);
5189 			policy->cond_custom_entitlement = NULL;
5190 		}
5191 
5192 		if (policy->cond_signing_identifier) {
5193 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5194 			kfree_data_addr(buffer);
5195 			policy->cond_signing_identifier = NULL;
5196 		}
5197 
5198 		zfree(necp_socket_policy_zone, policy);
5199 		return TRUE;
5200 	}
5201 
5202 	return FALSE;
5203 }
5204 
5205 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5206 __sized_by(MAX_RESULT_STRING_LEN)
5207 necp_get_result_description(char * __sized_by(MAX_RESULT_STRING_LEN) result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5208 {
5209 	uuid_string_t uuid_string;
5210 	switch (result) {
5211 	case NECP_KERNEL_POLICY_RESULT_NONE: {
5212 		snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5213 		break;
5214 	}
5215 	case NECP_KERNEL_POLICY_RESULT_PASS: {
5216 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5217 		break;
5218 	}
5219 	case NECP_KERNEL_POLICY_RESULT_SKIP: {
5220 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5221 		break;
5222 	}
5223 	case NECP_KERNEL_POLICY_RESULT_DROP: {
5224 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5225 		break;
5226 	}
5227 	case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5228 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5229 		break;
5230 	}
5231 	case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5232 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5233 		break;
5234 	}
5235 	case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5236 		ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5237 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5238 		break;
5239 	}
5240 	case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5241 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5242 		break;
5243 	}
5244 	case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5245 		ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5246 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5247 		break;
5248 	}
5249 	case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5250 		snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5251 		break;
5252 	}
5253 	case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5254 		snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5255 		break;
5256 	}
5257 	case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5258 		int index = 0;
5259 		char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5260 		struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5261 		if (route_rule != NULL) {
5262 			for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5263 				if (route_rule->exception_if_indices[index] != 0) {
5264 					ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5265 					snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5266 				} else {
5267 					memset(interface_names[index], 0, IFXNAMSIZ);
5268 				}
5269 			}
5270 			switch (route_rule->default_action) {
5271 			case NECP_ROUTE_RULE_DENY_INTERFACE:
5272 			case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5273 				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%s%s)",
5274 				    (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5275 				    (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5276 				    (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5277 				    (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5278 				    (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5279 				    (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5280 				    (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5281 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5282 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5283 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5284 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5285 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5286 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5287 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5288 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5289 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5290 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5291 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5292 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5293 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5294 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5295 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5296 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5297 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5298 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5299 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5300 				break;
5301 			case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5302 				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%s%s)",
5303 				    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5304 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5305 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5306 				    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5307 				    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5308 				    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5309 				    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5310 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5311 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5312 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5313 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5314 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5315 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5316 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5317 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5318 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5319 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5320 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5321 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5322 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5323 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5324 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5325 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5326 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5327 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5328 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5329 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5330 				break;
5331 			case NECP_ROUTE_RULE_QOS_MARKING:
5332 				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%s%s)",
5333 				    (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5334 				    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5335 				    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5336 				    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5337 				    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5338 				    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5339 				    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5340 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5341 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5342 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5343 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5344 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5345 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5346 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5347 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5348 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5349 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5350 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5351 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5352 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5353 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5354 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5355 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5356 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5357 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5358 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5359 				break;
5360 			default:
5361 				snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5362 				break;
5363 			}
5364 		}
5365 		break;
5366 	}
5367 	case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5368 		bool found_mapping = FALSE;
5369 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5370 		if (mapping != NULL) {
5371 			uuid_unparse(mapping->uuid, uuid_string);
5372 			found_mapping = TRUE;
5373 		}
5374 		snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5375 		break;
5376 	}
5377 	case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5378 		bool found_mapping = FALSE;
5379 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5380 		if (mapping != NULL) {
5381 			uuid_unparse(mapping->uuid, uuid_string);
5382 			found_mapping = TRUE;
5383 		}
5384 		snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5385 		break;
5386 	}
5387 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5388 		bool found_mapping = FALSE;
5389 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5390 		if (mapping != NULL) {
5391 			uuid_unparse(mapping->uuid, uuid_string);
5392 			found_mapping = TRUE;
5393 		}
5394 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5395 		break;
5396 	}
5397 	default: {
5398 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5399 		break;
5400 	}
5401 	}
5402 	return result_string;
5403 }
5404 
5405 static void
necp_kernel_socket_policies_dump_all(void)5406 necp_kernel_socket_policies_dump_all(void)
5407 {
5408 	if (necp_debug) {
5409 		struct necp_kernel_socket_policy *policy = NULL;
5410 		int policy_i;
5411 		int app_i;
5412 		char result_string[MAX_RESULT_STRING_LEN];
5413 		char proc_name_string[MAXCOMLEN + 1];
5414 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
5415 		memset(proc_name_string, 0, MAXCOMLEN + 1);
5416 
5417 		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5418 		NECPLOG0(LOG_DEBUG, "-----------\n");
5419 		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5420 			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5421 			proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5422 			NECPLOG(LOG_DEBUG, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %llx\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));
5423 		}
5424 		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5425 			NECPLOG0(LOG_DEBUG, "-----------\n");
5426 		}
5427 
5428 		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5429 		NECPLOG0(LOG_DEBUG, "-----------\n");
5430 		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5431 			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5432 			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5433 				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5434 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5435 				NECPLOG(LOG_DEBUG, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d\tMask: %llx\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));
5436 			}
5437 			NECPLOG0(LOG_DEBUG, "-----------\n");
5438 		}
5439 	}
5440 }
5441 
5442 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5443 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5444 {
5445 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5446 		// Drop always cancels out lower policies
5447 		return TRUE;
5448 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5449 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5450 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5451 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5452 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5453 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5454 		// Filters and route rules never cancel out lower policies
5455 		return FALSE;
5456 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5457 		if (upper_policy->session_order != lower_policy->session_order) {
5458 			// A skip cannot override a policy of a different session
5459 			return FALSE;
5460 		} else {
5461 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
5462 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5463 				// This policy is beyond the skip
5464 				return FALSE;
5465 			} else {
5466 				// This policy is inside the skip
5467 				return TRUE;
5468 			}
5469 		}
5470 	}
5471 
5472 	// A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5473 	return TRUE;
5474 }
5475 
5476 static bool
necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy * policy,struct necp_kernel_socket_policy ** __indexable policy_array,int valid_indices)5477 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5478 {
5479 	bool can_skip = FALSE;
5480 	u_int32_t highest_skip_session_order = 0;
5481 	u_int32_t highest_skip_order = 0;
5482 	int i;
5483 	for (i = 0; i < valid_indices; i++) {
5484 		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5485 
5486 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
5487 		if (can_skip) {
5488 			if (highest_skip_session_order != compared_policy->session_order ||
5489 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5490 				// If we've moved on to the next session, or passed the skip window
5491 				highest_skip_session_order = 0;
5492 				highest_skip_order = 0;
5493 				can_skip = FALSE;
5494 			} else {
5495 				// If this policy is also a skip, in can increase the skip window
5496 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5497 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5498 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5499 					}
5500 				}
5501 				continue;
5502 			}
5503 		}
5504 
5505 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5506 			// This policy is a skip. Set the skip window accordingly
5507 			can_skip = TRUE;
5508 			highest_skip_session_order = compared_policy->session_order;
5509 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5510 		}
5511 
5512 		// The result of the compared policy must be able to block out this policy result
5513 		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5514 			continue;
5515 		}
5516 
5517 		// If new policy matches All Interfaces, compared policy must also
5518 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5519 			continue;
5520 		}
5521 
5522 		// If new policy matches Local Networks, compared policy must also
5523 		if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5524 		    policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5525 			continue;
5526 		}
5527 
5528 		// Default makes lower policies unecessary always
5529 		if (compared_policy->condition_mask == 0) {
5530 			return TRUE;
5531 		}
5532 
5533 		// Compared must be more general than policy, and include only conditions within policy
5534 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5535 			continue;
5536 		}
5537 
5538 		// Negative conditions must match for the overlapping conditions
5539 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5540 			continue;
5541 		}
5542 
5543 		if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5544 		    compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5545 		    strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5546 			continue;
5547 		}
5548 
5549 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5550 		    compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5551 			continue;
5552 		}
5553 
5554 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5555 		    strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5556 			continue;
5557 		}
5558 
5559 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5560 		    strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5561 			continue;
5562 		}
5563 
5564 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5565 		    compared_policy->cond_account_id != policy->cond_account_id) {
5566 			continue;
5567 		}
5568 
5569 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5570 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
5571 			continue;
5572 		}
5573 
5574 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5575 		    compared_policy->cond_app_id != policy->cond_app_id) {
5576 			continue;
5577 		}
5578 
5579 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5580 		    compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5581 			continue;
5582 		}
5583 
5584 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5585 		    (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5586 			continue;
5587 		}
5588 
5589 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5590 		    compared_policy->cond_uid != policy->cond_uid) {
5591 			continue;
5592 		}
5593 
5594 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5595 		    compared_policy->cond_real_uid != policy->cond_real_uid) {
5596 			continue;
5597 		}
5598 
5599 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5600 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5601 			continue;
5602 		}
5603 
5604 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5605 		    compared_policy->cond_protocol != policy->cond_protocol) {
5606 			continue;
5607 		}
5608 
5609 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5610 		    compared_policy->cond_client_flags != policy->cond_client_flags) {
5611 			continue;
5612 		}
5613 
5614 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5615 		    !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5616 		    compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5617 			continue;
5618 		}
5619 
5620 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5621 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5622 				if (!necp_is_range_in_range(SA(&policy->cond_local_start), SA(&policy->cond_local_end), SA(&compared_policy->cond_local_start), SA(&compared_policy->cond_local_end))) {
5623 					continue;
5624 				}
5625 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5626 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5627 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5628 					continue;
5629 				}
5630 			}
5631 		}
5632 
5633 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5634 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5635 				if (!necp_is_range_in_range(SA(&policy->cond_remote_start), SA(&policy->cond_remote_end), SA(&compared_policy->cond_remote_start), SA(&compared_policy->cond_remote_end))) {
5636 					continue;
5637 				}
5638 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5639 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5640 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5641 					continue;
5642 				}
5643 			}
5644 		}
5645 
5646 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5647 		    memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5648 			continue;
5649 		}
5650 
5651 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5652 		    memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5653 			continue;
5654 		}
5655 
5656 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5657 		    memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5658 			continue;
5659 		}
5660 
5661 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5662 		    memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5663 			continue;
5664 		}
5665 
5666 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5667 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5668 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5669 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5670 			continue;
5671 		}
5672 
5673 		return TRUE;
5674 	}
5675 
5676 	return FALSE;
5677 }
5678 
5679 static bool
necp_kernel_socket_policies_reprocess(void)5680 necp_kernel_socket_policies_reprocess(void)
5681 {
5682 	int app_i;
5683 	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5684 	int app_layer_current_free_index = 0;
5685 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5686 
5687 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5688 
5689 	// Reset mask to 0
5690 	necp_kernel_application_policies_condition_mask = 0;
5691 	necp_kernel_socket_policies_condition_mask = 0;
5692 	necp_kernel_application_policies_count = 0;
5693 	necp_kernel_socket_policies_count = 0;
5694 	necp_kernel_socket_policies_non_app_count = 0;
5695 
5696 	// Reset all maps to NULL
5697 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5698 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5699 			kfree_type(struct necp_kernel_socket_policy *,
5700 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5701 			    necp_kernel_socket_policies_map[app_i]);
5702 			necp_kernel_socket_policies_map[app_i] = NULL;
5703 		}
5704 
5705 		// Init counts
5706 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5707 	}
5708 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5709 		kfree_type(struct necp_kernel_socket_policy *,
5710 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5711 		    necp_kernel_socket_policies_app_layer_map);
5712 	}
5713 	necp_kernel_socket_policies_app_layer_map = NULL;
5714 	necp_kernel_socket_policies_app_layer_map_count = 0;
5715 
5716 	// Create masks and counts
5717 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5718 		// App layer mask/count
5719 		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5720 		necp_kernel_application_policies_count++;
5721 		necp_kernel_socket_policies_app_layer_map_count++;
5722 
5723 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5724 			// Agent type conditions only apply to app layer
5725 			continue;
5726 		}
5727 
5728 		// Update socket layer bucket mask/counts
5729 		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5730 		necp_kernel_socket_policies_count++;
5731 
5732 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5733 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5734 			necp_kernel_socket_policies_non_app_count++;
5735 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5736 				necp_kernel_socket_policies_map_counts[app_i]++;
5737 			}
5738 		} else {
5739 			necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5740 		}
5741 	}
5742 
5743 	// Allocate maps
5744 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5745 		if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5746 			// Allocate a NULL-terminated array of policy pointers for each bucket
5747 			necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5748 			    necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5749 			if (necp_kernel_socket_policies_map[app_i] == NULL) {
5750 				goto fail;
5751 			}
5752 		}
5753 		bucket_current_free_index[app_i] = 0;
5754 	}
5755 	necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5756 	    necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5757 	if (necp_kernel_socket_policies_app_layer_map == NULL) {
5758 		goto fail;
5759 	}
5760 
5761 	// Fill out maps
5762 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5763 		// Add app layer policies
5764 		if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5765 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5766 			app_layer_current_free_index++;
5767 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5768 		}
5769 
5770 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5771 			// Agent type conditions only apply to app layer
5772 			continue;
5773 		}
5774 
5775 		// Add socket policies
5776 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5777 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5778 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5779 				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])) {
5780 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5781 					bucket_current_free_index[app_i]++;
5782 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5783 				}
5784 			}
5785 		} else {
5786 			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5787 			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])) {
5788 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5789 				bucket_current_free_index[app_i]++;
5790 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5791 			}
5792 		}
5793 	}
5794 	necp_kernel_socket_policies_dump_all();
5795 	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5796 	return TRUE;
5797 
5798 fail:
5799 	// Free memory, reset masks to 0
5800 	necp_kernel_application_policies_condition_mask = 0;
5801 	necp_kernel_socket_policies_condition_mask = 0;
5802 	necp_kernel_application_policies_count = 0;
5803 	necp_kernel_socket_policies_count = 0;
5804 	necp_kernel_socket_policies_non_app_count = 0;
5805 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5806 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5807 			kfree_type(struct necp_kernel_socket_policy *,
5808 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5809 			    necp_kernel_socket_policies_map[app_i]);
5810 			necp_kernel_socket_policies_map[app_i] = NULL;
5811 		}
5812 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5813 	}
5814 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5815 		kfree_type(struct necp_kernel_socket_policy *,
5816 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5817 		    necp_kernel_socket_policies_app_layer_map);
5818 		necp_kernel_socket_policies_app_layer_map = NULL;
5819 	}
5820 	necp_kernel_socket_policies_app_layer_map_count = 0;
5821 	return FALSE;
5822 }
5823 
5824 static u_int32_t
necp_get_new_string_id(void)5825 necp_get_new_string_id(void)
5826 {
5827 	static u_int32_t necp_last_string_id = 0;
5828 
5829 	u_int32_t newid = 0;
5830 
5831 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5832 
5833 	bool wrapped = FALSE;
5834 	do {
5835 		necp_last_string_id++;
5836 		if (necp_last_string_id < 1) {
5837 			if (wrapped) {
5838 				// Already wrapped, give up
5839 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5840 				return 0;
5841 			}
5842 			necp_last_string_id = 1;
5843 			wrapped = TRUE;
5844 		}
5845 		newid = necp_last_string_id;
5846 	} while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5847 
5848 	if (newid == 0) {
5849 		NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5850 		return 0;
5851 	}
5852 
5853 	return newid;
5854 }
5855 
5856 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5857 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5858 {
5859 	struct necp_string_id_mapping *searchentry = NULL;
5860 	struct necp_string_id_mapping *foundentry = NULL;
5861 
5862 	LIST_FOREACH(searchentry, list, chain) {
5863 		if (strcmp(searchentry->string, string) == 0) {
5864 			foundentry = searchentry;
5865 			break;
5866 		}
5867 	}
5868 
5869 	return foundentry;
5870 }
5871 
5872 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5873 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5874 {
5875 	struct necp_string_id_mapping *searchentry = NULL;
5876 	struct necp_string_id_mapping *foundentry = NULL;
5877 
5878 	LIST_FOREACH(searchentry, list, chain) {
5879 		if (searchentry->id == local_id) {
5880 			foundentry = searchentry;
5881 			break;
5882 		}
5883 	}
5884 
5885 	return foundentry;
5886 }
5887 
5888 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5889 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5890 {
5891 	u_int32_t string_id = 0;
5892 	struct necp_string_id_mapping *existing_mapping = NULL;
5893 
5894 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5895 
5896 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5897 	if (existing_mapping != NULL) {
5898 		string_id = existing_mapping->id;
5899 		os_ref_retain_locked(&existing_mapping->refcount);
5900 	} else {
5901 		struct necp_string_id_mapping * __single new_mapping = NULL;
5902 		new_mapping = kalloc_type(struct necp_string_id_mapping,
5903 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5904 
5905 		size_t length = strlen(string) + 1;
5906 		char *buffer = kalloc_data(length, Z_WAITOK);
5907 		if (buffer != NULL) {
5908 			strlcpy(buffer, string, length);
5909 			new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5910 			new_mapping->id = necp_get_new_string_id();
5911 			os_ref_init(&new_mapping->refcount, &necp_refgrp);
5912 			LIST_INSERT_HEAD(list, new_mapping, chain);
5913 			string_id = new_mapping->id;
5914 		} else {
5915 			kfree_type(struct necp_string_id_mapping, new_mapping);
5916 			new_mapping = NULL;
5917 		}
5918 	}
5919 	return string_id;
5920 }
5921 
5922 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5923 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5924 {
5925 	struct necp_string_id_mapping * __single existing_mapping = NULL;
5926 	char * __indexable buffer = NULL;
5927 
5928 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5929 
5930 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5931 	if (existing_mapping != NULL) {
5932 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5933 			LIST_REMOVE(existing_mapping, chain);
5934 			buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5935 			kfree_data_addr(buffer);
5936 			kfree_type(struct necp_string_id_mapping, existing_mapping);
5937 		}
5938 		return TRUE;
5939 	}
5940 
5941 	return FALSE;
5942 }
5943 
5944 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5945 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5946 {
5947 	struct necp_domain_filter *searchfilter = NULL;
5948 	struct necp_domain_filter *foundfilter = NULL;
5949 
5950 	LIST_FOREACH(searchfilter, list, chain) {
5951 		if (searchfilter->id == filter_id) {
5952 			foundfilter = searchfilter;
5953 			break;
5954 		}
5955 	}
5956 
5957 	return foundfilter;
5958 }
5959 
5960 static u_int32_t
necp_get_new_domain_filter_id(void)5961 necp_get_new_domain_filter_id(void)
5962 {
5963 	static u_int32_t necp_last_filter_id = 0;
5964 
5965 	u_int32_t newid = 0;
5966 
5967 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5968 
5969 	bool wrapped = FALSE;
5970 	do {
5971 		// Scope id within its space
5972 		if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5973 			necp_last_filter_id = 0;
5974 		}
5975 		if (necp_last_filter_id < 1) {
5976 			if (wrapped) {
5977 				// Already wrapped, give up
5978 				NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5979 				return 0;
5980 			}
5981 			necp_last_filter_id = 1;
5982 			wrapped = TRUE;
5983 		}
5984 		newid = necp_last_filter_id;
5985 	} while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5986 
5987 	if (newid == 0) {
5988 		NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5989 		return 0;
5990 	}
5991 
5992 	return newid;
5993 }
5994 
5995 static u_int32_t
necp_create_domain_filter(struct necp_domain_filter_list * list,struct necp_domain_filter_list * owner_list,struct net_bloom_filter * filter)5996 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5997 {
5998 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5999 
6000 	struct necp_domain_filter *new_filter = NULL;
6001 	new_filter = kalloc_type(struct necp_domain_filter,
6002 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6003 
6004 	new_filter->filter = filter;
6005 	new_filter->id = necp_get_new_domain_filter_id();
6006 	LIST_INSERT_HEAD(list, new_filter, chain);
6007 	LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
6008 	os_ref_init(&new_filter->refcount, &necp_refgrp);
6009 
6010 	return new_filter->id;
6011 }
6012 
6013 static bool
necp_remove_domain_filter(struct necp_domain_filter_list * list,__unused struct necp_domain_filter_list * owner_list,u_int32_t filter_id)6014 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
6015 {
6016 	struct necp_domain_filter * __single existing_filter = NULL;
6017 
6018 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6019 
6020 	existing_filter = necp_lookup_domain_filter(list, filter_id);
6021 	if (existing_filter != NULL) {
6022 		if (os_ref_release_locked(&existing_filter->refcount) == 0) {
6023 			LIST_REMOVE(existing_filter, chain);
6024 			LIST_REMOVE(existing_filter, owner_chain);
6025 			net_bloom_filter_destroy(existing_filter->filter);
6026 			kfree_type(struct necp_domain_filter, existing_filter);
6027 		}
6028 		return true;
6029 	}
6030 
6031 	return false;
6032 }
6033 
6034 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6035 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6036 {
6037 	struct necp_domain_trie *searchTrie = NULL;
6038 	struct necp_domain_trie *foundTrie = NULL;
6039 
6040 	LIST_FOREACH(searchTrie, list, chain) {
6041 		if (searchTrie->id == id) {
6042 			foundTrie = searchTrie;
6043 			break;
6044 		}
6045 	}
6046 
6047 	return foundTrie;
6048 }
6049 
6050 static u_int32_t
necp_get_new_domain_trie_id(void)6051 necp_get_new_domain_trie_id(void)
6052 {
6053 	static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6054 	u_int32_t newid = necp_last_trie_id;
6055 
6056 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6057 
6058 	bool wrapped = FALSE;
6059 	do {
6060 		if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6061 			if (wrapped) {
6062 				// Already wrapped, give up
6063 				NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6064 				return 0;
6065 			}
6066 			necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6067 			wrapped = TRUE;
6068 		}
6069 		newid = necp_last_trie_id;
6070 	} while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6071 
6072 	if (newid == NECP_DOMAIN_TRIE_ID_START) {
6073 		NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6074 		return 0;
6075 	}
6076 
6077 	return newid;
6078 }
6079 
6080 static u_int32_t
necp_create_domain_trie(struct necp_domain_trie_list * list,struct necp_domain_trie_list * owner_list,struct necp_domain_trie_request * trie_request,size_t trie_request_size)6081 necp_create_domain_trie(struct necp_domain_trie_list *list,
6082     struct necp_domain_trie_list *owner_list,
6083     struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6084 {
6085 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6086 
6087 	struct necp_domain_trie *new_trie = NULL;
6088 	new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6089 	if (new_trie == NULL) {
6090 		NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6091 		return 0;
6092 	}
6093 
6094 	if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6095 	    trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6096 	    trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6097 		NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6098 		kfree_type(struct necp_domain_trie, new_trie);
6099 		return 0;
6100 	}
6101 	new_trie->trie_request = trie_request;
6102 	new_trie->trie_request_size = trie_request_size;
6103 	new_trie->id = necp_get_new_domain_trie_id();
6104 	new_trie->trie_request->id = new_trie->id;
6105 	LIST_INSERT_HEAD(list, new_trie, chain);
6106 	LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6107 
6108 	os_ref_init(&new_trie->refcount, &necp_refgrp);
6109 	necp_trie_count++;
6110 	return new_trie->id;
6111 }
6112 
6113 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6114 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6115 {
6116 	if (existing_trie != NULL) {
6117 		uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6118 		kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6119 		kfree_type(struct necp_domain_trie, existing_trie);
6120 	}
6121 }
6122 
6123 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6124 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6125 {
6126 	struct necp_domain_trie * __single existing_trie = NULL;
6127 
6128 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6129 
6130 	existing_trie = necp_lookup_domain_trie(list, id);
6131 	if (existing_trie != NULL) {
6132 		if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6133 			LIST_REMOVE(existing_trie, chain);
6134 			LIST_REMOVE(existing_trie, owner_chain);
6135 			necp_free_domain_trie(existing_trie);
6136 			necp_trie_count--;
6137 		}
6138 		return true;
6139 	}
6140 
6141 	return false;
6142 }
6143 
6144 static Boolean
necp_match_domain_with_trie(struct necp_domain_trie_list * list,u_int32_t id,char * __sized_by (length)domain,size_t length)6145 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6146 {
6147 	size_t metadata_length = 0;
6148 	const uint8_t * __sized_by(metadata_length) metadata = NULL;
6149 
6150 	struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6151 	if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6152 		return false;
6153 	}
6154 	Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6155 	Boolean allow_partial_match  = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6156 	return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6157 	           &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6158 }
6159 
6160 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6161 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6162 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6163 necp_get_new_route_rule_id(bool aggregate)
6164 {
6165 	static u_int32_t necp_last_route_rule_id = 0;
6166 	static u_int32_t necp_last_aggregate_route_rule_id = 0;
6167 
6168 	u_int32_t newid = 0;
6169 
6170 	if (!aggregate) {
6171 		// Main necp_kernel_policy_lock protects non-aggregate rule IDs
6172 		LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6173 
6174 		bool wrapped = FALSE;
6175 		do {
6176 			necp_last_route_rule_id++;
6177 			if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6178 			    necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6179 				if (wrapped) {
6180 					// Already wrapped, give up
6181 					NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6182 					return 0;
6183 				}
6184 				necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6185 				wrapped = TRUE;
6186 			}
6187 			newid = necp_last_route_rule_id;
6188 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6189 	} else {
6190 		// necp_route_rule_lock protects aggregate rule IDs
6191 		LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6192 
6193 		bool wrapped = FALSE;
6194 		do {
6195 			necp_last_aggregate_route_rule_id++;
6196 			if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6197 				if (wrapped) {
6198 					// Already wrapped, give up
6199 					NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6200 					return 0;
6201 				}
6202 				necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6203 				wrapped = TRUE;
6204 			}
6205 			newid = necp_last_aggregate_route_rule_id;
6206 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6207 	}
6208 
6209 	if (newid == 0) {
6210 		NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6211 		return 0;
6212 	}
6213 
6214 	return newid;
6215 }
6216 
6217 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6218 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6219 {
6220 	struct necp_route_rule *searchentry = NULL;
6221 	struct necp_route_rule *foundentry = NULL;
6222 
6223 	LIST_FOREACH(searchentry, list, chain) {
6224 		if (searchentry->id == route_rule_id) {
6225 			foundentry = searchentry;
6226 			break;
6227 		}
6228 	}
6229 
6230 	return foundentry;
6231 }
6232 
6233 static struct necp_route_rule *
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_int8_t companion_action,u_int8_t vpn_action,u_int32_t * __indexable if_indices,u_int8_t * __indexable if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit,u_int32_t effective_type)6234 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_int8_t companion_action, u_int8_t vpn_action, u_int32_t * __indexable if_indices, u_int8_t * __indexable if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
6235 {
6236 	struct necp_route_rule *searchentry = NULL;
6237 	struct necp_route_rule *foundentry = NULL;
6238 
6239 	LIST_FOREACH(searchentry, list, chain) {
6240 		if (searchentry->default_action == default_action &&
6241 		    searchentry->cellular_action == cellular_action &&
6242 		    searchentry->wifi_action == wifi_action &&
6243 		    searchentry->wired_action == wired_action &&
6244 		    searchentry->expensive_action == expensive_action &&
6245 		    searchentry->constrained_action == constrained_action &&
6246 		    searchentry->companion_action == companion_action &&
6247 		    searchentry->vpn_action == vpn_action &&
6248 		    searchentry->control_unit == control_unit &&
6249 		    searchentry->effective_type == effective_type) {
6250 			bool match_failed = FALSE;
6251 			size_t index_a = 0;
6252 			size_t index_b = 0;
6253 			size_t count_a = 0;
6254 			size_t count_b = 0;
6255 			for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6256 				bool found_index = FALSE;
6257 				if (searchentry->exception_if_indices[index_a] == 0) {
6258 					break;
6259 				}
6260 				count_a++;
6261 				for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6262 					if (if_indices[index_b] == 0) {
6263 						break;
6264 					}
6265 					if (index_b >= count_b) {
6266 						count_b = index_b + 1;
6267 					}
6268 					if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6269 					    searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6270 						found_index = TRUE;
6271 						break;
6272 					}
6273 				}
6274 				if (!found_index) {
6275 					match_failed = TRUE;
6276 					break;
6277 				}
6278 			}
6279 
6280 			if (match_failed || count_a != count_b) {
6281 				continue;
6282 			}
6283 
6284 			bool has_agent_a = !uuid_is_null(netagent_uuid);
6285 			bool has_agent_b = (searchentry->netagent_id != 0);
6286 			if (has_agent_a != has_agent_b) {
6287 				continue;
6288 			}
6289 
6290 			if (has_agent_a) {
6291 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
6292 				if (mapping == NULL) {
6293 					// Bad mapping, doesn't match
6294 					continue;
6295 				}
6296 				if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6297 					// UUIDs don't match
6298 					continue;
6299 				}
6300 			}
6301 
6302 			bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6303 			bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6304 			if (has_match_agent_a != has_match_agent_b) {
6305 				continue;
6306 			}
6307 
6308 			if (has_match_agent_a) {
6309 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
6310 				if (mapping == NULL) {
6311 					// Bad mapping, doesn't match
6312 					continue;
6313 				}
6314 				if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6315 					// UUIDs don't match
6316 					continue;
6317 				}
6318 			}
6319 
6320 			// Rules match!
6321 			foundentry = searchentry;
6322 			break;
6323 		}
6324 	}
6325 
6326 	return foundentry;
6327 }
6328 
6329 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list * list,u_int8_t * __sized_by (route_rules_array_size)route_rules_array,u_int32_t route_rules_array_size,bool * has_socket_only_actions)6330 necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size,
6331     bool *has_socket_only_actions)
6332 {
6333 	size_t offset = 0;
6334 	u_int32_t route_rule_id = 0;
6335 	struct necp_route_rule *existing_rule = NULL;
6336 	u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6337 	u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6338 	u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6339 	u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6340 	u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6341 	u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6342 	u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6343 	u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6344 	u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6345 	size_t num_valid_indices = 0;
6346 	memset(&if_indices, 0, sizeof(if_indices));
6347 	u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6348 	memset(&if_actions, 0, sizeof(if_actions));
6349 
6350 	uuid_t netagent_uuid = {};
6351 
6352 	uuid_t match_netagent_uuid = {};
6353 	uint32_t control_unit = 0;
6354 	uint32_t effective_type = 0;
6355 
6356 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6357 
6358 	if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6359 		return 0;
6360 	}
6361 
6362 	// Process rules
6363 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6364 		ifnet_t __single rule_interface = NULL;
6365 		char interface_name[IFXNAMSIZ];
6366 		u_int32_t length = 0;
6367 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6368 
6369 		if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6370 			// Invalid TLV goes beyond end of the rules array
6371 			break;
6372 		}
6373 
6374 		// Increment offset for the next time through the loop
6375 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6376 
6377 		u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6378 		u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6379 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6380 		u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6381 
6382 		if (rule_action == NECP_ROUTE_RULE_NONE) {
6383 			// Don't allow an explicit rule to be None action
6384 			continue;
6385 		}
6386 
6387 		if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6388 		    rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6389 			if (rule_length < sizeof(uuid_t)) {
6390 				// Too short, skip
6391 				continue;
6392 			}
6393 
6394 			if (!uuid_is_null(netagent_uuid)) {
6395 				if (uuid_compare(netagent_uuid, rule_value) != 0) {
6396 					// UUIDs don't match, skip
6397 					continue;
6398 				}
6399 			} else {
6400 				// Copy out agent UUID
6401 				memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6402 			}
6403 
6404 			// Adjust remaining length
6405 			rule_value += sizeof(netagent_uuid);
6406 			rule_length -= sizeof(netagent_uuid);
6407 			*has_socket_only_actions = true;
6408 		} else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6409 			if (rule_length < sizeof(control_unit)) {
6410 				// Too short, skip
6411 				continue;
6412 			}
6413 
6414 			memcpy(&control_unit, rule_value, sizeof(control_unit));
6415 
6416 			// Adjust remaining length
6417 			rule_value += sizeof(control_unit);
6418 			rule_length -= sizeof(control_unit);
6419 			*has_socket_only_actions = true;
6420 		} else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6421 			if (rule_length < sizeof(effective_type)) {
6422 				// Too short, skip
6423 				continue;
6424 			}
6425 
6426 			memcpy(&effective_type, rule_value, sizeof(effective_type));
6427 
6428 			// Adjust remaining length
6429 			rule_value += sizeof(effective_type);
6430 			rule_length -= sizeof(effective_type);
6431 		}
6432 
6433 		if (rule_length == 0) {
6434 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6435 				cellular_action = rule_action;
6436 			}
6437 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6438 				wifi_action = rule_action;
6439 			}
6440 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6441 				wired_action = rule_action;
6442 			}
6443 			if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6444 				expensive_action = rule_action;
6445 			}
6446 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6447 				constrained_action = rule_action;
6448 			}
6449 			if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6450 				companion_action = rule_action;
6451 			}
6452 			if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6453 				vpn_action = rule_action;
6454 			}
6455 			if (rule_flags == 0) {
6456 				default_action = rule_action;
6457 			}
6458 			continue;
6459 		} else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6460 			if (rule_length < sizeof(uuid_t)) {
6461 				// Too short, skip
6462 				continue;
6463 			}
6464 
6465 			// Store the netagent UUID to match
6466 			memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6467 			// If the data is exactly a UUID, this is the default action
6468 			if (rule_length == sizeof(uuid_t)) {
6469 				default_action = rule_action;
6470 				continue;
6471 			}
6472 
6473 			// If the data is longer than a UUID, this also includes an interface name
6474 			// Adjust remaining length to make sure the interface name is picked up below
6475 			rule_value += sizeof(uuid_t);
6476 			rule_length -= sizeof(uuid_t);
6477 		}
6478 
6479 		if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6480 			continue;
6481 		}
6482 
6483 		if (rule_length <= IFXNAMSIZ) {
6484 			memcpy(interface_name, rule_value, rule_length);
6485 			interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6486 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6487 				if_actions[num_valid_indices] = rule_action;
6488 				if_indices[num_valid_indices++] = rule_interface->if_index;
6489 				ifnet_release(rule_interface);
6490 			}
6491 		}
6492 	}
6493 
6494 	existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, vpn_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6495 	if (existing_rule != NULL) {
6496 		route_rule_id = existing_rule->id;
6497 		os_ref_retain_locked(&existing_rule->refcount);
6498 	} else {
6499 		struct necp_route_rule *new_rule = NULL;
6500 		new_rule = kalloc_type(struct necp_route_rule,
6501 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6502 		route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6503 		if (!uuid_is_null(netagent_uuid)) {
6504 			new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6505 		}
6506 		if (!uuid_is_null(match_netagent_uuid)) {
6507 			new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6508 		}
6509 		new_rule->effective_type = effective_type;
6510 		new_rule->control_unit = control_unit;
6511 		new_rule->default_action = default_action;
6512 		new_rule->cellular_action = cellular_action;
6513 		new_rule->wifi_action = wifi_action;
6514 		new_rule->wired_action = wired_action;
6515 		new_rule->expensive_action = expensive_action;
6516 		new_rule->constrained_action =  constrained_action;
6517 		new_rule->companion_action =  companion_action;
6518 		new_rule->vpn_action =  vpn_action;
6519 		memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6520 		memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6521 		os_ref_init(&new_rule->refcount, &necp_refgrp);
6522 		LIST_INSERT_HEAD(list, new_rule, chain);
6523 	}
6524 	return route_rule_id;
6525 }
6526 
6527 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6528 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6529 {
6530 	if (rule_id) {
6531 		lck_rw_lock_exclusive(&necp_route_rule_lock);
6532 
6533 		struct necp_aggregate_route_rule * __single existing_rule = NULL;
6534 		struct necp_aggregate_route_rule *tmp_rule = NULL;
6535 
6536 		LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6537 			int index = 0;
6538 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6539 				u_int32_t route_rule_id = existing_rule->rule_ids[index];
6540 				if (route_rule_id == rule_id) {
6541 					LIST_REMOVE(existing_rule, chain);
6542 					kfree_type(struct necp_aggregate_route_rule, existing_rule);
6543 					break;
6544 				}
6545 			}
6546 		}
6547 
6548 		lck_rw_done(&necp_route_rule_lock);
6549 	}
6550 }
6551 
6552 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6553 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6554 {
6555 	struct necp_route_rule * __single existing_rule = NULL;
6556 
6557 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6558 
6559 	existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6560 	if (existing_rule != NULL) {
6561 		if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6562 			necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6563 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6564 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6565 			LIST_REMOVE(existing_rule, chain);
6566 			kfree_type(struct necp_route_rule, existing_rule);
6567 		}
6568 		return TRUE;
6569 	}
6570 
6571 	return FALSE;
6572 }
6573 
6574 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6575 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6576 {
6577 	struct necp_aggregate_route_rule *searchentry = NULL;
6578 	struct necp_aggregate_route_rule *foundentry = NULL;
6579 
6580 	lck_rw_lock_shared(&necp_route_rule_lock);
6581 
6582 	LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6583 		if (searchentry->id == route_rule_id) {
6584 			foundentry = searchentry;
6585 			break;
6586 		}
6587 	}
6588 
6589 	lck_rw_done(&necp_route_rule_lock);
6590 
6591 	return foundentry;
6592 }
6593 
6594 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6595 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6596 {
6597 	u_int32_t aggregate_route_rule_id = 0;
6598 	struct necp_aggregate_route_rule *new_rule = NULL;
6599 	struct necp_aggregate_route_rule *existing_rule = NULL;
6600 
6601 	lck_rw_lock_exclusive(&necp_route_rule_lock);
6602 
6603 	// Check if the rule already exists
6604 	LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6605 		if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6606 			lck_rw_done(&necp_route_rule_lock);
6607 			return existing_rule->id;
6608 		}
6609 	}
6610 
6611 	new_rule = kalloc_type(struct necp_aggregate_route_rule,
6612 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6613 	aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6614 	new_rule->id = aggregate_route_rule_id;
6615 	memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6616 	LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6617 	lck_rw_done(&necp_route_rule_lock);
6618 
6619 	return aggregate_route_rule_id;
6620 }
6621 
6622 #define NECP_NULL_SERVICE_ID 1
6623 #define NECP_FIRST_VALID_SERVICE_ID  2
6624 #define NECP_FIRST_VALID_APP_ID  UINT16_MAX
6625 static u_int32_t
necp_get_new_uuid_id(bool service)6626 necp_get_new_uuid_id(bool service)
6627 {
6628 	static u_int32_t necp_last_service_uuid_id = 0;
6629 	static u_int32_t necp_last_app_uuid_id = 0;
6630 
6631 	u_int32_t newid = 0;
6632 
6633 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6634 
6635 	if (service) {
6636 		bool wrapped = FALSE;
6637 		do {
6638 			necp_last_service_uuid_id++;
6639 			if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6640 			    necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6641 				if (wrapped) {
6642 					// Already wrapped, give up
6643 					NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6644 					return NECP_NULL_SERVICE_ID;
6645 				}
6646 				necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6647 				wrapped = TRUE;
6648 			}
6649 			newid = necp_last_service_uuid_id;
6650 		} while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6651 	} else {
6652 		bool wrapped = FALSE;
6653 		do {
6654 			necp_last_app_uuid_id++;
6655 			if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6656 				if (wrapped) {
6657 					// Already wrapped, give up
6658 					NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6659 					return NECP_NULL_SERVICE_ID;
6660 				}
6661 				necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6662 				wrapped = TRUE;
6663 			}
6664 			newid = necp_last_app_uuid_id;
6665 		} while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6666 	}
6667 
6668 	if (newid == NECP_NULL_SERVICE_ID) {
6669 		NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6670 		return NECP_NULL_SERVICE_ID;
6671 	}
6672 
6673 	return newid;
6674 }
6675 
6676 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6677 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6678 {
6679 	struct necp_uuid_id_mapping *searchentry = NULL;
6680 	struct necp_uuid_id_mapping *foundentry = NULL;
6681 
6682 	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6683 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6684 			foundentry = searchentry;
6685 			break;
6686 		}
6687 	}
6688 
6689 	return foundentry;
6690 }
6691 
6692 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6693 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6694 {
6695 	struct necp_uuid_id_mapping *searchentry = NULL;
6696 	struct necp_uuid_id_mapping *foundentry = NULL;
6697 
6698 	struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6699 	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--) {
6700 		LIST_FOREACH(searchentry, uuid_list_head, chain) {
6701 			if (searchentry->id == local_id) {
6702 				foundentry = searchentry;
6703 				break;
6704 			}
6705 		}
6706 	}
6707 
6708 	return foundentry;
6709 }
6710 
6711 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6712 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6713 {
6714 	u_int32_t local_id = 0;
6715 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6716 
6717 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6718 
6719 	if (allocated_mapping) {
6720 		*allocated_mapping = FALSE;
6721 	}
6722 
6723 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6724 	if (existing_mapping != NULL) {
6725 		local_id = existing_mapping->id;
6726 		os_ref_retain_locked(&existing_mapping->refcount);
6727 		if (uuid_policy_table) {
6728 			existing_mapping->table_usecount++;
6729 		}
6730 	} else {
6731 		struct necp_uuid_id_mapping *new_mapping = NULL;
6732 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6733 		    Z_WAITOK | Z_NOFAIL);
6734 		uuid_copy(new_mapping->uuid, uuid);
6735 		new_mapping->id = necp_get_new_uuid_id(false);
6736 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6737 		if (uuid_policy_table) {
6738 			new_mapping->table_usecount = 1;
6739 		} else {
6740 			new_mapping->table_usecount = 0;
6741 		}
6742 
6743 		LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6744 
6745 		if (allocated_mapping) {
6746 			*allocated_mapping = TRUE;
6747 		}
6748 
6749 		local_id = new_mapping->id;
6750 	}
6751 
6752 	return local_id;
6753 }
6754 
6755 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6756 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6757 {
6758 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6759 
6760 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6761 
6762 	if (removed_mapping) {
6763 		*removed_mapping = FALSE;
6764 	}
6765 
6766 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6767 	if (existing_mapping != NULL) {
6768 		if (uuid_policy_table) {
6769 			existing_mapping->table_usecount--;
6770 		}
6771 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6772 			LIST_REMOVE(existing_mapping, chain);
6773 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6774 			if (removed_mapping) {
6775 				*removed_mapping = TRUE;
6776 			}
6777 		}
6778 		return TRUE;
6779 	}
6780 
6781 	return FALSE;
6782 }
6783 
6784 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6785 necp_uuid_get_null_service_id_mapping(void)
6786 {
6787 	static struct necp_uuid_id_mapping null_mapping;
6788 	uuid_clear(null_mapping.uuid);
6789 	null_mapping.id = NECP_NULL_SERVICE_ID;
6790 
6791 	return &null_mapping;
6792 }
6793 
6794 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6795 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6796 {
6797 	struct necp_uuid_id_mapping *searchentry = NULL;
6798 	struct necp_uuid_id_mapping *foundentry = NULL;
6799 
6800 	if (uuid_is_null(uuid)) {
6801 		return necp_uuid_get_null_service_id_mapping();
6802 	}
6803 
6804 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6805 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6806 			foundentry = searchentry;
6807 			break;
6808 		}
6809 	}
6810 
6811 	return foundentry;
6812 }
6813 
6814 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6815 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6816 {
6817 	struct necp_uuid_id_mapping *searchentry = NULL;
6818 	struct necp_uuid_id_mapping *foundentry = NULL;
6819 
6820 	if (local_id == NECP_NULL_SERVICE_ID) {
6821 		return necp_uuid_get_null_service_id_mapping();
6822 	}
6823 
6824 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6825 		if (searchentry->id == local_id) {
6826 			foundentry = searchentry;
6827 			break;
6828 		}
6829 	}
6830 
6831 	return foundentry;
6832 }
6833 
6834 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6835 necp_create_uuid_service_id_mapping(uuid_t uuid)
6836 {
6837 	u_int32_t local_id = 0;
6838 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6839 
6840 	if (uuid_is_null(uuid)) {
6841 		return NECP_NULL_SERVICE_ID;
6842 	}
6843 
6844 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6845 
6846 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6847 	if (existing_mapping != NULL) {
6848 		local_id = existing_mapping->id;
6849 		os_ref_retain_locked(&existing_mapping->refcount);
6850 	} else {
6851 		struct necp_uuid_id_mapping *new_mapping = NULL;
6852 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6853 		    Z_WAITOK | Z_NOFAIL);
6854 		uuid_copy(new_mapping->uuid, uuid);
6855 		new_mapping->id = necp_get_new_uuid_id(true);
6856 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6857 
6858 		LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6859 
6860 		local_id = new_mapping->id;
6861 	}
6862 
6863 	return local_id;
6864 }
6865 
6866 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6867 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6868 {
6869 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6870 
6871 	if (uuid_is_null(uuid)) {
6872 		return TRUE;
6873 	}
6874 
6875 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6876 
6877 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6878 	if (existing_mapping != NULL) {
6879 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6880 			LIST_REMOVE(existing_mapping, chain);
6881 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6882 		}
6883 		return TRUE;
6884 	}
6885 
6886 	return FALSE;
6887 }
6888 
6889 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6890 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6891 {
6892 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6893 
6894 	if (service_id == 0) {
6895 		return TRUE;
6896 	}
6897 
6898 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6899 
6900 	existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6901 	if (existing_mapping != NULL) {
6902 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6903 			LIST_REMOVE(existing_mapping, chain);
6904 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6905 		}
6906 		return TRUE;
6907 	}
6908 
6909 	return FALSE;
6910 }
6911 
6912 static bool
necp_kernel_socket_policies_update_uuid_table(void)6913 necp_kernel_socket_policies_update_uuid_table(void)
6914 {
6915 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6916 
6917 	if (necp_uuid_app_id_mappings_dirty) {
6918 		uuid_t dummy_uuid = {};
6919 		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6920 			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6921 			return FALSE;
6922 		}
6923 
6924 		if (necp_num_uuid_app_id_mappings > 0) {
6925 			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6926 			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--) {
6927 				struct necp_uuid_id_mapping *mapping = NULL;
6928 				LIST_FOREACH(mapping, uuid_list_head, chain) {
6929 					if (mapping->table_usecount > 0 &&
6930 					    proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6931 						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6932 					}
6933 				}
6934 			}
6935 		}
6936 
6937 		necp_uuid_app_id_mappings_dirty = FALSE;
6938 	}
6939 
6940 	return TRUE;
6941 }
6942 
6943 #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 | NECP_KERNEL_CONDITION_SCHEME_PORT | NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)
6944 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_int64_t condition_mask,u_int64_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,u_int16_t cond_scheme_port,u_int32_t cond_bound_interface_flags,u_int32_t cond_bound_interface_eflags,u_int32_t cond_bound_interface_xflags,u_int8_t cond_local_networks_flags,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)6945 necp_kernel_ip_output_policy_add(necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_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, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6946 {
6947 	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6948 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6949 
6950 	new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6951 	new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6952 	new_kernel_policy->suborder = suborder;
6953 	new_kernel_policy->order = order;
6954 	new_kernel_policy->session_order = session_order;
6955 	new_kernel_policy->session_pid = session_pid;
6956 
6957 	// Sanitize condition mask
6958 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6959 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6960 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6961 	}
6962 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6963 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6964 	}
6965 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6966 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6967 	}
6968 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6969 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6970 	}
6971 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6972 
6973 	// Set condition values
6974 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6975 		new_kernel_policy->cond_policy_id = cond_policy_id;
6976 	}
6977 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6978 		if (cond_bound_interface) {
6979 			ifnet_reference(cond_bound_interface);
6980 		}
6981 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
6982 	}
6983 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6984 		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6985 	}
6986 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6987 		new_kernel_policy->cond_protocol = cond_protocol;
6988 	}
6989 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6990 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6991 	}
6992 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6993 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6994 	}
6995 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6996 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
6997 	}
6998 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6999 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
7000 	}
7001 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7002 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7003 	}
7004 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7005 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7006 	}
7007 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7008 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7009 	}
7010 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7011 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
7012 	}
7013 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7014 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7015 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7016 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7017 	}
7018 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7019 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7020 	}
7021 
7022 	new_kernel_policy->result = result;
7023 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7024 
7025 	if (necp_debug) {
7026 		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7027 	}
7028 	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7029 
7030 	return new_kernel_policy ? new_kernel_policy->id : 0;
7031 }
7032 
7033 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7034 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7035 {
7036 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7037 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7038 
7039 	if (policy_id == 0) {
7040 		return NULL;
7041 	}
7042 
7043 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7044 		if (kernel_policy->id == policy_id) {
7045 			return kernel_policy;
7046 		}
7047 	}
7048 
7049 	return NULL;
7050 }
7051 
7052 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7053 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7054 {
7055 	struct necp_kernel_ip_output_policy * __single policy = NULL;
7056 
7057 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7058 
7059 	policy = necp_kernel_ip_output_policy_find(policy_id);
7060 	if (policy) {
7061 		LIST_REMOVE(policy, chain);
7062 
7063 		if (policy->cond_bound_interface) {
7064 			ifnet_release(policy->cond_bound_interface);
7065 			policy->cond_bound_interface = NULL;
7066 		}
7067 
7068 		zfree(necp_ip_policy_zone, policy);
7069 		return TRUE;
7070 	}
7071 
7072 	return FALSE;
7073 }
7074 
7075 static void
necp_kernel_ip_output_policies_dump_all(void)7076 necp_kernel_ip_output_policies_dump_all(void)
7077 {
7078 	if (necp_debug) {
7079 		struct necp_kernel_ip_output_policy *policy = NULL;
7080 		int policy_i;
7081 		int id_i;
7082 		char result_string[MAX_RESULT_STRING_LEN];
7083 		char proc_name_string[MAXCOMLEN + 1];
7084 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
7085 		memset(proc_name_string, 0, MAXCOMLEN + 1);
7086 
7087 		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7088 		NECPLOG0(LOG_DEBUG, "-----------\n");
7089 		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7090 			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7091 			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++) {
7092 				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7093 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7094 				NECPLOG(LOG_DEBUG, "\t%3d. Policy ID: %5d\tProcess: %10.10s\tOrder: %04d.%04d.%d\tMask: %llx\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));
7095 			}
7096 			NECPLOG0(LOG_DEBUG, "-----------\n");
7097 		}
7098 	}
7099 }
7100 
7101 static inline bool
necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy * upper_policy,struct necp_kernel_ip_output_policy * lower_policy)7102 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7103 {
7104 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7105 		if (upper_policy->session_order != lower_policy->session_order) {
7106 			// A skip cannot override a policy of a different session
7107 			return FALSE;
7108 		} else {
7109 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
7110 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7111 				// This policy is beyond the skip
7112 				return FALSE;
7113 			} else {
7114 				// This policy is inside the skip
7115 				return TRUE;
7116 			}
7117 		}
7118 	}
7119 
7120 	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7121 	return TRUE;
7122 }
7123 
7124 static bool
necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy * policy,struct necp_kernel_ip_output_policy ** __indexable policy_array,int valid_indices)7125 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy ** __indexable policy_array, int valid_indices)
7126 {
7127 	bool can_skip = FALSE;
7128 	u_int32_t highest_skip_session_order = 0;
7129 	u_int32_t highest_skip_order = 0;
7130 	int i;
7131 	for (i = 0; i < valid_indices; i++) {
7132 		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7133 
7134 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
7135 		if (can_skip) {
7136 			if (highest_skip_session_order != compared_policy->session_order ||
7137 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7138 				// If we've moved on to the next session, or passed the skip window
7139 				highest_skip_session_order = 0;
7140 				highest_skip_order = 0;
7141 				can_skip = FALSE;
7142 			} else {
7143 				// If this policy is also a skip, in can increase the skip window
7144 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7145 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7146 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7147 					}
7148 				}
7149 				continue;
7150 			}
7151 		}
7152 
7153 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7154 			// This policy is a skip. Set the skip window accordingly
7155 			can_skip = TRUE;
7156 			highest_skip_session_order = compared_policy->session_order;
7157 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7158 		}
7159 
7160 		// The result of the compared policy must be able to block out this policy result
7161 		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7162 			continue;
7163 		}
7164 
7165 		// If new policy matches All Interfaces, compared policy must also
7166 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7167 			continue;
7168 		}
7169 
7170 		// If new policy matches Local Networks, compared policy must also
7171 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7172 			continue;
7173 		}
7174 
7175 		// Default makes lower policies unnecessary always
7176 		if (compared_policy->condition_mask == 0) {
7177 			return TRUE;
7178 		}
7179 
7180 		// Compared must be more general than policy, and include only conditions within policy
7181 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7182 			continue;
7183 		}
7184 
7185 		// Negative conditions must match for the overlapping conditions
7186 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7187 			continue;
7188 		}
7189 
7190 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7191 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
7192 			continue;
7193 		}
7194 
7195 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7196 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7197 			continue;
7198 		}
7199 
7200 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7201 		    compared_policy->cond_protocol != policy->cond_protocol) {
7202 			continue;
7203 		}
7204 
7205 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7206 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7207 				if (!necp_is_range_in_range(SA(&policy->cond_local_start), SA(&policy->cond_local_end), SA(&compared_policy->cond_local_start), SA(&compared_policy->cond_local_end))) {
7208 					continue;
7209 				}
7210 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7211 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7212 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7213 					continue;
7214 				}
7215 			}
7216 		}
7217 
7218 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7219 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7220 				if (!necp_is_range_in_range(SA(&policy->cond_remote_start), SA(&policy->cond_remote_end), SA(&compared_policy->cond_remote_start), SA(&compared_policy->cond_remote_end))) {
7221 					continue;
7222 				}
7223 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7224 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7225 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7226 					continue;
7227 				}
7228 			}
7229 		}
7230 
7231 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7232 		    compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7233 			continue;
7234 		}
7235 
7236 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7237 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7238 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7239 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7240 			continue;
7241 		}
7242 
7243 		return TRUE;
7244 	}
7245 
7246 	return FALSE;
7247 }
7248 
7249 static bool
necp_kernel_ip_output_policies_reprocess(void)7250 necp_kernel_ip_output_policies_reprocess(void)
7251 {
7252 	int i;
7253 	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7254 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7255 
7256 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7257 
7258 	// Reset mask to 0
7259 	necp_kernel_ip_output_policies_condition_mask = 0;
7260 	necp_kernel_ip_output_policies_count = 0;
7261 	necp_kernel_ip_output_policies_non_id_count = 0;
7262 
7263 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7264 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7265 			kfree_type(struct necp_kernel_ip_output_policy *,
7266 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7267 			    necp_kernel_ip_output_policies_map[i]);
7268 			necp_kernel_ip_output_policies_map[i] = NULL;
7269 		}
7270 
7271 		// Init counts
7272 		necp_kernel_ip_output_policies_map_counts[i] = 0;
7273 	}
7274 
7275 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7276 		// Update mask
7277 		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7278 		necp_kernel_ip_output_policies_count++;
7279 
7280 		/* Update bucket counts:
7281 		 * Non-id and SKIP policies will be added to all buckets
7282 		 * Add local networks policy to all buckets for incoming IP
7283 		 */
7284 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7285 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7286 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7287 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7288 				necp_kernel_ip_output_policies_map_counts[i]++;
7289 			}
7290 		}
7291 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7292 			necp_kernel_ip_output_policies_non_id_count++;
7293 		} else {
7294 			necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7295 		}
7296 	}
7297 
7298 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7299 		if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7300 			// Allocate a NULL-terminated array of policy pointers for each bucket
7301 			necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7302 			    necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7303 			if (necp_kernel_ip_output_policies_map[i] == NULL) {
7304 				goto fail;
7305 			}
7306 		}
7307 		bucket_current_free_index[i] = 0;
7308 	}
7309 
7310 	u_int32_t current_session_order = 0;
7311 	u_int32_t current_session_last_non_skip_policy = 0;
7312 
7313 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7314 		// For each new session, find the last non-skip policy. We can
7315 		// avoid adding any skip policies that don't actually skip over
7316 		// any non-skip policies.
7317 		if (current_session_order != kernel_policy->session_order) {
7318 			current_session_order = kernel_policy->session_order;
7319 			current_session_last_non_skip_policy = 0;
7320 
7321 			struct necp_kernel_ip_output_policy *inner_policy = NULL;
7322 			LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7323 				if (inner_policy->session_order < current_session_order) {
7324 					continue;
7325 				}
7326 				if (inner_policy->session_order > current_session_order) {
7327 					break;
7328 				}
7329 				if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7330 					continue;
7331 				}
7332 
7333 				current_session_last_non_skip_policy = inner_policy->order;
7334 			}
7335 		}
7336 
7337 		if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7338 			if (current_session_last_non_skip_policy == 0) {
7339 				// No useful policies to skip over, don't add
7340 				continue;
7341 			}
7342 			if (kernel_policy->order >= current_session_last_non_skip_policy) {
7343 				// Skip policy is after the last useful policy, don't add
7344 				continue;
7345 			}
7346 		}
7347 
7348 		// Insert pointers into map
7349 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7350 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7351 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7352 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7353 				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])) {
7354 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7355 					bucket_current_free_index[i]++;
7356 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7357 				}
7358 			}
7359 		} else {
7360 			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7361 			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])) {
7362 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7363 				bucket_current_free_index[i]++;
7364 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7365 			}
7366 		}
7367 	}
7368 
7369 	if (bucket_current_free_index[0] == 0) {
7370 		// No non-id policies were actually added
7371 		necp_kernel_ip_output_policies_non_id_count = 0;
7372 
7373 		// Also check if no policies at all were added
7374 		bool policies_added = FALSE;
7375 		for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7376 			if (bucket_current_free_index[i] != 0) {
7377 				policies_added = TRUE;
7378 				break;
7379 			}
7380 		}
7381 		if (!policies_added) {
7382 			necp_kernel_ip_output_policies_condition_mask = 0;
7383 			necp_kernel_ip_output_policies_count = 0;
7384 		}
7385 	}
7386 
7387 	necp_kernel_ip_output_policies_dump_all();
7388 	return TRUE;
7389 
7390 fail:
7391 	// Free memory, reset mask to 0
7392 	necp_kernel_ip_output_policies_condition_mask = 0;
7393 	necp_kernel_ip_output_policies_count = 0;
7394 	necp_kernel_ip_output_policies_non_id_count = 0;
7395 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7396 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7397 			kfree_type(struct necp_kernel_ip_output_policy *,
7398 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7399 			    necp_kernel_ip_output_policies_map[i]);
7400 			necp_kernel_ip_output_policies_map[i] = NULL;
7401 		}
7402 	}
7403 	return FALSE;
7404 }
7405 
7406 // Outbound Policy Matching
7407 // ---------------------
7408 struct substring {
7409 	size_t length;
7410 	char * __sized_by(length) string;
7411 };
7412 
7413 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7414 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7415 {
7416 	struct substring sub = {};
7417 	char * __indexable ptr = string;
7418 	size_t len = string ? length : 0;
7419 
7420 	while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7421 		ptr++;
7422 		len--;
7423 	}
7424 
7425 	while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7426 		len--;
7427 	}
7428 
7429 	sub.string = ptr;
7430 	sub.length = len;
7431 	return sub;
7432 }
7433 
7434 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7435 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7436 {
7437 	size_t trimmed_domain_length = 0;
7438 	char *trimmed_domain = NULL;
7439 	struct substring sub = necp_trim_dots_and_stars(string, length);
7440 
7441 	trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7442 	trimmed_domain_length = sub.length + 1;
7443 	if (trimmed_domain == NULL) {
7444 		return NULL;
7445 	}
7446 
7447 	strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7448 	trimmed_domain[sub.length] = 0;
7449 
7450 	return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7451 }
7452 
7453 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7454 necp_count_dots(char * __sized_by(length)string, size_t length)
7455 {
7456 	int dot_count = 0;
7457 	size_t i = 0;
7458 
7459 	for (i = 0; i < length; i++) {
7460 		if (string[i] == '.') {
7461 			dot_count++;
7462 		}
7463 	}
7464 
7465 	return dot_count;
7466 }
7467 
7468 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7469 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7470 {
7471 	if (parent.length <= suffix.length) {
7472 		return FALSE;
7473 	}
7474 
7475 	size_t length_difference = (parent.length - suffix.length);
7476 
7477 	if (require_dot_before_suffix) {
7478 		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7479 			return FALSE;
7480 		}
7481 	}
7482 
7483 	// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7484 	return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7485 }
7486 
7487 static bool
necp_hostname_matches_domain(struct substring hostname_substring,u_int8_t hostname_dot_count,char * domain __null_terminated,u_int8_t domain_dot_count)7488 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7489 {
7490 	if (hostname_substring.string == NULL || domain == NULL) {
7491 		return hostname_substring.string == domain;
7492 	}
7493 
7494 	struct substring domain_substring;
7495 	domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7496 	domain_substring.length = strlen(domain);
7497 
7498 	if (hostname_dot_count == domain_dot_count) {
7499 		// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7500 		if (hostname_substring.length == domain_substring.length &&
7501 		    strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7502 			return TRUE;
7503 		}
7504 	} else if (domain_dot_count < hostname_dot_count) {
7505 		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7506 			return TRUE;
7507 		}
7508 	}
7509 
7510 	return FALSE;
7511 }
7512 
7513 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7514 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7515 {
7516 	if (hostname_string == NULL ||
7517 	    domain_string == NULL) {
7518 		return false;
7519 	}
7520 
7521 	struct substring hostname_substring;
7522 	hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7523 	hostname_substring.length = strlen(hostname_string);
7524 
7525 	return necp_hostname_matches_domain(hostname_substring,
7526 	           necp_count_dots(hostname_substring.string, hostname_substring.length),
7527 	           domain_string,
7528 	           necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7529 }
7530 
7531 #define NECP_MAX_STRING_LEN 1024
7532 
7533 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7534 necp_copy_string(char * __sized_by(length)string, size_t length)
7535 {
7536 	size_t copied_string_length = 0;
7537 	char * __sized_by(copied_string_length) copied_string = NULL;
7538 
7539 	if (length > NECP_MAX_STRING_LEN) {
7540 		return NULL;
7541 	}
7542 
7543 	copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7544 	copied_string_length = length + 1;
7545 	if (copied_string == NULL) {
7546 		return NULL;
7547 	}
7548 
7549 	memcpy(copied_string, string, length);
7550 	copied_string[length] = 0;
7551 
7552 	return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7553 }
7554 
7555 static u_int32_t
necp_get_primary_direct_interface_index(void)7556 necp_get_primary_direct_interface_index(void)
7557 {
7558 	u_int32_t interface_index = IFSCOPE_NONE;
7559 
7560 	ifnet_head_lock_shared();
7561 	struct ifnet *ordered_interface = NULL;
7562 	TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7563 		const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7564 		if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7565 		    functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7566 			// All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7567 			interface_index = ordered_interface->if_index;
7568 			break;
7569 		}
7570 	}
7571 	ifnet_head_done();
7572 
7573 	return interface_index;
7574 }
7575 
7576 static inline bool
necp_task_has_match_entitlement(task_t task)7577 necp_task_has_match_entitlement(task_t task)
7578 {
7579 	return task != NULL &&
7580 	       (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7581 	       IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7582 }
7583 
7584 // Loopback traffic from certain entitled process will be dropped
7585 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7586 necp_task_has_loopback_drop_entitlement(task_t task)
7587 {
7588 	bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7589 	if (drop) {
7590 		necp_drop_loopback_count++;
7591 	}
7592 	return drop;
7593 }
7594 
7595 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7596 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7597 {
7598 	coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7599 
7600 	if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7601 		// No parent, nothing to do
7602 		return;
7603 	}
7604 
7605 	task_t __single lead_task = coalition_get_leader(coal);
7606 	if (lead_task != NULL) {
7607 		info->is_entitled = necp_task_has_match_entitlement(lead_task);
7608 		task_deallocate(lead_task);
7609 	}
7610 }
7611 
7612 // Some processes, due to particular entitlements, require using an NECP client to
7613 // access networking. Returns true if the result should be a Drop.
7614 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7615 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7616 {
7617 	if (necp_is_platform_binary(proc)) {
7618 		// This check is currently for the "on-demand-install-capable"
7619 		// entitlement, which by definition cannot be a built-in platform
7620 		// binary.
7621 		return false;
7622 	}
7623 
7624 	task_t __single task = proc_task(proc ? proc : current_proc());
7625 
7626 	if (!info->has_client &&
7627 	    task != NULL &&
7628 	    IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7629 		// Drop connections that don't use NECP clients and have the
7630 		// com.apple.developer.on-demand-install-capable entitlement.
7631 		// This effectively restricts those processes to only using
7632 		// an NECP-aware path for networking.
7633 		return true;
7634 	} else {
7635 		return false;
7636 	}
7637 }
7638 
7639 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7640 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7641 {
7642 	if (!necp_restrict_multicast || proc == NULL) {
7643 		return false;
7644 	}
7645 
7646 	// Check for multicast/broadcast here
7647 	if (info->remote_addr.sa.sa_family == AF_INET) {
7648 		if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7649 		    info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7650 			return false;
7651 		}
7652 	} else if (info->remote_addr.sa.sa_family == AF_INET6) {
7653 		if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7654 			return false;
7655 		}
7656 	} else {
7657 		// Not IPv4/IPv6
7658 		return false;
7659 	}
7660 
7661 	if (necp_is_platform_binary(proc)) {
7662 		return false;
7663 	}
7664 
7665 	const uint32_t platform = proc_platform(proc);
7666 	const uint32_t sdk = proc_sdk(proc);
7667 
7668 	// Enforce for iOS, linked on or after version 14
7669 	// If the caller set `check_minor_version`, only enforce starting at 14.5
7670 	if ((platform != PLATFORM_IOS ||
7671 	    sdk == 0 ||
7672 	    (sdk >> 16) < 14 ||
7673 	    (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7674 		return false;
7675 	}
7676 
7677 	// Allow entitled processes to use multicast
7678 	task_t __single task = proc_task(proc);
7679 	if (task != NULL &&
7680 	    IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7681 		return false;
7682 	}
7683 
7684 	const uint32_t min_sdk = proc_min_sdk(proc);
7685 	NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7686 
7687 	return true;
7688 }
7689 
7690 #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 | NECP_KERNEL_CONDITION_SCHEME_PORT)
7691 static void
necp_application_fillout_info_locked(task_t task,uuid_t application_uuid,uuid_t real_application_uuid,uuid_t responsible_application_uuid,char * account __null_terminated,char * domain __null_terminated,char * url __null_terminated,pid_t pid,int32_t pid_version,uid_t uid,uid_t real_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,bool has_system_signed_result,proc_t real_proc,proc_t proc,proc_t responsible_proc,u_int32_t drop_order,u_int32_t client_flags,u_int16_t scheme_port,struct necp_socket_info * info,bool is_loopback,bool is_delegated)7692 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account __null_terminated, char *domain __null_terminated, char *url __null_terminated, pid_t pid, int32_t pid_version, uid_t uid, uid_t real_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, bool has_system_signed_result, proc_t real_proc, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, u_int16_t scheme_port, struct necp_socket_info *info, bool is_loopback, bool is_delegated)
7693 {
7694 	memset(info, 0, sizeof(struct necp_socket_info));
7695 
7696 	info->pid = pid;
7697 	info->pid_version = pid_version;
7698 	info->uid = uid;
7699 	info->real_uid = real_uid;
7700 	info->protocol = protocol;
7701 	info->bound_interface_index = bound_interface_index;
7702 	info->traffic_class = traffic_class;
7703 	info->has_client = has_client;
7704 	info->has_system_signed_result = has_system_signed_result;
7705 	info->drop_order = drop_order;
7706 	info->client_flags = client_flags;
7707 	info->is_loopback = is_loopback;
7708 	info->is_delegated = is_delegated;
7709 
7710 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7711 	    info->bound_interface_index != IFSCOPE_NONE) {
7712 		ifnet_head_lock_shared();
7713 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7714 		if (interface != NULL) {
7715 			info->bound_interface_flags = interface->if_flags;
7716 			info->bound_interface_eflags = interface->if_eflags;
7717 			info->bound_interface_xflags = interface->if_xflags;
7718 		}
7719 		ifnet_head_done();
7720 	}
7721 
7722 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7723 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7724 		if (existing_mapping) {
7725 			info->application_id = existing_mapping->id;
7726 		}
7727 	}
7728 
7729 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7730 		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7731 			info->real_application_id = info->application_id;
7732 		} else {
7733 			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7734 			if (existing_mapping) {
7735 				info->real_application_id = existing_mapping->id;
7736 			}
7737 		}
7738 	}
7739 
7740 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7741 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7742 		if (existing_mapping != NULL) {
7743 			info->real_application_id = info->application_id;
7744 			info->application_id = existing_mapping->id;
7745 			info->used_responsible_pid = true;
7746 		}
7747 	}
7748 
7749 	if (info->used_responsible_pid) {
7750 		proc = responsible_proc;
7751 	}
7752 
7753 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7754 		info->is_entitled = necp_task_has_match_entitlement(task);
7755 		if (!info->is_entitled) {
7756 			// Task does not have entitlement, check the parent task
7757 			necp_get_parent_is_entitled(task, info);
7758 		}
7759 	}
7760 
7761 	if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7762 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7763 		if (necp_is_platform_binary(proc)) {
7764 			info->is_platform_binary = true;
7765 		} else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7766 			info->is_platform_binary = true;
7767 			info->used_responsible_pid = true;
7768 		} else {
7769 			info->is_platform_binary = false;
7770 		}
7771 	}
7772 
7773 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7774 		info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7775 	}
7776 
7777 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7778 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7779 		if (existing_mapping) {
7780 			info->account_id = existing_mapping->id;
7781 		}
7782 	}
7783 
7784 	if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7785 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7786 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7787 		info->domain = domain;
7788 	}
7789 
7790 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7791 		info->url = url;
7792 	}
7793 
7794 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
7795 	    necp_restrict_multicast ||
7796 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7797 		if (local_addr && local_addr->sa.sa_len > 0) {
7798 			SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7799 			if (local_port != 0) {
7800 				info->local_addr.sin6.sin6_port = local_port;
7801 			}
7802 		} else {
7803 			if (remote_addr && remote_addr->sa.sa_len > 0) {
7804 				info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7805 				info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7806 			} else {
7807 				info->local_addr.sin6.sin6_family = AF_INET6;
7808 				info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7809 			}
7810 			if (local_port != 0) {
7811 				info->local_addr.sin6.sin6_port = local_port;
7812 			}
7813 		}
7814 		if (remote_addr && remote_addr->sa.sa_len > 0) {
7815 			SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7816 			if (remote_port != 0) {
7817 				info->remote_addr.sin6.sin6_port = remote_port;
7818 			}
7819 		} else if (remote_port != 0) {
7820 			info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7821 			info->remote_addr.sin6.sin6_family = AF_INET6;
7822 			info->remote_addr.sin6.sin6_port = remote_port;
7823 		}
7824 	}
7825 
7826 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7827 		info->scheme_port = scheme_port;
7828 	}
7829 }
7830 
7831 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7832 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7833 {
7834 	struct kev_netpolicy_ifdenied ev_ifdenied;
7835 
7836 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7837 
7838 	ev_ifdenied.ev_data.epid = pid;
7839 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7840 	ev_ifdenied.ev_if_functional_type = if_functional_type;
7841 
7842 	netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7843 }
7844 
7845 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7846 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7847 {
7848 	struct kev_netpolicy_netdenied ev_netdenied = {};
7849 
7850 	bzero(&ev_netdenied, sizeof(ev_netdenied));
7851 
7852 	ev_netdenied.ev_data.epid = pid;
7853 	uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7854 	ev_netdenied.ev_network_type = network_type;
7855 
7856 	netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7857 }
7858 
7859 extern char *proc_name_address(void *p);
7860 
7861 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7862 	if (!has_checked_delegation_entitlement) { \
7863 	        has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7864 	        has_checked_delegation_entitlement = TRUE; \
7865 	} \
7866 	if (!has_delegation_entitlement) { \
7867 	        NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7868 	                                          proc_name_address(_p), proc_pid(_p), _d); \
7869 	        break; \
7870 	}
7871 
7872 int
necp_application_find_policy_match_internal(proc_t proc,u_int8_t * __sized_by (parameters_size)parameters,u_int32_t parameters_size,struct necp_aggregate_result * returned_result,u_int32_t * flags,u_int32_t * reason,u_int required_interface_index,const union necp_sockaddr_union * override_local_addr,const union necp_sockaddr_union * override_remote_addr,struct necp_client_endpoint * returned_v4_gateway,struct necp_client_endpoint * returned_v6_gateway,struct rtentry ** returned_route,bool ignore_address,bool has_client,uuid_t * returned_override_euuid)7873 necp_application_find_policy_match_internal(proc_t proc,
7874     u_int8_t * __sized_by(parameters_size)parameters,
7875     u_int32_t parameters_size,
7876     struct necp_aggregate_result *returned_result,
7877     u_int32_t *flags,
7878     u_int32_t *reason,
7879     u_int required_interface_index,
7880     const union necp_sockaddr_union *override_local_addr,
7881     const union necp_sockaddr_union *override_remote_addr,
7882     struct necp_client_endpoint *returned_v4_gateway,
7883     struct necp_client_endpoint *returned_v6_gateway,
7884     struct rtentry **returned_route, bool ignore_address,
7885     bool has_client,
7886     uuid_t *returned_override_euuid)
7887 {
7888 	int error = 0;
7889 	size_t offset = 0;
7890 
7891 	struct necp_kernel_socket_policy *matched_policy = NULL;
7892 	struct necp_socket_info info = {};
7893 	necp_kernel_policy_filter filter_control_unit = 0;
7894 	necp_kernel_policy_result service_action = 0;
7895 	necp_kernel_policy_service service = { 0, 0 };
7896 
7897 	u_int16_t protocol = 0;
7898 	u_int32_t bound_interface_index = required_interface_index;
7899 	u_int32_t traffic_class = 0;
7900 	u_int32_t client_flags = 0;
7901 	u_int16_t scheme_port = 0;
7902 	union necp_sockaddr_union local_addr;
7903 	union necp_sockaddr_union remote_addr;
7904 	bool no_remote_addr = FALSE;
7905 	u_int8_t remote_family = 0;
7906 	bool no_local_addr = FALSE;
7907 	u_int16_t local_port = 0;
7908 	u_int16_t remote_port = 0;
7909 	u_int32_t remote_endpoint_type = 0;
7910 	bool remote_address_is_empty = false;
7911 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7912 	bool is_delegated = false;
7913 
7914 	if (override_local_addr) {
7915 		memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7916 	} else {
7917 		memset(&local_addr, 0, sizeof(local_addr));
7918 	}
7919 	if (override_remote_addr) {
7920 		memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7921 	} else {
7922 		memset(&remote_addr, 0, sizeof(remote_addr));
7923 	}
7924 
7925 	// Initialize UID, PID, and UUIDs to the current process
7926 	uid_t uid = 0;
7927 	uid_t real_uid = 0;
7928 	kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7929 	if (cred != NULL) {
7930 		uid = kauth_cred_getuid(cred);
7931 		real_uid = uid;
7932 	}
7933 	task_t __single task = proc_task(proc);
7934 	pid_t pid = proc_pid(proc);
7935 	int32_t pid_version = proc_pidversion(proc);
7936 	uuid_t application_uuid;
7937 	uuid_clear(application_uuid);
7938 	uuid_t real_application_uuid;
7939 	uuid_clear(real_application_uuid);
7940 	proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7941 	uuid_copy(application_uuid, real_application_uuid);
7942 	uuid_t responsible_application_uuid;
7943 	uuid_clear(responsible_application_uuid);
7944 
7945 	char *domain __null_terminated = NULL;
7946 	char *url __null_terminated = NULL;
7947 	char *account __null_terminated = NULL;
7948 
7949 #define NECP_MAX_REQUIRED_AGENTS 16
7950 	u_int32_t num_required_agent_types = 0;
7951 	struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7952 	memset(&required_agent_types, 0, sizeof(required_agent_types));
7953 
7954 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7955 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7956 	memset(&netagent_ids, 0, sizeof(netagent_ids));
7957 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7958 	int netagent_cursor;
7959 
7960 	bool has_checked_delegation_entitlement = false;
7961 	bool has_delegation_entitlement = false;
7962 	bool has_system_signed_result = false;
7963 
7964 	proc_t responsible_proc = PROC_NULL;
7965 	proc_t effective_proc = proc;
7966 	bool release_eproc = false;
7967 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7968 
7969 	u_int32_t flow_divert_aggregate_unit = 0;
7970 
7971 	if (returned_result == NULL) {
7972 		if (cred != NULL) {
7973 			kauth_cred_unref(&cred);
7974 		}
7975 		return EINVAL;
7976 	}
7977 
7978 	if (returned_v4_gateway != NULL) {
7979 		memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7980 	}
7981 
7982 	if (returned_v6_gateway != NULL) {
7983 		memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7984 	}
7985 
7986 	if (returned_override_euuid != NULL) {
7987 		uuid_clear(*returned_override_euuid);
7988 	}
7989 
7990 	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7991 
7992 	u_int32_t drop_order = necp_process_drop_order(cred);
7993 
7994 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7995 
7996 	lck_rw_lock_shared(&necp_kernel_policy_lock);
7997 	if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7998 		if (necp_drop_all_order > 0 || drop_order > 0) {
7999 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8000 			lck_rw_done(&necp_kernel_policy_lock);
8001 			if (cred != NULL) {
8002 				kauth_cred_unref(&cred);
8003 			}
8004 			return 0;
8005 		}
8006 	}
8007 	lck_rw_done(&necp_kernel_policy_lock);
8008 
8009 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8010 		u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8011 		u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8012 
8013 		if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8014 			// If the length is larger than what can fit in the remaining parameters size, bail
8015 			NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8016 			break;
8017 		}
8018 
8019 		if (length > 0) {
8020 			u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8021 			if (value != NULL) {
8022 				switch (type) {
8023 				case NECP_CLIENT_PARAMETER_APPLICATION: {
8024 					if (length >= sizeof(uuid_t)) {
8025 						if (uuid_compare(application_uuid, value) == 0) {
8026 							// No delegation
8027 							break;
8028 						}
8029 
8030 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8031 
8032 						is_delegated = true;
8033 						uuid_copy(application_uuid, value);
8034 					}
8035 					break;
8036 				}
8037 				case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8038 					if (length >= sizeof(uuid_t)) {
8039 						if (uuid_compare(real_application_uuid, value) == 0) {
8040 							// No delegation
8041 							break;
8042 						}
8043 
8044 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8045 
8046 						is_delegated = true;
8047 						uuid_copy(real_application_uuid, value);
8048 					}
8049 					break;
8050 				}
8051 				case NECP_CLIENT_PARAMETER_PID: {
8052 					if (length >= sizeof(pid_t)) {
8053 						if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8054 							// No delegation
8055 							break;
8056 						}
8057 
8058 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8059 
8060 						is_delegated = true;
8061 						memcpy(&pid, value, sizeof(pid_t));
8062 					}
8063 					break;
8064 				}
8065 				case NECP_CLIENT_PARAMETER_UID: {
8066 					if (length >= sizeof(uid_t)) {
8067 						if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8068 							// No delegation
8069 							break;
8070 						}
8071 
8072 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8073 
8074 						is_delegated = true;
8075 						memcpy(&uid, value, sizeof(uid_t));
8076 					}
8077 					break;
8078 				}
8079 				case NECP_CLIENT_PARAMETER_DOMAIN: {
8080 					char *ptr = (char *)value;
8081 					ptr[length - 1] = 0;
8082 					domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8083 					break;
8084 				}
8085 				case NECP_CLIENT_PARAMETER_URL: {
8086 					char *ptr = (char *)value;
8087 					ptr[length - 1] = 0;
8088 					url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8089 					break;
8090 				}
8091 				case NECP_CLIENT_PARAMETER_ACCOUNT: {
8092 					char *ptr = (char *)value;
8093 					ptr[length - 1] = 0;
8094 					account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8095 					break;
8096 				}
8097 				case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8098 					if (length >= sizeof(u_int32_t)) {
8099 						memcpy(&traffic_class, value, sizeof(u_int32_t));
8100 					}
8101 					break;
8102 				}
8103 				case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8104 					if (length >= sizeof(u_int16_t)) {
8105 						memcpy(&protocol, value, sizeof(u_int16_t));
8106 					} else if (length >= sizeof(u_int8_t)) {
8107 						memcpy(&protocol, value, sizeof(u_int8_t));
8108 					}
8109 					break;
8110 				}
8111 				case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8112 					if (length <= IFXNAMSIZ && length > 0) {
8113 						ifnet_t __single bound_interface = NULL;
8114 						char interface_name[IFXNAMSIZ];
8115 						memcpy(interface_name, value, length);
8116 						interface_name[length - 1] = 0;         // Make sure the string is NULL terminated
8117 						if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8118 							bound_interface_index = bound_interface->if_index;
8119 							ifnet_release(bound_interface);
8120 						}
8121 					}
8122 					break;
8123 				}
8124 				case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8125 					if (ignore_address || override_local_addr) {
8126 						break;
8127 					}
8128 
8129 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8130 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8131 						if (necp_address_is_valid(&address_struct->address.sa)) {
8132 							memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8133 						}
8134 					}
8135 					break;
8136 				}
8137 				case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8138 					if (ignore_address || override_remote_addr) {
8139 						break;
8140 					}
8141 
8142 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8143 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8144 						if (necp_address_is_valid(&address_struct->address.sa)) {
8145 							memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8146 						}
8147 					}
8148 					break;
8149 				}
8150 				case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8151 					if (ignore_address || override_local_addr) {
8152 						break;
8153 					}
8154 
8155 					if (length >= sizeof(struct necp_client_endpoint)) {
8156 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8157 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8158 						    endpoint->u.endpoint.endpoint_port != 0) {
8159 							// Save port
8160 							local_port = endpoint->u.endpoint.endpoint_port;
8161 						}
8162 					}
8163 					break;
8164 				}
8165 				case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8166 					if (ignore_address || override_remote_addr) {
8167 						break;
8168 					}
8169 
8170 					if (length >= sizeof(struct necp_client_endpoint)) {
8171 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8172 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8173 							remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8174 							if (endpoint->u.endpoint.endpoint_port != 0) {
8175 								// Save port
8176 								remote_port = endpoint->u.endpoint.endpoint_port;
8177 							}
8178 						} else if (necp_addr_is_empty(&endpoint->u.sa)) {
8179 							remote_address_is_empty = true;
8180 						}
8181 					}
8182 					break;
8183 				}
8184 				case NECP_CLIENT_PARAMETER_FLAGS: {
8185 					if (length >= sizeof(client_flags)) {
8186 						memcpy(&client_flags, value, sizeof(client_flags));
8187 					}
8188 					break;
8189 				}
8190 				case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8191 				case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8192 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8193 						break;
8194 					}
8195 					if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8196 						memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8197 						num_required_agent_types++;
8198 					}
8199 					break;
8200 				}
8201 				case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8202 					if (length >= sizeof(scheme_port)) {
8203 						memcpy(&scheme_port, value, sizeof(scheme_port));
8204 					}
8205 					break;
8206 				}
8207 				case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8208 					has_system_signed_result = true;
8209 					struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8210 					if (length >= sizeof(struct necp_client_validatable)) {
8211 						// Check for system-signed sign_type values
8212 						if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8213 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8214 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8215 							has_system_signed_result = true;
8216 						}
8217 					}
8218 					break;
8219 				}
8220 				default: {
8221 					break;
8222 				}
8223 				}
8224 			}
8225 		}
8226 
8227 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8228 	}
8229 
8230 	// Check for loopback exception
8231 	if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8232 		if (necp_task_has_loopback_drop_entitlement(task)) {
8233 			// Disallow certain entitled processes to send loopback traffic
8234 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8235 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8236 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8237 			if (cred != NULL) {
8238 				kauth_cred_unref(&cred);
8239 			}
8240 			return 0;
8241 		}
8242 		if (necp_pass_loopback > 0) {
8243 			bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8244 		}
8245 	} else if (bound_interface_index != IFSCOPE_NONE) {
8246 		// Check for inter-process exception
8247 		struct sockaddr *dst = SA(&remote_addr.sa);
8248 		if (dst->sa_family == AF_INET6) {
8249 			struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8250 			if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8251 				ifnet_head_lock_shared();
8252 				ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8253 				if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8254 					bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8255 				}
8256 				ifnet_head_done();
8257 			}
8258 		}
8259 	}
8260 
8261 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8262 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8263 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8264 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8265 		if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8266 			returned_result->routed_interface_index = lo_ifp->if_index;
8267 			*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8268 		} else {
8269 			returned_result->routed_interface_index = bound_interface_index;
8270 		}
8271 		if (cred != NULL) {
8272 			kauth_cred_unref(&cred);
8273 		}
8274 		return 0;
8275 	}
8276 
8277 	if (drop_order != 0) {
8278 		if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8279 		    client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8280 		    ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8281 			// Allow listeners, inbound connections without remote addresses, and
8282 			// application service connections to bypass the unentitled drop order,
8283 			// to allow them to connect to application services (not directly over
8284 			// physical networking interfaces)
8285 			drop_order = 0;
8286 		}
8287 	}
8288 
8289 	if (proc_pid(effective_proc) != pid) {
8290 		proc_t found_proc = proc_find(pid);
8291 		if (found_proc != PROC_NULL) {
8292 			effective_proc = found_proc;
8293 			pid_version = proc_pidversion(effective_proc);
8294 			release_eproc = true;
8295 		}
8296 	}
8297 #if defined(XNU_TARGET_OS_OSX)
8298 	if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8299 		proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8300 		responsible_proc = proc_find(effective_proc->p_responsible_pid);
8301 	}
8302 #endif /* defined(XNU_TARGET_OS_OSX) */
8303 
8304 	// Lock
8305 	lck_rw_lock_shared(&necp_kernel_policy_lock);
8306 
8307 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8308 	size_t route_rule_id_array_count = 0;
8309 	necp_application_fillout_info_locked(task, application_uuid, real_application_uuid, responsible_application_uuid, account, domain, url, pid, pid_version, uid, real_uid, protocol, bound_interface_index, traffic_class, &local_addr, &remote_addr, local_port, remote_port, has_client, has_system_signed_result, proc, effective_proc, responsible_proc, drop_order, client_flags, scheme_port, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), is_delegated);
8310 
8311 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8312 	NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8313 
8314 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8315 	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8316 	    &info,
8317 	    &filter_control_unit,
8318 	    route_rule_id_array,
8319 	    &route_rule_id_array_count,
8320 	    MAX_AGGREGATE_ROUTE_RULES,
8321 	    &service_action,
8322 	    &service,
8323 	    netagent_ids,
8324 	    NECP_MAX_NETAGENTS,
8325 	    netagent_use_flags,
8326 	    NECP_MAX_NETAGENTS,
8327 	    required_agent_types,
8328 	    num_required_agent_types,
8329 	    info.used_responsible_pid ? responsible_proc : effective_proc,
8330 	    0,
8331 	    &skip_policy_id,
8332 	    NULL,
8333 	    &drop_dest_policy_result,
8334 	    &drop_all_bypass,
8335 	    &flow_divert_aggregate_unit,
8336 	    NULL,
8337 	    debug);
8338 
8339 	// Check for loopback exception again after the policy match
8340 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8341 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8342 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8343 		if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8344 			returned_result->filter_control_unit = 0;
8345 		} else {
8346 			returned_result->filter_control_unit = filter_control_unit;
8347 		}
8348 
8349 		if (flow_divert_aggregate_unit > 0) {
8350 			returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8351 		}
8352 
8353 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8354 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8355 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8356 		returned_result->routed_interface_index = lo_ifp->if_index;
8357 		*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8358 		error = 0;
8359 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8360 		goto done;
8361 	}
8362 
8363 	if (matched_policy) {
8364 		returned_result->policy_id = matched_policy->id;
8365 		returned_result->skip_policy_id = skip_policy_id;
8366 		returned_result->routing_result = matched_policy->result;
8367 		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8368 		if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8369 			uuid_copy(*returned_override_euuid, responsible_application_uuid);
8370 		}
8371 	} else {
8372 		bool drop_all = false;
8373 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8374 			// Mark socket as a drop if drop_all is set
8375 			drop_all = true;
8376 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8377 				drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8378 			}
8379 		}
8380 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8381 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8382 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8383 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8384 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8385 		} else {
8386 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8387 			returned_result->skip_policy_id = skip_policy_id;
8388 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8389 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8390 		}
8391 	}
8392 	if (necp_check_missing_client_drop(proc, &info) ||
8393 	    necp_check_restricted_multicast_drop(proc, &info, false)) {
8394 		// Mark as drop
8395 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8396 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8397 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8398 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8399 	}
8400 	if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8401 		returned_result->filter_control_unit = 0;
8402 	} else {
8403 		returned_result->filter_control_unit = filter_control_unit;
8404 	}
8405 
8406 	if (flow_divert_aggregate_unit > 0) {
8407 		returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8408 	}
8409 
8410 	returned_result->service_action = service_action;
8411 
8412 	// Fetch service registration
8413 	if (service.identifier != 0) {
8414 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8415 		if (mapping != NULL) {
8416 			struct necp_service_registration *service_registration = NULL;
8417 			uuid_copy(returned_result->service_uuid, mapping->uuid);
8418 			returned_result->service_data = service.data;
8419 			if (service.identifier == NECP_NULL_SERVICE_ID) {
8420 				// NULL service is always 'registered'
8421 				returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8422 			} else {
8423 				LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8424 					if (service.identifier == service_registration->service_id) {
8425 						returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8426 						break;
8427 					}
8428 				}
8429 			}
8430 		}
8431 	}
8432 
8433 	// Handle netagents
8434 	size_t netagent_i = 0;
8435 	for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8436 		struct necp_uuid_id_mapping *mapping = NULL;
8437 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
8438 		if (netagent_id == 0) {
8439 			continue;
8440 		}
8441 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8442 		if (mapping != NULL) {
8443 			uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8444 			returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8445 			netagent_i++;
8446 		}
8447 
8448 		// If the flags say to remove, clear the local copy
8449 		if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8450 			netagent_ids[netagent_cursor] = 0;
8451 		}
8452 	}
8453 
8454 	// Do routing evaluation
8455 	u_int output_bound_interface = bound_interface_index;
8456 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8457 		output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8458 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8459 		output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8460 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8461 		output_bound_interface = necp_get_primary_direct_interface_index();
8462 		if (output_bound_interface == IFSCOPE_NONE) {
8463 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8464 		} else {
8465 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8466 			returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8467 		}
8468 	}
8469 
8470 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8471 	    returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8472 		if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8473 			// Trigger the event that we dropped due to a local network policy
8474 #if defined(XNU_TARGET_OS_OSX)
8475 			bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8476 			necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8477 			    should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8478 			    NETPOLICY_NETWORKTYPE_LOCAL);
8479 #else
8480 			necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8481 #endif
8482 		}
8483 		if (reason != NULL) {
8484 			*reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8485 		}
8486 	}
8487 
8488 	if (local_addr.sa.sa_len == 0 ||
8489 	    (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8490 	    (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8491 		no_local_addr = TRUE;
8492 	}
8493 
8494 	if (remote_addr.sa.sa_len == 0 ||
8495 	    (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8496 	    (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8497 		no_remote_addr = TRUE;
8498 		remote_family = remote_addr.sa.sa_family;
8499 	}
8500 
8501 	returned_result->routed_interface_index = 0;
8502 	struct rtentry *rt = NULL;
8503 	if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8504 		// Treat the output bound interface as the routed interface for local address
8505 		// validation later.
8506 		returned_result->routed_interface_index = output_bound_interface;
8507 	} else {
8508 		if (no_remote_addr) {
8509 			memset(&remote_addr, 0, sizeof(remote_addr));
8510 			if (remote_family == AF_INET6) {
8511 				// Reset address to ::
8512 				remote_addr.sa.sa_family = AF_INET6;
8513 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8514 			} else {
8515 				// Reset address to 0.0.0.0
8516 				remote_addr.sa.sa_family = AF_INET;
8517 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8518 			}
8519 		}
8520 
8521 		rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8522 		    output_bound_interface);
8523 
8524 		if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8525 		    IS_INTF_CLAT46(rt->rt_ifp)) {
8526 			rtfree(rt);
8527 			rt = NULL;
8528 			returned_result->routed_interface_index = 0;
8529 		}
8530 
8531 		if (no_remote_addr && remote_family == AF_UNSPEC &&
8532 		    (rt == NULL || rt->rt_ifp == NULL)) {
8533 			// Route lookup for default IPv4 failed, try IPv6
8534 
8535 			// Cleanup old route if necessary
8536 			if (rt != NULL) {
8537 				rtfree(rt);
8538 				rt = NULL;
8539 			}
8540 
8541 			// Reset address to ::
8542 			memset(&remote_addr, 0, sizeof(remote_addr));
8543 			remote_addr.sa.sa_family = AF_INET6;
8544 			remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8545 
8546 			// Get route
8547 			rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8548 			    output_bound_interface);
8549 		}
8550 
8551 		if (rt != NULL &&
8552 		    rt->rt_ifp != NULL) {
8553 			returned_result->routed_interface_index = rt->rt_ifp->if_index;
8554 			/*
8555 			 * For local addresses, we allow the interface scope to be
8556 			 * either the loopback interface or the interface hosting the
8557 			 * local address.
8558 			 */
8559 			if (bound_interface_index != IFSCOPE_NONE &&
8560 			    rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8561 			    (output_bound_interface == lo_ifp->if_index ||
8562 			    rt->rt_ifp->if_index == lo_ifp->if_index ||
8563 			    rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8564 				struct sockaddr_storage dst;
8565 				unsigned int ifscope = bound_interface_index;
8566 
8567 				/*
8568 				 * Transform dst into the internal routing table form
8569 				 */
8570 				(void) sa_copy(SA(&remote_addr),
8571 				    &dst, &ifscope);
8572 
8573 				if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8574 				    rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8575 					returned_result->routed_interface_index =
8576 					    bound_interface_index;
8577 				}
8578 			}
8579 		}
8580 	}
8581 
8582 	if (returned_result->routed_interface_index != 0 &&
8583 	    returned_result->routed_interface_index != lo_ifp->if_index &&     // Loopback can accept any local address
8584 	    !no_local_addr) {
8585 		// Transform local_addr into the ifaddr form
8586 		// IPv6 Scope IDs are always embedded in the ifaddr list
8587 		struct sockaddr_storage local_address_sanitized;
8588 		u_int ifscope = IFSCOPE_NONE;
8589 		(void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8590 		SIN(&local_address_sanitized)->sin_port = 0;
8591 		if (local_address_sanitized.ss_family == AF_INET6) {
8592 			if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8593 				SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8594 			}
8595 		}
8596 
8597 		// Validate local address on routed interface
8598 		struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8599 		if (ifa == NULL) {
8600 			// Interface address not found, reject route
8601 			returned_result->routed_interface_index = 0;
8602 			if (rt != NULL) {
8603 				rtfree(rt);
8604 				rt = NULL;
8605 			}
8606 		} else {
8607 			ifaddr_release(ifa);
8608 			ifa = NULL;
8609 		}
8610 	}
8611 
8612 	if (flags != NULL) {
8613 #if SKYWALK
8614 		if (kernel_is_macos_or_server()) {
8615 			enum net_filter_event_subsystems filters = net_filter_event_get_state();
8616 
8617 			if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8618 				*flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8619 			}
8620 			if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8621 				*flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8622 			}
8623 			if (filters & NET_FILTER_EVENT_ALF) {
8624 				*flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8625 			}
8626 			if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8627 				*flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8628 			}
8629 		}
8630 #endif /* SKYWALK */
8631 		if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8632 			// Check for local/direct
8633 			bool is_local = FALSE;
8634 			if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8635 				is_local = TRUE;
8636 			} else if (returned_result->routed_interface_index != 0 &&
8637 			    !no_remote_addr) {
8638 				// Clean up the address before comparison with interface addresses
8639 
8640 				// Transform remote_addr into the ifaddr form
8641 				// IPv6 Scope IDs are always embedded in the ifaddr list
8642 				struct sockaddr_storage remote_address_sanitized;
8643 				u_int ifscope = IFSCOPE_NONE;
8644 				(void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8645 				SIN(&remote_address_sanitized)->sin_port = 0;
8646 				if (remote_address_sanitized.ss_family == AF_INET6) {
8647 					if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8648 						SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8649 					}
8650 				}
8651 
8652 				// Check if remote address is an interface address
8653 				struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8654 				if (ifa != NULL && ifa->ifa_ifp != NULL) {
8655 					u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8656 					if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8657 					    if_index_for_remote_addr == lo_ifp->if_index) {
8658 						is_local = TRUE;
8659 					}
8660 				}
8661 				if (ifa != NULL) {
8662 					ifaddr_release(ifa);
8663 					ifa = NULL;
8664 				}
8665 			}
8666 
8667 			if (is_local) {
8668 				*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8669 			} else if (rt != NULL) {
8670 				if (rt->rt_flags & RTF_GLOBAL) {
8671 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8672 				} else if (!(rt->rt_flags & RTF_GATEWAY) &&
8673 				    (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8674 					// Route is directly accessible
8675 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8676 				}
8677 			}
8678 
8679 			if (rt != NULL &&
8680 			    rt->rt_ifp != NULL) {
8681 				// Check probe status
8682 				if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8683 					*flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8684 				}
8685 
8686 				if (if_link_heuristics_enabled(rt->rt_ifp)) {
8687 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_HEURISTICS;
8688 				}
8689 
8690 				if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8691 					struct if_cellular_status_v1 *ifsr;
8692 
8693 					ifnet_lock_shared(rt->rt_ifp);
8694 					lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8695 
8696 					if (rt->rt_ifp->if_link_status != NULL) {
8697 						ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8698 
8699 						if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8700 							if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8701 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8702 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8703 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8704 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8705 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8706 							}
8707 						}
8708 					}
8709 					lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8710 					ifnet_lock_done(rt->rt_ifp);
8711 				}
8712 
8713 				// Check link quality
8714 				if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8715 				    (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8716 				    rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8717 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8718 				}
8719 
8720 				// Check QoS marking (fastlane)
8721 				for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8722 					if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8723 						*flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8724 						// If the route can use QoS markings, stop iterating route rules
8725 						break;
8726 					}
8727 				}
8728 
8729 				if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8730 					*flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8731 				}
8732 
8733 				if (traffic_class == SO_TC_BK_SYS) {
8734 					// Block BK_SYS traffic if interface is throttled
8735 					u_int32_t throttle_level = 0;
8736 					if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8737 						if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8738 							returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8739 							memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8740 						}
8741 					}
8742 				}
8743 			}
8744 		}
8745 
8746 		u_int interface_to_check = returned_result->routed_interface_index;
8747 		if (interface_to_check == 0) {
8748 			interface_to_check = output_bound_interface;
8749 		}
8750 		union necp_sockaddr_union default_address;
8751 		struct rtentry *v4Route = NULL;
8752 		struct rtentry *v6Route = NULL;
8753 
8754 		memset(&default_address, 0, sizeof(default_address));
8755 
8756 		// Reset address to 0.0.0.0
8757 		default_address.sa.sa_family = AF_INET;
8758 		default_address.sa.sa_len = sizeof(struct sockaddr_in);
8759 		v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8760 		    returned_result->routed_interface_index);
8761 
8762 		// Reset address to ::
8763 		default_address.sa.sa_family = AF_INET6;
8764 		default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8765 		v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8766 		    returned_result->routed_interface_index);
8767 
8768 		if (v4Route != NULL) {
8769 			if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8770 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8771 			}
8772 			if (returned_v4_gateway != NULL &&
8773 			    v4Route->rt_gateway != NULL &&
8774 			    v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8775 				memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8776 				memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8777 			}
8778 			rtfree(v4Route);
8779 			v4Route = NULL;
8780 		}
8781 
8782 		if (v6Route != NULL) {
8783 			if (v6Route->rt_ifp != NULL) {
8784 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8785 
8786 				if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8787 					*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8788 				}
8789 			}
8790 			if (returned_v6_gateway != NULL &&
8791 			    v6Route->rt_gateway != NULL &&
8792 			    v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8793 				SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8794 			}
8795 			rtfree(v6Route);
8796 			v6Route = NULL;
8797 		}
8798 	}
8799 
8800 	// Take two passes through the rule list: first for rules that don't match based on agents,
8801 	// second for rules that match based on agents. Since rules can modify the agent list itself,
8802 	// this makes the logic more deterministic. This allows a non-agent matching rule to remove
8803 	// an agent before it is used for matching later.
8804 	size_t route_rule_index = 0;
8805 	bool second_pass = false;
8806 	while (route_rule_index < route_rule_id_array_count) {
8807 		bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8808 		if (rule_matches_agents != second_pass) {
8809 			// Process rules that match based on agents only in the second pass
8810 			route_rule_index++;
8811 			if (route_rule_index == route_rule_id_array_count && !second_pass) {
8812 				route_rule_index = 0;
8813 				second_pass = true;
8814 			}
8815 			continue;
8816 		}
8817 
8818 		u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8819 		bool route_is_allowed = necp_route_is_allowed(rt, NULL, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &interface_type_denied);
8820 		if (!route_is_allowed) {
8821 			// If the route is blocked, treat the lookup as a drop
8822 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8823 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8824 
8825 			if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8826 				if (reason != NULL) {
8827 					if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8828 						*reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8829 					} else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8830 						*reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8831 					}
8832 				}
8833 				necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8834 			}
8835 			// If the route gets denied, stop matching rules
8836 			break;
8837 		}
8838 
8839 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8840 		if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8841 			u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8842 			    route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8843 			if (flow_divert_control_unit != 0) {
8844 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8845 				returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8846 			}
8847 			if (flow_divert_aggregate_unit != 0) {
8848 				returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8849 			}
8850 		}
8851 
8852 		// Check if there is a route rule that adds or removes an agent
8853 		bool remove = false;
8854 		u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8855 		if (netagent_id != 0) {
8856 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8857 			if (mapping != NULL) {
8858 				bool agent_already_present = false;
8859 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8860 					if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8861 						// Found the agent already present
8862 						agent_already_present = true;
8863 						if (remove) {
8864 							// Mark as remove if necessary
8865 							returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8866 						}
8867 					} else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8868 						// Found open slot
8869 						if (!agent_already_present) {
8870 							uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8871 							if (remove) {
8872 								returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8873 							} else {
8874 								returned_result->netagent_use_flags[netagent_cursor] = 0;
8875 							}
8876 						}
8877 						break;
8878 					}
8879 				}
8880 			}
8881 
8882 			// Update the local netagent_ids array for future evaluations
8883 			if (remove) {
8884 				// Check if the agent ID is in the array, and remove it
8885 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8886 					if (netagent_id == netagent_ids[netagent_cursor]) {
8887 						netagent_ids[netagent_cursor] = 0;
8888 					}
8889 				}
8890 			} else {
8891 				// Check if the agent ID is not yet in the array, and add it
8892 				bool found = false;
8893 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8894 					if (netagent_id == netagent_ids[netagent_cursor]) {
8895 						found = true;
8896 						break;
8897 					}
8898 				}
8899 				if (!found) {
8900 					for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8901 						if (netagent_ids[netagent_cursor] == 0) {
8902 							// Empty slot, add the agent
8903 							netagent_ids[netagent_cursor] = netagent_id;
8904 							break;
8905 						}
8906 					}
8907 				}
8908 			}
8909 		}
8910 
8911 		route_rule_index++;
8912 		if (route_rule_index == route_rule_id_array_count && !second_pass) {
8913 			route_rule_index = 0;
8914 			second_pass = true;
8915 		}
8916 	}
8917 
8918 	if (rt != NULL && rt->rt_ifp != NULL) {
8919 		const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8920 		const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8921 		const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8922 		    IFNET_IS_EXPENSIVE(rt->rt_ifp));
8923 		const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8924 		    IFNET_IS_CONSTRAINED(rt->rt_ifp));
8925 		const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8926 		    IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8927 		    !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8928 
8929 		const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8930 		if (!is_listener && !is_browser) {
8931 			if (reason != NULL) {
8932 				if (expensive_prohibited) {
8933 					*reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8934 				} else if (constrained_prohibited) {
8935 					*reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8936 				} else if (ultra_constrained_not_allowed) {
8937 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8938 					necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
8939 				}
8940 			}
8941 			if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8942 				// If a property of the interface was not allowed, treat it as a drop
8943 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8944 				memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8945 			}
8946 		}
8947 	}
8948 
8949 	if (rt != NULL) {
8950 		if (returned_route != NULL) {
8951 			*returned_route = rt;
8952 		} else {
8953 			rtfree(rt);
8954 		}
8955 		rt = NULL;
8956 	}
8957 
8958 done:
8959 	// Unlock
8960 	lck_rw_done(&necp_kernel_policy_lock);
8961 
8962 	if (release_eproc && effective_proc != PROC_NULL) {
8963 		proc_rele(effective_proc);
8964 	}
8965 #if defined(XNU_TARGET_OS_OSX)
8966 	if (responsible_proc != PROC_NULL) {
8967 		proc_rele(responsible_proc);
8968 	}
8969 #endif
8970 
8971 	if (cred != NULL) {
8972 		kauth_cred_unref(&cred);
8973 	}
8974 
8975 	return error;
8976 }
8977 
8978 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8979 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8980 {
8981 	struct rtentry *rt = NULL;
8982 	bool is_local = FALSE;
8983 
8984 	if (remote_addr == NULL) {
8985 		return NULL;
8986 	}
8987 
8988 	if (remote_addr->sa.sa_len == 0 ||
8989 	    (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8990 	    (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8991 		return FALSE;
8992 	}
8993 
8994 	// Lookup route regardless of the scoped interface to check if
8995 	// remote address is in a local network.
8996 	rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8997 
8998 	if (rt == NULL) {
8999 		goto done;
9000 	}
9001 	if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
9002 		goto free_rt;
9003 	}
9004 	is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9005 
9006 free_rt:
9007 	rtfree(rt);
9008 
9009 done:
9010 	return is_local;
9011 }
9012 
9013 static bool
necp_socket_check_policy(struct necp_kernel_socket_policy * kernel_policy,necp_app_id app_id,necp_app_id real_app_id,uint8_t is_entitled,u_int32_t account_id,struct substring domain,u_int8_t domain_dot_count,const char * url __null_terminated,pid_t pid,int32_t pid_version,uid_t uid,uid_t real_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 * __counted_by (num_required_agent_types)required_agent_types,u_int32_t num_required_agent_types,bool has_client,uint32_t client_flags,int is_platform_binary,bool has_signed_result,proc_t proc,u_int16_t pf_tag,u_int16_t scheme_port,struct rtentry * rt,bool is_loopback,int debug,bool real_is_platform_binary,u_int32_t bound_interface_flags,u_int32_t bound_interface_eflags,u_int32_t bound_interface_xflags,struct necp_socket_info * info,bool is_delegated,struct socket * socket)9014 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9015     necp_app_id app_id,
9016     necp_app_id real_app_id,
9017     uint8_t is_entitled,
9018     u_int32_t account_id,
9019     struct substring domain,
9020     u_int8_t domain_dot_count,
9021     const char *url __null_terminated,
9022     pid_t pid,
9023     int32_t pid_version,
9024     uid_t uid,
9025     uid_t real_uid,
9026     u_int32_t bound_interface_index,
9027     u_int32_t traffic_class,
9028     u_int16_t protocol,
9029     union necp_sockaddr_union *local,
9030     union necp_sockaddr_union *remote,
9031     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9032     u_int32_t num_required_agent_types,
9033     bool has_client,
9034     uint32_t client_flags,
9035     int is_platform_binary,
9036     bool has_signed_result,
9037     proc_t proc,
9038     u_int16_t pf_tag,
9039     u_int16_t scheme_port,
9040     struct rtentry *rt,
9041     bool is_loopback,
9042     int debug,
9043     bool real_is_platform_binary,
9044     u_int32_t bound_interface_flags,
9045     u_int32_t bound_interface_eflags,
9046     u_int32_t bound_interface_xflags,
9047     struct necp_socket_info *info,
9048     bool is_delegated,
9049     struct socket *socket)
9050 {
9051 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9052 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9053 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9054 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9055 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9056 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9057 				if (bound_interface_index == cond_bound_interface_index) {
9058 					// No match, matches forbidden interface
9059 					return FALSE;
9060 				}
9061 			} else {
9062 				if (bound_interface_index != cond_bound_interface_index) {
9063 					// No match, does not match required interface
9064 					return FALSE;
9065 				}
9066 			}
9067 		}
9068 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9069 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9070 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9071 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9072 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9073 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9074 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9075 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9076 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9077 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9078 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9079 					// No match, matches some forbidden interface flags
9080 					return FALSE;
9081 				}
9082 			} else {
9083 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9084 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9085 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9086 					// No match, does not match some required interface xflags
9087 					return FALSE;
9088 				}
9089 			}
9090 		}
9091 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9092 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9093 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9094 			if (bound_interface_index != 0) {
9095 				// No match, requires a non-bound packet
9096 				return FALSE;
9097 			}
9098 		}
9099 	}
9100 
9101 	if (kernel_policy->condition_mask == 0) {
9102 		return TRUE;
9103 	}
9104 
9105 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9106 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9107 		    "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9108 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9109 			if (app_id == kernel_policy->cond_app_id) {
9110 				// No match, matches forbidden application
9111 				return FALSE;
9112 			}
9113 		} else {
9114 			if (app_id != kernel_policy->cond_app_id) {
9115 				// No match, does not match required application
9116 				return FALSE;
9117 			}
9118 		}
9119 
9120 		// Check signing identifier only after APP ID matched
9121 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9122 		    kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9123 			u_int8_t matched = necp_boolean_state_false;
9124 			const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9125 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9126 			    "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9127 			    kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9128 			    signing_id ? signing_id : "<n/a>");
9129 			if (signing_id != NULL) {
9130 				if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9131 					matched = necp_boolean_state_true;
9132 				}
9133 			}
9134 
9135 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9136 				if (matched == necp_boolean_state_true) {
9137 					return FALSE;
9138 				}
9139 			} else {
9140 				if (matched != necp_boolean_state_true) {
9141 					return FALSE;
9142 				}
9143 			}
9144 		}
9145 	}
9146 
9147 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9148 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9149 		    "NECP_KERNEL_CONDITION_REAL_APP_ID",
9150 		    kernel_policy->cond_real_app_id, real_app_id);
9151 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9152 			if (real_app_id == kernel_policy->cond_real_app_id) {
9153 				// No match, matches forbidden application
9154 				return FALSE;
9155 			}
9156 		} else {
9157 			if (real_app_id != kernel_policy->cond_real_app_id) {
9158 				// No match, does not match required application
9159 				return FALSE;
9160 			}
9161 		}
9162 	}
9163 
9164 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9165 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9166 		if (!has_client) {
9167 			return FALSE;
9168 		}
9169 	}
9170 
9171 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9172 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9173 		if (!is_entitled) {
9174 			// Process is missing entitlement
9175 			return FALSE;
9176 		}
9177 	}
9178 
9179 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9180 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY, "NECP_KERNEL_CONDITION_PLATFORM_BINARY", 0, is_platform_binary);
9181 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9182 			if (is_platform_binary) {
9183 				// Process is platform binary
9184 				return FALSE;
9185 			}
9186 		} else {
9187 			if (!is_platform_binary) {
9188 				// Process is not platform binary
9189 				return FALSE;
9190 			}
9191 		}
9192 	}
9193 
9194 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9195 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9196 		if (has_signed_result == 0) {
9197 			// Client did not have a system-signed result
9198 			return FALSE;
9199 		}
9200 	}
9201 
9202 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9203 		if (proc != NULL) {
9204 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9205 			    kernel_policy->cond_sdk_version.platform,
9206 			    kernel_policy->cond_sdk_version.min_version,
9207 			    kernel_policy->cond_sdk_version.version,
9208 			    proc_platform(proc),
9209 			    proc_min_sdk(proc),
9210 			    proc_sdk(proc));
9211 			if (kernel_policy->cond_sdk_version.platform != 0) {
9212 				if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9213 					// Process does not match platform
9214 					return FALSE;
9215 				}
9216 			}
9217 
9218 			if (kernel_policy->cond_sdk_version.min_version != 0) {
9219 				if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9220 					// Process min version is older than required min version
9221 					return FALSE;
9222 				}
9223 			}
9224 
9225 			if (kernel_policy->cond_sdk_version.version != 0) {
9226 				if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9227 					// Process SDK version is older than required version
9228 					return FALSE;
9229 				}
9230 			}
9231 		}
9232 	}
9233 
9234 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9235 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9236 		if (kernel_policy->cond_custom_entitlement != NULL) {
9237 			if (proc == NULL) {
9238 				// No process found, cannot check entitlement
9239 				return FALSE;
9240 			}
9241 			task_t __single task = proc_task(proc);
9242 			if (task == NULL ||
9243 			    !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
9244 				// Process is missing custom entitlement
9245 				return FALSE;
9246 			}
9247 		}
9248 	}
9249 
9250 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9251 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9252 		    "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9253 		// Exact match requires the number of dots to match (no suffix matching allowed)
9254 		bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9255 		    necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9256 		if (domain_matches && socket != NULL) {
9257 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9258 		}
9259 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9260 			if (domain_matches) {
9261 				// No match, matches forbidden domain
9262 				return FALSE;
9263 			}
9264 		} else {
9265 			if (!domain_matches) {
9266 				// No match, does not match required domain
9267 				return FALSE;
9268 			}
9269 		}
9270 	} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9271 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9272 		    "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9273 		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9274 		if (domain_matches && socket != NULL) {
9275 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9276 		}
9277 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9278 			if (domain_matches) {
9279 				// No match, matches forbidden domain
9280 				return FALSE;
9281 			}
9282 		} else {
9283 			if (!domain_matches) {
9284 				// No match, does not match required domain
9285 				return FALSE;
9286 			}
9287 		}
9288 	}
9289 
9290 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9291 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9292 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9293 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9294 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9295 		bool domain_matches = false;
9296 		if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9297 			struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9298 			if (filter != NULL && filter->filter != NULL) {
9299 				domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9300 			}
9301 		} else {
9302 			domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9303 			if (debug) {
9304 				NECPLOG(LOG_ERR, "DATA-TRACE: matching <%s %zu> with trie id %d - matched %d", domain.string, domain.length, kernel_policy->cond_domain_filter, domain_matches);
9305 			}
9306 		}
9307 		if (domain_matches && socket != NULL) {
9308 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9309 		}
9310 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9311 			if (domain_matches) {
9312 				// No match, matches forbidden domain
9313 				return FALSE;
9314 			}
9315 		} else {
9316 			if (!domain_matches) {
9317 				// No match, does not match required domain
9318 				return FALSE;
9319 			}
9320 		}
9321 	}
9322 
9323 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9324 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9325 		    "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9326 		bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9327 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9328 			if (url_matches) {
9329 				// No match, matches forbidden url
9330 				return FALSE;
9331 			}
9332 		} else {
9333 			if (!url_matches) {
9334 				// No match, does not match required url
9335 				return FALSE;
9336 			}
9337 		}
9338 	}
9339 
9340 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9341 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9342 		    "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9343 		    kernel_policy->cond_account_id, account_id);
9344 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9345 			if (account_id == kernel_policy->cond_account_id) {
9346 				// No match, matches forbidden account
9347 				return FALSE;
9348 			}
9349 		} else {
9350 			if (account_id != kernel_policy->cond_account_id) {
9351 				// No match, does not match required account
9352 				return FALSE;
9353 			}
9354 		}
9355 	}
9356 
9357 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9358 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9359 		    "NECP_KERNEL_CONDITION_PID",
9360 		    kernel_policy->cond_pid, pid);
9361 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9362 			if (pid == kernel_policy->cond_pid) {
9363 				// No match, matches forbidden pid
9364 				return FALSE;
9365 			}
9366 			if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9367 				return FALSE;
9368 			}
9369 		} else {
9370 			if (pid != kernel_policy->cond_pid) {
9371 				// No match, does not match required pid
9372 				return FALSE;
9373 			}
9374 			if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9375 				return FALSE;
9376 			}
9377 		}
9378 	}
9379 
9380 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9381 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9382 		    "NECP_KERNEL_CONDITION_UID",
9383 		    kernel_policy->cond_uid, uid);
9384 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9385 			if (uid == kernel_policy->cond_uid) {
9386 				// No match, matches forbidden uid
9387 				return FALSE;
9388 			}
9389 		} else {
9390 			if (uid != kernel_policy->cond_uid) {
9391 				// No match, does not match required uid
9392 				return FALSE;
9393 			}
9394 		}
9395 	}
9396 
9397 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9398 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9399 		    "NECP_KERNEL_CONDITION_REAL_UID",
9400 		    kernel_policy->cond_real_uid, real_uid);
9401 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9402 			if (real_uid == kernel_policy->cond_real_uid) {
9403 				// No match, matches forbidden uid
9404 				return FALSE;
9405 			}
9406 		} else {
9407 			if (real_uid != kernel_policy->cond_real_uid) {
9408 				// No match, does not match required uid
9409 				return FALSE;
9410 			}
9411 		}
9412 	}
9413 
9414 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9415 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9416 		    kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9417 		    traffic_class, 0, 0);
9418 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9419 			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9420 			    traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9421 				// No match, matches forbidden traffic class
9422 				return FALSE;
9423 			}
9424 		} else {
9425 			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9426 			    traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9427 				// No match, does not match required traffic class
9428 				return FALSE;
9429 			}
9430 		}
9431 	}
9432 
9433 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9434 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9435 		    "NECP_KERNEL_CONDITION_PROTOCOL",
9436 		    kernel_policy->cond_protocol, protocol);
9437 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9438 			if (protocol == kernel_policy->cond_protocol) {
9439 				// No match, matches forbidden protocol
9440 				return FALSE;
9441 			}
9442 		} else {
9443 			if (protocol != kernel_policy->cond_protocol) {
9444 				// No match, does not match required protocol
9445 				return FALSE;
9446 			}
9447 		}
9448 	}
9449 
9450 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9451 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9452 		    kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9453 		    "n/a", "n/a", "n/a");
9454 		bool matches_agent_type = FALSE;
9455 		for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9456 			struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9457 			if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9458 			    strbufcmp(required_agent_type->netagent_domain, sizeof(required_agent_type->netagent_domain), kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0) &&
9459 			    (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9460 			    strbufcmp(required_agent_type->netagent_type, sizeof(required_agent_type->netagent_type), kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0)) {
9461 				// Found a required agent that matches
9462 				matches_agent_type = TRUE;
9463 				break;
9464 			}
9465 		}
9466 		if (!matches_agent_type) {
9467 			return FALSE;
9468 		}
9469 	}
9470 
9471 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9472 		bool is_local = FALSE;
9473 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9474 
9475 		if (rt != NULL) {
9476 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9477 		} else {
9478 			is_local = necp_is_route_local(remote, include_local_addresses);
9479 		}
9480 		if (info != NULL) {
9481 			info->is_local = is_local;
9482 		}
9483 
9484 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
9485 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9486 			if (is_local) {
9487 				// Match local-networks, fail
9488 				return FALSE;
9489 			}
9490 		} else {
9491 			if (!is_local) {
9492 				// Either no route to validate or no match for local networks
9493 				return FALSE;
9494 			}
9495 		}
9496 	}
9497 
9498 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9499 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9500 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9501 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9502 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9503 				if (inRange) {
9504 					return FALSE;
9505 				}
9506 			} else {
9507 				if (!inRange) {
9508 					return FALSE;
9509 				}
9510 			}
9511 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9512 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9513 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
9514 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9515 				if (inSubnet) {
9516 					return FALSE;
9517 				}
9518 			} else {
9519 				if (!inSubnet) {
9520 					return FALSE;
9521 				}
9522 			}
9523 		}
9524 	}
9525 
9526 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9527 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9528 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9529 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9530 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9531 				if (inRange) {
9532 					return FALSE;
9533 				}
9534 			} else {
9535 				if (!inRange) {
9536 					return FALSE;
9537 				}
9538 			}
9539 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9540 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9541 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
9542 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9543 				if (inSubnet) {
9544 					return FALSE;
9545 				}
9546 			} else {
9547 				if (!inSubnet) {
9548 					return FALSE;
9549 				}
9550 			}
9551 		}
9552 	}
9553 
9554 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9555 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9556 		    "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9557 		    kernel_policy->cond_client_flags, client_flags);
9558 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9559 			if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9560 				// Flags do match, and condition is negative, fail.
9561 				return FALSE;
9562 			}
9563 		} else {
9564 			if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9565 				// Flags do not match, fail.
9566 				return FALSE;
9567 			}
9568 		}
9569 	}
9570 
9571 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9572 		bool isEmpty = necp_addr_is_empty(SA(local));
9573 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9574 		    "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9575 		    0, isEmpty);
9576 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9577 			if (isEmpty) {
9578 				return FALSE;
9579 			}
9580 		} else {
9581 			if (!isEmpty) {
9582 				return FALSE;
9583 			}
9584 		}
9585 	}
9586 
9587 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9588 		bool isEmpty = necp_addr_is_empty(SA(remote));
9589 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9590 		    "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9591 		    0, isEmpty);
9592 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9593 			if (isEmpty) {
9594 				return FALSE;
9595 			}
9596 		} else {
9597 			if (!isEmpty) {
9598 				return FALSE;
9599 			}
9600 		}
9601 	}
9602 
9603 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9604 		u_int16_t remote_port = 0;
9605 		if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9606 			remote_port = SIN(remote)->sin_port;
9607 		}
9608 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9609 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
9610 		    scheme_port, remote_port);
9611 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9612 			if (kernel_policy->cond_scheme_port == scheme_port ||
9613 			    kernel_policy->cond_scheme_port == remote_port) {
9614 				return FALSE;
9615 			}
9616 		} else {
9617 			if (kernel_policy->cond_scheme_port != scheme_port &&
9618 			    kernel_policy->cond_scheme_port != remote_port) {
9619 				return FALSE;
9620 			}
9621 		}
9622 	}
9623 
9624 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9625 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9626 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9627 		    kernel_policy->cond_packet_filter_tags,
9628 		    pf_tag);
9629 		bool tags_matched = false;
9630 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9631 			if (pf_tag == PF_TAG_ID_STACK_DROP) {
9632 				tags_matched = true;
9633 			}
9634 		}
9635 
9636 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9637 			if (tags_matched) {
9638 				return FALSE;
9639 			}
9640 		} else {
9641 			if (!tags_matched) {
9642 				return FALSE;
9643 			}
9644 		}
9645 	}
9646 
9647 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9648 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9649 		    "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9650 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9651 			if (is_loopback) {
9652 				return FALSE;
9653 			}
9654 		} else {
9655 			if (!is_loopback) {
9656 				return FALSE;
9657 			}
9658 		}
9659 	}
9660 
9661 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9662 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9663 		    "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9664 		if (is_delegated) {
9665 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9666 				if (real_is_platform_binary) {
9667 					return FALSE;
9668 				}
9669 			} else {
9670 				if (!real_is_platform_binary) {
9671 					return FALSE;
9672 				}
9673 			}
9674 		} else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9675 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9676 			// If the connection is not delegated, and the policy did not specify a particular effective process UUID
9677 			// or PID, check the process directly
9678 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9679 				if (is_platform_binary) {
9680 					return FALSE;
9681 				}
9682 			} else {
9683 				if (!is_platform_binary) {
9684 					return FALSE;
9685 				}
9686 			}
9687 		}
9688 	}
9689 
9690 	return TRUE;
9691 }
9692 
9693 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9694 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9695 {
9696 	return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9697 }
9698 
9699 static void
necp_socket_fillout_info_locked(struct inpcb * inp,struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,u_int32_t override_bound_interface,soflow_direction_t override_direction,u_int32_t drop_order,proc_t * socket_proc,struct necp_socket_info * info,bool is_loopback,int input_ifindex)9700 necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, soflow_direction_t override_direction, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback, int input_ifindex)
9701 {
9702 	struct socket *so = NULL;
9703 	proc_t sock_proc = NULL;
9704 	proc_t curr_proc = current_proc();
9705 
9706 	memset(info, 0, sizeof(struct necp_socket_info));
9707 
9708 	so = inp->inp_socket;
9709 
9710 	info->drop_order = drop_order;
9711 	info->is_loopback = is_loopback;
9712 	info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9713 
9714 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9715 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9716 		info->uid = kauth_cred_getuid(so->so_cred);
9717 		info->real_uid = info->uid;
9718 	}
9719 
9720 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9721 		info->traffic_class = so->so_traffic_class;
9722 	}
9723 
9724 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9725 		info->has_client = !uuid_is_null(inp->necp_client_uuid);
9726 	}
9727 
9728 	if (inp->inp_ip_p) {
9729 		info->protocol = inp->inp_ip_p;
9730 	} else {
9731 		info->protocol = SOCK_PROTO(so);
9732 	}
9733 
9734 	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9735 		u_int32_t responsible_application_id = 0;
9736 
9737 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9738 		if (existing_mapping) {
9739 			info->application_id = existing_mapping->id;
9740 		}
9741 
9742 #if defined(XNU_TARGET_OS_OSX)
9743 		if (so->so_rpid > 0) {
9744 			existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9745 			if (existing_mapping != NULL) {
9746 				responsible_application_id = existing_mapping->id;
9747 			}
9748 		}
9749 #endif
9750 
9751 		if (responsible_application_id > 0) {
9752 			info->real_application_id = info->application_id;
9753 			info->application_id = responsible_application_id;
9754 			info->used_responsible_pid = true;
9755 		} else if (!(so->so_flags & SOF_DELEGATED)) {
9756 			info->real_application_id = info->application_id;
9757 		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9758 			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9759 			if (real_existing_mapping) {
9760 				info->real_application_id = real_existing_mapping->id;
9761 			}
9762 		}
9763 	}
9764 
9765 	pid_t socket_pid =
9766 #if defined(XNU_TARGET_OS_OSX)
9767 	    info->used_responsible_pid ? so->so_rpid :
9768 #endif
9769 	    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9770 	if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9771 		sock_proc = proc_find(socket_pid);
9772 		if (socket_proc) {
9773 			*socket_proc = sock_proc;
9774 		}
9775 	}
9776 
9777 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9778 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9779 		info->is_entitled = necp_task_has_match_entitlement(task);
9780 		if (!info->is_entitled) {
9781 			// Task does not have entitlement, check the parent task
9782 			necp_get_parent_is_entitled(task, info);
9783 		}
9784 	}
9785 
9786 	info->pid = socket_pid;
9787 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9788 		info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9789 	}
9790 
9791 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9792 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9793 		if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9794 			info->is_platform_binary = true;
9795 		} else if (so->so_rpid != 0) {
9796 			proc_t responsible_proc = proc_find(so->so_rpid);
9797 			if (responsible_proc != NULL) {
9798 				if (necp_is_platform_binary(responsible_proc)) {
9799 					info->is_platform_binary = true;
9800 					info->used_responsible_pid = true;
9801 				}
9802 				proc_rele(responsible_proc);
9803 			}
9804 		}
9805 	}
9806 
9807 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9808 		proc_t real_proc = curr_proc;
9809 		bool release_real_proc = false;
9810 		if (so->last_pid != proc_pid(real_proc)) {
9811 			if (so->last_pid == socket_pid && sock_proc != NULL) {
9812 				real_proc = sock_proc;
9813 			} else {
9814 				proc_t last_proc = proc_find(so->last_pid);
9815 				if (last_proc != NULL) {
9816 					real_proc = last_proc;
9817 					release_real_proc = true;
9818 				}
9819 			}
9820 		}
9821 		if (real_proc != NULL) {
9822 			if (real_proc == kernproc) {
9823 				info->real_is_platform_binary = true;
9824 			} else {
9825 				info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9826 			}
9827 			if (release_real_proc) {
9828 				proc_rele(real_proc);
9829 			}
9830 		}
9831 	}
9832 
9833 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9834 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9835 		if (existing_mapping) {
9836 			info->account_id = existing_mapping->id;
9837 		}
9838 	}
9839 
9840 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9841 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9842 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9843 		info->domain = inp->inp_necp_attributes.inp_domain;
9844 	}
9845 
9846 	if (override_bound_interface) {
9847 		info->bound_interface_index = override_bound_interface;
9848 	} else {
9849 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9850 			info->bound_interface_index = inp->inp_boundifp->if_index;
9851 		}
9852 	}
9853 
9854 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9855 	    info->bound_interface_index != IFSCOPE_NONE) {
9856 		ifnet_head_lock_shared();
9857 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9858 		if (interface != NULL) {
9859 			info->bound_interface_flags = interface->if_flags;
9860 			info->bound_interface_eflags = interface->if_eflags;
9861 			info->bound_interface_xflags = interface->if_xflags;
9862 		}
9863 		ifnet_head_done();
9864 	}
9865 
9866 	bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9867 	    uuid_is_null(inp->necp_client_uuid) &&
9868 	    necp_socket_has_resolver_signature(inp));
9869 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
9870 	    necp_restrict_multicast ||
9871 	    needs_address_for_signature ||
9872 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9873 	    NEED_DGRAM_FLOW_TRACKING(so)) {
9874 		if (override_local_addr != NULL) {
9875 			if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9876 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9877 				if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9878 					struct sockaddr_in sin;
9879 					in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9880 					memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9881 					memcpy(&info->local_addr, &sin, sin.sin_len);
9882 				}
9883 			} else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9884 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9885 			}
9886 		} else {
9887 			if (inp->inp_vflag & INP_IPV6) {
9888 				SIN6(&info->local_addr)->sin6_family = AF_INET6;
9889 				SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9890 				SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9891 				memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9892 			} else if (inp->inp_vflag & INP_IPV4) {
9893 				SIN(&info->local_addr)->sin_family = AF_INET;
9894 				SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9895 				SIN(&info->local_addr)->sin_port = inp->inp_lport;
9896 				memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9897 			}
9898 		}
9899 
9900 		if (override_remote_addr != NULL) {
9901 			if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9902 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9903 				if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9904 					struct sockaddr_in sin;
9905 					in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9906 					memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9907 					memcpy(&info->remote_addr, &sin, sin.sin_len);
9908 				}
9909 			} else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9910 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9911 			}
9912 		} else {
9913 			if (inp->inp_vflag & INP_IPV6) {
9914 				SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9915 				SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9916 				SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9917 				memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9918 			} else if (inp->inp_vflag & INP_IPV4) {
9919 				SIN(&info->remote_addr)->sin_family = AF_INET;
9920 				SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9921 				SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9922 				memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9923 			}
9924 		}
9925 		// Clear the embedded scope id from v6 addresses
9926 		if (info->local_addr.sa.sa_family == AF_INET6) {
9927 			struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9928 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9929 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9930 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9931 					sin6->sin6_addr.s6_addr16[1] = 0;
9932 				}
9933 			}
9934 		}
9935 		if (info->remote_addr.sa.sa_family == AF_INET6) {
9936 			struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9937 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9938 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9939 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9940 					sin6->sin6_addr.s6_addr16[1] = 0;
9941 				}
9942 			}
9943 		}
9944 	}
9945 
9946 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9947 		// For checking sockets, only validate that there is an NECP client present. It will have
9948 		// already checked for the signature.
9949 		if (!uuid_is_null(inp->necp_client_uuid)) {
9950 			info->has_system_signed_result = true;
9951 		} else {
9952 			info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9953 		}
9954 	}
9955 
9956 	if (NEED_DGRAM_FLOW_TRACKING(so)) {
9957 		info->soflow_entry = soflow_get_flow(so, NULL, &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
9958 	} else {
9959 		info->soflow_entry = NULL;
9960 	}
9961 
9962 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9963 		info->client_flags = 0;
9964 		if (INP_NO_CONSTRAINED(inp)) {
9965 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9966 		}
9967 		if (INP_NO_EXPENSIVE(inp)) {
9968 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9969 		}
9970 		if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9971 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9972 		}
9973 		if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9974 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9975 		}
9976 		if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9977 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9978 		}
9979 		if (NEED_DGRAM_FLOW_TRACKING(so)) {
9980 			// If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
9981 			// and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
9982 			if (info->soflow_entry != NULL) {
9983 				if (!info->soflow_entry->soflow_outgoing) {
9984 					info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9985 				}
9986 			} else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
9987 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9988 			}
9989 		} else {
9990 			// If the socket is explicitly marked as inbound then set the inbound flag.
9991 			if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
9992 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9993 			}
9994 		}
9995 		if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9996 		    inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9997 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9998 		}
9999 		if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
10000 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
10001 		}
10002 		if (inp->inp_socket->so_options & SO_REUSEPORT) {
10003 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
10004 		}
10005 	}
10006 }
10007 
10008 #define IS_NECP_KERNEL_POLICY_IP_RESULT(result) (result == NECP_KERNEL_POLICY_RESULT_PASS || result == NECP_KERNEL_POLICY_RESULT_DROP || result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL || result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES)
10009 
10010 static inline struct necp_kernel_socket_policy *
necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,struct necp_socket_info * info,necp_kernel_policy_filter * return_filter,u_int32_t * __counted_by (route_rule_id_array_count)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 * __counted_by (netagent_array_count)return_netagent_array,size_t netagent_array_count,u_int32_t * __counted_by (netagent_use_flags_array_count)return_netagent_use_flags_array,size_t netagent_use_flags_array_count,struct necp_client_parameter_netagent_type * __counted_by (num_required_agent_types)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,struct socket * so,int debug)10011 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
10012     struct necp_socket_info *info,
10013     necp_kernel_policy_filter *return_filter,
10014     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10015     size_t *return_route_rule_id_array_count,
10016     size_t route_rule_id_array_count,
10017     necp_kernel_policy_result *return_service_action,
10018     necp_kernel_policy_service *return_service,
10019     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10020     size_t netagent_array_count,
10021     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10022     size_t netagent_use_flags_array_count,
10023     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10024     u_int32_t num_required_agent_types,
10025     proc_t proc,
10026     u_int16_t pf_tag,
10027     necp_kernel_policy_id *skip_policy_id,
10028     struct rtentry *rt,
10029     necp_kernel_policy_result *return_drop_dest_policy_result,
10030     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10031     u_int32_t *return_flow_divert_aggregate_unit,
10032     struct socket *so,
10033     int debug)
10034 {
10035 	struct necp_kernel_socket_policy *matched_policy = NULL;
10036 	u_int32_t skip_order = 0;
10037 	u_int32_t skip_session_order = 0;
10038 	bool skipped_ip_result = false;
10039 	size_t route_rule_id_count = 0;
10040 	int i;
10041 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10042 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10043 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10044 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10045 	size_t netagent_cursor = 0;
10046 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10047 	size_t netagent_array_count_adjusted = netagent_array_count;
10048 	if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10049 		netagent_array_count_adjusted = netagent_use_flags_array_count;
10050 	}
10051 
10052 	if (return_drop_all_bypass != NULL) {
10053 		*return_drop_all_bypass = drop_all_bypass;
10054 	}
10055 
10056 	if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10057 		netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10058 	}
10059 
10060 	// Pre-process domain for quick matching
10061 	struct substring domain_substring = {};
10062 	u_int8_t domain_dot_count = 0;
10063 	if (info->domain != NULL) {
10064 		domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10065 		domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10066 	}
10067 
10068 	if (return_filter != NULL) {
10069 		*return_filter = 0;
10070 	}
10071 
10072 	if (return_route_rule_id_array_count != NULL) {
10073 		*return_route_rule_id_array_count = 0;
10074 	}
10075 
10076 	if (return_service_action != NULL) {
10077 		*return_service_action = 0;
10078 	}
10079 
10080 	if (return_service != NULL) {
10081 		return_service->identifier = 0;
10082 		return_service->data = 0;
10083 	}
10084 
10085 	// Do not subject layer-2 filter to NECP policies, return a PASS policy
10086 	if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10087 		return &pass_policy;
10088 	}
10089 
10090 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10091 
10092 	if (policy_search_array != NULL) {
10093 		for (i = 0; policy_search_array[i] != NULL; i++) {
10094 			NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10095 
10096 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10097 				// We've hit a drop all rule
10098 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10099 					drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10100 					if (return_drop_all_bypass != NULL) {
10101 						*return_drop_all_bypass = drop_all_bypass;
10102 					}
10103 				}
10104 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10105 					NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10106 					break;
10107 				}
10108 			}
10109 			if (necp_drop_dest_policy.entry_count != 0 &&
10110 			    necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10111 				// We've hit a drop by destination address rule
10112 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10113 				break;
10114 			}
10115 			if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10116 				// We've hit a drop order for this socket
10117 				break;
10118 			}
10119 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10120 				// Done skipping
10121 				skip_order = 0;
10122 				skip_session_order = 0;
10123 				// If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10124 				if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10125 					*skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10126 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10127 				}
10128 			}
10129 			if (skip_order) {
10130 				if (policy_search_array[i]->order < skip_order) {
10131 					// Skip this policy
10132 					// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10133 					// didn't, clear out the return value for skip ID when we are done with each session.'
10134 					if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10135 						skipped_ip_result = true;
10136 						NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10137 					}
10138 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10139 					continue;
10140 				} else {
10141 					// Done skipping
10142 					skip_order = 0;
10143 					skip_session_order = 0;
10144 				}
10145 			} else if (skip_session_order) {
10146 				// Skip this policy
10147 				// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10148 				// didn't, clear out the return value for skip ID when we are done with each session.'
10149 				if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10150 					skipped_ip_result = true;
10151 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10152 				}
10153 				NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10154 				continue;
10155 			}
10156 
10157 			if (necp_socket_check_policy(policy_search_array[i],
10158 			    info->application_id,
10159 			    info->real_application_id,
10160 			    info->is_entitled,
10161 			    info->account_id,
10162 			    domain_substring,
10163 			    domain_dot_count,
10164 			    info->url,
10165 			    info->pid,
10166 			    info->pid_version,
10167 			    info->uid,
10168 			    info->real_uid,
10169 			    info->bound_interface_index,
10170 			    info->traffic_class,
10171 			    info->protocol,
10172 			    &info->local_addr,
10173 			    &info->remote_addr,
10174 			    required_agent_types,
10175 			    num_required_agent_types,
10176 			    info->has_client,
10177 			    info->client_flags,
10178 			    info->is_platform_binary,
10179 			    info->has_system_signed_result,
10180 			    proc,
10181 			    pf_tag,
10182 			    info->scheme_port,
10183 			    rt,
10184 			    info->is_loopback,
10185 			    debug,
10186 			    info->real_is_platform_binary,
10187 			    info->bound_interface_flags,
10188 			    info->bound_interface_eflags,
10189 			    info->bound_interface_xflags,
10190 			    info,
10191 			    info->is_delegated,
10192 			    so)) {
10193 				if (!debug && necp_data_tracing_session_order) {
10194 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10195 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10196 						NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10197 					}
10198 				}
10199 
10200 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10201 					if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10202 						necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10203 						if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10204 							*return_filter = control_unit;
10205 						} else {
10206 							// Preserve pre-existing connections only if all filters preserve.
10207 							bool preserve_bit_off = false;
10208 							if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10209 							    (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10210 								preserve_bit_off = true;
10211 							}
10212 							*return_filter |= control_unit;
10213 							if (preserve_bit_off == true) {
10214 								*return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10215 							}
10216 						}
10217 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10218 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *return_filter);
10219 						}
10220 					}
10221 					continue;
10222 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10223 					if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10224 						return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10225 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10226 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.route_rule_id);
10227 						}
10228 					}
10229 					continue;
10230 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10231 				    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10232 					if (netagent_cursor < netagent_array_count_adjusted) {
10233 						bool agent_already_present = false;
10234 						for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10235 							if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10236 								// Already present. Mark the "SCOPED" flag if flags are necessary.
10237 								agent_already_present = true;
10238 								if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10239 								    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10240 									netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10241 								}
10242 							}
10243 						}
10244 
10245 						if (!agent_already_present) {
10246 							netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10247 							if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10248 								netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10249 							}
10250 							netagent_cursor++;
10251 						}
10252 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10253 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10254 							    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10255 							    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10256 							    policy_search_array[i]->result_parameter.netagent_id);
10257 						}
10258 					}
10259 					continue;
10260 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10261 					bool agent_already_present = false;
10262 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10263 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10264 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10265 							agent_already_present = true;
10266 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10267 						}
10268 					}
10269 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10270 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
10271 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10272 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10273 						netagent_cursor++;
10274 					}
10275 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10276 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10277 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10278 						    policy_search_array[i]->result_parameter.netagent_id);
10279 					}
10280 					continue;
10281 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10282 					u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10283 					if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10284 						/* For transparent proxies, accumulate the control unit and continue to the next policy */
10285 						if (return_flow_divert_aggregate_unit != NULL) {
10286 							*return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10287 							if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10288 								NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, control_unit);
10289 							}
10290 						}
10291 						continue;
10292 					}
10293 				}
10294 
10295 				// Matched policy is a skip. Do skip and continue.
10296 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10297 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10298 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10299 					skip_session_order = policy_search_array[i]->session_order + 1;
10300 					if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10301 						*skip_policy_id = policy_search_array[i]->id;
10302 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10303 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: MATCHED SKIP POLICY (Application %d Real Application %d BoundInterface %d Proto %d) set skip_policy_id %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *skip_policy_id);
10304 						}
10305 					}
10306 					continue;
10307 				}
10308 
10309 				// Matched an allow unentitled, which clears any drop order
10310 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10311 					info->drop_order = 0;
10312 					continue;
10313 				}
10314 
10315 				// Passed all tests, found a match
10316 				matched_policy = policy_search_array[i];
10317 				NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10318 				break;
10319 			}
10320 		}
10321 	}
10322 
10323 	if (return_netagent_array != NULL) {
10324 		if (return_netagent_use_flags_array != NULL) {
10325 			memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10326 			memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10327 		} else {
10328 			for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10329 				if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10330 					return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10331 				} else {
10332 					return_netagent_array[netagent_i] = 0;
10333 				}
10334 			}
10335 		}
10336 	}
10337 
10338 	if (return_route_rule_id_array_count != NULL) {
10339 		*return_route_rule_id_array_count = route_rule_id_count;
10340 	}
10341 	return matched_policy;
10342 }
10343 
10344 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10345 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10346 {
10347 	bool found_match = FALSE;
10348 	ifaddr_t ifa;
10349 	union necp_sockaddr_union address_storage;
10350 	int family = AF_INET;
10351 
10352 	ifnet_head_lock_shared();
10353 	ifnet_t interface = ifindex2ifnet[interface_index];
10354 	ifnet_head_done();
10355 
10356 	if (inp == NULL || interface == NULL) {
10357 		return FALSE;
10358 	}
10359 
10360 	if (inp->inp_vflag & INP_IPV4) {
10361 		family = AF_INET;
10362 	} else if (inp->inp_vflag & INP_IPV6) {
10363 		family = AF_INET6;
10364 	} else {
10365 		return FALSE;
10366 	}
10367 
10368 	// Match socket address against interface addresses
10369 	ifnet_lock_shared(interface);
10370 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10371 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10372 			if (address_storage.sa.sa_family != family) {
10373 				continue;
10374 			}
10375 
10376 			if (family == AF_INET) {
10377 				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10378 					found_match = TRUE;
10379 					break;
10380 				}
10381 			} else if (family == AF_INET6) {
10382 				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10383 					found_match = TRUE;
10384 					break;
10385 				}
10386 			}
10387 		}
10388 	}
10389 	ifnet_lock_done(interface);
10390 
10391 	return found_match;
10392 }
10393 
10394 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10395 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10396 {
10397 	if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10398 		proc_t curr_proc = current_proc();
10399 		proc_t sock_proc = NULL;
10400 		struct socket *so = inp ? inp->inp_socket : NULL;
10401 		pid_t socket_pid = (so == NULL) ? 0 :
10402 #if defined(XNU_TARGET_OS_OSX)
10403 		    so->so_rpid ? so->so_rpid :
10404 #endif
10405 		    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10406 		if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10407 			sock_proc = proc_find(socket_pid);
10408 		}
10409 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10410 		if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10411 			if (sock_proc) {
10412 				proc_rele(sock_proc);
10413 			}
10414 			return NECP_BYPASS_TYPE_DROP;
10415 		}
10416 		if (sock_proc) {
10417 			proc_rele(sock_proc);
10418 		}
10419 
10420 		if (necp_pass_loopback > 0) {
10421 			return NECP_BYPASS_TYPE_LOOPBACK;
10422 		}
10423 	} else if (necp_is_intcoproc(inp, NULL)) {
10424 		return NECP_BYPASS_TYPE_INTCOPROC;
10425 	}
10426 
10427 	return NECP_BYPASS_TYPE_NONE;
10428 }
10429 
10430 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10431 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10432 {
10433 	u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10434 	ifnet_t tunnel_interface = NULL;
10435 
10436 	ifnet_head_lock_shared();
10437 	tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10438 	ifnet_head_done();
10439 
10440 	if (tunnel_interface != NULL) {
10441 		tcp_set_tso(intotcpcb(inp), tunnel_interface);
10442 	}
10443 }
10444 
10445 static inline void
necp_unscope(struct inpcb * inp)10446 necp_unscope(struct inpcb *inp)
10447 {
10448 	// If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10449 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10450 		inp->inp_flags &= ~INP_BOUND_IF;
10451 		inp->inp_boundifp = NULL;
10452 	}
10453 }
10454 
10455 static inline void
necp_clear_tunnel(struct inpcb * inp)10456 necp_clear_tunnel(struct inpcb *inp)
10457 {
10458 	if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10459 		inp->inp_flags &= ~INP_BOUND_IF;
10460 		inp->inp_boundifp = NULL;
10461 	}
10462 }
10463 
10464 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10465 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10466 {
10467 	// Verify netagents
10468 	for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10469 		struct necp_uuid_id_mapping *mapping = NULL;
10470 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
10471 		if (netagent_id == 0) {
10472 			continue;
10473 		}
10474 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10475 		if (mapping != NULL) {
10476 			u_int32_t agent_flags = 0;
10477 			agent_flags = netagent_get_flags(mapping->uuid);
10478 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10479 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10480 					continue;
10481 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10482 					if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10483 						int trigger_error = 0;
10484 						trigger_error = netagent_kernel_trigger(mapping->uuid);
10485 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10486 							NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> Triggering inactive agent (%d), error %d", (uint64_t)VM_KERNEL_ADDRPERM(so), netagent_id, trigger_error);
10487 						}
10488 					}
10489 					return false;
10490 				}
10491 			}
10492 		}
10493 	}
10494 	return true;
10495 }
10496 
10497 necp_kernel_policy_id
necp_socket_find_policy_match(struct inpcb * inp,struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,u_int32_t override_bound_interface)10498 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10499 {
10500 	struct socket *so = NULL;
10501 	necp_kernel_policy_filter filter_control_unit = 0;
10502 	struct necp_kernel_socket_policy *matched_policy = NULL;
10503 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10504 	necp_kernel_policy_result service_action = 0;
10505 	necp_kernel_policy_service service = { 0, 0 };
10506 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10507 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10508 	proc_t __single socket_proc = NULL;
10509 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10510 
10511 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10512 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10513 
10514 	struct necp_socket_info info = {};
10515 
10516 	u_int32_t flow_divert_aggregate_unit = 0;
10517 
10518 	if (inp == NULL) {
10519 		return NECP_KERNEL_POLICY_ID_NONE;
10520 	}
10521 
10522 	// Ignore invalid addresses
10523 	if (override_local_addr != NULL &&
10524 	    !necp_address_is_valid(override_local_addr)) {
10525 		override_local_addr = NULL;
10526 	}
10527 	if (override_remote_addr != NULL &&
10528 	    !necp_address_is_valid(override_remote_addr)) {
10529 		override_remote_addr = NULL;
10530 	}
10531 
10532 	so = inp->inp_socket;
10533 
10534 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10535 
10536 	// Don't lock. Possible race condition, but we don't want the performance hit.
10537 	if (necp_drop_management_order == 0 &&
10538 	    (necp_kernel_socket_policies_count == 0 ||
10539 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10540 		if (necp_drop_all_order > 0 || drop_order > 0) {
10541 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10542 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10543 			inp->inp_policyresult.policy_gencount = 0;
10544 			inp->inp_policyresult.app_id = 0;
10545 			inp->inp_policyresult.flowhash = 0;
10546 			inp->inp_policyresult.results.filter_control_unit = 0;
10547 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10548 			inp->inp_policyresult.results.route_rule_id = 0;
10549 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10550 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10551 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10552 			} else {
10553 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10554 			}
10555 		}
10556 		return NECP_KERNEL_POLICY_ID_NONE;
10557 	}
10558 
10559 	// Check for loopback exception
10560 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10561 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10562 		// Mark socket as a drop
10563 		necp_unscope(inp);
10564 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10565 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10566 		inp->inp_policyresult.policy_gencount = 0;
10567 		inp->inp_policyresult.app_id = 0;
10568 		inp->inp_policyresult.flowhash = 0;
10569 		inp->inp_policyresult.results.filter_control_unit = 0;
10570 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10571 		inp->inp_policyresult.results.route_rule_id = 0;
10572 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10573 		return NECP_KERNEL_POLICY_ID_NONE;
10574 	}
10575 
10576 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10577 		// Mark socket as a pass
10578 		necp_unscope(inp);
10579 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10580 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10581 		inp->inp_policyresult.policy_gencount = 0;
10582 		inp->inp_policyresult.app_id = 0;
10583 		inp->inp_policyresult.flowhash = 0;
10584 		inp->inp_policyresult.results.filter_control_unit = 0;
10585 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10586 		inp->inp_policyresult.results.route_rule_id = 0;
10587 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10588 		return NECP_KERNEL_POLICY_ID_NONE;
10589 	}
10590 
10591 	// Lock
10592 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10593 	necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, SOFLOW_DIRECTION_UNKNOWN, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), 0);
10594 
10595 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10596 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10597 
10598 	// Check info
10599 	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10600 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10601 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10602 	    inp->inp_policyresult.flowhash == flowhash) {
10603 		// If already matched this socket on this generation of table, skip
10604 
10605 		if (info.soflow_entry != NULL) {
10606 			soflow_free_flow(info.soflow_entry);
10607 		}
10608 
10609 		// Unlock
10610 		lck_rw_done(&necp_kernel_policy_lock);
10611 
10612 		if (socket_proc) {
10613 			proc_rele(socket_proc);
10614 		}
10615 
10616 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10617 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10618 			    inp->inp_socket, info.bound_interface_index, info.protocol,
10619 			    inp->inp_policyresult.policy_id,
10620 			    inp->inp_policyresult.results.result,
10621 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10622 		}
10623 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10624 		return inp->inp_policyresult.policy_id;
10625 	}
10626 
10627 	inp->inp_policyresult.app_id = info.application_id;
10628 
10629 	// Match socket to policy
10630 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10631 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10632 	size_t route_rule_id_array_count = 0;
10633 
10634 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10635 	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)],
10636 	    &info,
10637 	    &filter_control_unit,
10638 	    route_rule_id_array,
10639 	    &route_rule_id_array_count,
10640 	    MAX_AGGREGATE_ROUTE_RULES,
10641 	    &service_action,
10642 	    &service,
10643 	    netagent_ids,
10644 	    NECP_MAX_NETAGENTS,
10645 	    NULL,
10646 	    0,
10647 	    NULL,
10648 	    0,
10649 	    effective_proc,
10650 	    0,
10651 	    &skip_policy_id,
10652 	    inp->inp_route.ro_rt,
10653 	    &drop_dest_policy_result,
10654 	    &drop_all_bypass,
10655 	    &flow_divert_aggregate_unit,
10656 	    so,
10657 	    debug);
10658 
10659 	// Check for loopback exception again after the policy match
10660 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10661 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10662 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10663 		// Mark socket as a pass
10664 		necp_unscope(inp);
10665 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10666 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10667 		inp->inp_policyresult.policy_gencount = 0;
10668 		inp->inp_policyresult.app_id = 0;
10669 		inp->inp_policyresult.flowhash = 0;
10670 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10671 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10672 		inp->inp_policyresult.results.route_rule_id = 0;
10673 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10674 		if (info.soflow_entry != NULL) {
10675 			info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10676 			info.soflow_entry->soflow_policies_gencount = 0;
10677 			soflow_free_flow(info.soflow_entry);
10678 		}
10679 
10680 		// Unlock
10681 		lck_rw_done(&necp_kernel_policy_lock);
10682 
10683 		if (socket_proc) {
10684 			proc_rele(socket_proc);
10685 		}
10686 
10687 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10688 		return NECP_KERNEL_POLICY_ID_NONE;
10689 	}
10690 
10691 	// Verify netagents
10692 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10693 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10694 			NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (uint64_t)VM_KERNEL_ADDRPERM(so), info.bound_interface_index, info.protocol);
10695 		}
10696 
10697 		// Mark socket as a drop if required agent is not active
10698 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10699 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10700 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10701 		inp->inp_policyresult.flowhash = flowhash;
10702 		inp->inp_policyresult.results.filter_control_unit = 0;
10703 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10704 		inp->inp_policyresult.results.route_rule_id = 0;
10705 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10706 		if (info.soflow_entry != NULL) {
10707 			info.soflow_entry->soflow_filter_control_unit = 0;
10708 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10709 			soflow_free_flow(info.soflow_entry);
10710 		}
10711 
10712 		// Unlock
10713 		lck_rw_done(&necp_kernel_policy_lock);
10714 
10715 		if (socket_proc) {
10716 			proc_rele(socket_proc);
10717 		}
10718 
10719 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Inactive Agent DROP", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10720 		return NECP_KERNEL_POLICY_ID_NONE;
10721 	}
10722 
10723 	u_int32_t route_rule_id = 0;
10724 	if (route_rule_id_array_count == 1) {
10725 		route_rule_id = route_rule_id_array[0];
10726 	} else if (route_rule_id_array_count > 1) {
10727 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10728 	}
10729 
10730 	bool reset_tcp_tunnel_interface = false;
10731 	bool send_local_network_denied_event = false;
10732 	if (matched_policy) {
10733 		// For PASS policy result, clear previous rescope / tunnel inteface
10734 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10735 		    (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10736 			necp_unscope(inp);
10737 			necp_clear_tunnel(inp);
10738 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10739 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10740 			}
10741 		}
10742 		matched_policy_id = matched_policy->id;
10743 		inp->inp_policyresult.policy_id = matched_policy->id;
10744 		inp->inp_policyresult.skip_policy_id = skip_policy_id;
10745 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10746 		inp->inp_policyresult.flowhash = flowhash;
10747 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10748 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10749 		inp->inp_policyresult.results.route_rule_id = route_rule_id;
10750 		inp->inp_policyresult.results.result = matched_policy->result;
10751 		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10752 		if (info.soflow_entry != NULL) {
10753 			info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10754 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10755 		}
10756 
10757 		if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10758 			inp->inp_policyresult.app_id = info.real_application_id;
10759 		}
10760 
10761 		if (necp_socket_is_connected(inp) &&
10762 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10763 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10764 			NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10765 			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10766 		} else if (necp_socket_is_connected(inp) &&
10767 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10768 		    info.protocol == IPPROTO_TCP) {
10769 			// Reset TCP socket interface based parameters if tunnel policy changes
10770 			reset_tcp_tunnel_interface = true;
10771 		}
10772 
10773 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10774 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d Filter %d", (uint64_t)VM_KERNEL_ADDRPERM(so), info.bound_interface_index, info.protocol, matched_policy->id, skip_policy_id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index, inp->inp_policyresult.results.filter_control_unit);
10775 		}
10776 
10777 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10778 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10779 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10780 			// Trigger the event that we dropped due to a local network policy
10781 			send_local_network_denied_event = true;
10782 		}
10783 	} else {
10784 		bool drop_all = false;
10785 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10786 			// Mark socket as a drop if set
10787 			drop_all = true;
10788 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10789 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10790 			}
10791 		}
10792 
10793 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10794 		u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(NULL, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &flow_divert_aggregate_unit);
10795 		if (flow_divert_control_unit != 0) {
10796 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10797 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10798 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10799 			inp->inp_policyresult.flowhash = flowhash;
10800 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10801 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10802 			inp->inp_policyresult.results.route_rule_id = route_rule_id;
10803 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10804 			inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10805 			if (info.soflow_entry != NULL) {
10806 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10807 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10808 			}
10809 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "FLOW DIVERT <ROUTE RULE>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10810 		} else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10811 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10812 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10813 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10814 			inp->inp_policyresult.flowhash = flowhash;
10815 			inp->inp_policyresult.results.filter_control_unit = 0;
10816 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10817 			inp->inp_policyresult.results.route_rule_id = 0;
10818 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10819 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <NO MATCH>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10820 			if (info.soflow_entry != NULL) {
10821 				info.soflow_entry->soflow_filter_control_unit = 0;
10822 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10823 			}
10824 		} else {
10825 			// Mark non-matching socket so we don't re-check it
10826 			necp_unscope(inp);
10827 			if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10828 				necp_clear_tunnel(inp);
10829 			}
10830 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10831 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for <NO MATCH>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10832 			}
10833 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10834 			inp->inp_policyresult.skip_policy_id = skip_policy_id;
10835 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10836 			inp->inp_policyresult.flowhash = flowhash;
10837 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10838 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10839 			inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10840 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10841 			if (info.soflow_entry != NULL) {
10842 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10843 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10844 			}
10845 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10846 		}
10847 	}
10848 
10849 	if (necp_check_missing_client_drop(effective_proc, &info) ||
10850 	    necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10851 		// Mark as drop
10852 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10853 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10854 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10855 		inp->inp_policyresult.flowhash = flowhash;
10856 		inp->inp_policyresult.results.filter_control_unit = 0;
10857 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10858 		inp->inp_policyresult.results.route_rule_id = 0;
10859 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10860 		if (info.soflow_entry != NULL) {
10861 			info.soflow_entry->soflow_filter_control_unit = 0;
10862 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10863 		}
10864 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10865 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10866 		}
10867 	}
10868 
10869 	if (info.soflow_entry != NULL) {
10870 		soflow_free_flow(info.soflow_entry);
10871 	}
10872 
10873 	// Unlock
10874 	lck_rw_done(&necp_kernel_policy_lock);
10875 
10876 	if (reset_tcp_tunnel_interface) {
10877 		// Update MSS when not holding the policy lock to avoid recursive locking
10878 		tcp_mtudisc(inp, 0);
10879 
10880 		// Update TSO flag based on the tunnel interface
10881 		necp_socket_ip_tunnel_tso(inp);
10882 	}
10883 
10884 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10885 		inp->inp_policyresult.network_denied_notifies++;
10886 #if defined(XNU_TARGET_OS_OSX)
10887 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10888 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10889 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10890 		    NETPOLICY_NETWORKTYPE_LOCAL);
10891 #else
10892 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10893 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10894 		    NETPOLICY_NETWORKTYPE_LOCAL);
10895 #endif
10896 	}
10897 
10898 	if (socket_proc) {
10899 		proc_rele(socket_proc);
10900 	}
10901 
10902 	return matched_policy_id;
10903 }
10904 
10905 static bool
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,int debug)10906 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, int debug)
10907 {
10908 	u_int32_t bound_interface_flags = 0;
10909 	u_int32_t bound_interface_eflags = 0;
10910 	u_int32_t bound_interface_xflags = 0;
10911 
10912 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10913 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10914 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10915 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10916 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10917 			    cond_bound_interface_index, bound_interface_index);
10918 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10919 				if (bound_interface_index == cond_bound_interface_index) {
10920 					// No match, matches forbidden interface
10921 					return FALSE;
10922 				}
10923 			} else {
10924 				if (bound_interface_index != cond_bound_interface_index) {
10925 					// No match, does not match required interface
10926 					return FALSE;
10927 				}
10928 			}
10929 		}
10930 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10931 			if (bound_interface_index != IFSCOPE_NONE) {
10932 				ifnet_head_lock_shared();
10933 				ifnet_t interface = ifindex2ifnet[bound_interface_index];
10934 				if (interface != NULL) {
10935 					bound_interface_flags = interface->if_flags;
10936 					bound_interface_eflags = interface->if_eflags;
10937 					bound_interface_xflags = interface->if_xflags;
10938 				}
10939 				ifnet_head_done();
10940 			}
10941 
10942 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10943 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10944 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10945 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10946 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10947 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10948 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10949 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10950 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10951 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10952 					// No match, matches some forbidden interface flags
10953 					return FALSE;
10954 				}
10955 			} else {
10956 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10957 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10958 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10959 					// No match, does not match some required interface xflags
10960 					return FALSE;
10961 				}
10962 			}
10963 		}
10964 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10965 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10966 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10967 			if (bound_interface_index != 0) {
10968 				// No match, requires a non-bound packet
10969 				return FALSE;
10970 			}
10971 		}
10972 	}
10973 
10974 	if (kernel_policy->condition_mask == 0) {
10975 		return TRUE;
10976 	}
10977 
10978 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10979 		necp_kernel_policy_id matched_policy_id =
10980 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10981 		NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10982 		    "NECP_KERNEL_CONDITION_POLICY_ID",
10983 		    kernel_policy->cond_policy_id, 0, 0,
10984 		    matched_policy_id, socket_policy_id, socket_skip_policy_id);
10985 		if (matched_policy_id != kernel_policy->cond_policy_id) {
10986 			// No match, does not match required id
10987 			return FALSE;
10988 		}
10989 	}
10990 
10991 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10992 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10993 		    "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10994 		    kernel_policy->cond_last_interface_index, last_interface_index);
10995 		if (last_interface_index != kernel_policy->cond_last_interface_index) {
10996 			return FALSE;
10997 		}
10998 	}
10999 
11000 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11001 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
11002 		    "NECP_KERNEL_CONDITION_PROTOCOL",
11003 		    kernel_policy->cond_protocol, protocol);
11004 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11005 			if (protocol == kernel_policy->cond_protocol) {
11006 				// No match, matches forbidden protocol
11007 				return FALSE;
11008 			}
11009 		} else {
11010 			if (protocol != kernel_policy->cond_protocol) {
11011 				// No match, does not match required protocol
11012 				return FALSE;
11013 			}
11014 		}
11015 	}
11016 
11017 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11018 		bool is_local = FALSE;
11019 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11020 
11021 		if (rt != NULL) {
11022 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11023 		} else {
11024 			is_local = necp_is_route_local(remote, include_local_addresses);
11025 		}
11026 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
11027 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11028 			if (is_local) {
11029 				// Match local-networks, fail
11030 				return FALSE;
11031 			}
11032 		} else {
11033 			if (!is_local) {
11034 				// Either no route to validate or no match for local networks
11035 				return FALSE;
11036 			}
11037 		}
11038 	}
11039 
11040 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11041 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11042 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11043 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11044 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11045 				if (inRange) {
11046 					return FALSE;
11047 				}
11048 			} else {
11049 				if (!inRange) {
11050 					return FALSE;
11051 				}
11052 			}
11053 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11054 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11055 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11056 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11057 				if (inSubnet) {
11058 					return FALSE;
11059 				}
11060 			} else {
11061 				if (!inSubnet) {
11062 					return FALSE;
11063 				}
11064 			}
11065 		}
11066 	}
11067 
11068 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11069 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11070 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11071 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11072 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11073 				if (inRange) {
11074 					return FALSE;
11075 				}
11076 			} else {
11077 				if (!inRange) {
11078 					return FALSE;
11079 				}
11080 			}
11081 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11082 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11083 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11084 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11085 				if (inSubnet) {
11086 					return FALSE;
11087 				}
11088 			} else {
11089 				if (!inSubnet) {
11090 					return FALSE;
11091 				}
11092 			}
11093 		}
11094 	}
11095 
11096 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11097 		u_int16_t remote_port = 0;
11098 		if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11099 			remote_port = SIN(remote)->sin_port;
11100 		}
11101 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11102 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
11103 		    0, remote_port);
11104 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11105 			if (kernel_policy->cond_scheme_port == remote_port) {
11106 				return FALSE;
11107 			}
11108 		} else {
11109 			if (kernel_policy->cond_scheme_port != remote_port) {
11110 				return FALSE;
11111 			}
11112 		}
11113 	}
11114 
11115 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11116 		bool tags_matched = false;
11117 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11118 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11119 		    kernel_policy->cond_packet_filter_tags, pf_tag);
11120 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11121 			if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11122 				tags_matched = true;
11123 			}
11124 
11125 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11126 				if (tags_matched) {
11127 					return FALSE;
11128 				}
11129 			} else {
11130 				if (!tags_matched) {
11131 					return FALSE;
11132 				}
11133 			}
11134 		}
11135 	}
11136 
11137 	return TRUE;
11138 }
11139 
11140 static inline struct necp_kernel_ip_output_policy *
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,int debug)11141 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, int debug)
11142 {
11143 	u_int32_t skip_order = 0;
11144 	u_int32_t skip_session_order = 0;
11145 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11146 	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)];
11147 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11148 	size_t route_rule_id_count = 0;
11149 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11150 	if (return_drop_all_bypass != NULL) {
11151 		*return_drop_all_bypass = drop_all_bypass;
11152 	}
11153 
11154 	if (return_route_rule_id != NULL) {
11155 		*return_route_rule_id = 0;
11156 	}
11157 
11158 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11159 
11160 	if (policy_search_array != NULL) {
11161 		for (int i = 0; policy_search_array[i] != NULL; i++) {
11162 			NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11163 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11164 				// We've hit a drop all rule
11165 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11166 					drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11167 					if (return_drop_all_bypass != NULL) {
11168 						*return_drop_all_bypass = drop_all_bypass;
11169 					}
11170 				}
11171 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11172 					NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11173 					break;
11174 				}
11175 			}
11176 			if (necp_drop_dest_policy.entry_count > 0 &&
11177 			    necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11178 				// We've hit a drop by destination address rule
11179 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11180 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11181 				break;
11182 			}
11183 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11184 				// Done skipping
11185 				skip_order = 0;
11186 				skip_session_order = 0;
11187 			}
11188 			if (skip_order) {
11189 				if (policy_search_array[i]->order < skip_order) {
11190 					// Skip this policy
11191 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11192 					continue;
11193 				} else {
11194 					// Done skipping
11195 					skip_order = 0;
11196 					skip_session_order = 0;
11197 				}
11198 			} else if (skip_session_order) {
11199 				// Skip this policy
11200 				NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11201 				continue;
11202 			}
11203 
11204 			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, debug)) {
11205 				if (!debug && necp_data_tracing_session_order) {
11206 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11207 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11208 						NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11209 					}
11210 				}
11211 
11212 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11213 					if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11214 						route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11215 					}
11216 					continue;
11217 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11218 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11219 					skip_session_order = policy_search_array[i]->session_order + 1;
11220 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11221 					continue;
11222 				}
11223 
11224 				// Passed all tests, found a match
11225 				matched_policy = policy_search_array[i];
11226 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11227 				break;
11228 			}
11229 		}
11230 	}
11231 
11232 	if (route_rule_id_count == 1) {
11233 		*return_route_rule_id = route_rule_id_array[0];
11234 	} else if (route_rule_id_count > 1) {
11235 		*return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11236 	}
11237 
11238 	return matched_policy;
11239 }
11240 
11241 static inline bool
necp_output_bypass(struct mbuf * packet)11242 necp_output_bypass(struct mbuf *packet)
11243 {
11244 	if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11245 		return true;
11246 	}
11247 	if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11248 		return true;
11249 	}
11250 	if (necp_is_intcoproc(NULL, packet)) {
11251 		return true;
11252 	}
11253 	return false;
11254 }
11255 
11256 necp_kernel_policy_id
necp_ip_output_find_policy_match(struct mbuf * packet,int flags,struct ip_out_args * ipoa,struct rtentry * rt,necp_kernel_policy_result * result,necp_kernel_policy_result_parameter * result_parameter)11257 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11258     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11259 {
11260 	struct ip *ip = NULL;
11261 	int hlen = sizeof(struct ip);
11262 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11263 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11264 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11265 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11266 	u_int16_t protocol = 0;
11267 	u_int32_t bound_interface_index = 0;
11268 	u_int32_t last_interface_index = 0;
11269 	union necp_sockaddr_union local_addr = { };
11270 	union necp_sockaddr_union remote_addr = { };
11271 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11272 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11273 	u_int16_t pf_tag = 0;
11274 
11275 	if (result) {
11276 		*result = 0;
11277 	}
11278 
11279 	if (result_parameter) {
11280 		memset(result_parameter, 0, sizeof(*result_parameter));
11281 	}
11282 
11283 	if (packet == NULL) {
11284 		return NECP_KERNEL_POLICY_ID_NONE;
11285 	}
11286 
11287 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11288 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11289 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11290 
11291 	// Exit early for an empty list
11292 	// Don't lock. Possible race condition, but we don't want the performance hit.
11293 	if (necp_kernel_ip_output_policies_count == 0 ||
11294 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11295 		if (necp_drop_all_order > 0) {
11296 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11297 			if (result) {
11298 				if (necp_output_bypass(packet)) {
11299 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11300 				} else {
11301 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11302 				}
11303 			}
11304 		}
11305 
11306 		return matched_policy_id;
11307 	}
11308 
11309 	// Check for loopback exception
11310 	if (necp_output_bypass(packet)) {
11311 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11312 		if (result) {
11313 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11314 		}
11315 		return matched_policy_id;
11316 	}
11317 
11318 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11319 
11320 	// Process packet to get relevant fields
11321 	ip = mtod(packet, struct ip *);
11322 #ifdef _IP_VHL
11323 	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11324 #else
11325 	hlen = ip->ip_hl << 2;
11326 #endif
11327 
11328 	protocol = ip->ip_p;
11329 
11330 	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11331 	    (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11332 	    ipoa->ipoa_boundif != IFSCOPE_NONE) {
11333 		bound_interface_index = ipoa->ipoa_boundif;
11334 	}
11335 
11336 	local_addr.sin.sin_family = AF_INET;
11337 	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11338 	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11339 
11340 	remote_addr.sin.sin_family = AF_INET;
11341 	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11342 	memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11343 
11344 	switch (protocol) {
11345 	case IPPROTO_TCP: {
11346 		struct tcphdr th;
11347 		if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11348 			m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11349 			SIN(&local_addr)->sin_port = th.th_sport;
11350 			SIN(&remote_addr)->sin_port = th.th_dport;
11351 		}
11352 		break;
11353 	}
11354 	case IPPROTO_UDP: {
11355 		struct udphdr uh;
11356 		if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11357 			m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11358 			SIN(&local_addr)->sin_port = uh.uh_sport;
11359 			SIN(&remote_addr)->sin_port = uh.uh_dport;
11360 		}
11361 		break;
11362 	}
11363 	default: {
11364 		SIN(&local_addr)->sin_port = 0;
11365 		SIN(&remote_addr)->sin_port = 0;
11366 		break;
11367 	}
11368 	}
11369 
11370 	// Match packet to policy
11371 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11372 	u_int32_t route_rule_id = 0;
11373 
11374 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11375 	NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11376 
11377 	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, debug);
11378 	if (matched_policy) {
11379 		matched_policy_id = matched_policy->id;
11380 		if (result) {
11381 			*result = matched_policy->result;
11382 		}
11383 
11384 		if (result_parameter) {
11385 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11386 		}
11387 
11388 		if (route_rule_id != 0 &&
11389 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11390 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11391 		}
11392 
11393 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11394 			NECPLOG(LOG_DEBUG, "DATA-TRACE: IP Output: RESULT - MATCHED (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);
11395 		}
11396 	} else {
11397 		bool drop_all = false;
11398 		/*
11399 		 * Apply drop-all only to packets which have never matched a primary policy (check
11400 		 * if the packet saved policy id is none or falls within the socket policy id range).
11401 		 */
11402 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11403 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11404 			drop_all = true;
11405 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11406 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11407 			}
11408 		}
11409 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11410 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11411 			if (result) {
11412 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11413 				NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11414 			}
11415 		} else if (route_rule_id != 0 &&
11416 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11417 			// If we matched a route rule, mark it
11418 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11419 		}
11420 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11421 			NECPLOG(LOG_DEBUG, "DATA-TRACE: IP Output: RESULT - NO MATCH (ID %d BoundInterface %d LastInterface %d Proto %d)", socket_policy_id, bound_interface_index, last_interface_index, protocol);
11422 		}
11423 	}
11424 
11425 	lck_rw_done(&necp_kernel_policy_lock);
11426 
11427 	return matched_policy_id;
11428 }
11429 
11430 necp_kernel_policy_id
necp_ip6_output_find_policy_match(struct mbuf * packet,int flags,struct ip6_out_args * ip6oa,struct rtentry * rt,necp_kernel_policy_result * result,necp_kernel_policy_result_parameter * result_parameter)11431 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11432     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11433 {
11434 	struct ip6_hdr *ip6 = NULL;
11435 	int next = -1;
11436 	int offset = 0;
11437 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11438 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11439 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11440 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11441 	u_int16_t protocol = 0;
11442 	u_int32_t bound_interface_index = 0;
11443 	u_int32_t last_interface_index = 0;
11444 	union necp_sockaddr_union local_addr = { };
11445 	union necp_sockaddr_union remote_addr = { };
11446 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11447 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11448 	u_int16_t pf_tag = 0;
11449 
11450 	if (result) {
11451 		*result = 0;
11452 	}
11453 
11454 	if (result_parameter) {
11455 		memset(result_parameter, 0, sizeof(*result_parameter));
11456 	}
11457 
11458 	if (packet == NULL) {
11459 		return NECP_KERNEL_POLICY_ID_NONE;
11460 	}
11461 
11462 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11463 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11464 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11465 
11466 	// Exit early for an empty list
11467 	// Don't lock. Possible race condition, but we don't want the performance hit.
11468 	if (necp_drop_management_order == 0 &&
11469 	    (necp_kernel_ip_output_policies_count == 0 ||
11470 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11471 		if (necp_drop_all_order > 0) {
11472 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11473 			if (result) {
11474 				if (necp_output_bypass(packet)) {
11475 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11476 				} else {
11477 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11478 				}
11479 			}
11480 		}
11481 
11482 		return matched_policy_id;
11483 	}
11484 
11485 	// Check for loopback exception
11486 	if (necp_output_bypass(packet)) {
11487 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11488 		if (result) {
11489 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11490 		}
11491 		return matched_policy_id;
11492 	}
11493 
11494 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11495 
11496 	// Process packet to get relevant fields
11497 	ip6 = mtod(packet, struct ip6_hdr *);
11498 
11499 	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11500 	    (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11501 	    ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11502 		bound_interface_index = ip6oa->ip6oa_boundif;
11503 	}
11504 
11505 	SIN6(&local_addr)->sin6_family = AF_INET6;
11506 	SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11507 	memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11508 
11509 	SIN6(&remote_addr)->sin6_family = AF_INET6;
11510 	SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11511 	memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11512 
11513 	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11514 	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11515 		protocol = next;
11516 		switch (protocol) {
11517 		case IPPROTO_TCP: {
11518 			struct tcphdr th;
11519 			if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11520 				m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11521 				SIN6(&local_addr)->sin6_port = th.th_sport;
11522 				SIN6(&remote_addr)->sin6_port = th.th_dport;
11523 			}
11524 			break;
11525 		}
11526 		case IPPROTO_UDP: {
11527 			struct udphdr uh;
11528 			if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11529 				m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11530 				SIN6(&local_addr)->sin6_port = uh.uh_sport;
11531 				SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11532 			}
11533 			break;
11534 		}
11535 		default: {
11536 			SIN6(&local_addr)->sin6_port = 0;
11537 			SIN6(&remote_addr)->sin6_port = 0;
11538 			break;
11539 		}
11540 		}
11541 	}
11542 
11543 	// Match packet to policy
11544 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11545 	u_int32_t route_rule_id = 0;
11546 
11547 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11548 	NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11549 
11550 	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, debug);
11551 	if (matched_policy) {
11552 		matched_policy_id = matched_policy->id;
11553 		if (result) {
11554 			*result = matched_policy->result;
11555 		}
11556 
11557 		if (result_parameter) {
11558 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11559 		}
11560 
11561 		if (route_rule_id != 0 &&
11562 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11563 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11564 		}
11565 
11566 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11567 			NECPLOG(LOG_DEBUG, "DATA-TRACE: IP6 Output: RESULT - MATCHED (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);
11568 		}
11569 	} else {
11570 		bool drop_all = false;
11571 		/*
11572 		 * Apply drop-all only to packets which have never matched a primary policy (check
11573 		 * if the packet saved policy id is none or falls within the socket policy id range).
11574 		 */
11575 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11576 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11577 			drop_all = true;
11578 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11579 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11580 			}
11581 		}
11582 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11583 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11584 			if (result) {
11585 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11586 				NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11587 			}
11588 		} else if (route_rule_id != 0 &&
11589 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11590 			// If we matched a route rule, mark it
11591 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11592 		}
11593 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11594 			NECPLOG(LOG_DEBUG, "DATA-TRACE: IP6 Output: RESULT - NO MATCH (ID %d BoundInterface %d LastInterface %d Proto %d)", socket_policy_id, bound_interface_index, last_interface_index, protocol);
11595 		}
11596 	}
11597 
11598 	lck_rw_done(&necp_kernel_policy_lock);
11599 
11600 	return matched_policy_id;
11601 }
11602 
11603 // Utilities
11604 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11605 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11606 {
11607 	int cmp = 0;
11608 
11609 	if (addr == NULL || range_start == NULL || range_end == NULL) {
11610 		return FALSE;
11611 	}
11612 
11613 	/* Must be greater than or equal to start */
11614 	cmp = necp_addr_compare(addr, range_start, 1);
11615 	if (cmp != 0 && cmp != 1) {
11616 		return FALSE;
11617 	}
11618 
11619 	/* Must be less than or equal to end */
11620 	cmp = necp_addr_compare(addr, range_end, 1);
11621 	if (cmp != 0 && cmp != -1) {
11622 		return FALSE;
11623 	}
11624 
11625 	return TRUE;
11626 }
11627 
11628 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)11629 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11630 {
11631 	int cmp = 0;
11632 
11633 	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11634 		return FALSE;
11635 	}
11636 
11637 	/* Must be greater than or equal to start */
11638 	cmp = necp_addr_compare(inner_range_start, range_start, 1);
11639 	if (cmp != 0 && cmp != 1) {
11640 		return FALSE;
11641 	}
11642 
11643 	/* Must be less than or equal to end */
11644 	cmp = necp_addr_compare(inner_range_end, range_end, 1);
11645 	if (cmp != 0 && cmp != -1) {
11646 		return FALSE;
11647 	}
11648 
11649 	return TRUE;
11650 }
11651 
11652 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11653 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11654 {
11655 	if (addr == NULL || subnet_addr == NULL) {
11656 		return FALSE;
11657 	}
11658 
11659 	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11660 		return FALSE;
11661 	}
11662 
11663 	switch (addr->sa_family) {
11664 	case AF_INET: {
11665 		if (satosin(subnet_addr)->sin_port != 0 &&
11666 		    satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11667 			return FALSE;
11668 		}
11669 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11670 	}
11671 	case AF_INET6: {
11672 		if (satosin6(subnet_addr)->sin6_port != 0 &&
11673 		    satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11674 			return FALSE;
11675 		}
11676 		if (satosin6(addr)->sin6_scope_id &&
11677 		    satosin6(subnet_addr)->sin6_scope_id &&
11678 		    satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11679 			return FALSE;
11680 		}
11681 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11682 	}
11683 	default: {
11684 		return FALSE;
11685 	}
11686 	}
11687 
11688 	return FALSE;
11689 }
11690 
11691 /*
11692  * Return values:
11693  * -1: sa1 < sa2
11694  * 0: sa1 == sa2
11695  * 1: sa1 > sa2
11696  * 2: Not comparable or error
11697  */
11698 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11699 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11700 {
11701 	int result = 0;
11702 	int port_result = 0;
11703 
11704 	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11705 		return 2;
11706 	}
11707 
11708 	if (sa1->sa_len == 0) {
11709 		return 0;
11710 	}
11711 
11712 	switch (sa1->sa_family) {
11713 	case AF_INET: {
11714 		if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11715 			return 2;
11716 		}
11717 
11718 		result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11719 
11720 		if (check_port) {
11721 			if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11722 				port_result = -1;
11723 			} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11724 				port_result = 1;
11725 			}
11726 
11727 			if (result == 0) {
11728 				result = port_result;
11729 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11730 				return 2;
11731 			}
11732 		}
11733 
11734 		break;
11735 	}
11736 	case AF_INET6: {
11737 		if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11738 			return 2;
11739 		}
11740 
11741 		if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11742 			return 2;
11743 		}
11744 
11745 		result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11746 
11747 		if (check_port) {
11748 			if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11749 				port_result = -1;
11750 			} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11751 				port_result = 1;
11752 			}
11753 
11754 			if (result == 0) {
11755 				result = port_result;
11756 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11757 				return 2;
11758 			}
11759 		}
11760 
11761 		break;
11762 	}
11763 	default: {
11764 		result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11765 		break;
11766 	}
11767 	}
11768 
11769 	if (result < 0) {
11770 		result = (-1);
11771 	} else if (result > 0) {
11772 		result = (1);
11773 	}
11774 
11775 	return result;
11776 }
11777 
11778 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11779 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11780 {
11781 	u_int8_t mask;
11782 
11783 	/* Handle null pointers */
11784 	if (p1 == NULL || p2 == NULL) {
11785 		return p1 == p2;
11786 	}
11787 
11788 	while (bits >= 8) {
11789 		if (*p1++ != *p2++) {
11790 			return FALSE;
11791 		}
11792 		bits -= 8;
11793 	}
11794 
11795 	if (bits > 0) {
11796 		mask = ~((1 << (8 - bits)) - 1);
11797 		if ((*p1 & mask) != (*p2 & mask)) {
11798 			return FALSE;
11799 		}
11800 	}
11801 	return TRUE;
11802 }
11803 
11804 static bool
necp_addr_is_empty(struct sockaddr * addr)11805 necp_addr_is_empty(struct sockaddr *addr)
11806 {
11807 	if (addr == NULL) {
11808 		return TRUE;
11809 	}
11810 
11811 	if (addr->sa_len == 0) {
11812 		return TRUE;
11813 	}
11814 
11815 	switch (addr->sa_family) {
11816 	case AF_INET: {
11817 		static struct sockaddr_in ipv4_empty_address = {
11818 			.sin_len = sizeof(struct sockaddr_in),
11819 			.sin_family = AF_INET,
11820 			.sin_port = 0,
11821 			.sin_addr = { .s_addr = 0 }, // 0.0.0.0
11822 			.sin_zero = {0},
11823 		};
11824 		if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11825 			return TRUE;
11826 		} else {
11827 			return FALSE;
11828 		}
11829 	}
11830 	case AF_INET6: {
11831 		static struct sockaddr_in6 ipv6_empty_address = {
11832 			.sin6_len = sizeof(struct sockaddr_in6),
11833 			.sin6_family = AF_INET6,
11834 			.sin6_port = 0,
11835 			.sin6_flowinfo = 0,
11836 			.sin6_addr = IN6ADDR_ANY_INIT, // ::
11837 			.sin6_scope_id = 0,
11838 		};
11839 		if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11840 			return TRUE;
11841 		} else {
11842 			return FALSE;
11843 		}
11844 	}
11845 	default:
11846 		return FALSE;
11847 	}
11848 
11849 	return FALSE;
11850 }
11851 
11852 static bool
necp_update_qos_marking(struct ifnet * ifp,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)11853 necp_update_qos_marking(struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
11854 {
11855 	bool qos_marking = FALSE;
11856 	int exception_index = 0;
11857 	struct necp_route_rule *route_rule = NULL;
11858 
11859 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11860 	if (route_rule == NULL) {
11861 		qos_marking = FALSE;
11862 		goto done;
11863 	}
11864 
11865 	if (route_rule->match_netagent_id != 0) {
11866 		if (netagent_array == NULL || netagent_array_count == 0) {
11867 			// No agents, ignore rule
11868 			goto done;
11869 		}
11870 		bool found_match = FALSE;
11871 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11872 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11873 				found_match = TRUE;
11874 				break;
11875 			}
11876 		}
11877 		if (!found_match) {
11878 			// Agents don't match, ignore rule
11879 			goto done;
11880 		}
11881 	}
11882 
11883 	qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11884 
11885 	if (ifp == NULL) {
11886 		goto done;
11887 	}
11888 
11889 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11890 		if (route_rule->exception_if_indices[exception_index] == 0) {
11891 			break;
11892 		}
11893 		if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11894 			continue;
11895 		}
11896 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11897 			qos_marking = TRUE;
11898 			if (necp_debug > 2) {
11899 				NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11900 				    route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11901 			}
11902 			goto done;
11903 		}
11904 	}
11905 
11906 	if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11907 	    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11908 	    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11909 	    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11910 	    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11911 	    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11912 	    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11913 		qos_marking = TRUE;
11914 		if (necp_debug > 2) {
11915 			NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11916 			    route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11917 			    route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11918 		}
11919 		goto done;
11920 	}
11921 done:
11922 	if (necp_debug > 1) {
11923 		NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11924 		    route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11925 	}
11926 	return qos_marking;
11927 }
11928 
11929 bool
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)11930 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)
11931 {
11932 	bool new_qos_marking = old_qos_marking;
11933 	struct ifnet *ifp = interface;
11934 
11935 	if (net_qos_policy_restricted == 0) {
11936 		return new_qos_marking;
11937 	}
11938 
11939 	/*
11940 	 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11941 	 */
11942 	if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11943 		return new_qos_marking;
11944 	}
11945 
11946 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11947 
11948 	if (ifp == NULL && route != NULL) {
11949 		ifp = route->rt_ifp;
11950 	}
11951 	/*
11952 	 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11953 	 */
11954 	if (ifp == NULL || route_rule_id == 0) {
11955 		new_qos_marking = FALSE;
11956 		goto done;
11957 	}
11958 
11959 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11960 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11961 		if (aggregate_route_rule != NULL) {
11962 			int index = 0;
11963 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11964 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11965 				if (sub_route_rule_id == 0) {
11966 					break;
11967 				}
11968 				new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11969 				if (new_qos_marking == TRUE) {
11970 					break;
11971 				}
11972 			}
11973 		}
11974 	} else {
11975 		new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11976 	}
11977 	/*
11978 	 * Now that we have an interface we remember the gencount
11979 	 */
11980 	*qos_marking_gencount = necp_kernel_socket_policies_gencount;
11981 
11982 done:
11983 	lck_rw_done(&necp_kernel_policy_lock);
11984 	return new_qos_marking;
11985 }
11986 
11987 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11988 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11989 {
11990 	bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11991 
11992 	if (net_qos_policy_restricted == 0) {
11993 		return;
11994 	}
11995 	if (inp->inp_socket == NULL) {
11996 		return;
11997 	}
11998 	if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11999 		return;
12000 	}
12001 
12002 	qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
12003 
12004 	if (qos_marking == TRUE) {
12005 		inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
12006 	} else {
12007 		inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
12008 	}
12009 }
12010 
12011 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)12012 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
12013 {
12014 	if (ifp != NULL &&
12015 	    (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12016 	    ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12017 		return true;
12018 	}
12019 	if (delegated_ifp != NULL &&
12020 	    (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12021 	    delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12022 		return true;
12023 	}
12024 	return false;
12025 }
12026 
12027 static bool
necp_route_is_allowed_inner(struct rtentry * route,struct ifnet * ifp,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)12028 necp_route_is_allowed_inner(struct rtentry *route, struct ifnet *ifp, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
12029     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12030 {
12031 	bool default_is_allowed = TRUE;
12032 	u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12033 	int exception_index = 0;
12034 	struct ifnet *delegated_ifp = NULL;
12035 	struct necp_route_rule *route_rule = NULL;
12036 
12037 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12038 	if (route_rule == NULL) {
12039 		return TRUE;
12040 	}
12041 
12042 	if (route_rule->match_netagent_id != 0) {
12043 		if (netagent_array == NULL || netagent_array_count == 0) {
12044 			// No agents, ignore rule
12045 			return TRUE;
12046 		}
12047 		bool found_match = FALSE;
12048 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12049 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12050 				found_match = TRUE;
12051 				break;
12052 			}
12053 		}
12054 		if (!found_match) {
12055 			// Agents don't match, ignore rule
12056 			return TRUE;
12057 		}
12058 	}
12059 
12060 	default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12061 	if (ifp == NULL && route != NULL) {
12062 		ifp = route->rt_ifp;
12063 	}
12064 	if (ifp == NULL) {
12065 		if (necp_debug > 1 && !default_is_allowed) {
12066 			NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12067 		}
12068 		return default_is_allowed;
12069 	}
12070 
12071 	delegated_ifp = ifp->if_delegated.ifp;
12072 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12073 		if (route_rule->exception_if_indices[exception_index] == 0) {
12074 			break;
12075 		}
12076 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12077 		    (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12078 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12079 				const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12080 				if (necp_debug > 1 && lqm_abort) {
12081 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12082 					    route_rule->exception_if_indices[exception_index], route_rule_id);
12083 				}
12084 				return false;
12085 			} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12086 				if (necp_debug > 1) {
12087 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Allowed %d", route_rule->exception_if_indices[exception_index], route_rule_id, (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE));
12088 				}
12089 				if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12090 					*interface_type_denied = route_rule->effective_type;
12091 				}
12092 				return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12093 			}
12094 		}
12095 	}
12096 
12097 	if (IFNET_IS_CELLULAR(ifp)) {
12098 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12099 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12100 				if (interface_type_denied != NULL) {
12101 					*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12102 					if (route_rule->effective_type != 0) {
12103 						*interface_type_denied = route_rule->effective_type;
12104 					}
12105 				}
12106 				// Mark aggregate action as deny
12107 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12108 			}
12109 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12110 			if (interface_type_denied != NULL) {
12111 				*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12112 				if (route_rule->effective_type != 0) {
12113 					*interface_type_denied = route_rule->effective_type;
12114 				}
12115 			}
12116 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12117 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12118 			    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12119 				// Deny wins if there is a conflict
12120 				type_aggregate_action = route_rule->cellular_action;
12121 			}
12122 		}
12123 	}
12124 
12125 	if (IFNET_IS_WIFI(ifp)) {
12126 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12127 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12128 				if (interface_type_denied != NULL) {
12129 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12130 					if (route_rule->effective_type != 0) {
12131 						*interface_type_denied = route_rule->effective_type;
12132 					}
12133 				}
12134 				// Mark aggregate action as deny
12135 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12136 			}
12137 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12138 			if (interface_type_denied != NULL) {
12139 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12140 				if (route_rule->effective_type != 0) {
12141 					*interface_type_denied = route_rule->effective_type;
12142 				}
12143 			}
12144 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12145 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12146 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12147 				// Deny wins if there is a conflict
12148 				type_aggregate_action = route_rule->wifi_action;
12149 			}
12150 		}
12151 	}
12152 
12153 	if (IFNET_IS_COMPANION_LINK(ifp) ||
12154 	    (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12155 		if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12156 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12157 				if (interface_type_denied != NULL) {
12158 					*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12159 					if (route_rule->effective_type != 0) {
12160 						*interface_type_denied = route_rule->effective_type;
12161 					}
12162 				}
12163 				// Mark aggregate action as deny
12164 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12165 			}
12166 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12167 			if (interface_type_denied != NULL) {
12168 				*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12169 				if (route_rule->effective_type != 0) {
12170 					*interface_type_denied = route_rule->effective_type;
12171 				}
12172 			}
12173 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12174 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12175 			    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12176 				// Deny wins if there is a conflict
12177 				type_aggregate_action = route_rule->companion_action;
12178 			}
12179 		}
12180 	}
12181 
12182 	if (IFNET_IS_WIRED(ifp)) {
12183 		if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12184 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12185 				if (interface_type_denied != NULL) {
12186 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12187 					if (route_rule->effective_type != 0) {
12188 						*interface_type_denied = route_rule->effective_type;
12189 					}
12190 				}
12191 				// Mark aggregate action as deny
12192 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12193 			}
12194 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12195 			if (interface_type_denied != NULL) {
12196 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12197 				if (route_rule->effective_type != 0) {
12198 					*interface_type_denied = route_rule->effective_type;
12199 				}
12200 			}
12201 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12202 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12203 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12204 				// Deny wins if there is a conflict
12205 				type_aggregate_action = route_rule->wired_action;
12206 			}
12207 		}
12208 	}
12209 
12210 	if (IFNET_IS_EXPENSIVE(ifp)) {
12211 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12212 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12213 				// Mark aggregate action as deny
12214 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12215 			}
12216 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12217 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12218 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12219 			    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12220 				// Deny wins if there is a conflict
12221 				type_aggregate_action = route_rule->expensive_action;
12222 			}
12223 		}
12224 	}
12225 
12226 	if (IFNET_IS_CONSTRAINED(ifp)) {
12227 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12228 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12229 				// Mark aggregate action as deny
12230 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12231 			}
12232 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12233 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12234 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12235 			    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12236 				// Deny wins if there is a conflict
12237 				type_aggregate_action = route_rule->constrained_action;
12238 			}
12239 		}
12240 	}
12241 
12242 	if (IFNET_IS_VPN(ifp)) {
12243 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12244 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12245 				// Mark aggregate action as deny
12246 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12247 			}
12248 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12249 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12250 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12251 			    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12252 				// Deny wins if there is a conflict
12253 				type_aggregate_action = route_rule->vpn_action;
12254 			}
12255 		}
12256 	}
12257 
12258 	if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12259 		if (necp_debug > 1) {
12260 			NECPLOG(LOG_DEBUG, "Route Allowed: C:%d WF:%d W:%d E:%d Cmpn:%d VPN:%d for Rule %d Allowed %d", route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action, route_rule->expensive_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, (IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE));
12261 		}
12262 		return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12263 	}
12264 
12265 	if (necp_debug > 1 && !default_is_allowed) {
12266 		NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12267 	}
12268 	return default_is_allowed;
12269 }
12270 
12271 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12272 necp_proc_is_allowed_on_management_interface(proc_t proc)
12273 {
12274 	bool allowed = false;
12275 	const task_t __single task = proc_task(proc);
12276 
12277 	if (task != NULL) {
12278 		if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12279 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12280 #if DEBUG || DEVELOPMENT
12281 		    || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12282 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12283 #endif /* DEBUG || DEVELOPMENT */
12284 		    ) {
12285 			allowed = true;
12286 		}
12287 	}
12288 	return allowed;
12289 }
12290 
12291 __attribute__((noinline))
12292 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12293 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12294 {
12295 	char buf[128];
12296 
12297 	if (inp != NULL) {
12298 		inp_snprintf_tuple(inp, buf, sizeof(buf));
12299 	} else {
12300 		*buf = 0;
12301 	}
12302 	os_log(OS_LOG_DEFAULT,
12303 	    "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12304 	    proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12305 	    proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12306 	    inp != NULL ? buf : "",
12307 	    ifp->if_xname);
12308 }
12309 
12310 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12311 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12312 {
12313 	if (if_management_interface_check_needed == false) {
12314 		return true;
12315 	}
12316 	if (necp_drop_management_order == 0) {
12317 		return true;
12318 	}
12319 	if (ifp == NULL && route != NULL) {
12320 		ifp = route->rt_ifp;
12321 	}
12322 	if (ifp == NULL) {
12323 		return true;
12324 	}
12325 
12326 	if (IFNET_IS_MANAGEMENT(ifp)) {
12327 		bool allowed = true;
12328 
12329 		if (inp != NULL) {
12330 			/*
12331 			 * The entitlement check is already performed for socket flows
12332 			 */
12333 			allowed = INP_MANAGEMENT_ALLOWED(inp);
12334 		} else if (proc != NULL) {
12335 			allowed = necp_proc_is_allowed_on_management_interface(proc);
12336 		}
12337 		if (__improbable(if_management_verbose > 1 && allowed == false)) {
12338 			necp_log_interface_not_allowed(ifp, proc, inp);
12339 		}
12340 		return allowed;
12341 	}
12342 	return true;
12343 }
12344 
12345 static bool
necp_route_is_allowed(struct rtentry * route,struct ifnet * interface,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)12346 necp_route_is_allowed(struct rtentry *route, struct ifnet *interface, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count,
12347     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12348 {
12349 	if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12350 		if (necp_debug > 1) {
12351 			NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12352 		}
12353 		return TRUE;
12354 	}
12355 
12356 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12357 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12358 		if (aggregate_route_rule != NULL) {
12359 			int index = 0;
12360 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12361 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12362 				if (sub_route_rule_id == 0) {
12363 					break;
12364 				}
12365 				if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
12366 					return FALSE;
12367 				}
12368 			}
12369 		}
12370 	} else {
12371 		return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
12372 	}
12373 
12374 	return TRUE;
12375 }
12376 
12377 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12378 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12379 {
12380 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12381 	if (route_rule == NULL) {
12382 		return false;
12383 	}
12384 
12385 	return route_rule->match_netagent_id != 0;
12386 }
12387 
12388 static uint32_t
necp_route_get_netagent(struct rtentry * route,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,bool * remove)12389 necp_route_get_netagent(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove)
12390 {
12391 	if (remove == NULL) {
12392 		return 0;
12393 	}
12394 
12395 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12396 	if (route_rule == NULL) {
12397 		return 0;
12398 	}
12399 
12400 	// No netagent, skip
12401 	if (route_rule->netagent_id == 0) {
12402 		return 0;
12403 	}
12404 
12405 	if (route_rule->match_netagent_id != 0) {
12406 		if (netagent_array == NULL || netagent_array_count == 0) {
12407 			// No agents, ignore rule
12408 			return 0;
12409 		}
12410 		bool found_match = FALSE;
12411 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12412 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12413 				found_match = TRUE;
12414 				break;
12415 			}
12416 		}
12417 		if (!found_match) {
12418 			// Agents don't match, ignore rule
12419 			return 0;
12420 		}
12421 	}
12422 
12423 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12424 	if (ifp == NULL) {
12425 		// No interface, apply the default action
12426 		if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12427 		    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12428 			*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12429 			return route_rule->netagent_id;
12430 		}
12431 		return 0;
12432 	}
12433 
12434 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12435 		if (route_rule->exception_if_indices[exception_index] == 0) {
12436 			break;
12437 		}
12438 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12439 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12440 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12441 			    route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12442 				*remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12443 				return route_rule->netagent_id;
12444 			}
12445 			return 0;
12446 		}
12447 	}
12448 
12449 	if (ifp->if_type == IFT_CELLULAR &&
12450 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12451 		if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12452 		    route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12453 			*remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12454 			return route_rule->netagent_id;
12455 		}
12456 		return 0;
12457 	}
12458 
12459 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12460 	    route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12461 		if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12462 		    route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12463 			*remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12464 			return route_rule->netagent_id;
12465 		}
12466 		return 0;
12467 	}
12468 
12469 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12470 	    route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12471 		if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12472 		    route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12473 			*remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12474 			return route_rule->netagent_id;
12475 		}
12476 		return 0;
12477 	}
12478 
12479 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12480 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12481 		if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12482 		    route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12483 			*remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12484 			return route_rule->netagent_id;
12485 		}
12486 		return 0;
12487 	}
12488 
12489 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12490 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12491 		if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12492 		    route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12493 			*remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12494 			return route_rule->netagent_id;
12495 		}
12496 		return 0;
12497 	}
12498 
12499 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12500 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12501 		if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12502 		    route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12503 			*remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12504 			return route_rule->netagent_id;
12505 		}
12506 		return 0;
12507 	}
12508 
12509 	if (ifp->if_xflags & IFXF_IS_VPN &&
12510 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12511 		if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12512 		    route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12513 			*remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12514 			return route_rule->netagent_id;
12515 		}
12516 		return 0;
12517 	}
12518 
12519 	// No more specific case matched, apply the default action
12520 	if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12521 	    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12522 		*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12523 		return route_rule->netagent_id;
12524 	}
12525 
12526 	return 0;
12527 }
12528 
12529 static uint32_t
necp_route_get_flow_divert_inner(struct rtentry * route,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)12530 necp_route_get_flow_divert_inner(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
12531 {
12532 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12533 	if (route_rule == NULL) {
12534 		return 0;
12535 	}
12536 
12537 	// No control unit, skip
12538 	if (route_rule->control_unit == 0) {
12539 		return 0;
12540 	}
12541 
12542 	if (route_rule->match_netagent_id != 0) {
12543 		if (netagent_array == NULL || netagent_array_count == 0) {
12544 			// No agents, ignore rule
12545 			return 0;
12546 		}
12547 		bool found_match = FALSE;
12548 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12549 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12550 				found_match = TRUE;
12551 				break;
12552 			}
12553 		}
12554 		if (!found_match) {
12555 			// Agents don't match, ignore rule
12556 			return 0;
12557 		}
12558 	}
12559 
12560 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12561 	if (ifp == NULL) {
12562 		// No interface, apply the default action
12563 		if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12564 			return route_rule->control_unit;
12565 		}
12566 		return 0;
12567 	}
12568 
12569 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12570 		if (route_rule->exception_if_indices[exception_index] == 0) {
12571 			break;
12572 		}
12573 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12574 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12575 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12576 				return route_rule->control_unit;
12577 			}
12578 			return 0;
12579 		}
12580 	}
12581 
12582 	if (ifp->if_type == IFT_CELLULAR &&
12583 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12584 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12585 			return route_rule->control_unit;
12586 		}
12587 		return 0;
12588 	}
12589 
12590 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12591 	    route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12592 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12593 			return route_rule->control_unit;
12594 		}
12595 		return 0;
12596 	}
12597 
12598 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12599 	    route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12600 		if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12601 			return route_rule->control_unit;
12602 		}
12603 		return 0;
12604 	}
12605 
12606 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12607 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12608 		if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12609 			return route_rule->control_unit;
12610 		}
12611 		return 0;
12612 	}
12613 
12614 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12615 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12616 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12617 			return route_rule->control_unit;
12618 		}
12619 		return 0;
12620 	}
12621 
12622 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12623 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12624 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12625 			return route_rule->control_unit;
12626 		}
12627 		return 0;
12628 	}
12629 
12630 	if (ifp->if_xflags & IFXF_IS_VPN &&
12631 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12632 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12633 			return route_rule->control_unit;
12634 		}
12635 		return 0;
12636 	}
12637 
12638 	// No more specific case matched, apply the default action
12639 	if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12640 		return route_rule->control_unit;
12641 	}
12642 	return 0;
12643 }
12644 
12645 static uint32_t
necp_route_get_flow_divert(struct rtentry * route,u_int32_t * __counted_by (netagent_array_count)netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * flow_divert_aggregate_unit)12646 necp_route_get_flow_divert(struct rtentry *route, u_int32_t * __counted_by(netagent_array_count)netagent_array, size_t netagent_array_count, u_int32_t route_rule_id,
12647     u_int32_t *flow_divert_aggregate_unit)
12648 {
12649 	if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12650 		return 0;
12651 	}
12652 
12653 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12654 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12655 		if (aggregate_route_rule != NULL) {
12656 			int index = 0;
12657 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12658 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12659 				if (sub_route_rule_id == 0) {
12660 					break;
12661 				}
12662 				uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12663 				if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12664 					// For transparent proxies, accumulate the control unit and continue to the next route rule
12665 					*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12666 					continue;
12667 				}
12668 
12669 				if (control_unit != 0) {
12670 					return control_unit;
12671 				}
12672 			}
12673 		}
12674 	} else {
12675 		uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12676 		if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12677 			// For transparent proxies, accumulate the control unit and let the caller continue
12678 			*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12679 			return 0;
12680 		}
12681 		return control_unit;
12682 	}
12683 
12684 	return 0;
12685 }
12686 
12687 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12688 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12689 {
12690 	bool is_allowed = true;
12691 	u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12692 	if (route_rule_id != 0 &&
12693 	    interface != NULL) {
12694 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12695 		is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12696 		lck_rw_done(&necp_kernel_policy_lock);
12697 	}
12698 	return is_allowed;
12699 }
12700 
12701 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12702 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12703 {
12704 	size_t netagent_cursor;
12705 	for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12706 		struct necp_uuid_id_mapping *mapping = NULL;
12707 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
12708 		if (netagent_id == 0) {
12709 			continue;
12710 		}
12711 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12712 		if (mapping != NULL) {
12713 			u_int32_t agent_flags = 0;
12714 			agent_flags = netagent_get_flags(mapping->uuid);
12715 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12716 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12717 					continue;
12718 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12719 					return FALSE;
12720 				}
12721 			}
12722 		}
12723 	}
12724 	return TRUE;
12725 }
12726 
12727 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12728 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12729 {
12730 	bool allowed_to_receive = TRUE;
12731 
12732 	if (pf_tag == PF_TAG_ID_STACK_DROP &&
12733 	    (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12734 		allowed_to_receive = FALSE;
12735 	}
12736 
12737 	return allowed_to_receive;
12738 }
12739 
12740 static bool
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)12741 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)
12742 {
12743 	u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12744 	bool allowed_to_receive = TRUE;
12745 	struct necp_socket_info info = {};
12746 	u_int32_t flowhash = 0;
12747 	necp_kernel_policy_result service_action = 0;
12748 	necp_kernel_policy_service service = { 0, 0 };
12749 	u_int32_t route_rule_id = 0;
12750 	struct rtentry *route = NULL;
12751 	u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12752 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12753 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12754 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12755 	proc_t __single socket_proc = NULL;
12756 	necp_kernel_policy_filter filter_control_unit = 0;
12757 	u_int32_t pass_flags = 0;
12758 	u_int32_t flow_divert_aggregate_unit = 0;
12759 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12760 	int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12761 
12762 	memset(&netagent_ids, 0, sizeof(netagent_ids));
12763 
12764 	if (return_policy_id) {
12765 		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12766 	}
12767 	if (return_skip_policy_id) {
12768 		*return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12769 	}
12770 	if (return_route_rule_id) {
12771 		*return_route_rule_id = 0;
12772 	}
12773 	if (return_pass_flags) {
12774 		*return_pass_flags = 0;
12775 	}
12776 
12777 	if (inp == NULL) {
12778 		goto done;
12779 	}
12780 
12781 	route = inp->inp_route.ro_rt;
12782 
12783 	struct socket *so = inp->inp_socket;
12784 
12785 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12786 
12787 	// Don't lock. Possible race condition, but we don't want the performance hit.
12788 	if (necp_drop_management_order == 0 &&
12789 	    (necp_kernel_socket_policies_count == 0 ||
12790 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12791 		if (necp_drop_all_order > 0 || drop_order > 0) {
12792 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12793 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12794 				allowed_to_receive = TRUE;
12795 			} else {
12796 				allowed_to_receive = FALSE;
12797 			}
12798 		}
12799 		goto done;
12800 	}
12801 
12802 	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
12803 	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12804 		bool policies_have_changed = FALSE;
12805 		bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12806 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12807 			policies_have_changed = TRUE;
12808 		} else {
12809 			if (inp->inp_policyresult.results.route_rule_id != 0) {
12810 				lck_rw_lock_shared(&necp_kernel_policy_lock);
12811 				if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12812 					route_allowed = FALSE;
12813 				}
12814 				lck_rw_done(&necp_kernel_policy_lock);
12815 			}
12816 		}
12817 
12818 		if (!policies_have_changed) {
12819 			if (debug) {
12820 				necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? SOFLOW_DIRECTION_INBOUND : SOFLOW_DIRECTION_OUTBOUND, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), verifyifindex);
12821 				debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12822 			}
12823 
12824 			if (!route_allowed ||
12825 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12826 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12827 			    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12828 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12829 				allowed_to_receive = FALSE;
12830 				NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START - RESULT - CACHED DROP", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12831 			} else {
12832 				if (return_policy_id) {
12833 					*return_policy_id = inp->inp_policyresult.policy_id;
12834 				}
12835 				if (return_skip_policy_id) {
12836 					*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12837 				}
12838 				if (return_route_rule_id) {
12839 					*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12840 				}
12841 				if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12842 					pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12843 				}
12844 				NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START - RESULT - CACHED", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12845 			}
12846 			goto done;
12847 		}
12848 	}
12849 
12850 	// Check for loopback exception
12851 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12852 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12853 		allowed_to_receive = FALSE;
12854 		goto done;
12855 	}
12856 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12857 		allowed_to_receive = TRUE;
12858 		goto done;
12859 	}
12860 
12861 	// Actually calculate policy result
12862 	lck_rw_lock_shared(&necp_kernel_policy_lock);
12863 	necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? SOFLOW_DIRECTION_INBOUND : SOFLOW_DIRECTION_OUTBOUND, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), verifyifindex);
12864 
12865 	debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12866 	NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12867 
12868 	flowhash = necp_socket_calc_flowhash_locked(&info);
12869 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12870 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12871 	    inp->inp_policyresult.flowhash == flowhash) {
12872 		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12873 		    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12874 		    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12875 		    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12876 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12877 		    (inp->inp_policyresult.results.route_rule_id != 0 &&
12878 		    !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12879 			allowed_to_receive = FALSE;
12880 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <DROP>", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12881 		} else {
12882 			if (return_policy_id) {
12883 				*return_policy_id = inp->inp_policyresult.policy_id;
12884 			}
12885 			if (return_route_rule_id) {
12886 				*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12887 			}
12888 			if (return_skip_policy_id) {
12889 				*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12890 			}
12891 			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12892 				pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12893 			}
12894 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12895 				NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - Send/Recv - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d",
12896 				    inp->inp_socket, info.bound_interface_index, info.protocol,
12897 				    inp->inp_policyresult.policy_id,
12898 				    inp->inp_policyresult.skip_policy_id,
12899 				    inp->inp_policyresult.results.result,
12900 				    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12901 			}
12902 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12903 			    return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12904 		}
12905 		lck_rw_done(&necp_kernel_policy_lock);
12906 		goto done;
12907 	}
12908 
12909 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12910 	size_t route_rule_id_array_count = 0;
12911 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12912 	struct necp_kernel_socket_policy *matched_policy =
12913 	    necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12914 	    &info,
12915 	    &filter_control_unit,
12916 	    route_rule_id_array,
12917 	    &route_rule_id_array_count,
12918 	    MAX_AGGREGATE_ROUTE_RULES,
12919 	    &service_action,
12920 	    &service,
12921 	    netagent_ids,
12922 	    NECP_MAX_NETAGENTS,
12923 	    NULL,
12924 	    0,
12925 	    NULL,
12926 	    0,
12927 	    effective_proc,
12928 	    pf_tag,
12929 	    return_skip_policy_id,
12930 	    inp->inp_route.ro_rt,
12931 	    &drop_dest_policy_result,
12932 	    &drop_all_bypass,
12933 	    &flow_divert_aggregate_unit,
12934 	    so,
12935 	    debug);
12936 
12937 	// Check for loopback exception again after the policy match
12938 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12939 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12940 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12941 		// If policies haven't changed since last evaluation, do not update filter result in order to
12942 		// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12943 		// allow content filter to detect and drop pre-existing flows.
12944 		uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
12945 		int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
12946 		if (info.soflow_entry != NULL) {
12947 			current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
12948 			current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
12949 		}
12950 		if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
12951 		    current_filter_control_unit != filter_control_unit) {
12952 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12953 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12954 			if (info.soflow_entry != NULL) {
12955 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
12956 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12957 			}
12958 		}
12959 		if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12960 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12961 		}
12962 		allowed_to_receive = TRUE;
12963 		lck_rw_done(&necp_kernel_policy_lock);
12964 
12965 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - loopback", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12966 		goto done;
12967 	}
12968 
12969 	if (info.protocol != IPPROTO_UDP) {
12970 		goto skip_agent_check;
12971 	}
12972 
12973 	// Verify netagents
12974 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12975 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12976 			NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (uint64_t)VM_KERNEL_ADDRPERM(so), info.bound_interface_index, info.protocol);
12977 		}
12978 
12979 		// Mark socket as a drop if required agent is not active
12980 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12981 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12982 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12983 		inp->inp_policyresult.flowhash = flowhash;
12984 		inp->inp_policyresult.results.filter_control_unit = 0;
12985 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12986 		inp->inp_policyresult.results.route_rule_id = 0;
12987 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12988 		if (info.soflow_entry != NULL) {
12989 			info.soflow_entry->soflow_filter_control_unit = 0;
12990 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
12991 		}
12992 
12993 		// Unlock
12994 		allowed_to_receive = FALSE;
12995 		lck_rw_done(&necp_kernel_policy_lock);
12996 
12997 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - AGENT INACTIVE", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12998 
12999 		goto done;
13000 	}
13001 
13002 skip_agent_check:
13003 
13004 	if (route_rule_id_array_count == 1) {
13005 		route_rule_id = route_rule_id_array[0];
13006 	} else if (route_rule_id_array_count > 1) {
13007 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
13008 	}
13009 
13010 	bool send_local_network_denied_event = false;
13011 	if (matched_policy != NULL) {
13012 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
13013 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13014 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13015 			// Trigger the event that we dropped due to a local network policy
13016 			send_local_network_denied_event = true;
13017 		}
13018 
13019 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13020 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13021 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13022 		    matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13023 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13024 		    (route_rule_id != 0 &&
13025 		    !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
13026 		    !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13027 			allowed_to_receive = FALSE;
13028 		} else {
13029 			if (return_policy_id) {
13030 				*return_policy_id = matched_policy->id;
13031 			}
13032 			if (return_route_rule_id) {
13033 				*return_route_rule_id = route_rule_id;
13034 			}
13035 			if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13036 				pass_flags = matched_policy->result_parameter.pass_flags;
13037 			}
13038 			// If policies haven't changed since last evaluation, do not update filter result in order to
13039 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13040 			// allow content filter to detect and drop pre-existing flows.
13041 			uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13042 			int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13043 			if (info.soflow_entry != NULL) {
13044 				current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13045 				current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13046 			}
13047 			if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13048 			    current_filter_control_unit != filter_control_unit) {
13049 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13050 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13051 				if (info.soflow_entry != NULL) {
13052 					info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13053 					info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13054 				}
13055 			}
13056 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13057 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13058 			}
13059 		}
13060 
13061 		if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13062 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - Send/Recv: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d Allowed %d <filter_control_unit %d flow_divert_aggregate_unit %d>",
13063 			    inp->inp_socket, info.bound_interface_index, info.protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index, allowed_to_receive, filter_control_unit, flow_divert_aggregate_unit);
13064 		}
13065 	} else {
13066 		bool drop_all = false;
13067 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13068 			drop_all = true;
13069 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13070 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13071 			}
13072 		}
13073 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13074 			allowed_to_receive = FALSE;
13075 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13076 		} else {
13077 			if (return_policy_id) {
13078 				*return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13079 			}
13080 			if (return_route_rule_id) {
13081 				*return_route_rule_id = route_rule_id;
13082 			}
13083 
13084 			// If policies haven't changed since last evaluation, do not update filter result in order to
13085 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13086 			// allow content filter to detect and drop pre-existing flows.
13087 			uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13088 			int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13089 			if (info.soflow_entry != NULL) {
13090 				current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13091 				current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13092 			}
13093 			if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13094 			    current_filter_control_unit != filter_control_unit) {
13095 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13096 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13097 				if (info.soflow_entry != NULL) {
13098 					info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13099 					info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13100 				}
13101 			}
13102 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13103 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13104 			}
13105 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - NO MATCH", return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
13106 		}
13107 	}
13108 
13109 	if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13110 		allowed_to_receive = FALSE;
13111 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13112 	}
13113 
13114 	lck_rw_done(&necp_kernel_policy_lock);
13115 
13116 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13117 		inp->inp_policyresult.network_denied_notifies++;
13118 #if defined(XNU_TARGET_OS_OSX)
13119 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13120 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13121 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13122 		    NETPOLICY_NETWORKTYPE_LOCAL);
13123 #else
13124 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13125 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13126 		    NETPOLICY_NETWORKTYPE_LOCAL);
13127 #endif
13128 	}
13129 
13130 done:
13131 	if (return_pass_flags != NULL) {
13132 		*return_pass_flags = pass_flags;
13133 	}
13134 
13135 	if (pf_tag != 0 && allowed_to_receive) {
13136 		allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13137 	}
13138 
13139 	if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13140 		soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13141 	}
13142 
13143 	if (socket_proc) {
13144 		proc_rele(socket_proc);
13145 	}
13146 
13147 	if (info.soflow_entry != NULL) {
13148 		soflow_free_flow(info.soflow_entry);
13149 	}
13150 
13151 	return allowed_to_receive;
13152 }
13153 
13154 bool
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)13155 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)
13156 {
13157 	struct sockaddr_in local = {};
13158 	struct sockaddr_in remote = {};
13159 	local.sin_family = remote.sin_family = AF_INET;
13160 	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13161 	local.sin_port = local_port;
13162 	remote.sin_port = remote_port;
13163 	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13164 	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13165 
13166 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13167 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13168 }
13169 
13170 bool
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)13171 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)
13172 {
13173 	struct sockaddr_in6 local = {};
13174 	struct sockaddr_in6 remote = {};
13175 	local.sin6_family = remote.sin6_family = AF_INET6;
13176 	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13177 	local.sin6_port = local_port;
13178 	remote.sin6_port = remote_port;
13179 	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13180 	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13181 
13182 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13183 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13184 }
13185 
13186 bool
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,u_int32_t * return_route_rule_id,necp_kernel_policy_id * return_skip_policy_id,u_int32_t * return_pass_flags)13187 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,
13188     u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13189 {
13190 	return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13191 	           return_policy_id, return_route_rule_id,
13192 	           return_skip_policy_id, return_pass_flags);
13193 }
13194 
13195 int
necp_mark_packet_from_socket(struct mbuf * packet,struct inpcb * inp,necp_kernel_policy_id policy_id,u_int32_t route_rule_id,necp_kernel_policy_id skip_policy_id,u_int32_t pass_flags)13196 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13197     necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13198 {
13199 	if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13200 		return EINVAL;
13201 	}
13202 
13203 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13204 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13205 		    policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13206 	}
13207 
13208 	// Mark ID for Pass and IP Tunnel
13209 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13210 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13211 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13212 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13213 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13214 	} else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13215 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13216 		// This case is same as a PASS
13217 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13218 	} else {
13219 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13220 	}
13221 	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13222 	if (route_rule_id != 0) {
13223 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13224 	} else {
13225 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13226 	}
13227 	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);
13228 
13229 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13230 	    skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13231 		// Only mark the skip policy if it is a valid policy ID
13232 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13233 	} else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13234 	    inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13235 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13236 	} else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13237 		// Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13238 		// to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13239 		// See necp_get_skip_policy_id_from_packet() and
13240 		// necp_packet_should_skip_filters().
13241 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13242 	} else {
13243 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13244 	}
13245 
13246 	if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13247 	    ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13248 		m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13249 	}
13250 
13251 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13252 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13253 		    packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13254 	}
13255 
13256 	return 0;
13257 }
13258 
13259 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13260 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13261 {
13262 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13263 		return EINVAL;
13264 	}
13265 
13266 	// Mark ID for Pass and IP Tunnel
13267 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13268 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13269 	} else {
13270 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13271 	}
13272 
13273 	return 0;
13274 }
13275 
13276 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13277 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13278 {
13279 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13280 		return EINVAL;
13281 	}
13282 
13283 	// Mark ID for Pass and IP Tunnel
13284 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13285 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13286 	} else {
13287 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13288 	}
13289 
13290 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13291 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13292 	} else {
13293 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13294 	}
13295 	return 0;
13296 }
13297 
13298 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13299 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13300 {
13301 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13302 		return EINVAL;
13303 	}
13304 
13305 	// Mark ID for Pass and IP Tunnel
13306 	if (interface != NULL) {
13307 		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13308 	}
13309 
13310 	return 0;
13311 }
13312 
13313 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13314 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13315 {
13316 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13317 		return EINVAL;
13318 	}
13319 
13320 	if (is_keepalive) {
13321 		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13322 	} else {
13323 		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13324 	}
13325 
13326 	return 0;
13327 }
13328 
13329 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13330 necp_get_policy_id_from_packet(struct mbuf *packet)
13331 {
13332 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13333 		return NECP_KERNEL_POLICY_ID_NONE;
13334 	}
13335 
13336 	return packet->m_pkthdr.necp_mtag.necp_policy_id;
13337 }
13338 
13339 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13340 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13341 {
13342 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13343 		return NECP_KERNEL_POLICY_ID_NONE;
13344 	}
13345 
13346 	// Check for overloaded value. See necp_mark_packet_from_socket().
13347 	if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13348 		return NECP_KERNEL_POLICY_ID_NONE;
13349 	}
13350 
13351 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13352 }
13353 
13354 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13355 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13356 {
13357 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13358 		return 0;
13359 	}
13360 
13361 	return m_pftag(packet)->pftag_tag;
13362 }
13363 
13364 bool
necp_packet_should_skip_filters(struct mbuf * packet)13365 necp_packet_should_skip_filters(struct mbuf *packet)
13366 {
13367 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13368 		return false;
13369 	}
13370 
13371 	// Check for overloaded value. See necp_mark_packet_from_socket().
13372 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13373 }
13374 
13375 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13376 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13377 {
13378 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13379 		return 0;
13380 	}
13381 
13382 	return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13383 }
13384 
13385 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13386 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13387 {
13388 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13389 		return 0;
13390 	}
13391 
13392 	return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13393 }
13394 
13395 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13396 necp_get_app_uuid_from_packet(struct mbuf *packet,
13397     uuid_t app_uuid)
13398 {
13399 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13400 		return EINVAL;
13401 	}
13402 
13403 	bool found_mapping = FALSE;
13404 	if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13405 		lck_rw_lock_shared(&necp_kernel_policy_lock);
13406 		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);
13407 		struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13408 		if (entry != NULL) {
13409 			uuid_copy(app_uuid, entry->uuid);
13410 			found_mapping = true;
13411 		}
13412 		lck_rw_done(&necp_kernel_policy_lock);
13413 	}
13414 	if (!found_mapping) {
13415 		uuid_clear(app_uuid);
13416 	}
13417 	return 0;
13418 }
13419 
13420 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13421 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13422 {
13423 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13424 		return FALSE;
13425 	}
13426 
13427 	return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13428 }
13429 
13430 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13431 necp_socket_get_content_filter_control_unit(struct socket *so)
13432 {
13433 	struct inpcb *inp = sotoinpcb(so);
13434 
13435 	if (inp == NULL) {
13436 		return 0;
13437 	}
13438 	return inp->inp_policyresult.results.filter_control_unit;
13439 }
13440 
13441 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13442 necp_socket_get_policy_gencount(struct socket *so)
13443 {
13444 	struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13445 
13446 	if (inp == NULL) {
13447 		return 0;
13448 	}
13449 	return inp->inp_policyresult.policy_gencount;
13450 }
13451 
13452 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13453 necp_socket_should_use_flow_divert(struct inpcb *inp)
13454 {
13455 	if (inp == NULL) {
13456 		return FALSE;
13457 	}
13458 
13459 	return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13460 	       (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13461 	       (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13462 }
13463 
13464 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13465 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13466 {
13467 	if (inp == NULL) {
13468 		return 0;
13469 	}
13470 
13471 	if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13472 		return 0;
13473 	}
13474 
13475 	if (aggregate_unit != NULL &&
13476 	    inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13477 		*aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13478 	}
13479 
13480 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13481 		return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13482 	}
13483 
13484 	return 0;
13485 }
13486 
13487 bool
necp_socket_should_rescope(struct inpcb * inp)13488 necp_socket_should_rescope(struct inpcb *inp)
13489 {
13490 	if (inp == NULL) {
13491 		return FALSE;
13492 	}
13493 
13494 	return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13495 	       inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13496 }
13497 
13498 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13499 necp_socket_get_rescope_if_index(struct inpcb *inp)
13500 {
13501 	if (inp == NULL) {
13502 		return 0;
13503 	}
13504 
13505 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13506 		return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13507 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13508 		return necp_get_primary_direct_interface_index();
13509 	}
13510 
13511 	return 0;
13512 }
13513 
13514 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13515 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13516 {
13517 	if (inp == NULL) {
13518 		return current_mtu;
13519 	}
13520 
13521 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13522 	    (inp->inp_flags & INP_BOUND_IF) &&
13523 	    inp->inp_boundifp) {
13524 		u_int bound_interface_index = inp->inp_boundifp->if_index;
13525 		u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13526 
13527 		// The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13528 		if (bound_interface_index != tunnel_interface_index) {
13529 			ifnet_t tunnel_interface = NULL;
13530 
13531 			ifnet_head_lock_shared();
13532 			tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13533 			ifnet_head_done();
13534 
13535 			if (tunnel_interface != NULL) {
13536 				u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13537 				u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13538 				const char ipsec_prefix[] = "ipsec";
13539 				if (delegate_tunnel_mtu != 0 &&
13540 				    strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13541 					// For ipsec interfaces, calculate the overhead from the delegate interface
13542 					u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13543 					if (delegate_tunnel_mtu > tunnel_overhead) {
13544 						delegate_tunnel_mtu -= tunnel_overhead;
13545 					}
13546 
13547 					if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13548 						// If the (delegate - overhead) < direct, return (delegate - overhead)
13549 						return delegate_tunnel_mtu;
13550 					} else {
13551 						// Otherwise return direct
13552 						return direct_tunnel_mtu;
13553 					}
13554 				} else {
13555 					// For non-ipsec interfaces, just return the tunnel MTU
13556 					return direct_tunnel_mtu;
13557 				}
13558 			}
13559 		}
13560 	}
13561 
13562 	// By default, just return the MTU passed in
13563 	return current_mtu;
13564 }
13565 
13566 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13567 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13568 {
13569 	if (result_parameter == NULL) {
13570 		return NULL;
13571 	}
13572 
13573 	return ifindex2ifnet[result_parameter->tunnel_interface_index];
13574 }
13575 
13576 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13577 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13578 {
13579 	bool found_match = FALSE;
13580 	bool can_rebind = FALSE;
13581 	ifaddr_t ifa;
13582 	union necp_sockaddr_union address_storage;
13583 
13584 	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13585 		return FALSE;
13586 	}
13587 
13588 	// Match source address against interface addresses
13589 	ifnet_lock_shared(interface);
13590 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13591 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13592 			if (address_storage.sa.sa_family != family) {
13593 				continue;
13594 			}
13595 
13596 			if (family == AF_INET) {
13597 				struct ip *ip = mtod(packet, struct ip *);
13598 				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13599 					found_match = TRUE;
13600 					break;
13601 				}
13602 			} else if (family == AF_INET6) {
13603 				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13604 				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13605 					found_match = TRUE;
13606 					break;
13607 				}
13608 			}
13609 		}
13610 	}
13611 	const uint32_t if_idx = interface->if_index;
13612 	ifnet_lock_done(interface);
13613 
13614 	// If source address matched, attempt to construct a route to the destination address
13615 	if (found_match) {
13616 		ROUTE_RELEASE(new_route);
13617 
13618 		if (family == AF_INET) {
13619 			struct ip *ip = mtod(packet, struct ip *);
13620 			struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13621 			dst4->sin_family = AF_INET;
13622 			dst4->sin_len = sizeof(struct sockaddr_in);
13623 			dst4->sin_addr = ip->ip_dst;
13624 			rtalloc_scoped(new_route, if_idx);
13625 			if (!ROUTE_UNUSABLE(new_route)) {
13626 				can_rebind = TRUE;
13627 			}
13628 		} else if (family == AF_INET6) {
13629 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13630 			struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13631 			dst6->sin6_family = AF_INET6;
13632 			dst6->sin6_len = sizeof(struct sockaddr_in6);
13633 			dst6->sin6_addr = ip6->ip6_dst;
13634 			rtalloc_scoped(new_route, if_idx);
13635 			if (!ROUTE_UNUSABLE(new_route)) {
13636 				can_rebind = TRUE;
13637 			}
13638 		}
13639 	}
13640 
13641 	return can_rebind;
13642 }
13643 
13644 static bool
necp_addr_is_loopback(struct sockaddr * address)13645 necp_addr_is_loopback(struct sockaddr *address)
13646 {
13647 	if (address == NULL) {
13648 		return FALSE;
13649 	}
13650 
13651 	if (address->sa_family == AF_INET) {
13652 		return IN_LOOPBACK(ntohl(SIN(address)->sin_addr.s_addr));
13653 	} else if (address->sa_family == AF_INET6) {
13654 		if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13655 			return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13656 		} else {
13657 			// Match ::ffff:127.0.0.1 loopback address
13658 			in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13659 			return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13660 		}
13661 	}
13662 
13663 	return FALSE;
13664 }
13665 
13666 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)13667 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13668 {
13669 	// Note: This function only checks for the loopback addresses.
13670 	// In the future, we may want to expand to also allow any traffic
13671 	// going through the loopback interface, but until then, this
13672 	// check is cheaper.
13673 
13674 	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13675 		return TRUE;
13676 	}
13677 
13678 	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13679 		return TRUE;
13680 	}
13681 
13682 	if (inp != NULL) {
13683 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13684 			return TRUE;
13685 		}
13686 		if (inp->inp_vflag & INP_IPV4) {
13687 			if (IN_LOOPBACK(ntohl(inp->inp_laddr.s_addr)) ||
13688 			    IN_LOOPBACK(ntohl(inp->inp_faddr.s_addr))) {
13689 				return TRUE;
13690 			}
13691 		} else if (inp->inp_vflag & INP_IPV6) {
13692 			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13693 			    IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13694 				return TRUE;
13695 			}
13696 		}
13697 	} else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13698 		return TRUE;
13699 	}
13700 
13701 	if (packet != NULL) {
13702 		struct ip *ip = mtod(packet, struct ip *);
13703 		if (ip->ip_v == 4) {
13704 			if (IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) {
13705 				return TRUE;
13706 			}
13707 			if (IN_LOOPBACK(ntohl(ip->ip_dst.s_addr))) {
13708 				return TRUE;
13709 			}
13710 		} else if (ip->ip_v == 6) {
13711 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13712 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13713 				return TRUE;
13714 			}
13715 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13716 				return TRUE;
13717 			}
13718 		}
13719 	}
13720 
13721 	return FALSE;
13722 }
13723 
13724 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13725 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13726 {
13727 	if (inp != NULL) {
13728 		if (!(inp->inp_vflag & INP_IPV6)) {
13729 			return false;
13730 		}
13731 		if (INP_INTCOPROC_ALLOWED(inp)) {
13732 			return true;
13733 		}
13734 		if ((inp->inp_flags & INP_BOUND_IF) &&
13735 		    IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13736 			return true;
13737 		}
13738 		return false;
13739 	}
13740 	if (packet != NULL) {
13741 		struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13742 		struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13743 		if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13744 		    NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13745 			return true;
13746 		}
13747 	}
13748 
13749 	return false;
13750 }
13751 
13752 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13753 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13754 {
13755 	char dest_str[MAX_IPv6_STR_LEN];
13756 
13757 	if (necp_drop_dest_debug > 0) {
13758 		if (sau->sa.sa_family == AF_INET) {
13759 			(void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13760 		} else if (sau->sa.sa_family == AF_INET6) {
13761 			(void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13762 		} else {
13763 			dest_str[0] = 0;
13764 		}
13765 	}
13766 	for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13767 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13768 		struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13769 
13770 		if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13771 			if (necp_drop_dest_debug > 0) {
13772 				char subnet_str[MAX_IPv6_STR_LEN];
13773 				struct proc *p = current_proc();
13774 				pid_t pid = proc_pid(p);
13775 
13776 				if (sau->sa.sa_family == AF_INET) {
13777 					(void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13778 					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);
13779 				} else if (sau->sa.sa_family == AF_INET6) {
13780 					(void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13781 					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);
13782 				}
13783 			}
13784 			return true;
13785 		}
13786 	}
13787 	if (necp_drop_dest_debug > 1) {
13788 		struct proc *p = current_proc();
13789 		pid_t pid = proc_pid(p);
13790 
13791 		os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13792 	}
13793 	return false;
13794 }
13795 
13796 static int
13797 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13798 {
13799 #pragma unused(arg1, arg2, oidp)
13800 	int changed = 0;
13801 	int error = 0;
13802 	struct necp_drop_dest_policy tmp_drop_dest_policy;
13803 	struct proc *p = current_proc();
13804 	pid_t pid = proc_pid(p);
13805 
13806 	if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13807 	    priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13808 		NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13809 		return EPERM;
13810 	}
13811 	if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13812 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13813 		return EINVAL;
13814 	}
13815 
13816 	memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13817 	error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13818 	if (error != 0) {
13819 		NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13820 		return error;
13821 	}
13822 	if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13823 		return error;
13824 	}
13825 
13826 	//
13827 	// Validate the passed parameters
13828 	//
13829 	if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13830 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13831 		return EINVAL;
13832 	}
13833 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13834 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13835 		struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13836 
13837 		switch (tmp_drop_dest_entry->level) {
13838 		case NECP_SESSION_PRIORITY_UNKNOWN:
13839 			if (tmp_drop_dest_policy.entry_count != 0) {
13840 				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);
13841 				return EINVAL;
13842 			}
13843 			break;
13844 		case NECP_SESSION_PRIORITY_CONTROL:
13845 		case NECP_SESSION_PRIORITY_CONTROL_1:
13846 		case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13847 		case NECP_SESSION_PRIORITY_HIGH:
13848 		case NECP_SESSION_PRIORITY_HIGH_1:
13849 		case NECP_SESSION_PRIORITY_HIGH_2:
13850 		case NECP_SESSION_PRIORITY_HIGH_3:
13851 		case NECP_SESSION_PRIORITY_HIGH_4:
13852 		case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13853 		case NECP_SESSION_PRIORITY_DEFAULT:
13854 		case NECP_SESSION_PRIORITY_LOW:
13855 			if (tmp_drop_dest_policy.entry_count == 0) {
13856 				NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13857 				return EINVAL;
13858 			}
13859 			break;
13860 		default: {
13861 			NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13862 			return EINVAL;
13863 		}
13864 		}
13865 
13866 		switch (npca->address.sa.sa_family) {
13867 		case AF_INET: {
13868 			if (npca->prefix > 32) {
13869 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13870 				return EINVAL;
13871 			}
13872 			if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13873 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13874 				return EINVAL;
13875 			}
13876 			if (npca->address.sin.sin_port != 0) {
13877 				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);
13878 				return EINVAL;
13879 			}
13880 			break;
13881 		}
13882 		case AF_INET6: {
13883 			if (npca->prefix > 128) {
13884 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13885 				return EINVAL;
13886 			}
13887 			if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13888 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13889 				return EINVAL;
13890 			}
13891 			if (npca->address.sin6.sin6_port != 0) {
13892 				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);
13893 				return EINVAL;
13894 			}
13895 			if (npca->address.sin6.sin6_flowinfo != 0) {
13896 				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);
13897 				return EINVAL;
13898 			}
13899 			if (npca->address.sin6.sin6_scope_id != 0) {
13900 				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);
13901 				return EINVAL;
13902 			}
13903 			break;
13904 		}
13905 		default: {
13906 			return EINVAL;
13907 		}
13908 		}
13909 	}
13910 
13911 	//
13912 	// Commit the changed policy
13913 	//
13914 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13915 	memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13916 
13917 	necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13918 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13919 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13920 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13921 
13922 		memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13923 
13924 		necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13925 	}
13926 	lck_rw_done(&necp_kernel_policy_lock);
13927 
13928 	return 0;
13929 }
13930 
13931 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13932 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13933 {
13934 	uint16_t fam = address->sa.sa_family;
13935 	memset(addr_str, 0, MAX_IPv6_STR_LEN);
13936 	if (fam == AF_INET) {
13937 		(void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13938 	} else if (fam == AF_INET6) {
13939 		(void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13940 	}
13941 	return __unsafe_null_terminated_from_indexable(addr_str);
13942 }
13943