xref: /xnu-12377.1.9/bsd/net/necp.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
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_domain_filter {
287 	LIST_ENTRY(necp_domain_filter) owner_chain;
288 	LIST_ENTRY(necp_domain_filter) chain;
289 	u_int32_t       id;
290 	struct net_bloom_filter *filter;
291 	os_refcnt_t     refcount;
292 };
293 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
294 
295 /*
296  * Filter id space is split between domain bloom filter id and domain trie filter id.
297  * id <= 10000 - bloom filter ids
298  * id > 10000 - trie filter ids
299  */
300 #define NECP_DOMAIN_FILTER_ID_MAX           10000
301 #define NECP_DOMAIN_TRIE_ID_START           NECP_DOMAIN_FILTER_ID_MAX
302 #define NECP_IS_DOMAIN_FILTER_ID(id)        (id <= NECP_DOMAIN_FILTER_ID_MAX)
303 
304 struct necp_domain_trie {
305 	LIST_ENTRY(necp_domain_trie) owner_chain;
306 	LIST_ENTRY(necp_domain_trie) chain;
307 	u_int32_t       id;
308 	struct necp_domain_trie_request *trie_request;
309 	size_t trie_request_size;
310 	struct net_trie trie;
311 	os_refcnt_t     refcount;
312 };
313 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
314 
315 struct necp_session {
316 	u_int8_t                                        necp_fd_type;
317 	u_int32_t                                       control_unit;
318 	u_int32_t                                       session_priority; // Descriptive priority rating
319 	u_int32_t                                       session_order;
320 
321 	necp_policy_id                          last_policy_id;
322 
323 	decl_lck_mtx_data(, lock);
324 
325 	bool                                            proc_locked; // Messages must come from proc_uuid
326 	uuid_t                                          proc_uuid;
327 	int                                                     proc_pid;
328 
329 	bool                                            dirty;
330 	LIST_HEAD(_policies, necp_session_policy) policies;
331 
332 	struct necp_domain_filter_list domain_filters;
333 	struct necp_domain_trie_list domain_tries;
334 
335 	TAILQ_ENTRY(necp_session) chain;
336 };
337 
338 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
339 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
340 
341 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
342 
343 struct necp_socket_info {
344 	pid_t pid;
345 	int32_t pid_version;
346 	uid_t uid;
347 	uid_t real_uid;
348 	union necp_sockaddr_union local_addr;
349 	union necp_sockaddr_union remote_addr;
350 	u_int32_t bound_interface_index;
351 	u_int32_t bound_interface_flags;
352 	u_int32_t bound_interface_eflags;
353 	u_int32_t bound_interface_xflags;
354 	u_int32_t traffic_class;
355 	u_int16_t protocol;
356 	u_int16_t scheme_port;
357 	u_int32_t application_id;
358 	u_int32_t real_application_id;
359 	u_int32_t account_id;
360 	u_int32_t drop_order;
361 	u_int32_t client_flags;
362 	char *domain __null_terminated;
363 	char *url __null_terminated;
364 	struct soflow_hash_entry *soflow_entry;
365 	unsigned is_entitled : 1;
366 	unsigned has_client : 1;
367 	unsigned has_system_signed_result : 1;
368 	unsigned is_platform_binary : 1;
369 	unsigned used_responsible_pid : 1;
370 	unsigned is_loopback : 1;
371 	unsigned real_is_platform_binary : 1;
372 	unsigned is_delegated : 1;
373 	unsigned is_local : 1;
374 	unsigned __pad_bits : 7;
375 };
376 
377 static  LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
378 static  LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
379 static  LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
380     &necp_kernel_policy_mtx_attr);
381 
382 static  LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
383 static  LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
384 
385 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
386 
387 /*
388  * On modification, invalidate cached lookups by bumping the generation count.
389  * Other calls will need to take the slowpath of taking
390  * the subsystem lock.
391  */
392 static volatile int32_t necp_kernel_socket_policies_gencount;
393 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do {                                                     \
394 	if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) {      \
395 	        necp_kernel_socket_policies_gencount = 1;                                                                               \
396 	}                                                                                                                                                               \
397 } while (0)
398 
399 /*
400  * Drop-all Bypass:
401  * Allow priviledged processes to bypass the default drop-all
402  * via entitlement check.  For OSX, since entitlement check is
403  * not supported for configd, configd signing identity is checked
404  * instead.
405  */
406 #define SIGNING_ID_CONFIGD "com.apple.configd"
407 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
408 
409 typedef enum {
410 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
411 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
412 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
413 } necp_drop_all_bypass_check_result_t;
414 
415 static u_int64_t necp_kernel_application_policies_condition_mask;
416 static size_t necp_kernel_application_policies_count;
417 static u_int64_t necp_kernel_socket_policies_condition_mask;
418 static size_t necp_kernel_socket_policies_count;
419 static size_t necp_kernel_socket_policies_non_app_count;
420 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
421 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
422 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
423 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
424 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
425 static size_t necp_kernel_socket_policies_app_layer_map_count;
426 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
427 /*
428  * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
429  * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
430  * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
431  *
432  * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
433  */
434 
435 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
436 static size_t necp_kernel_ip_output_policies_count;
437 static size_t necp_kernel_ip_output_policies_non_id_count;
438 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
439 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
440 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
441 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
442 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
443 static struct necp_kernel_socket_policy pass_policy =
444 {
445 	.id = NECP_KERNEL_POLICY_ID_NO_MATCH,
446 	.result = NECP_KERNEL_POLICY_RESULT_PASS,
447 };
448 
449 static struct necp_session *necp_create_session(void);
450 static void necp_delete_session(struct necp_session *session);
451 
452 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
453     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
454 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
455 
456 #define MAX_RESULT_STRING_LEN 64
457 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);
458 
459 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);
460 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
461 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
462 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
463 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
464 static void necp_policy_apply_all(struct necp_session *session);
465 
466 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);
467 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
468 static bool necp_kernel_socket_policies_reprocess(void);
469 static bool necp_kernel_socket_policies_update_uuid_table(void);
470 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
471     struct necp_socket_info *info,
472     necp_kernel_policy_filter *return_filter,
473     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
474     size_t *return_route_rule_id_array_count,
475     size_t route_rule_id_array_count,
476     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
477     size_t netagent_array_count,
478     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
479     size_t netagent_use_flags_array_count,
480     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
481     u_int32_t num_required_agent_types,
482     proc_t proc,
483     u_int16_t pf_tag,
484     necp_kernel_policy_id *skip_policy_id,
485     struct rtentry *rt,
486     necp_kernel_policy_result *return_drop_dest_policy_result,
487     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
488     u_int32_t *return_flow_divert_aggregate_unit,
489     struct socket *so,
490     int debug);
491 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);
492 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
493 static bool necp_kernel_ip_output_policies_reprocess(void);
494 
495 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
496 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);
497 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
498 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
499 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
500 static bool necp_addr_is_empty(struct sockaddr *addr);
501 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);
502 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
503 
504 struct necp_uuid_id_mapping {
505 	LIST_ENTRY(necp_uuid_id_mapping) chain;
506 	uuid_t          uuid;
507 	u_int32_t       id;
508 	os_refcnt_t     refcount;
509 	u_int32_t       table_usecount; // Add to UUID policy table count
510 };
511 static size_t necp_num_uuid_app_id_mappings;
512 static bool necp_uuid_app_id_mappings_dirty;
513 #define NECP_UUID_APP_ID_HASH_SIZE 64
514 static u_long necp_uuid_app_id_hash_mask;
515 static u_long necp_uuid_app_id_hash_num_buckets;
516 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_agent_uuid_id_list; // App map is real hash table, agent map is just mapping
517 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
518 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
519 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
520 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t agent_id);
521 
522 static bool necp_agent_id_is_uuid(u_int32_t agent_id);
523 static struct necp_uuid_id_mapping *necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid);
524 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id);
525 static u_int32_t necp_create_agent_uuid_id_mapping(uuid_t uuid);
526 static bool necp_remove_agent_uuid_id_mapping(uuid_t uuid);
527 static bool necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id);
528 
529 struct necp_agent_type_id_mapping {
530 	LIST_ENTRY(necp_agent_type_id_mapping) chain;
531 	struct necp_policy_condition_agent_type agent_type;
532 	u_int32_t       id;
533 	os_refcnt_t     refcount;
534 };
535 static LIST_HEAD(necp_agent_type_id_mapping_list, necp_agent_type_id_mapping) necp_agent_type_id_list;
536 static u_int32_t necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type *agent_type);
537 static bool necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id);
538 static struct necp_agent_type_id_mapping *necp_lookup_agent_type_with_id_locked(u_int32_t agent_id);
539 
540 struct necp_string_id_mapping {
541 	LIST_ENTRY(necp_string_id_mapping) chain;
542 	char            *string __null_terminated;
543 	necp_app_id     id;
544 	os_refcnt_t     refcount;
545 };
546 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
547 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
548 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
549 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
550 
551 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);
552 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
553 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
554 
555 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
556     struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
557 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
558 static void necp_free_domain_trie(struct necp_domain_trie *trie);
559 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
560 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);
561 
562 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
563 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
564 
565 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
566 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
567 
568 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
569 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);
570 
571 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
572 
573 #define MAX_ROUTE_RULE_INTERFACES 10
574 struct necp_route_rule {
575 	LIST_ENTRY(necp_route_rule) chain;
576 	u_int32_t       id;
577 	u_int32_t       netagent_id;
578 	u_int32_t       control_unit;
579 	u_int32_t       match_netagent_id;
580 	u_int32_t       effective_type;
581 	u_int8_t        default_action;
582 	u_int8_t        cellular_action;
583 	u_int8_t        wifi_action;
584 	u_int8_t        wired_action;
585 	u_int8_t        expensive_action;
586 	u_int8_t        constrained_action;
587 	u_int8_t        companion_action;
588 	u_int8_t        vpn_action;
589 	u_int8_t        ultra_constrained_action;
590 	u_int           exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
591 	u_int8_t        exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
592 	os_refcnt_t     refcount;
593 };
594 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
595 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);
596 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
597 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
598 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,
599     u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied);
600 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);
601 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
602 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);
603 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
604 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
605 
606 #define MAX_AGGREGATE_ROUTE_RULES 16
607 struct necp_aggregate_route_rule {
608 	LIST_ENTRY(necp_aggregate_route_rule) chain;
609 	u_int32_t       id;
610 	u_int32_t       rule_ids[MAX_AGGREGATE_ROUTE_RULES];
611 };
612 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
613 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
614 
615 // Sysctl definitions
616 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
617 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
618 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
619 
620 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
621 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
624 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
625 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
626 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
627 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", "");
628 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", "");
629 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", "");
630 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
631 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, "");
632 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
633 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
634 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
635 
636 static struct necp_drop_dest_policy necp_drop_dest_policy;
637 static int necp_drop_dest_debug = 0;    // 0: off, 1: match, >1: every evaluation
638 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
639 
640 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
641 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
642     0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
643 
644 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
645 
646 /*
647  * data tracing control -
648  *
649  * necp_data_tracing_level    : 1 for brief trace, 2 for policy details, 3 for condition details
650  * necp_data_tracing_port     : match traffic with specified port
651  * necp_data_tracing_proto    : match traffic with specified protocol
652  * necp_data_tracing_pid      : match traffic with specified pid (only applied at socket level)
653  * necp_data_tracing_ifindex  : match traffic on specified ifindex
654  * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched.  Default is 0 to trace traffic if any specified attributes matched.
655  * data_tracing_session_order     : match policies in the specified session - log traffic that hit these policies
656  * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
657  */
658 static int necp_data_tracing_level = 0;
659 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
660 
661 static int necp_data_tracing_port = 0;
662 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
663 
664 static int necp_data_tracing_proto = 0;
665 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
666 
667 static int necp_data_tracing_pid = 0;
668 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
669 
670 static int necp_data_tracing_ifindex = 0;
671 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
672 
673 static int necp_data_tracing_match_all = 0;
674 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
675 
676 static int necp_data_tracing_session_order = 0;
677 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
678 
679 static int necp_data_tracing_policy_order = 0;
680 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
681 
682 #define NECP_DATA_TRACE_LEVEL_BRIEF     1
683 #define NECP_DATA_TRACE_LEVEL_POLICY    2
684 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
685 #define NECP_DATA_TRACE_LEVEL_DP        4
686 
687 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
688     (pid == necp_data_tracing_pid)
689 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
690     (protocol == necp_data_tracing_proto)
691 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
692     (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
693 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
694     (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
695 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
696 	(ifindex == necp_data_tracing_ifindex)
697 
698 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
699     ((necp_data_tracing_level && \
700 	((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
701 	(necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
702 	(necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
703 	(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)
704 
705 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
706     ((necp_data_tracing_level && \
707 	((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
708 	(!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
709 	(!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
710 	(!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)
711 
712 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
713     (necp_data_tracing_match_all ? \
714 	NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
715 	NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
716 
717 #define NECP_DATA_TRACE_ON(debug) (debug)
718 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
719 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
720 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
721 
722 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
723 
724 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
725     if (NECP_DATA_TRACE_ON(debug)) { \
726     char laddr_str[MAX_IPv6_STR_LEN]; \
727     char raddr_str[MAX_IPv6_STR_LEN]; \
728     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>", \
729 	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); \
730     }
731 
732 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
733     if (NECP_DATA_TRACE_ON(debug)) { \
734     char laddr_str[MAX_IPv6_STR_LEN]; \
735     char raddr_str[MAX_IPv6_STR_LEN]; \
736     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>", \
737 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); \
738     }
739 
740 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
741     if (NECP_DATA_TRACE_ON(debug)) { \
742     char laddr_str[MAX_IPv6_STR_LEN]; \
743     char raddr_str[MAX_IPv6_STR_LEN]; \
744     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>", \
745 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); \
746     }
747 
748 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
749     if (NECP_DATA_TRACE_ON(debug)) { \
750     char laddr_str[MAX_IPv6_STR_LEN]; \
751     char raddr_str[MAX_IPv6_STR_LEN]; \
752     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)", \
753 	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]); \
754     }
755 
756 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
757     if (NECP_DATA_TRACE_ON(debug)) { \
758     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
759 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
760     }
761 
762 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
763     if (NECP_DATA_TRACE_ON(debug)) { \
764     char laddr_str[MAX_IPv6_STR_LEN]; \
765     char raddr_str[MAX_IPv6_STR_LEN]; \
766     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>", \
767 	        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)); \
768     }
769 
770 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
771     if (NECP_DATA_TRACE_ON(debug)) { \
772     char laddr_str[MAX_IPv6_STR_LEN]; \
773     char raddr_str[MAX_IPv6_STR_LEN]; \
774     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>", \
775 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); \
776     }
777 
778 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
779     if (NECP_DATA_TRACE_ON(debug)) { \
780     char laddr_str[MAX_IPv6_STR_LEN]; \
781     char raddr_str[MAX_IPv6_STR_LEN]; \
782     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)", \
783 	    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]); \
784     }
785 
786 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
787     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
788     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)", \
789 	    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); \
790     }
791 
792 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
793     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
794     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)", \
795 	        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); \
796     }
797 
798 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
799     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
800     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)>", \
801 	        caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
802     }
803 
804 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
805     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
806     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
807 	    caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
808 	    input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
809     }
810 
811 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
812     NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
813 
814 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
815     NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
816 
817 
818 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
819     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
820     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)>", \
821 	    caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
822     }
823 
824 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
825     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
826     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
827 	caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
828 	input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
829     }
830 
831 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
832     NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
833 
834 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
835     NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
836 
837 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
838     (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
839      addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
840 
841 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
842 	"INVALID",
843 	"PASS",
844 	"SKIP",
845 	"DROP",
846 	"SOCKET_DIVERT",
847 	"SOCKET_FILTER",
848 	"IP_TUNNEL",
849 	"IP_FILTER",
850 	"TRIGGER",
851 	"TRIGGER_IF_NEEDED",
852 	"TRIGGER_SCOPED",
853 	"NO_TRIGGER_SCOPED",
854 	"SOCKET_SCOPED",
855 	"ROUTE_RULES",
856 	"USE_NETAGENT",
857 	"NETAGENT_SCOPED",
858 	"SCOPED_DIRECT",
859 	"ALLOW_UNENTITLED",
860 	"REMOVE_NETAGENT",
861 	"REMOVE_NETAGENT_TYPE"
862 };
863 
864 
865 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
866 
867 static int necp_drop_loopback_count = 0;
868 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
869 
870 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)871 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
872 {
873 	bool is_interface_address = false;
874 	if (addr == NULL) {
875 		return false;
876 	}
877 
878 	// Clean up the address before comparison with interface addresses
879 	// Transform remote_addr into the ifaddr form
880 	// IPv6 Scope IDs are always embedded in the ifaddr list
881 	struct sockaddr_storage remote_address_sanitized;
882 	u_int ifscope = IFSCOPE_NONE;
883 	(void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
884 	SIN(&remote_address_sanitized)->sin_port = 0;
885 	if (remote_address_sanitized.ss_family == AF_INET6) {
886 		if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
887 			SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
888 		}
889 	}
890 
891 	// Check if remote address is an interface address
892 	struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
893 	if (ifa != NULL && ifa->ifa_ifp != NULL) {
894 		is_interface_address = true;
895 	}
896 	if (ifa != NULL) {
897 		ifaddr_release(ifa);
898 		ifa = NULL;
899 	}
900 
901 	return is_interface_address;
902 }
903 
904 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
905     ((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)))
906 
907 // Session order allocation
908 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)909 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
910 {
911 	u_int32_t new_order = 0;
912 
913 	// For now, just allocate 1000 orders for each priority
914 	if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
915 		priority = NECP_SESSION_PRIORITY_DEFAULT;
916 	}
917 
918 	// Use the control unit to decide the offset into the priority list
919 	new_order = (control_unit) + ((priority - 1) * 1000);
920 
921 	return new_order;
922 }
923 
924 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)925 necp_get_first_order_for_priority(u_int32_t priority)
926 {
927 	if (priority == 0) {
928 		return 0;
929 	}
930 	return ((priority - 1) * 1000) + 1;
931 }
932 
933 // Sysctl handler
934 static int
935 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
936 {
937 #pragma unused(arg1, arg2)
938 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
939 	necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
940 	return error;
941 }
942 
943 static int
944 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
945 {
946 #pragma unused(arg1, arg2)
947 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
948 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
949 	return error;
950 }
951 
952 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
953 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)954 _necp_process_drop_order_inner(kauth_cred_t cred)
955 {
956 	if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
957 	    priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
958 		return necp_drop_unentitled_order;
959 	} else {
960 		return 0;
961 	}
962 }
963 
964 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
965 #pragma GCC poison _necp_process_drop_order_inner
966 
967 static int
968 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
969 {
970 #pragma unused(arg1, arg2)
971 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
972 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
973 	return error;
974 }
975 
976 static inline bool
necp_socket_is_connected(struct inpcb * inp)977 necp_socket_is_connected(struct inpcb *inp)
978 {
979 	return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
980 }
981 
982 
983 // Session fd
984 
985 static int necp_session_op_close(struct fileglob *, vfs_context_t);
986 
987 static const struct fileops necp_session_fd_ops = {
988 	.fo_type     = DTYPE_NETPOLICY,
989 	.fo_read     = fo_no_read,
990 	.fo_write    = fo_no_write,
991 	.fo_ioctl    = fo_no_ioctl,
992 	.fo_select   = fo_no_select,
993 	.fo_close    = necp_session_op_close,
994 	.fo_drain    = fo_no_drain,
995 	.fo_kqfilter = fo_no_kqfilter,
996 };
997 
998 static inline int
necp_is_platform_binary(proc_t proc)999 necp_is_platform_binary(proc_t proc)
1000 {
1001 	return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
1002 }
1003 
1004 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1005 necp_check_drop_all_bypass_result(proc_t proc)
1006 {
1007 	if (proc == NULL) {
1008 		proc = current_proc();
1009 		if (proc == NULL) {
1010 			return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1011 		}
1012 	}
1013 
1014 #if defined(XNU_TARGET_OS_OSX)
1015 	const char *signing_id __null_terminated = NULL;
1016 	const bool isConfigd = (necp_is_platform_binary(proc) &&
1017 	    (signing_id = cs_identity_get(proc)) &&
1018 	    (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1019 	    (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1020 	if (isConfigd) {
1021 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1022 	}
1023 #endif
1024 
1025 	const task_t __single task = proc_task(proc);
1026 	if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1027 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1028 	} else {
1029 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1030 	}
1031 }
1032 
1033 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1034 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1035 {
1036 #pragma unused(uap)
1037 	int error = 0;
1038 	struct necp_session *session = NULL;
1039 	struct fileproc * __single fp = NULL;
1040 	int fd = -1;
1041 	uid_t uid = kauth_cred_getuid(kauth_cred_get());
1042 
1043 	if (!necp_is_platform_binary(p)) {
1044 		NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1045 		error = EACCES;
1046 		goto done;
1047 	}
1048 
1049 	if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1050 		NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1051 		error = EACCES;
1052 		goto done;
1053 	}
1054 
1055 	error = falloc(p, &fp, &fd);
1056 	if (error != 0) {
1057 		goto done;
1058 	}
1059 
1060 	session = necp_create_session();
1061 	if (session == NULL) {
1062 		error = ENOMEM;
1063 		goto done;
1064 	}
1065 
1066 	fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1067 	fp->fp_glob->fg_flag = 0;
1068 	fp->fp_glob->fg_ops = &necp_session_fd_ops;
1069 	fp_set_data(fp, session);
1070 
1071 	proc_fdlock(p);
1072 	procfdtbl_releasefd(p, fd, NULL);
1073 	fp_drop(p, fd, fp, 1);
1074 	proc_fdunlock(p);
1075 
1076 	*retval = fd;
1077 done:
1078 	if (error != 0) {
1079 		if (fp != NULL) {
1080 			fp_free(p, fd, fp);
1081 			fp = NULL;
1082 		}
1083 	}
1084 
1085 	return error;
1086 }
1087 
1088 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1089 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1090 {
1091 #pragma unused(ctx)
1092 	struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1093 	fg_set_data(fg, NULL);
1094 
1095 	if (session != NULL) {
1096 		necp_policy_mark_all_for_deletion(session);
1097 		necp_policy_apply_all(session);
1098 		necp_delete_session(session);
1099 		return 0;
1100 	} else {
1101 		return ENOENT;
1102 	}
1103 }
1104 
1105 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1106 necp_session_find_from_fd(struct proc *p, int fd,
1107     struct fileproc **fpp, struct necp_session **session)
1108 {
1109 	struct fileproc * __single fp = NULL;
1110 	int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1111 
1112 	if (error == 0) {
1113 		*fpp = fp;
1114 		*session = (struct necp_session *)fp_get_data(fp);
1115 		if ((*session)->necp_fd_type != necp_fd_type_session) {
1116 			// Not a client fd, ignore
1117 			fp_drop(p, fd, fp, 0);
1118 			error = EINVAL;
1119 		}
1120 	}
1121 
1122 	return error;
1123 }
1124 
1125 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1126 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1127 {
1128 	int error = 0;
1129 	u_int8_t * __indexable tlv_buffer = NULL;
1130 
1131 	if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1132 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1133 		error = EINVAL;
1134 		goto done;
1135 	}
1136 
1137 	if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1138 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1139 		error = EINVAL;
1140 		goto done;
1141 	}
1142 
1143 	if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1144 		error = ENOMEM;
1145 		goto done;
1146 	}
1147 
1148 	error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1149 	if (error != 0) {
1150 		NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1151 		goto done;
1152 	}
1153 
1154 	necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1155 	if (error != 0) {
1156 		NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1157 		goto done;
1158 	}
1159 
1160 	error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1161 	if (error != 0) {
1162 		NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1163 		goto done;
1164 	}
1165 
1166 done:
1167 	if (tlv_buffer != NULL) {
1168 		kfree_data(tlv_buffer, uap->in_buffer_length);
1169 		tlv_buffer = NULL;
1170 	}
1171 	*retval = error;
1172 
1173 	return error;
1174 }
1175 
1176 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1177 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1178 {
1179 	int error = 0;
1180 	u_int8_t * __indexable response = NULL;
1181 
1182 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1183 		NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1184 		error = EINVAL;
1185 		goto done;
1186 	}
1187 
1188 	necp_policy_id policy_id = 0;
1189 	error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1190 	if (error != 0) {
1191 		NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1192 		goto done;
1193 	}
1194 
1195 	struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1196 	if (policy == NULL || policy->pending_deletion) {
1197 		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1198 		error = ENOENT;
1199 		goto done;
1200 	}
1201 
1202 	u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1203 	u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1204 	u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1205 
1206 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1207 		NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1208 		error = EINVAL;
1209 		goto done;
1210 	}
1211 
1212 	if (response_size > NECP_MAX_POLICY_SIZE) {
1213 		NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1214 		error = EINVAL;
1215 		goto done;
1216 	}
1217 
1218 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1219 	if (response == NULL) {
1220 		error = ENOMEM;
1221 		goto done;
1222 	}
1223 
1224 	u_int8_t *cursor = response;
1225 	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1226 	if (result_tlv_size) {
1227 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1228 	}
1229 	if (policy->conditions_size) {
1230 		memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1231 	}
1232 
1233 	error = copyout(response, uap->out_buffer, response_size);
1234 	if (error != 0) {
1235 		NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1236 		goto done;
1237 	}
1238 
1239 done:
1240 	if (response != NULL) {
1241 		kfree_data(response, response_size);
1242 		response = NULL;
1243 	}
1244 	*retval = error;
1245 
1246 	return error;
1247 }
1248 
1249 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1250 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1251 {
1252 	int error = 0;
1253 
1254 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1255 		NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1256 		error = EINVAL;
1257 		goto done;
1258 	}
1259 
1260 	necp_policy_id delete_policy_id = 0;
1261 	error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1262 	if (error != 0) {
1263 		NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1264 		goto done;
1265 	}
1266 
1267 	struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1268 	if (policy == NULL || policy->pending_deletion) {
1269 		NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1270 		error = ENOENT;
1271 		goto done;
1272 	}
1273 
1274 	necp_policy_mark_for_deletion(session, policy);
1275 done:
1276 	*retval = error;
1277 	return error;
1278 }
1279 
1280 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1281 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1282 {
1283 #pragma unused(uap)
1284 	necp_policy_apply_all(session);
1285 	*retval = 0;
1286 	return 0;
1287 }
1288 
1289 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1290 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1291 {
1292 	u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1293 	u_int32_t response_size = 0;
1294 	u_int8_t * __indexable response = NULL;
1295 	int num_policies = 0;
1296 	int cur_policy_index = 0;
1297 	int error = 0;
1298 	struct necp_session_policy *policy;
1299 
1300 	LIST_FOREACH(policy, &session->policies, chain) {
1301 		if (!policy->pending_deletion) {
1302 			num_policies++;
1303 		}
1304 	}
1305 
1306 	if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1307 		NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1308 		error = EINVAL;
1309 		goto done;
1310 	}
1311 
1312 	response_size = num_policies * tlv_size;
1313 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1314 		NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1315 		error = EINVAL;
1316 		goto done;
1317 	}
1318 
1319 	// Create a response with one Policy ID TLV for each policy
1320 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1321 	if (response == NULL) {
1322 		error = ENOMEM;
1323 		goto done;
1324 	}
1325 
1326 	u_int8_t *cursor = response;
1327 	LIST_FOREACH(policy, &session->policies, chain) {
1328 		if (!policy->pending_deletion && cur_policy_index < num_policies) {
1329 			cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1330 			cur_policy_index++;
1331 		}
1332 	}
1333 
1334 	error = copyout(response, uap->out_buffer, response_size);
1335 	if (error != 0) {
1336 		NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1337 		goto done;
1338 	}
1339 
1340 done:
1341 	if (response != NULL) {
1342 		kfree_data(response, response_size);
1343 		response = NULL;
1344 	}
1345 	*retval = error;
1346 
1347 	return error;
1348 }
1349 
1350 
1351 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1352 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1353 {
1354 #pragma unused(uap)
1355 	necp_policy_mark_all_for_deletion(session);
1356 	*retval = 0;
1357 	return 0;
1358 }
1359 
1360 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1361 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1362 {
1363 	int error = 0;
1364 	struct necp_session_policy *policy = NULL;
1365 	struct necp_session_policy *temp_policy = NULL;
1366 
1367 	if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1368 		NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1369 		error = EINVAL;
1370 		goto done;
1371 	}
1372 
1373 	necp_session_priority requested_session_priority = 0;
1374 	error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1375 	if (error != 0) {
1376 		NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1377 		goto done;
1378 	}
1379 
1380 	// Enforce special session priorities with entitlements
1381 	if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1382 	    requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1383 	    requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1384 	    requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1385 		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1386 		if (cred_result != 0) {
1387 			NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1388 			error = EPERM;
1389 			goto done;
1390 		}
1391 	}
1392 
1393 	if (session->session_priority != requested_session_priority) {
1394 		session->session_priority = requested_session_priority;
1395 		session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1396 		session->dirty = TRUE;
1397 
1398 		// Mark all policies as needing updates
1399 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1400 			policy->pending_update = TRUE;
1401 		}
1402 	}
1403 
1404 done:
1405 	*retval = error;
1406 	return error;
1407 }
1408 
1409 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1410 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1411 {
1412 #pragma unused(uap)
1413 	session->proc_locked = TRUE;
1414 	*retval = 0;
1415 	return 0;
1416 }
1417 
1418 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1419 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1420 {
1421 #pragma unused(session)
1422 	int error = 0;
1423 
1424 	if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1425 		NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1426 		error = EINVAL;
1427 		goto done;
1428 	}
1429 
1430 	error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1431 done:
1432 	*retval = error;
1433 	return error;
1434 }
1435 
1436 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1437 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1438 {
1439 	int error = 0;
1440 	struct net_bloom_filter *bloom_filter = NULL;
1441 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1442 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1443 
1444 	if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1445 	    in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1446 	    uap->in_buffer == 0) {
1447 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1448 		error = EINVAL;
1449 		goto done;
1450 	}
1451 
1452 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1453 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1454 		error = EINVAL;
1455 		goto done;
1456 	}
1457 
1458 	bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1459 	if (bloom_filter == NULL) {
1460 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1461 		error = ENOMEM;
1462 		goto done;
1463 	}
1464 
1465 	error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1466 	if (error != 0) {
1467 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1468 		goto done;
1469 	}
1470 
1471 	size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1472 	if (expected_filter_size != in_buffer_length) {
1473 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1474 		error = EINVAL;
1475 		goto done;
1476 	}
1477 
1478 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1479 	u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1480 	lck_rw_done(&necp_kernel_policy_lock);
1481 
1482 	if (filter_id == 0) {
1483 		error = ENOMEM;
1484 	} else {
1485 		// Bloom filter is taken over by the new filter entry, clear the local pointer
1486 		bloom_filter = NULL;
1487 
1488 		error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1489 		if (error != 0) {
1490 			NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1491 			goto done;
1492 		}
1493 	}
1494 
1495 done:
1496 	*retval = error;
1497 	if (error != 0 && bloom_filter != NULL) {
1498 		uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1499 		kfree_data(filter_buffer, in_buffer_length);
1500 		bloom_filter = NULL;
1501 	}
1502 	return error;
1503 }
1504 
1505 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1506 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1507 {
1508 	int error = 0;
1509 
1510 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1511 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1512 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1513 		error = EINVAL;
1514 		goto done;
1515 	}
1516 
1517 	u_int32_t filter_id;
1518 	error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1519 	if (error != 0) {
1520 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1521 		goto done;
1522 	}
1523 
1524 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1525 	bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1526 	if (!removed) {
1527 		error = ENOENT;
1528 	}
1529 	lck_rw_done(&necp_kernel_policy_lock);
1530 
1531 done:
1532 	*retval = error;
1533 	return error;
1534 }
1535 
1536 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1537 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1538 {
1539 #pragma unused(uap)
1540 
1541 	struct necp_domain_filter * __single filter = NULL;
1542 	struct necp_domain_filter *temp_filter = NULL;
1543 	LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1544 		if (os_ref_release_locked(&filter->refcount) == 0) {
1545 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1546 			LIST_REMOVE(filter, chain);
1547 			lck_rw_done(&necp_kernel_policy_lock);
1548 			LIST_REMOVE(filter, owner_chain);
1549 			net_bloom_filter_destroy(filter->filter);
1550 			kfree_type(struct necp_domain_filter, filter);
1551 		}
1552 	}
1553 
1554 	*retval = 0;
1555 	return 0;
1556 }
1557 
1558 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1559 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1560 {
1561 	int error = 0;
1562 
1563 	struct necp_domain_trie_request *domain_trie_request = NULL;
1564 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1565 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1566 
1567 	if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1568 	    in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1569 	    uap->in_buffer == 0) {
1570 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1571 		error = EINVAL;
1572 		goto done;
1573 	}
1574 
1575 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1576 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1577 		error = EINVAL;
1578 		goto done;
1579 	}
1580 
1581 	domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1582 	if (domain_trie_request == NULL) {
1583 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1584 		error = ENOMEM;
1585 		goto done;
1586 	}
1587 
1588 	error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1589 	if (error != 0) {
1590 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1591 		goto done;
1592 	}
1593 
1594 	NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1595 
1596 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1597 	u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1598 	lck_rw_done(&necp_kernel_policy_lock);
1599 
1600 	if (id == 0) {
1601 		error = ENOMEM;
1602 	} else {
1603 		error = copyout(&id, uap->out_buffer, sizeof(id));
1604 		if (error != 0) {
1605 			NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1606 			goto done;
1607 		}
1608 	}
1609 
1610 done:
1611 	*retval = error;
1612 	if (error != 0 && domain_trie_request != NULL) {
1613 		uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1614 		kfree_data(domain_buffer, in_buffer_length);
1615 		domain_trie_request = NULL;
1616 	}
1617 	return error;
1618 }
1619 
1620 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1621 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1622 {
1623 	int error = 0;
1624 
1625 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1626 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1627 		NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1628 		error = EINVAL;
1629 		goto done;
1630 	}
1631 
1632 	u_int32_t id;
1633 	error = copyin(uap->in_buffer, &id, sizeof(id));
1634 	if (error != 0) {
1635 		NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1636 		goto done;
1637 	}
1638 
1639 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1640 	bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1641 	if (!removed) {
1642 		error = ENOENT;
1643 	}
1644 	lck_rw_done(&necp_kernel_policy_lock);
1645 
1646 done:
1647 	*retval = error;
1648 	return error;
1649 }
1650 
1651 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1652 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1653 {
1654 #pragma unused(uap)
1655 	struct necp_domain_trie* __single trie = NULL;
1656 	struct necp_domain_trie* __single temp_trie = NULL;
1657 	LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1658 		if (os_ref_release_locked(&trie->refcount) == 0) {
1659 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1660 			LIST_REMOVE(trie, chain);
1661 			lck_rw_done(&necp_kernel_policy_lock);
1662 			LIST_REMOVE(trie, owner_chain);
1663 			necp_free_domain_trie(trie);
1664 		}
1665 	}
1666 	*retval = 0;
1667 	return 0;
1668 }
1669 
1670 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1671 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1672 {
1673 #pragma unused(session)
1674 
1675 	int error = 0;
1676 
1677 	uint8_t request_buffer[2000] = { 0 };
1678 	uint8_t *ptr = NULL;
1679 	uint32_t count = 0;
1680 	int output_length = 0;
1681 
1682 	lck_rw_lock_shared(&necp_kernel_policy_lock);
1683 	count = necp_trie_count;
1684 	lck_rw_done(&necp_kernel_policy_lock);
1685 
1686 	if (count == 0) {
1687 		error = ENOENT;
1688 		goto done;
1689 	}
1690 
1691 	output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1692 	if (output_length > uap->out_buffer_length) {
1693 		NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1694 		error = EINVAL;
1695 		goto done;
1696 	}
1697 	if (output_length > sizeof(request_buffer)) {
1698 		NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1699 		error = EINVAL;
1700 		goto done;
1701 	}
1702 
1703 	memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1704 	ptr = request_buffer + sizeof(count);
1705 
1706 	lck_rw_lock_shared(&necp_kernel_policy_lock);
1707 	struct necp_domain_trie* __single trie = NULL;
1708 	LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1709 		if (trie->trie_request != NULL) {
1710 			memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1711 			ptr += sizeof(struct necp_domain_trie_request);
1712 		}
1713 	}
1714 	lck_rw_done(&necp_kernel_policy_lock);
1715 
1716 	error = copyout(request_buffer, uap->out_buffer, output_length);
1717 
1718 done:
1719 	*retval = error;
1720 	return error;
1721 }
1722 
1723 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1724 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1725 {
1726 	struct fileproc * __single fp;
1727 	int error = 0;
1728 	int return_value = 0;
1729 	struct necp_session * __single session = NULL;
1730 
1731 	error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1732 	if (error != 0) {
1733 		NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1734 		return error;
1735 	}
1736 
1737 	NECP_SESSION_LOCK(session);
1738 
1739 	if (session->proc_locked) {
1740 		// Verify that the calling process is allowed to do actions
1741 		uuid_t proc_uuid;
1742 		proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1743 		if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1744 			error = EPERM;
1745 			goto done;
1746 		}
1747 	} else {
1748 		// If not locked, update the proc_uuid and proc_pid of the session
1749 		proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1750 		session->proc_pid = proc_pid(current_proc());
1751 	}
1752 
1753 	u_int32_t action = uap->action;
1754 	switch (action) {
1755 	case NECP_SESSION_ACTION_POLICY_ADD: {
1756 		return_value = necp_session_add_policy(session, uap, retval);
1757 		break;
1758 	}
1759 	case NECP_SESSION_ACTION_POLICY_GET: {
1760 		return_value = necp_session_get_policy(session, uap, retval);
1761 		break;
1762 	}
1763 	case NECP_SESSION_ACTION_POLICY_DELETE:  {
1764 		return_value = necp_session_delete_policy(session, uap, retval);
1765 		break;
1766 	}
1767 	case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1768 		return_value = necp_session_apply_all(session, uap, retval);
1769 		break;
1770 	}
1771 	case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1772 		return_value = necp_session_list_all(session, uap, retval);
1773 		break;
1774 	}
1775 	case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1776 		return_value = necp_session_delete_all(session, uap, retval);
1777 		break;
1778 	}
1779 	case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1780 		return_value = necp_session_set_session_priority(session, uap, retval);
1781 		break;
1782 	}
1783 	case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1784 		return_value = necp_session_lock_to_process(session, uap, retval);
1785 		break;
1786 	}
1787 	case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1788 		return_value = 0; // Ignore
1789 		break;
1790 	}
1791 	case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1792 		return_value = 0; // Ignore
1793 		break;
1794 	}
1795 	case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1796 		return_value = necp_session_dump_all(session, uap, retval);
1797 		break;
1798 	}
1799 	case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1800 		return_value = necp_session_add_domain_filter(session, uap, retval);
1801 		break;
1802 	}
1803 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1804 		return_value = necp_session_remove_domain_filter(session, uap, retval);
1805 		break;
1806 	}
1807 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1808 		return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1809 		break;
1810 	}
1811 	case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1812 		return_value = necp_session_add_domain_trie(session, uap, retval);
1813 		break;
1814 	}
1815 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1816 		return_value = necp_session_remove_domain_trie(session, uap, retval);
1817 		break;
1818 	}
1819 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1820 		return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1821 		break;
1822 	}
1823 	case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1824 		return_value = necp_session_trie_dump_all(session, uap, retval);
1825 		break;
1826 	}
1827 	default: {
1828 		NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1829 		return_value = EINVAL;
1830 		break;
1831 	}
1832 	}
1833 
1834 done:
1835 	NECP_SESSION_UNLOCK(session);
1836 	fp_drop(p, uap->necp_fd, fp, 0);
1837 	return return_value;
1838 }
1839 
1840 struct necp_resolver_key_state {
1841 	const struct ccdigest_info *digest_info;
1842 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1843 };
1844 static struct necp_resolver_key_state s_necp_resolver_key_state;
1845 
1846 static void
necp_generate_resolver_key(void)1847 necp_generate_resolver_key(void)
1848 {
1849 	s_necp_resolver_key_state.digest_info = ccsha256_di();
1850 	cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1851 }
1852 
1853 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)1854 necp_sign_update_context(const struct ccdigest_info *di,
1855     cchmac_ctx_t ctx,
1856     uuid_t client_id,
1857     u_int32_t sign_type,
1858     u_int8_t *data,
1859     size_t data_length)
1860 {
1861 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1862 	const char * __null_terminated context_string = "NECP Resolver Binder";
1863 	uint8_t separator = 0;
1864 	cchmac_update(di, ctx, sizeof(context), context);
1865 	cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1866 	cchmac_update(di, ctx, sizeof(separator), &separator);
1867 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1868 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1869 	cchmac_update(di, ctx, data_length, data);
1870 }
1871 
1872 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)1873 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1874     u_int8_t *data, size_t data_length,
1875     u_int8_t *tag, size_t *out_tag_length)
1876 {
1877 	if (s_necp_resolver_key_state.digest_info == NULL) {
1878 		return EINVAL;
1879 	}
1880 
1881 	if (data == NULL ||
1882 	    data_length == 0 ||
1883 	    tag == NULL ||
1884 	    out_tag_length == NULL) {
1885 		return EINVAL;
1886 	}
1887 
1888 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1889 	if (*out_tag_length < required_tag_length) {
1890 		return ERANGE;
1891 	}
1892 
1893 	*out_tag_length = required_tag_length;
1894 
1895 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1896 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1897 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1898 	    sizeof(s_necp_resolver_key_state.key),
1899 	    s_necp_resolver_key_state.key);
1900 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1901 	    ctx, client_id, sign_type, data, data_length);
1902 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1903 
1904 	return 0;
1905 }
1906 
1907 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)1908 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1909     u_int8_t * __sized_by(data_length)data, size_t data_length,
1910     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1911 {
1912 	if (s_necp_resolver_key_state.digest_info == NULL) {
1913 		return false;
1914 	}
1915 
1916 	if (data == NULL ||
1917 	    data_length == 0 ||
1918 	    tag == NULL ||
1919 	    tag_length == 0) {
1920 		return false;
1921 	}
1922 
1923 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1924 	if (tag_length != required_tag_length) {
1925 		return false;
1926 	}
1927 
1928 	uint8_t actual_tag[required_tag_length];
1929 
1930 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1931 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1932 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1933 	    sizeof(s_necp_resolver_key_state.key),
1934 	    s_necp_resolver_key_state.key);
1935 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1936 	    ctx, client_id, sign_type, data, data_length);
1937 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
1938 
1939 	return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
1940 }
1941 
1942 struct necp_application_id_key_state {
1943 	const struct ccdigest_info *digest_info;
1944 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1945 };
1946 static struct necp_application_id_key_state s_necp_application_id_key_state;
1947 
1948 static void
necp_generate_application_id_key(void)1949 necp_generate_application_id_key(void)
1950 {
1951 	s_necp_application_id_key_state.digest_info = ccsha256_di();
1952 	cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
1953 }
1954 
1955 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)1956 necp_sign_application_id_update_context(const struct ccdigest_info *di,
1957     cchmac_ctx_t ctx,
1958     uuid_t client_id,
1959     u_int32_t sign_type)
1960 {
1961 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1962 	const char context_string[] = "NECP Application ID";
1963 	uint8_t separator = 0;
1964 	cchmac_update(di, ctx, sizeof(context), context);
1965 	cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
1966 	cchmac_update(di, ctx, sizeof(separator), &separator);
1967 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1968 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1969 }
1970 
1971 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)1972 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
1973     u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
1974 {
1975 	if (s_necp_application_id_key_state.digest_info == NULL) {
1976 		return EINVAL;
1977 	}
1978 
1979 	if (tag == NULL ||
1980 	    out_tag_length == NULL) {
1981 		return EINVAL;
1982 	}
1983 
1984 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1985 	if (*out_tag_length < required_tag_length) {
1986 		return ERANGE;
1987 	}
1988 
1989 	*out_tag_length = required_tag_length;
1990 
1991 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1992 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
1993 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1994 	    sizeof(s_necp_application_id_key_state.key),
1995 	    s_necp_application_id_key_state.key);
1996 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1997 	    ctx, client_id, sign_type);
1998 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
1999 
2000 	return 0;
2001 }
2002 
2003 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)2004 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2005     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2006 {
2007 	if (s_necp_application_id_key_state.digest_info == NULL) {
2008 		return false;
2009 	}
2010 
2011 	if (tag == NULL ||
2012 	    tag_length == 0) {
2013 		return false;
2014 	}
2015 
2016 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2017 	if (tag_length != required_tag_length) {
2018 		return false;
2019 	}
2020 
2021 	uint8_t actual_tag[required_tag_length];
2022 
2023 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2024 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
2025 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2026 	    sizeof(s_necp_application_id_key_state.key),
2027 	    s_necp_application_id_key_state.key);
2028 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2029 	    ctx, client_id, sign_type);
2030 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2031 
2032 	return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2033 }
2034 
2035 void
necp_init(void)2036 necp_init(void)
2037 {
2038 	necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2039 	necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2040 
2041 	necp_client_init();
2042 
2043 	TAILQ_INIT(&necp_session_list);
2044 
2045 	LIST_INIT(&necp_kernel_socket_policies);
2046 	LIST_INIT(&necp_kernel_ip_output_policies);
2047 
2048 	LIST_INIT(&necp_account_id_list);
2049 
2050 	LIST_INIT(&necp_agent_uuid_id_list);
2051 
2052 	LIST_INIT(&necp_route_rules);
2053 	LIST_INIT(&necp_aggregate_route_rules);
2054 
2055 	LIST_INIT(&necp_global_domain_filter_list);
2056 	LIST_INIT(&necp_global_domain_trie_list);
2057 
2058 	necp_generate_resolver_key();
2059 	necp_generate_application_id_key();
2060 
2061 	necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2062 	    hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2063 	    NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2064 	necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2065 	necp_num_uuid_app_id_mappings = 0;
2066 	necp_uuid_app_id_mappings_dirty = FALSE;
2067 
2068 	necp_kernel_application_policies_condition_mask = 0;
2069 	necp_kernel_socket_policies_condition_mask = 0;
2070 	necp_kernel_ip_output_policies_condition_mask = 0;
2071 
2072 	necp_kernel_application_policies_count = 0;
2073 	necp_kernel_socket_policies_count = 0;
2074 	necp_kernel_socket_policies_non_app_count = 0;
2075 	necp_kernel_ip_output_policies_count = 0;
2076 	necp_kernel_ip_output_policies_non_id_count = 0;
2077 
2078 	necp_kernel_socket_policies_gencount = 1;
2079 
2080 	memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2081 	memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2082 	necp_kernel_socket_policies_app_layer_map = NULL;
2083 
2084 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2085 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2086 }
2087 
2088 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2089 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2090 {
2091 	struct kev_msg ev_msg;
2092 	memset(&ev_msg, 0, sizeof(ev_msg));
2093 
2094 	ev_msg.vendor_code      = KEV_VENDOR_APPLE;
2095 	ev_msg.kev_class        = KEV_NETWORK_CLASS;
2096 	ev_msg.kev_subclass     = KEV_NECP_SUBCLASS;
2097 	ev_msg.event_code       = KEV_NECP_POLICIES_CHANGED;
2098 
2099 	ev_msg.dv[0].data_ptr    = necp_event_data;
2100 	ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2101 	ev_msg.dv[1].data_length = 0;
2102 
2103 	kev_post_msg(&ev_msg);
2104 }
2105 
2106 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)2107 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2108     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2109 {
2110 	if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2111 		NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2112 		return false;
2113 	}
2114 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2115 	if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2116 	    (uintptr_t)(next_tlv - buffer) > buffer_length) {     // make sure the next TLV has enough room in buffer
2117 		NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2118 		    length, buffer_length);
2119 		return false;
2120 	}
2121 	return true;
2122 }
2123 
2124 u_int8_t * __counted_by(0)
2125 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2126     u_int32_t length, const void * __sized_by(length)value, bool *updated,
2127     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2128 {
2129 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2130 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2131 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2132 		// If we can't fit this TLV, return the current cursor
2133 		return cursor;
2134 	}
2135 	u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2136 	if (*updated || *(u_int8_t *)(cursor) != type) {
2137 		*(u_int8_t *)(cursor) = type;
2138 		*updated = TRUE;
2139 	}
2140 	if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2141 		*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2142 		*updated = TRUE;
2143 	}
2144 	if (length > 0) {
2145 		if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2146 			memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2147 			*updated = TRUE;
2148 		}
2149 	}
2150 	return next_tlv;
2151 }
2152 
2153 u_int8_t * __counted_by(0)
2154 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2155     u_int32_t length, const void * __sized_by(length)value,
2156     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2157 {
2158 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2159 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2160 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2161 		return NULL;
2162 	}
2163 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2164 	*(u_int8_t *)(cursor) = type;
2165 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2166 	if (length > 0) {
2167 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2168 	}
2169 
2170 	return next_tlv;
2171 }
2172 
2173 static u_int8_t * __counted_by(0)
2174 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2175     u_int32_t length, const void * __sized_by(length)value,
2176     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2177 {
2178 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2179 	// Add one extra byte to 'length' to account for the flags byte for validation.
2180 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2181 	if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2182 		return NULL;
2183 	}
2184 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2185 
2186 	// TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2187 	*(u_int8_t *)(cursor) = type;
2188 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2189 	*(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2190 	if (length > 0) {
2191 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2192 	}
2193 
2194 	return next_tlv;
2195 }
2196 
2197 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)2198 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2199 {
2200 	u_int8_t * __indexable type = NULL;
2201 	uint64_t end_offset = 0;
2202 
2203 	if (buffer == NULL ||
2204 	    os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2205 		return 0;
2206 	}
2207 
2208 	type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2209 	return type ? *type : 0;
2210 }
2211 
2212 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)2213 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2214 {
2215 	u_int32_t * __indexable length = NULL;
2216 	uint64_t end_offset = 0;
2217 
2218 	if (buffer == NULL ||
2219 	    os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2220 		return 0;
2221 	}
2222 
2223 	length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2224 	return length ? *length : 0;
2225 }
2226 
2227 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)2228 __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)
2229 {
2230 	u_int8_t * __indexable value = NULL;
2231 	uint64_t end_offset = 0;
2232 
2233 	if (buffer == NULL) {
2234 		return NULL;
2235 	}
2236 
2237 	u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2238 	if (length == 0) {
2239 		return NULL;
2240 	}
2241 
2242 	if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2243 		return NULL;
2244 	}
2245 
2246 	if (value_size) {
2247 		*value_size = length;
2248 	}
2249 
2250 	value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2251 	return value;
2252 }
2253 
2254 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)2255 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)
2256 {
2257 	if (err != NULL) {
2258 		*err = ENOENT;
2259 	}
2260 	if (offset < 0) {
2261 		if (err != NULL) {
2262 			*err = EINVAL;
2263 		}
2264 		return -1;
2265 	}
2266 	int cursor = offset;
2267 	int next_cursor;
2268 	u_int32_t curr_length;
2269 	u_int8_t curr_type;
2270 
2271 	while (TRUE) {
2272 		if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2273 			return -1;
2274 		}
2275 		if (!next) {
2276 			curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2277 		} else {
2278 			next = 0;
2279 			curr_type = NECP_TLV_NIL;
2280 		}
2281 		curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2282 		if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2283 			return -1;
2284 		}
2285 
2286 		next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2287 		if (curr_type == type) {
2288 			// check if entire TLV fits inside buffer
2289 			if (((u_int32_t)next_cursor) <= buffer_length) {
2290 				if (err != NULL) {
2291 					*err = 0;
2292 				}
2293 				return cursor;
2294 			} else {
2295 				return -1;
2296 			}
2297 		}
2298 		cursor = next_cursor;
2299 	}
2300 }
2301 
2302 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)2303 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)
2304 {
2305 	int cursor = -1;
2306 	if (buffer != NULL) {
2307 		cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2308 	}
2309 	return cursor;
2310 }
2311 
2312 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)2313 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2314     int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2315 {
2316 	if (buffer == NULL) {
2317 		NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2318 		return EINVAL;
2319 	}
2320 
2321 	// Handle buffer parsing
2322 
2323 	// Validate that buffer has enough room for any TLV
2324 	if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2325 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2326 		    buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2327 		return EINVAL;
2328 	}
2329 
2330 	// Validate that buffer has enough room for this TLV
2331 	u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2332 	if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2333 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2334 		    tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2335 		return EINVAL;
2336 	}
2337 
2338 	if (out_buffer != NULL && out_buffer_length > 0) {
2339 		// Validate that out buffer is large enough for  value
2340 		if (out_buffer_length < tlv_length) {
2341 			NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2342 			    out_buffer_length, tlv_length);
2343 			return EINVAL;
2344 		}
2345 
2346 		// Get value pointer
2347 		u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2348 		if (tlv_value == NULL) {
2349 			NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2350 			return ENOENT;
2351 		}
2352 
2353 		// Copy value
2354 		memcpy(out_buffer, tlv_value, tlv_length);
2355 	}
2356 
2357 	// Copy out length
2358 	if (value_size != NULL) {
2359 		*value_size = tlv_length;
2360 	}
2361 
2362 	return 0;
2363 }
2364 
2365 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)2366 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2367     int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2368 {
2369 	int error = 0;
2370 
2371 	int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2372 	if (tlv_offset < 0) {
2373 		return error;
2374 	}
2375 
2376 	return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2377 }
2378 
2379 // Session Management
2380 
2381 static struct necp_session *
necp_create_session(void)2382 necp_create_session(void)
2383 {
2384 	struct necp_session *new_session = NULL;
2385 
2386 	new_session = kalloc_type(struct necp_session,
2387 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2388 
2389 	new_session->necp_fd_type = necp_fd_type_session;
2390 	new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2391 	new_session->dirty = FALSE;
2392 	LIST_INIT(&new_session->policies);
2393 	LIST_INIT(&new_session->domain_filters);
2394 	LIST_INIT(&new_session->domain_tries);
2395 	lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2396 
2397 	// Take the lock
2398 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2399 
2400 	// Find the next available control unit
2401 	u_int32_t control_unit = 1;
2402 	struct necp_session *next_session = NULL;
2403 	TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2404 		if (next_session->control_unit > control_unit) {
2405 			// Found a gap, grab this control unit
2406 			break;
2407 		}
2408 
2409 		// Try the next control unit, loop around
2410 		control_unit = next_session->control_unit + 1;
2411 	}
2412 
2413 	new_session->control_unit = control_unit;
2414 	new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2415 
2416 	if (next_session != NULL) {
2417 		TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2418 	} else {
2419 		TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2420 	}
2421 
2422 	necp_session_count++;
2423 	lck_rw_done(&necp_kernel_policy_lock);
2424 
2425 	if (necp_debug) {
2426 		NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2427 	}
2428 
2429 	return new_session;
2430 }
2431 
2432 static void
necp_delete_session(struct necp_session * session)2433 necp_delete_session(struct necp_session *session)
2434 {
2435 	if (session != NULL) {
2436 		struct necp_domain_filter * __single filter = NULL;
2437 		struct necp_domain_filter *temp_filter = NULL;
2438 		LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2439 			if (os_ref_release_locked(&filter->refcount) == 0) {
2440 				lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2441 				LIST_REMOVE(filter, chain);
2442 				lck_rw_done(&necp_kernel_policy_lock);
2443 				LIST_REMOVE(filter, owner_chain);
2444 				net_bloom_filter_destroy(filter->filter);
2445 				kfree_type(struct necp_domain_filter, filter);
2446 			}
2447 		}
2448 		if (necp_debug) {
2449 			NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2450 		}
2451 
2452 		lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2453 		TAILQ_REMOVE(&necp_session_list, session, chain);
2454 		necp_session_count--;
2455 		lck_rw_done(&necp_kernel_policy_lock);
2456 
2457 		lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2458 		kfree_type(struct necp_session, session);
2459 	}
2460 }
2461 
2462 // Session Policy Management
2463 
2464 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2465 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2466 {
2467 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2468 }
2469 
2470 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2471 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2472 {
2473 	return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2474 }
2475 
2476 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2477 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2478 {
2479 	return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2480 }
2481 
2482 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2483 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2484 {
2485 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2486 	if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2487 		return TRUE;
2488 	}
2489 	return FALSE;
2490 }
2491 
2492 static inline bool
_necp_address_is_valid(struct sockaddr * address)2493 _necp_address_is_valid(struct sockaddr *address)
2494 {
2495 	if (address->sa_family == AF_INET) {
2496 		return address->sa_len == sizeof(struct sockaddr_in);
2497 	} else if (address->sa_family == AF_INET6) {
2498 		return address->sa_len == sizeof(struct sockaddr_in6);
2499 	} else {
2500 		return FALSE;
2501 	}
2502 }
2503 
2504 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2505 
2506 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2507 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2508 {
2509 	bool validated = FALSE;
2510 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2511 	u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2512 	*is_pass_skip = FALSE;
2513 	switch (type) {
2514 	case NECP_POLICY_RESULT_PASS: {
2515 		*is_pass_skip = TRUE;
2516 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2517 			validated = TRUE;
2518 		}
2519 		break;
2520 	}
2521 	case NECP_POLICY_RESULT_DROP: {
2522 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2523 			validated = TRUE;
2524 		}
2525 		break;
2526 	}
2527 	case NECP_POLICY_RESULT_ROUTE_RULES:
2528 	case NECP_POLICY_RESULT_SCOPED_DIRECT:
2529 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2530 		validated = TRUE;
2531 		break;
2532 	}
2533 	case NECP_POLICY_RESULT_SKIP:
2534 		*is_pass_skip = TRUE;
2535 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
2536 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
2537 		if (parameter_length >= sizeof(u_int32_t)) {
2538 			validated = TRUE;
2539 		}
2540 		break;
2541 	}
2542 	case NECP_POLICY_RESULT_IP_TUNNEL: {
2543 		if (parameter_length > sizeof(u_int32_t)) {
2544 			validated = TRUE;
2545 		}
2546 		break;
2547 	}
2548 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2549 		if (parameter_length > 0) {
2550 			validated = TRUE;
2551 		}
2552 		break;
2553 	}
2554 	case NECP_POLICY_RESULT_USE_NETAGENT:
2555 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2556 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2557 		if (parameter_length >= sizeof(uuid_t)) {
2558 			validated = TRUE;
2559 		}
2560 		break;
2561 	}
2562 	case NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
2563 		if (parameter_length >= sizeof(struct necp_policy_condition_agent_type)) {
2564 			validated = TRUE;
2565 		}
2566 		break;
2567 	}
2568 	default: {
2569 		validated = FALSE;
2570 		break;
2571 	}
2572 	}
2573 
2574 	if (necp_debug) {
2575 		NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2576 	}
2577 
2578 	return validated;
2579 }
2580 
2581 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2582 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2583 {
2584 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2585 }
2586 
2587 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2588 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2589 {
2590 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2591 }
2592 
2593 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2594 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2595 {
2596 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2597 }
2598 
2599 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2600 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2601 {
2602 	return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2603 }
2604 
2605 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2606 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2607 {
2608 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2609 }
2610 
2611 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2612 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2613 {
2614 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2615 }
2616 
2617 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2618 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2619 {
2620 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2621 }
2622 
2623 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2624 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2625 {
2626 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2627 	return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2628 }
2629 
2630 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2631 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2632 {
2633 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2634 	u_int32_t condition_length = 0;
2635 	pid_t *condition_value = NULL;
2636 
2637 	if (type == NECP_POLICY_CONDITION_PID) {
2638 		condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2639 		if (condition_length >= sizeof(pid_t)) {
2640 			condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2641 			return *condition_value == 0;
2642 		}
2643 	}
2644 	return false;
2645 }
2646 
2647 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2648 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2649 {
2650 	bool validated = FALSE;
2651 	bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2652 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2653 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2654 	    policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2655 	    policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2656 	    policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2657 	    policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2658 	    policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2659 	    policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT ||
2660 	    policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE) ? TRUE : FALSE;
2661 	u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2662 	u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2663 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2664 	u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2665 	switch (type) {
2666 	case NECP_POLICY_CONDITION_APPLICATION:
2667 	case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2668 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2669 		    condition_length >= sizeof(uuid_t) &&
2670 		    condition_value != NULL &&
2671 		    !uuid_is_null(condition_value)) {
2672 			validated = TRUE;
2673 		}
2674 		break;
2675 	}
2676 	case NECP_POLICY_CONDITION_DOMAIN:
2677 	case NECP_POLICY_CONDITION_ACCOUNT:
2678 	case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2679 	case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2680 	case NECP_POLICY_CONDITION_URL: {
2681 		if (condition_length > 0) {
2682 			validated = TRUE;
2683 		}
2684 		break;
2685 	}
2686 	case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2687 		if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2688 			validated = TRUE;
2689 		}
2690 		break;
2691 	}
2692 	case NECP_POLICY_CONDITION_DEFAULT:
2693 	case NECP_POLICY_CONDITION_ALL_INTERFACES:
2694 	case NECP_POLICY_CONDITION_ENTITLEMENT:
2695 	case NECP_POLICY_CONDITION_HAS_CLIENT:
2696 	case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2697 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2698 			validated = TRUE;
2699 		}
2700 		break;
2701 	}
2702 	case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2703 		if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2704 			validated = TRUE;
2705 		}
2706 		break;
2707 	}
2708 	case NECP_POLICY_CONDITION_SDK_VERSION: {
2709 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2710 		    condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2711 			validated = TRUE;
2712 		}
2713 		break;
2714 	}
2715 	case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2716 		if (condition_length >= sizeof(u_int16_t)) {
2717 			validated = TRUE;
2718 		}
2719 		break;
2720 	}
2721 	case NECP_POLICY_CONDITION_PID: {
2722 		if (condition_length >= sizeof(pid_t) &&
2723 		    condition_value != NULL) {
2724 			validated = TRUE;
2725 		}
2726 		break;
2727 	}
2728 	case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2729 		if (condition_length >= sizeof(u_int32_t)) {
2730 			validated = TRUE;
2731 		}
2732 		break;
2733 	}
2734 	case NECP_POLICY_CONDITION_UID:
2735 	case NECP_POLICY_CONDITION_REAL_UID: {
2736 		if (condition_length >= sizeof(uid_t)) {
2737 			validated = TRUE;
2738 		}
2739 		break;
2740 	}
2741 	case NECP_POLICY_CONDITION_LOCAL_ADDR:
2742 	case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2743 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2744 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2745 			validated = TRUE;
2746 		}
2747 		break;
2748 	}
2749 	case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2750 	case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2751 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2752 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2753 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2754 			validated = TRUE;
2755 		}
2756 		break;
2757 	}
2758 	case NECP_POLICY_CONDITION_AGENT_TYPE: {
2759 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2760 		    condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2761 			validated = TRUE;
2762 		}
2763 		break;
2764 	}
2765 	case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2766 		if (condition_length >= sizeof(u_int16_t)) {
2767 			validated = TRUE;
2768 		}
2769 		break;
2770 	}
2771 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2772 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2773 		if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2774 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2775 			validated = TRUE;
2776 		}
2777 		break;
2778 	}
2779 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2780 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2781 		if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2782 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2783 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2784 			validated = TRUE;
2785 		}
2786 		break;
2787 	}
2788 	case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2789 		if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2790 			validated = TRUE;
2791 		}
2792 		break;
2793 	}
2794 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2795 		validated = TRUE;
2796 		break;
2797 	}
2798 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2799 		validated = TRUE;
2800 		break;
2801 	}
2802 	case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2803 		if (condition_length >= sizeof(u_int16_t)) {
2804 			u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2805 			if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2806 				validated = TRUE;
2807 			}
2808 		}
2809 		break;
2810 	}
2811 	case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2812 		validated = TRUE;
2813 		break;
2814 	}
2815 	case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2816 		validated = TRUE;
2817 		break;
2818 	}
2819 	case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2820 		validated = TRUE;
2821 		break;
2822 	}
2823 	case NECP_POLICY_CONDITION_SCHEME_PORT: {
2824 		if (condition_length >= sizeof(u_int16_t)) {
2825 			validated = TRUE;
2826 		}
2827 		break;
2828 	}
2829 	case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2830 		if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2831 			validated = TRUE;
2832 		}
2833 		break;
2834 	}
2835 	default: {
2836 		validated = FALSE;
2837 		break;
2838 	}
2839 	}
2840 
2841 	if (necp_debug) {
2842 		NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2843 	}
2844 
2845 	return validated;
2846 }
2847 
2848 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2849 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2850 {
2851 	return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2852 	       necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2853 }
2854 
2855 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2856 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2857 {
2858 	bool validated = FALSE;
2859 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2860 	switch (type) {
2861 	case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2862 		validated = TRUE;
2863 		break;
2864 	}
2865 	case NECP_ROUTE_RULE_DENY_INTERFACE: {
2866 		validated = TRUE;
2867 		break;
2868 	}
2869 	case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2870 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2871 		validated = (rule_length >= sizeof(u_int32_t));
2872 		break;
2873 	}
2874 	case NECP_ROUTE_RULE_QOS_MARKING: {
2875 		validated = TRUE;
2876 		break;
2877 	}
2878 	case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2879 		validated = TRUE;
2880 		break;
2881 	}
2882 	case NECP_ROUTE_RULE_USE_NETAGENT:
2883 	case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2884 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2885 		validated = (rule_length >= sizeof(uuid_t));
2886 		break;
2887 	}
2888 	case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2889 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2890 		validated = (rule_length >= sizeof(uint32_t));
2891 		break;
2892 	}
2893 	default: {
2894 		validated = FALSE;
2895 		break;
2896 	}
2897 	}
2898 
2899 	if (necp_debug) {
2900 		NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2901 	}
2902 
2903 	return validated;
2904 }
2905 
2906 static int
necp_get_posix_error_for_necp_error(int response_error)2907 necp_get_posix_error_for_necp_error(int response_error)
2908 {
2909 	switch (response_error) {
2910 	case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2911 	case NECP_ERROR_INVALID_TLV:
2912 	case NECP_ERROR_POLICY_RESULT_INVALID:
2913 	case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2914 	case NECP_ERROR_ROUTE_RULES_INVALID: {
2915 		return EINVAL;
2916 	}
2917 	case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2918 		return ENOENT;
2919 	}
2920 	case NECP_ERROR_INVALID_PROCESS: {
2921 		return EPERM;
2922 	}
2923 	case NECP_ERROR_INTERNAL:
2924 	default: {
2925 		return ENOMEM;
2926 	}
2927 	}
2928 }
2929 
2930 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)2931 necp_handle_policy_add(struct necp_session *session,
2932     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2933 {
2934 	bool has_default_condition = FALSE;
2935 	bool has_non_default_condition = FALSE;
2936 	bool has_application_condition = FALSE;
2937 	bool has_real_application_condition = FALSE;
2938 	bool requires_application_condition = FALSE;
2939 	bool has_kernel_pid = FALSE;
2940 	bool is_pass_skip = FALSE;
2941 	u_int32_t conditions_array_size = 0;
2942 	u_int8_t *conditions_array = NULL;
2943 	int conditions_array_cursor;
2944 
2945 	bool has_default_route_rule = FALSE;
2946 	u_int32_t route_rules_array_size = 0;
2947 	u_int8_t *route_rules_array = NULL;
2948 	int route_rules_array_cursor;
2949 
2950 	int cursor;
2951 	int error = 0;
2952 	u_int32_t response_error = NECP_ERROR_INTERNAL;
2953 
2954 	necp_policy_order order = 0;
2955 	struct necp_session_policy *policy = NULL;
2956 	u_int32_t policy_result_size = 0;
2957 	u_int8_t *policy_result = NULL;
2958 
2959 	// Read policy order
2960 	error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
2961 	if (error) {
2962 		NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2963 		response_error = NECP_ERROR_INVALID_TLV;
2964 		goto fail;
2965 	}
2966 
2967 	// Read policy result
2968 	cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
2969 	if (error || cursor < 0) {
2970 		NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2971 		response_error = NECP_ERROR_INVALID_TLV;
2972 		goto fail;
2973 	}
2974 
2975 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
2976 	if (error || policy_result_size == 0) {
2977 		NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2978 		response_error = NECP_ERROR_INVALID_TLV;
2979 		goto fail;
2980 	}
2981 	if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2982 		NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2983 		response_error = NECP_ERROR_INVALID_TLV;
2984 		goto fail;
2985 	}
2986 	policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2987 	if (policy_result == NULL) {
2988 		NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2989 		response_error = NECP_ERROR_INTERNAL;
2990 		goto fail;
2991 	}
2992 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
2993 	if (error) {
2994 		NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2995 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2996 		goto fail;
2997 	}
2998 	if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
2999 		NECPLOG0(LOG_ERR, "Failed to validate policy result");
3000 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3001 		goto fail;
3002 	}
3003 
3004 	if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3005 		// Read route rules conditions
3006 
3007 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3008 		    cursor >= 0;
3009 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3010 			u_int32_t route_rule_size = 0;
3011 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3012 			if (os_add_overflow(route_rules_array_size,
3013 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3014 			    &route_rules_array_size)) {
3015 				NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3016 				response_error = NECP_ERROR_INVALID_TLV;
3017 				goto fail;
3018 			}
3019 		}
3020 
3021 		if (route_rules_array_size == 0) {
3022 			NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3023 			response_error = NECP_ERROR_INVALID_TLV;
3024 			goto fail;
3025 		}
3026 		if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3027 			NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3028 			response_error = NECP_ERROR_INVALID_TLV;
3029 			goto fail;
3030 		}
3031 		route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3032 		if (route_rules_array == NULL) {
3033 			NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3034 			response_error = NECP_ERROR_INTERNAL;
3035 			goto fail;
3036 		}
3037 
3038 		route_rules_array_cursor = 0;
3039 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3040 		    cursor >= 0;
3041 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3042 			u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3043 			u_int32_t route_rule_size = 0;
3044 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3045 			if (route_rule_size > 0 &&
3046 			    (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3047 				// Add type
3048 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3049 				route_rules_array_cursor += sizeof(route_rule_type);
3050 
3051 				// Add length
3052 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3053 				route_rules_array_cursor += sizeof(route_rule_size);
3054 
3055 				// Add value
3056 				necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3057 
3058 				if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3059 					NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3060 					response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3061 					goto fail;
3062 				}
3063 
3064 				if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3065 					if (has_default_route_rule) {
3066 						NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3067 						response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3068 						goto fail;
3069 					}
3070 					has_default_route_rule = TRUE;
3071 				}
3072 
3073 				route_rules_array_cursor += route_rule_size;
3074 			}
3075 		}
3076 	}
3077 
3078 	// Read policy conditions
3079 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3080 	    cursor >= 0;
3081 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3082 		u_int32_t condition_size = 0;
3083 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3084 
3085 		if (condition_size > 0) {
3086 			if (os_add_overflow(conditions_array_size,
3087 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3088 			    &conditions_array_size)) {
3089 				NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3090 				response_error = NECP_ERROR_INVALID_TLV;
3091 				goto fail;
3092 			}
3093 		}
3094 	}
3095 
3096 	if (conditions_array_size == 0) {
3097 		NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3098 		response_error = NECP_ERROR_INVALID_TLV;
3099 		goto fail;
3100 	}
3101 	if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3102 		NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3103 		response_error = NECP_ERROR_INVALID_TLV;
3104 		goto fail;
3105 	}
3106 	conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3107 	if (conditions_array == NULL) {
3108 		NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3109 		response_error = NECP_ERROR_INTERNAL;
3110 		goto fail;
3111 	}
3112 
3113 	conditions_array_cursor = 0;
3114 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3115 	    cursor >= 0;
3116 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3117 		u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3118 		u_int32_t condition_size = 0;
3119 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3120 		if (condition_size > 0 &&
3121 		    (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3122 			// Add type
3123 			memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3124 			conditions_array_cursor += sizeof(condition_type);
3125 
3126 			// Add length
3127 			memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3128 			conditions_array_cursor += sizeof(condition_size);
3129 
3130 			// Add value
3131 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3132 			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))) {
3133 				NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3134 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3135 				goto fail;
3136 			}
3137 
3138 			if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3139 				has_default_condition = TRUE;
3140 			} else {
3141 				has_non_default_condition = TRUE;
3142 			}
3143 			if (has_default_condition && has_non_default_condition) {
3144 				NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3145 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3146 				goto fail;
3147 			}
3148 
3149 			if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3150 				has_application_condition = TRUE;
3151 			}
3152 
3153 			if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3154 				has_real_application_condition = TRUE;
3155 			}
3156 
3157 			if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3158 				requires_application_condition = TRUE;
3159 			}
3160 
3161 			if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3162 				has_kernel_pid = TRUE;
3163 			}
3164 
3165 			conditions_array_cursor += condition_size;
3166 		}
3167 	}
3168 
3169 	if (requires_application_condition && !has_application_condition) {
3170 		NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3171 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3172 		goto fail;
3173 	}
3174 
3175 	if (has_kernel_pid && !is_pass_skip) {
3176 		NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3177 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3178 		goto fail;
3179 	}
3180 
3181 	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) {
3182 		response_error = NECP_ERROR_INTERNAL;
3183 		goto fail;
3184 	}
3185 
3186 	return policy->local_id;
3187 
3188 fail:
3189 	if (policy_result != NULL) {
3190 		kfree_data_sized_by(policy_result, policy_result_size);
3191 	}
3192 	if (conditions_array != NULL) {
3193 		kfree_data_sized_by(conditions_array, conditions_array_size);
3194 	}
3195 	if (route_rules_array != NULL) {
3196 		kfree_data_sized_by(route_rules_array, route_rules_array_size);
3197 	}
3198 
3199 	if (return_error != NULL) {
3200 		*return_error = necp_get_posix_error_for_necp_error(response_error);
3201 	}
3202 	return 0;
3203 }
3204 
3205 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3206 necp_policy_get_new_id(struct necp_session *session)
3207 {
3208 	session->last_policy_id++;
3209 	if (session->last_policy_id < 1) {
3210 		session->last_policy_id = 1;
3211 	}
3212 
3213 	necp_policy_id newid = session->last_policy_id;
3214 
3215 	if (newid == 0) {
3216 		NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3217 		return 0;
3218 	}
3219 
3220 	return newid;
3221 }
3222 
3223 /*
3224  *	For the policy dump response this is the structure:
3225  *
3226  *	<NECP_PACKET_HEADER>
3227  *	{
3228  *		type	:	NECP_TLV_POLICY_DUMP
3229  *		length	:	...
3230  *		value	:
3231  *		{
3232  *			{
3233  *				type	:	NECP_TLV_POLICY_ID
3234  *				len		:	...
3235  *				value	:	...
3236  *			}
3237  *			{
3238  *				type	:	NECP_TLV_POLICY_ORDER
3239  *				len		:	...
3240  *				value	:	...
3241  *			}
3242  *			{
3243  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3244  *				len		:	...
3245  *				value	:	...
3246  *			}
3247  *			{
3248  *				type	:	NECP_TLV_POLICY_OWNER
3249  *				len		:	...
3250  *				value	:	...
3251  *			}
3252  *			{
3253  *				type	:	NECP_TLV_POLICY_CONDITION
3254  *				len		:	...
3255  *				value	:
3256  *				{
3257  *					{
3258  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3259  *						len		:	...
3260  *						value	:	...
3261  *					}
3262  *					{
3263  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3264  *						len		:	...
3265  *						value	:	...
3266  *					}
3267  *					...
3268  *				}
3269  *			}
3270  *		}
3271  *	}
3272  *	{
3273  *		type	:	NECP_TLV_POLICY_DUMP
3274  *		length	:	...
3275  *		value	:
3276  *		{
3277  *			{
3278  *				type	:	NECP_TLV_POLICY_ID
3279  *				len		:	...
3280  *				value	:	...
3281  *			}
3282  *			{
3283  *				type	:	NECP_TLV_POLICY_ORDER
3284  *				len		:	...
3285  *				value	:	...
3286  *			}
3287  *			{
3288  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3289  *				len		:	...
3290  *				value	:	...
3291  *			}
3292  *			{
3293  *				type	:	NECP_TLV_POLICY_OWNER
3294  *				len		:	...
3295  *				value	:	...
3296  *			}
3297  *			{
3298  *				type	:	NECP_TLV_POLICY_CONDITION
3299  *				len		:	...
3300  *				value	:
3301  *				{
3302  *					{
3303  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3304  *						len		:	...
3305  *						value	:	...
3306  *					}
3307  *					{
3308  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3309  *						len		:	...
3310  *						value	:	...
3311  *					}
3312  *					...
3313  *				}
3314  *			}
3315  *		}
3316  *	}
3317  *	...
3318  */
3319 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3320 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3321 {
3322 	struct necp_kernel_socket_policy * __single policy = NULL;
3323 	int policy_i;
3324 	int policy_count = 0;
3325 	u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3326 	u_int32_t * __indexable tlv_buffer_lengths = NULL;
3327 	u_int32_t total_tlv_len = 0;
3328 	u_int8_t * __indexable result_buf = NULL;
3329 	u_int8_t *result_buf_cursor = result_buf;
3330 	char result_string[MAX_RESULT_STRING_LEN];
3331 	char proc_name_string[MAXCOMLEN + 1];
3332 
3333 	int error_code = 0;
3334 	bool error_occured = false;
3335 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3336 
3337 #define REPORT_ERROR(error) error_occured = true;               \
3338 	                                                response_error = error;         \
3339 	                                                goto done
3340 
3341 #define UNLOCK_AND_REPORT_ERROR(lock, error)    lck_rw_done(lock);      \
3342 	                                                                                        REPORT_ERROR(error)
3343 
3344 	errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3345 	if (cred_result != 0) {
3346 		NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3347 		REPORT_ERROR(NECP_ERROR_INTERNAL);
3348 	}
3349 
3350 	// LOCK
3351 	lck_rw_lock_shared(&necp_kernel_policy_lock);
3352 
3353 	if (necp_debug) {
3354 		NECPLOG0(LOG_DEBUG, "Gathering policies");
3355 	}
3356 
3357 	policy_count = necp_kernel_application_policies_count;
3358 
3359 	tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3360 	if (tlv_buffer_pointers == NULL) {
3361 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3362 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3363 	}
3364 
3365 	tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3366 	if (tlv_buffer_lengths == NULL) {
3367 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3368 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3369 	}
3370 
3371 	for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3372 		policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3373 
3374 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
3375 		memset(proc_name_string, 0, MAXCOMLEN + 1);
3376 
3377 		necp_get_result_description(result_string, policy->result, policy->result_parameter);
3378 		proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3379 
3380 		u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3381 		u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3382 
3383 		if (necp_debug) {
3384 			NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3385 		}
3386 
3387 		u_int32_t total_allocated_bytes =       sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) +                                     // NECP_TLV_POLICY_ID
3388 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) +                                                                                              // NECP_TLV_POLICY_ORDER
3389 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) +                                                                              // NECP_TLV_POLICY_SESSION_ORDER
3390 		    sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len +                                                                                                          // NECP_TLV_POLICY_RESULT_STRING
3391 		    sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len +                                                                                                              // NECP_TLV_POLICY_OWNER
3392 		    sizeof(u_int8_t) + sizeof(u_int32_t);                                                                                                                                               // NECP_TLV_POLICY_CONDITION
3393 
3394 		// We now traverse the condition_mask to see how much space we need to allocate
3395 		u_int64_t condition_mask = policy->condition_mask;
3396 		u_int64_t condition_negated_mask = policy->condition_negated_mask;
3397 		u_int8_t num_conditions = 0;
3398 		struct necp_string_id_mapping *account_id_entry = NULL;
3399 		char if_name[IFXNAMSIZ];
3400 		u_int32_t condition_tlv_length = 0;
3401 		memset(if_name, 0, sizeof(if_name));
3402 
3403 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3404 			num_conditions++;
3405 		} else {
3406 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3407 				num_conditions++;
3408 			}
3409 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3410 				num_conditions++;
3411 			}
3412 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3413 				snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3414 				condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3415 				num_conditions++;
3416 			}
3417 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3418 				condition_tlv_length += sizeof(policy->cond_protocol);
3419 				num_conditions++;
3420 			}
3421 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3422 				condition_tlv_length += sizeof(uuid_t);
3423 				num_conditions++;
3424 			}
3425 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3426 				condition_tlv_length += sizeof(uuid_t);
3427 				num_conditions++;
3428 			}
3429 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3430 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3431 				u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3432 				condition_tlv_length += domain_len;
3433 				num_conditions++;
3434 			}
3435 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3436 				condition_tlv_length += sizeof(u_int32_t);
3437 				num_conditions++;
3438 			}
3439 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3440 				u_int32_t url_len = strlen(policy->cond_url) + 1;
3441 				condition_tlv_length += url_len;
3442 				num_conditions++;
3443 			}
3444 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3445 				account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3446 				u_int32_t account_id_len = 0;
3447 				if (account_id_entry) {
3448 					account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3449 				}
3450 				condition_tlv_length += account_id_len;
3451 				num_conditions++;
3452 			}
3453 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3454 				condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3455 				num_conditions++;
3456 			}
3457 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3458 				condition_tlv_length += sizeof(uid_t);
3459 				num_conditions++;
3460 			}
3461 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3462 				condition_tlv_length += sizeof(uid_t);
3463 				num_conditions++;
3464 			}
3465 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3466 				condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3467 				num_conditions++;
3468 			}
3469 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3470 				num_conditions++;
3471 			}
3472 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3473 				u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3474 				condition_tlv_length += entitlement_len;
3475 				num_conditions++;
3476 			}
3477 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3478 				num_conditions++;
3479 			}
3480 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3481 				num_conditions++;
3482 			}
3483 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3484 				condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3485 				num_conditions++;
3486 			}
3487 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3488 				condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3489 				num_conditions++;
3490 			}
3491 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3492 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3493 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3494 				} else {
3495 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3496 				}
3497 				num_conditions++;
3498 			}
3499 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3500 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3501 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3502 				} else {
3503 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3504 				}
3505 				num_conditions++;
3506 			}
3507 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3508 				condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3509 				num_conditions++;
3510 			}
3511 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3512 				condition_tlv_length += sizeof(u_int32_t);
3513 				num_conditions++;
3514 			}
3515 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3516 				num_conditions++;
3517 			}
3518 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3519 				num_conditions++;
3520 			}
3521 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3522 				u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3523 				condition_tlv_length += identifier_len;
3524 				num_conditions++;
3525 			}
3526 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3527 				condition_tlv_length += sizeof(u_int16_t);
3528 				num_conditions++;
3529 			}
3530 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3531 				num_conditions++;
3532 			}
3533 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3534 				num_conditions++;
3535 			}
3536 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3537 				condition_tlv_length += sizeof(u_int16_t);
3538 				num_conditions++;
3539 			}
3540 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3541 				condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3542 				num_conditions++;
3543 			}
3544 		}
3545 
3546 		// These are for the condition TLVs (id, length, flags).  The space for "value" is already accounted for above.
3547 		condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3548 		total_allocated_bytes += condition_tlv_length;
3549 
3550 		u_int8_t * __indexable tlv_buffer;
3551 		tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3552 		if (tlv_buffer == NULL) {
3553 			NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3554 			continue;
3555 		}
3556 
3557 		u_int8_t *cursor = tlv_buffer;
3558 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3559 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3560 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3561 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3562 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3563 
3564 #define N_QUICK 256
3565 		u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3566 
3567 		u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3568 		if (condition_tlv_length <= N_QUICK) {
3569 			cond_buf = q_cond_buf;
3570 		} else {
3571 			cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3572 			if (cond_buf == NULL) {
3573 				NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3574 				kfree_data(tlv_buffer, total_allocated_bytes);
3575 				continue;
3576 			}
3577 		}
3578 
3579 		memset(cond_buf, 0, condition_tlv_length);
3580 		u_int8_t *cond_buf_cursor = cond_buf;
3581 		u_int8_t cond_flags = 0;
3582 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3583 			cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3584 		} else {
3585 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3586 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3587 				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);
3588 			}
3589 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3590 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3591 				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);
3592 			}
3593 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3594 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3595 				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);
3596 			}
3597 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3598 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3599 				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,
3600 				    if_name, cond_buf, condition_tlv_length);
3601 			}
3602 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3603 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3604 				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,
3605 				    cond_buf, condition_tlv_length);
3606 			}
3607 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3608 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3609 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3610 				if (entry != NULL) {
3611 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3612 					    cond_buf, condition_tlv_length);
3613 				}
3614 			}
3615 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3616 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3617 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3618 				if (entry != NULL) {
3619 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3620 					    cond_buf, condition_tlv_length);
3621 				}
3622 			}
3623 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3624 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3625 				cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3626 				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);
3627 			}
3628 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3629 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3630 				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,
3631 				    cond_buf, condition_tlv_length);
3632 			}
3633 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3634 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3635 				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);
3636 			}
3637 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3638 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3639 				if (account_id_entry != NULL) {
3640 					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);
3641 				}
3642 			}
3643 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3644 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3645 				uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3646 				memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3647 				memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3648 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3649 				    cond_buf, condition_tlv_length);
3650 			}
3651 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3652 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3653 				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,
3654 				    cond_buf, condition_tlv_length);
3655 			}
3656 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3657 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3658 				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,
3659 				    cond_buf, condition_tlv_length);
3660 			}
3661 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3662 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3663 				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,
3664 				    cond_buf, condition_tlv_length);
3665 			}
3666 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3667 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3668 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3669 				    cond_buf, condition_tlv_length);
3670 			}
3671 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3672 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3673 				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);
3674 			}
3675 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3676 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3677 				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);
3678 			}
3679 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3680 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3681 				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);
3682 			}
3683 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3684 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3685 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3686 				    sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3687 				    cond_buf, condition_tlv_length);
3688 			}
3689 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3690 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3691 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3692 					struct necp_policy_condition_addr_range range;
3693 					memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3694 					memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3695 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3696 					    cond_buf, condition_tlv_length);
3697 				} else {
3698 					struct necp_policy_condition_addr addr;
3699 					addr.prefix = policy->cond_local_prefix;
3700 					memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3701 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3702 					    cond_buf, condition_tlv_length);
3703 				}
3704 			}
3705 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3706 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3707 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3708 					struct necp_policy_condition_addr_range range;
3709 					memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3710 					memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3711 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3712 					    cond_buf, condition_tlv_length);
3713 				} else {
3714 					struct necp_policy_condition_addr addr;
3715 					addr.prefix = policy->cond_remote_prefix;
3716 					memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3717 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3718 					    cond_buf, condition_tlv_length);
3719 				}
3720 			}
3721 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3722 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3723 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3724 				    sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3725 				    cond_buf, condition_tlv_length);
3726 			}
3727 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3728 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3729 				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);
3730 			}
3731 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3732 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3733 				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);
3734 			}
3735 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3736 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3737 				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);
3738 			}
3739 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3740 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3741 				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);
3742 			}
3743 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3744 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3745 				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);
3746 			}
3747 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3748 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3749 				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);
3750 			}
3751 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3752 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3753 				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);
3754 			}
3755 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3756 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3757 				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);
3758 			}
3759 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3760 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3761 				uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3762 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3763 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3764 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3765 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3766 				    cond_buf, condition_tlv_length);
3767 			}
3768 		}
3769 
3770 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3771 		if (cond_buf != q_cond_buf) {
3772 			kfree_data(cond_buf, condition_tlv_length);
3773 		}
3774 
3775 		tlv_buffer_pointers[policy_i] = tlv_buffer;
3776 		tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3777 
3778 		// This is the length of the TLV for NECP_TLV_POLICY_DUMP
3779 		total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3780 	}
3781 
3782 	// UNLOCK
3783 	lck_rw_done(&necp_kernel_policy_lock);
3784 
3785 	// Copy out
3786 	if (out_buffer != 0) {
3787 		if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3788 			NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3789 			REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3790 		}
3791 
3792 		// Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3793 		result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3794 		if (result_buf == NULL) {
3795 			NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3796 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3797 		}
3798 
3799 		// Add four bytes for total length at the start
3800 		memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3801 
3802 		// Copy the TLVs
3803 		result_buf_cursor = result_buf + sizeof(u_int32_t);
3804 		for (int i = 0; i < policy_count; i++) {
3805 			if (tlv_buffer_pointers[i] != NULL) {
3806 				result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3807 				    result_buf, total_tlv_len + sizeof(u_int32_t));
3808 			}
3809 		}
3810 
3811 		int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3812 		if (copy_error) {
3813 			NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3814 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3815 		}
3816 	}
3817 
3818 done:
3819 
3820 	if (error_occured) {
3821 		error_code = necp_get_posix_error_for_necp_error(response_error);
3822 	}
3823 
3824 	if (result_buf != NULL) {
3825 		kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3826 	}
3827 
3828 	if (tlv_buffer_pointers != NULL) {
3829 		for (int i = 0; i < policy_count; i++) {
3830 			if (tlv_buffer_pointers[i] != NULL) {
3831 				kfree_data_addr(tlv_buffer_pointers[i]);
3832 				tlv_buffer_pointers[i] = NULL;
3833 			}
3834 		}
3835 		kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3836 	}
3837 
3838 	if (tlv_buffer_lengths != NULL) {
3839 		kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3840 	}
3841 #undef N_QUICK
3842 #undef RESET_COND_BUF
3843 #undef REPORT_ERROR
3844 #undef UNLOCK_AND_REPORT_ERROR
3845 
3846 	return error_code;
3847 }
3848 
3849 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)3850 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)
3851 {
3852 	struct necp_session_policy *new_policy = NULL;
3853 	struct necp_session_policy *tmp_policy = NULL;
3854 
3855 	if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3856 		goto done;
3857 	}
3858 
3859 	new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3860 	new_policy->applied = FALSE;
3861 	new_policy->pending_deletion = FALSE;
3862 	new_policy->pending_update = FALSE;
3863 	new_policy->order = order;
3864 	new_policy->conditions = conditions_array;
3865 	new_policy->conditions_size = conditions_array_size;
3866 	new_policy->route_rules = route_rules_array;
3867 	new_policy->route_rules_size = route_rules_array_size;
3868 	new_policy->result = result;
3869 	new_policy->result_size = result_size;
3870 	new_policy->local_id = necp_policy_get_new_id(session);
3871 
3872 	LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3873 
3874 	session->dirty = TRUE;
3875 
3876 	if (necp_debug) {
3877 		NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3878 	}
3879 done:
3880 	return new_policy;
3881 }
3882 
3883 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3884 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3885 {
3886 	struct necp_session_policy *policy = NULL;
3887 	if (policy_id == 0) {
3888 		return NULL;
3889 	}
3890 
3891 	LIST_FOREACH(policy, &session->policies, chain) {
3892 		if (policy->local_id == policy_id) {
3893 			return policy;
3894 		}
3895 	}
3896 
3897 	return NULL;
3898 }
3899 
3900 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3901 necp_policy_get_result_type(struct necp_session_policy *policy)
3902 {
3903 	return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3904 }
3905 
3906 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3907 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3908 {
3909 	return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3910 }
3911 
3912 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)3913 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)
3914 {
3915 	if (policy) {
3916 		u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3917 		if (parameter_buffer_length >= parameter_length) {
3918 			u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3919 			if (parameter && parameter_buffer) {
3920 				memcpy(parameter_buffer, parameter, parameter_length);
3921 				return TRUE;
3922 			}
3923 		}
3924 	}
3925 
3926 	return FALSE;
3927 }
3928 
3929 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)3930 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3931 {
3932 	if (session == NULL || policy == NULL) {
3933 		return FALSE;
3934 	}
3935 
3936 	policy->pending_deletion = TRUE;
3937 	session->dirty = TRUE;
3938 
3939 	if (necp_debug) {
3940 		NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3941 	}
3942 	return TRUE;
3943 }
3944 
3945 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)3946 necp_policy_mark_all_for_deletion(struct necp_session *session)
3947 {
3948 	struct necp_session_policy *policy = NULL;
3949 	struct necp_session_policy *temp_policy = NULL;
3950 
3951 	LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3952 		necp_policy_mark_for_deletion(session, policy);
3953 	}
3954 
3955 	return TRUE;
3956 }
3957 
3958 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)3959 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3960 {
3961 	if (session == NULL || policy == NULL) {
3962 		return FALSE;
3963 	}
3964 
3965 	LIST_REMOVE(policy, chain);
3966 
3967 	if (policy->result) {
3968 		kfree_data_sized_by(policy->result, policy->result_size);
3969 		policy->result = NULL;
3970 		policy->result_size = 0;
3971 	}
3972 
3973 	if (policy->conditions) {
3974 		kfree_data_sized_by(policy->conditions, policy->conditions_size);
3975 		policy->conditions = NULL;
3976 		policy->conditions_size = 0;
3977 	}
3978 
3979 	if (policy->route_rules) {
3980 		kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
3981 		policy->route_rules = NULL;
3982 		policy->route_rules_size = 0;
3983 	}
3984 
3985 	zfree(necp_session_policy_zone, policy);
3986 
3987 	if (necp_debug) {
3988 		NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3989 	}
3990 	return TRUE;
3991 }
3992 
3993 static bool
necp_policy_unapply(struct necp_session_policy * policy)3994 necp_policy_unapply(struct necp_session_policy *policy)
3995 {
3996 	int i = 0;
3997 	if (policy == NULL) {
3998 		return FALSE;
3999 	}
4000 
4001 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4002 
4003 	// Release local uuid mappings
4004 	if (!uuid_is_null(policy->applied_app_uuid)) {
4005 		bool removed_mapping = FALSE;
4006 		if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4007 			necp_uuid_app_id_mappings_dirty = TRUE;
4008 			necp_num_uuid_app_id_mappings--;
4009 		}
4010 		uuid_clear(policy->applied_app_uuid);
4011 	}
4012 	if (!uuid_is_null(policy->applied_real_app_uuid)) {
4013 		necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4014 		uuid_clear(policy->applied_real_app_uuid);
4015 	}
4016 	if (!uuid_is_null(policy->applied_result_uuid)) {
4017 		necp_remove_agent_uuid_id_mapping(policy->applied_result_uuid);
4018 		uuid_clear(policy->applied_result_uuid);
4019 	}
4020 
4021 	// Release string mappings
4022 	if (policy->applied_account != NULL) {
4023 		necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4024 		kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4025 		policy->applied_account = NULL;
4026 		policy->applied_account_size = 0;
4027 	}
4028 
4029 	// Release route rule
4030 	if (policy->applied_route_rules_id != 0) {
4031 		necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4032 		policy->applied_route_rules_id = 0;
4033 	}
4034 
4035 	// Release agent type mapping
4036 	if (policy->applied_agent_type_id != 0) {
4037 		necp_remove_agent_type_to_id_mapping(policy->applied_agent_type_id);
4038 		policy->applied_agent_type_id = 0;
4039 	}
4040 
4041 	// Remove socket policies
4042 	for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4043 		if (policy->kernel_socket_policies[i] != 0) {
4044 			necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4045 			policy->kernel_socket_policies[i] = 0;
4046 		}
4047 	}
4048 
4049 	// Remove IP output policies
4050 	for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4051 		if (policy->kernel_ip_output_policies[i] != 0) {
4052 			necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4053 			policy->kernel_ip_output_policies[i] = 0;
4054 		}
4055 	}
4056 
4057 	policy->applied = FALSE;
4058 
4059 	return TRUE;
4060 }
4061 
4062 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION                 0
4063 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION             1
4064 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION                                2
4065 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS                   3
4066 struct necp_policy_result_ip_tunnel {
4067 	u_int32_t secondary_result;
4068 	char interface_name[IFXNAMSIZ];
4069 } __attribute__((__packed__));
4070 
4071 struct necp_policy_result_service {
4072 	uuid_t identifier;
4073 	u_int32_t data;
4074 } __attribute__((__packed__));
4075 
4076 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy,bool * should_update_immediately)4077 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy, bool *should_update_immediately)
4078 {
4079 	bool socket_only_conditions = FALSE;
4080 	bool socket_ip_conditions = FALSE;
4081 
4082 	bool socket_layer_non_id_conditions = FALSE;
4083 	bool ip_output_layer_non_id_conditions = FALSE;
4084 	bool ip_output_layer_non_id_only = FALSE;
4085 	bool ip_output_layer_id_condition = FALSE;
4086 	bool ip_output_layer_tunnel_condition_from_id = FALSE;
4087 	bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4088 	necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4089 
4090 	u_int64_t master_condition_mask = 0;
4091 	u_int64_t master_condition_negated_mask = 0;
4092 	ifnet_t __single cond_bound_interface = NULL;
4093 	u_int32_t cond_account_id = 0;
4094 	char *cond_domain __null_terminated = NULL;
4095 	u_int32_t cond_domain_filter = 0;
4096 	char *cond_url __null_terminated = NULL;
4097 	char *cond_custom_entitlement __null_terminated = NULL;
4098 	char *cond_signing_identifier __null_terminated = NULL;
4099 	pid_t cond_pid = 0;
4100 	int32_t cond_pid_version = 0;
4101 	uid_t cond_uid = 0;
4102 	uid_t cond_real_uid = 0;
4103 	necp_app_id cond_app_id = 0;
4104 	necp_app_id cond_real_app_id = 0;
4105 	struct necp_policy_condition_tc_range cond_traffic_class;
4106 	cond_traffic_class.start_tc = 0;
4107 	cond_traffic_class.end_tc = 0;
4108 	u_int16_t cond_protocol = 0;
4109 	union necp_sockaddr_union cond_local_start;
4110 	union necp_sockaddr_union cond_local_end;
4111 	u_int8_t cond_local_prefix = 0;
4112 	union necp_sockaddr_union cond_remote_start;
4113 	union necp_sockaddr_union cond_remote_end;
4114 	u_int8_t cond_remote_prefix = 0;
4115 	u_int32_t cond_client_flags = 0;
4116 	u_int8_t cond_local_networks_flags = 0;
4117 	u_int32_t offset = 0;
4118 	u_int8_t ultimate_result = 0;
4119 	u_int32_t secondary_result = 0;
4120 	struct necp_policy_condition_agent_type cond_agent_type = {};
4121 	struct necp_policy_condition_sdk_version cond_sdk_version = {};
4122 	u_int16_t cond_packet_filter_tags = 0;
4123 	u_int16_t cond_scheme_port = 0;
4124 	u_int32_t cond_bound_interface_flags = 0;
4125 	u_int32_t cond_bound_interface_eflags = 0;
4126 	u_int32_t cond_bound_interface_xflags = 0;
4127 	necp_kernel_policy_result_parameter secondary_result_parameter;
4128 	memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4129 	u_int32_t cond_last_interface_index = 0;
4130 	necp_kernel_policy_result_parameter ultimate_result_parameter;
4131 	memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4132 
4133 	if (policy == NULL) {
4134 		return FALSE;
4135 	}
4136 
4137 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4138 
4139 	// Process conditions
4140 	while (offset < policy->conditions_size) {
4141 		u_int32_t length = 0;
4142 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4143 
4144 		u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4145 		u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4146 		bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4147 		u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4148 		u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4149 		switch (condition_type) {
4150 		case NECP_POLICY_CONDITION_DEFAULT: {
4151 			socket_ip_conditions = TRUE;
4152 			break;
4153 		}
4154 		case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4155 			master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4156 			socket_ip_conditions = TRUE;
4157 			break;
4158 		}
4159 		case NECP_POLICY_CONDITION_HAS_CLIENT: {
4160 			master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4161 			socket_only_conditions = TRUE;
4162 			break;
4163 		}
4164 		case NECP_POLICY_CONDITION_ENTITLEMENT: {
4165 			if (condition_length > 0) {
4166 				if (cond_custom_entitlement == NULL) {
4167 					cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4168 					if (cond_custom_entitlement != NULL) {
4169 						master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4170 						socket_only_conditions = TRUE;
4171 					}
4172 				}
4173 			} else {
4174 				master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4175 				socket_only_conditions = TRUE;
4176 			}
4177 			break;
4178 		}
4179 		case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4180 			master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4181 			if (condition_is_negative) {
4182 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4183 			}
4184 			socket_only_conditions = TRUE;
4185 			break;
4186 		}
4187 		case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4188 			master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4189 			socket_only_conditions = TRUE;
4190 			break;
4191 		}
4192 		case NECP_POLICY_CONDITION_SDK_VERSION: {
4193 			if (condition_length >= sizeof(cond_sdk_version)) {
4194 				master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4195 				memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4196 				socket_only_conditions = TRUE;
4197 			}
4198 			break;
4199 		}
4200 		case NECP_POLICY_CONDITION_DOMAIN: {
4201 			// Make sure there is only one such rule
4202 			if (condition_length > 0 && cond_domain == NULL) {
4203 				const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4204 
4205 				u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4206 				cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4207 				if (cond_domain != NULL) {
4208 					master_condition_mask |= mask_value;
4209 					if (condition_is_negative) {
4210 						master_condition_negated_mask |= mask_value;
4211 					}
4212 					socket_only_conditions = TRUE;
4213 				}
4214 			}
4215 			break;
4216 		}
4217 		case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4218 			// Make sure there is only one such rule
4219 			if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4220 				memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4221 				if (cond_domain_filter != 0) {
4222 					master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4223 					if (condition_is_negative) {
4224 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4225 					}
4226 					socket_only_conditions = TRUE;
4227 				}
4228 			}
4229 			break;
4230 		}
4231 		case NECP_POLICY_CONDITION_URL: {
4232 			// Make sure there is only one such rule
4233 			if (condition_length > 0 && cond_url == NULL) {
4234 				u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4235 				cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4236 				if (cond_url != NULL) {
4237 					master_condition_mask |= mask_value;
4238 					if (condition_is_negative) {
4239 						master_condition_negated_mask |= mask_value;
4240 					}
4241 					socket_only_conditions = TRUE;
4242 				}
4243 			}
4244 			break;
4245 		}
4246 		case NECP_POLICY_CONDITION_ACCOUNT: {
4247 			// Make sure there is only one such rule
4248 			if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4249 				size_t string_buffer_size = 0;
4250 				char * __sized_by(string_buffer_size) string = NULL;
4251 				string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4252 				string_buffer_size = condition_length + 1;
4253 				if (string != NULL) {
4254 					memcpy(string, condition_value, condition_length);
4255 					string[condition_length] = 0;
4256 					cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4257 					if (cond_account_id != 0) {
4258 						policy->applied_account = string;         // Save the string in parent policy
4259 						policy->applied_account_size = string_buffer_size;
4260 						master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4261 						if (condition_is_negative) {
4262 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4263 						}
4264 						socket_only_conditions = TRUE;
4265 					} else {
4266 						kfree_data_sized_by(string, string_buffer_size);
4267 					}
4268 				}
4269 			}
4270 			break;
4271 		}
4272 		case NECP_POLICY_CONDITION_APPLICATION: {
4273 			// Make sure there is only one such rule, because we save the uuid in the policy
4274 			if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4275 				bool allocated_mapping = FALSE;
4276 				uuid_t application_uuid;
4277 				memcpy(application_uuid, condition_value, sizeof(uuid_t));
4278 				cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4279 				if (cond_app_id != 0) {
4280 					if (allocated_mapping) {
4281 						necp_uuid_app_id_mappings_dirty = TRUE;
4282 						necp_num_uuid_app_id_mappings++;
4283 					}
4284 					uuid_copy(policy->applied_app_uuid, application_uuid);
4285 					master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4286 					if (condition_is_negative) {
4287 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4288 					}
4289 					socket_only_conditions = TRUE;
4290 				}
4291 			}
4292 			break;
4293 		}
4294 		case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4295 			// Make sure there is only one such rule, because we save the uuid in the policy
4296 			if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4297 				uuid_t real_application_uuid;
4298 				memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4299 				cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4300 				if (cond_real_app_id != 0) {
4301 					uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4302 					master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4303 					if (condition_is_negative) {
4304 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4305 					}
4306 					socket_only_conditions = TRUE;
4307 				}
4308 			}
4309 			break;
4310 		}
4311 		case NECP_POLICY_CONDITION_PID: {
4312 			if (condition_length >= sizeof(pid_t)) {
4313 				master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4314 				if (condition_is_negative) {
4315 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4316 				}
4317 				memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4318 				if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4319 					memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4320 				}
4321 				socket_only_conditions = TRUE;
4322 			}
4323 			break;
4324 		}
4325 		case NECP_POLICY_CONDITION_UID: {
4326 			if (condition_length >= sizeof(uid_t)) {
4327 				master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4328 				if (condition_is_negative) {
4329 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4330 				}
4331 				memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4332 				socket_only_conditions = TRUE;
4333 			}
4334 			break;
4335 		}
4336 		case NECP_POLICY_CONDITION_REAL_UID: {
4337 			if (condition_length >= sizeof(uid_t)) {
4338 				master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4339 				if (condition_is_negative) {
4340 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4341 				}
4342 				memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4343 				socket_only_conditions = TRUE;
4344 			}
4345 			break;
4346 		}
4347 		case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4348 			if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4349 				master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4350 				if (condition_is_negative) {
4351 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4352 				}
4353 				memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4354 				socket_only_conditions = TRUE;
4355 			}
4356 			break;
4357 		}
4358 		case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4359 			if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4360 				char interface_name[IFXNAMSIZ];
4361 				memcpy(interface_name, condition_value, condition_length);
4362 				interface_name[condition_length - 1] = 0;         // Make sure the string is NULL terminated
4363 				if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4364 					master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4365 					if (condition_is_negative) {
4366 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4367 					}
4368 				}
4369 				socket_ip_conditions = TRUE;
4370 			}
4371 			break;
4372 		}
4373 		case NECP_POLICY_CONDITION_IP_PROTOCOL:
4374 		case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4375 			if (condition_length >= sizeof(u_int16_t)) {
4376 				master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4377 				if (condition_is_negative) {
4378 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4379 				}
4380 				memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4381 				if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4382 					socket_only_conditions = TRUE;
4383 				} else {
4384 					socket_ip_conditions = TRUE;
4385 				}
4386 			}
4387 			break;
4388 		}
4389 		case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4390 			if (condition_is_negative) {
4391 				master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4392 			}
4393 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4394 			socket_ip_conditions = TRUE;
4395 			if (condition_length >= sizeof(u_int8_t)) {
4396 				memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4397 			}
4398 			break;
4399 		}
4400 		case NECP_POLICY_CONDITION_LOCAL_ADDR:
4401 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4402 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4403 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4404 				break;
4405 			}
4406 
4407 			cond_local_prefix = address_struct->prefix;
4408 			memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4409 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4410 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4411 			if (condition_is_negative) {
4412 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4413 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4414 			}
4415 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4416 				socket_only_conditions = TRUE;
4417 			} else {
4418 				socket_ip_conditions = TRUE;
4419 			}
4420 			break;
4421 		}
4422 		case NECP_POLICY_CONDITION_REMOTE_ADDR:
4423 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4424 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4425 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4426 				break;
4427 			}
4428 
4429 			cond_remote_prefix = address_struct->prefix;
4430 			memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4431 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4432 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4433 			if (condition_is_negative) {
4434 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4435 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4436 			}
4437 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4438 				socket_only_conditions = TRUE;
4439 			} else {
4440 				socket_ip_conditions = TRUE;
4441 			}
4442 			break;
4443 		}
4444 		case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4445 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4446 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4447 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4448 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4449 				break;
4450 			}
4451 
4452 			memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4453 			memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4454 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4455 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4456 			if (condition_is_negative) {
4457 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4458 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4459 			}
4460 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4461 				socket_only_conditions = TRUE;
4462 			} else {
4463 				socket_ip_conditions = TRUE;
4464 			}
4465 			break;
4466 		}
4467 		case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4468 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4469 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4470 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4471 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4472 				break;
4473 			}
4474 
4475 			memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4476 			memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4477 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4478 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4479 			if (condition_is_negative) {
4480 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4481 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4482 			}
4483 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4484 				socket_only_conditions = TRUE;
4485 			} else {
4486 				socket_ip_conditions = TRUE;
4487 			}
4488 			break;
4489 		}
4490 		case NECP_POLICY_CONDITION_AGENT_TYPE: {
4491 			if (condition_length >= sizeof(cond_agent_type)) {
4492 				master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4493 				memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4494 				socket_only_conditions = TRUE;
4495 			}
4496 			break;
4497 		}
4498 		case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4499 			if (condition_is_negative) {
4500 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4501 			}
4502 			master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4503 			socket_only_conditions = TRUE;
4504 			if (condition_length >= sizeof(u_int32_t)) {
4505 				memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4506 			} else {
4507 				// Empty means match on fallback traffic
4508 				cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4509 			}
4510 			break;
4511 		}
4512 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4513 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4514 			if (condition_is_negative) {
4515 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4516 			}
4517 			socket_only_conditions = TRUE;
4518 			break;
4519 		}
4520 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4521 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4522 			if (condition_is_negative) {
4523 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4524 			}
4525 			socket_only_conditions = TRUE;
4526 			break;
4527 		}
4528 		case NECP_POLICY_CONDITION_SCHEME_PORT: {
4529 			master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4530 			if (condition_is_negative) {
4531 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4532 			}
4533 			memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4534 			socket_ip_conditions = TRUE;
4535 			break;
4536 		}
4537 		case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4538 			if (condition_length > 0) {
4539 				if (cond_signing_identifier == NULL) {
4540 					cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4541 					if (cond_signing_identifier != NULL) {
4542 						master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4543 						socket_only_conditions = TRUE;
4544 						if (condition_is_negative) {
4545 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4546 						}
4547 					}
4548 				}
4549 			}
4550 			break;
4551 		}
4552 		case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4553 			if (condition_length >= sizeof(u_int16_t)) {
4554 				master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4555 				if (condition_is_negative) {
4556 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4557 				}
4558 				memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4559 				socket_ip_conditions = TRUE;
4560 			}
4561 			break;
4562 		}
4563 		case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4564 			master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4565 			if (condition_is_negative) {
4566 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4567 			}
4568 			socket_only_conditions = TRUE;
4569 			break;
4570 		}
4571 		case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4572 			master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4573 			if (condition_is_negative) {
4574 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4575 			}
4576 			socket_only_conditions = TRUE;
4577 			break;
4578 		}
4579 		case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4580 			if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4581 				u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4582 				memcpy(&flags, condition_value, sizeof(flags));
4583 				cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4584 				cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4585 				cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4586 				master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4587 				if (condition_is_negative) {
4588 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4589 				}
4590 				socket_ip_conditions = TRUE;
4591 			}
4592 			break;
4593 		}
4594 		default: {
4595 			break;
4596 		}
4597 		}
4598 
4599 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4600 	}
4601 
4602 	// Process result
4603 	ultimate_result = necp_policy_get_result_type(policy);
4604 	switch (ultimate_result) {
4605 	case NECP_POLICY_RESULT_PASS: {
4606 		u_int32_t pass_flags = 0;
4607 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4608 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4609 				ultimate_result_parameter.pass_flags = pass_flags;
4610 			}
4611 		}
4612 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4613 			socket_layer_non_id_conditions = TRUE;
4614 			ip_output_layer_id_condition = TRUE;
4615 		} else if (socket_ip_conditions) {
4616 			socket_layer_non_id_conditions = TRUE;
4617 			ip_output_layer_id_condition = TRUE;
4618 			ip_output_layer_non_id_conditions = TRUE;
4619 		}
4620 		break;
4621 	}
4622 	case NECP_POLICY_RESULT_DROP: {
4623 		u_int32_t drop_flags = 0;
4624 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4625 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4626 				ultimate_result_parameter.drop_flags = drop_flags;
4627 				if (ultimate_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_DEFUNCT_ALL_FLOWS) {
4628 					if (should_update_immediately != NULL) {
4629 						*should_update_immediately = TRUE;
4630 					}
4631 				}
4632 			}
4633 		}
4634 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4635 			socket_layer_non_id_conditions = TRUE;
4636 		} else if (socket_ip_conditions) {
4637 			socket_layer_non_id_conditions = TRUE;
4638 			ip_output_layer_non_id_conditions = TRUE;
4639 			ip_output_layer_non_id_only = TRUE;         // Only apply drop to packets that didn't go through socket layer
4640 		}
4641 		break;
4642 	}
4643 	case NECP_POLICY_RESULT_SKIP: {
4644 		u_int32_t skip_policy_order = 0;
4645 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4646 			ultimate_result_parameter.skip_policy_order = skip_policy_order;
4647 		}
4648 
4649 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4650 			socket_layer_non_id_conditions = TRUE;
4651 			ip_output_layer_id_condition = TRUE;
4652 		} else if (socket_ip_conditions) {
4653 			socket_layer_non_id_conditions = TRUE;
4654 			ip_output_layer_non_id_conditions = TRUE;
4655 		}
4656 		break;
4657 	}
4658 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
4659 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
4660 		u_int32_t control_unit = 0;
4661 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4662 			ultimate_result_parameter.flow_divert_control_unit = control_unit;
4663 		}
4664 		socket_layer_non_id_conditions = TRUE;
4665 		break;
4666 	}
4667 	case NECP_POLICY_RESULT_IP_TUNNEL: {
4668 		struct necp_policy_result_ip_tunnel tunnel_parameters;
4669 		u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4670 		if (tunnel_parameters_length > sizeof(u_int32_t) &&
4671 		    tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4672 		    necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4673 			ifnet_t __single tunnel_interface = NULL;
4674 			tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0;         // Make sure the string is NULL terminated
4675 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4676 				ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4677 				ifnet_release(tunnel_interface);
4678 			}
4679 
4680 			secondary_result = tunnel_parameters.secondary_result;
4681 			if (secondary_result) {
4682 				cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4683 			}
4684 		}
4685 
4686 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4687 			socket_layer_non_id_conditions = TRUE;
4688 			ip_output_layer_id_condition = TRUE;
4689 			if (secondary_result) {
4690 				ip_output_layer_tunnel_condition_from_id = TRUE;
4691 			}
4692 		} else if (socket_ip_conditions) {
4693 			socket_layer_non_id_conditions = TRUE;
4694 			ip_output_layer_id_condition = TRUE;
4695 			ip_output_layer_non_id_conditions = TRUE;
4696 			if (secondary_result) {
4697 				ip_output_layer_tunnel_condition_from_id = TRUE;
4698 				ip_output_layer_tunnel_condition_from_non_id = TRUE;
4699 			}
4700 		}
4701 		break;
4702 	}
4703 	case NECP_POLICY_RESULT_USE_NETAGENT:
4704 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4705 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4706 		uuid_t netagent_uuid;
4707 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4708 			ultimate_result_parameter.netagent_id = necp_create_agent_uuid_id_mapping(netagent_uuid);
4709 			if (ultimate_result_parameter.netagent_id != 0) {
4710 				uuid_copy(policy->applied_result_uuid, netagent_uuid);
4711 				socket_layer_non_id_conditions = TRUE;
4712 			}
4713 		}
4714 		break;
4715 	}
4716 	case NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
4717 		struct necp_policy_condition_agent_type netagent_type = {};
4718 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_type, sizeof(netagent_type))) {
4719 			ultimate_result_parameter.netagent_id = necp_create_agent_type_to_id_mapping(&netagent_type);
4720 			if (ultimate_result_parameter.netagent_id != 0) {
4721 				policy->applied_agent_type_id = ultimate_result_parameter.netagent_id;
4722 				socket_layer_non_id_conditions = TRUE;
4723 			}
4724 		}
4725 		break;
4726 	}
4727 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4728 		u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4729 		if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4730 			char interface_name[IFXNAMSIZ];
4731 			ifnet_t __single scope_interface = NULL;
4732 			necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4733 			interface_name[interface_name_length - 1] = 0;         // Make sure the string is NULL terminated
4734 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4735 				ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4736 				socket_layer_non_id_conditions = TRUE;
4737 				ifnet_release(scope_interface);
4738 			}
4739 		}
4740 		break;
4741 	}
4742 	case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4743 		socket_layer_non_id_conditions = TRUE;
4744 		break;
4745 	}
4746 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4747 		socket_layer_non_id_conditions = TRUE;
4748 		break;
4749 	}
4750 	case NECP_POLICY_RESULT_ROUTE_RULES: {
4751 		if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4752 			bool has_socket_only_actions = FALSE;
4753 			u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4754 			if (route_rule_id > 0) {
4755 				policy->applied_route_rules_id = route_rule_id;
4756 				ultimate_result_parameter.route_rule_id = route_rule_id;
4757 				if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4758 					socket_layer_non_id_conditions = TRUE;
4759 				} else if (socket_ip_conditions) {
4760 					socket_layer_non_id_conditions = TRUE;
4761 					ip_output_layer_non_id_conditions = TRUE;
4762 					ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4763 				}
4764 			}
4765 		}
4766 		break;
4767 	}
4768 	default: {
4769 		break;
4770 	}
4771 	}
4772 
4773 	if (socket_layer_non_id_conditions) {
4774 		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);
4775 
4776 		if (policy_id == 0) {
4777 			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4778 			goto fail;
4779 		}
4780 
4781 		cond_ip_output_layer_id = policy_id;
4782 		policy->kernel_socket_policies[0] = policy_id;
4783 	}
4784 
4785 	if (ip_output_layer_non_id_conditions) {
4786 		u_int64_t condition_mask = master_condition_mask;
4787 		if (ip_output_layer_non_id_only) {
4788 			condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4789 		}
4790 
4791 		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);
4792 
4793 		if (policy_id == 0) {
4794 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4795 			goto fail;
4796 		}
4797 
4798 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4799 	}
4800 
4801 	if (ip_output_layer_id_condition) {
4802 		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);
4803 
4804 		if (policy_id == 0) {
4805 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4806 			goto fail;
4807 		}
4808 
4809 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4810 	}
4811 
4812 	// Extra policies for IP Output tunnels for when packets loop back
4813 	if (ip_output_layer_tunnel_condition_from_id) {
4814 		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);
4815 
4816 		if (policy_id == 0) {
4817 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4818 			goto fail;
4819 		}
4820 
4821 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4822 	}
4823 
4824 	if (ip_output_layer_tunnel_condition_from_id) {
4825 		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);
4826 
4827 		if (policy_id == 0) {
4828 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4829 			goto fail;
4830 		}
4831 
4832 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4833 	}
4834 
4835 	policy->applied = TRUE;
4836 	policy->pending_update = FALSE;
4837 	return TRUE;
4838 
4839 fail:
4840 	return FALSE;
4841 }
4842 
4843 static void
necp_policy_apply_all(struct necp_session * session)4844 necp_policy_apply_all(struct necp_session *session)
4845 {
4846 	struct necp_session_policy *policy = NULL;
4847 	struct necp_session_policy *temp_policy = NULL;
4848 	struct kev_necp_policies_changed_data kev_data;
4849 	kev_data.changed_count = 0;
4850 	bool should_update_immediately = FALSE;
4851 
4852 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4853 
4854 	// Remove exisiting applied policies
4855 	if (session->dirty) {
4856 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4857 			if (policy->pending_deletion) {
4858 				if (policy->applied) {
4859 					necp_policy_unapply(policy);
4860 				}
4861 				// Delete the policy
4862 				necp_policy_delete(session, policy);
4863 			} else if (!policy->applied) {
4864 				necp_policy_apply(session, policy, &should_update_immediately);
4865 			} else if (policy->pending_update) {
4866 				// Must have been applied, but needs an update. Remove and re-add.
4867 				necp_policy_unapply(policy);
4868 				necp_policy_apply(session, policy, &should_update_immediately);
4869 			}
4870 		}
4871 
4872 		necp_kernel_socket_policies_update_uuid_table();
4873 		necp_kernel_socket_policies_reprocess();
4874 		necp_kernel_ip_output_policies_reprocess();
4875 
4876 		// Clear dirty bit flags
4877 		session->dirty = FALSE;
4878 	}
4879 
4880 	lck_rw_done(&necp_kernel_policy_lock);
4881 
4882 	if (!should_update_immediately) {
4883 		necp_update_all_clients();
4884 	} else {
4885 		necp_update_all_clients_immediately_if_needed(true);
4886 	}
4887 
4888 	necp_post_change_event(&kev_data);
4889 
4890 	if (necp_debug) {
4891 		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4892 	}
4893 }
4894 
4895 // Kernel Policy Management
4896 // ---------------------
4897 // Kernel policies are derived from session policies
4898 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4899 necp_kernel_policy_get_new_id(bool socket_level)
4900 {
4901 	static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4902 	static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4903 
4904 	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4905 
4906 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4907 
4908 	if (socket_level) {
4909 		bool wrapped = FALSE;
4910 		do {
4911 			necp_last_kernel_socket_policy_id++;
4912 			if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4913 			    necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4914 				if (wrapped) {
4915 					// Already wrapped, give up
4916 					NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4917 					return NECP_KERNEL_POLICY_ID_NONE;
4918 				}
4919 				necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4920 				wrapped = TRUE;
4921 			}
4922 			newid = necp_last_kernel_socket_policy_id;
4923 		} while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4924 	} else {
4925 		bool wrapped = FALSE;
4926 		do {
4927 			necp_last_kernel_ip_policy_id++;
4928 			if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4929 				if (wrapped) {
4930 					// Already wrapped, give up
4931 					NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4932 					return NECP_KERNEL_POLICY_ID_NONE;
4933 				}
4934 				necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4935 				wrapped = TRUE;
4936 			}
4937 			newid = necp_last_kernel_ip_policy_id;
4938 		} while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4939 	}
4940 
4941 	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4942 		NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4943 		return NECP_KERNEL_POLICY_ID_NONE;
4944 	}
4945 
4946 	return newid;
4947 }
4948 
4949 #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)
4950 
4951 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)4952 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)
4953 {
4954 	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4955 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4956 
4957 	new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4958 
4959 	new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4960 	new_kernel_policy->order = order;
4961 	new_kernel_policy->session_order = session_order;
4962 	new_kernel_policy->session_pid = session_pid;
4963 
4964 	// Sanitize condition mask
4965 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4966 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4967 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4968 	}
4969 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4970 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4971 	}
4972 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4973 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4974 	}
4975 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4976 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4977 	}
4978 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4979 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4980 	}
4981 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4982 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4983 	}
4984 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4985 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4986 	}
4987 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4988 
4989 	// Set condition values
4990 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4991 		new_kernel_policy->cond_app_id = cond_app_id;
4992 	}
4993 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4994 		new_kernel_policy->cond_real_app_id = cond_real_app_id;
4995 	}
4996 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4997 		new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4998 	}
4999 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5000 		new_kernel_policy->cond_account_id = cond_account_id;
5001 	}
5002 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5003 	    (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5004 		new_kernel_policy->cond_domain = cond_domain;
5005 		new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5006 	}
5007 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5008 		new_kernel_policy->cond_domain_filter = cond_domain_filter;
5009 	}
5010 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5011 		new_kernel_policy->cond_url = cond_url;
5012 	}
5013 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5014 		new_kernel_policy->cond_pid = cond_pid;
5015 		new_kernel_policy->cond_pid_version = cond_pid_version;
5016 	}
5017 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5018 		new_kernel_policy->cond_uid = cond_uid;
5019 	}
5020 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5021 		new_kernel_policy->cond_real_uid = cond_real_uid;
5022 	}
5023 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5024 		if (cond_bound_interface) {
5025 			ifnet_reference(cond_bound_interface);
5026 		}
5027 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
5028 	}
5029 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5030 		new_kernel_policy->cond_traffic_class = cond_traffic_class;
5031 	}
5032 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5033 		new_kernel_policy->cond_protocol = cond_protocol;
5034 	}
5035 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5036 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5037 	}
5038 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5039 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5040 	}
5041 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5042 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
5043 	}
5044 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5045 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5046 	}
5047 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5048 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5049 	}
5050 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5051 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5052 	}
5053 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5054 		memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5055 	}
5056 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5057 		memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5058 	}
5059 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5060 		new_kernel_policy->cond_client_flags = cond_client_flags;
5061 	}
5062 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5063 		new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5064 	}
5065 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5066 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5067 	}
5068 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5069 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
5070 	}
5071 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5072 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5073 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5074 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5075 	}
5076 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5077 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5078 	}
5079 
5080 	new_kernel_policy->result = result;
5081 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5082 
5083 	if (necp_debug) {
5084 		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5085 	}
5086 	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5087 
5088 	return new_kernel_policy ? new_kernel_policy->id : 0;
5089 }
5090 
5091 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5092 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5093 {
5094 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5095 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5096 
5097 	if (policy_id == 0) {
5098 		return NULL;
5099 	}
5100 
5101 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5102 		if (kernel_policy->id == policy_id) {
5103 			return kernel_policy;
5104 		}
5105 	}
5106 
5107 	return NULL;
5108 }
5109 
5110 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5111 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5112 {
5113 	struct necp_kernel_socket_policy * __single policy = NULL;
5114 	char * __indexable buffer = NULL;
5115 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5116 
5117 	policy = necp_kernel_socket_policy_find(policy_id);
5118 	if (policy) {
5119 		LIST_REMOVE(policy, chain);
5120 
5121 		if (policy->cond_bound_interface) {
5122 			ifnet_release(policy->cond_bound_interface);
5123 			policy->cond_bound_interface = NULL;
5124 		}
5125 
5126 		if (policy->cond_domain) {
5127 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5128 			kfree_data_addr(buffer);
5129 			policy->cond_domain = NULL;
5130 		}
5131 
5132 		if (policy->cond_url) {
5133 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5134 			kfree_data_addr(buffer);
5135 			policy->cond_url = NULL;
5136 		}
5137 
5138 		if (policy->cond_custom_entitlement) {
5139 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5140 			kfree_data_addr(buffer);
5141 			policy->cond_custom_entitlement = NULL;
5142 		}
5143 
5144 		if (policy->cond_signing_identifier) {
5145 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5146 			kfree_data_addr(buffer);
5147 			policy->cond_signing_identifier = NULL;
5148 		}
5149 
5150 		zfree(necp_socket_policy_zone, policy);
5151 		return TRUE;
5152 	}
5153 
5154 	return FALSE;
5155 }
5156 
5157 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5158 __sized_by(MAX_RESULT_STRING_LEN)
5159 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)
5160 {
5161 	uuid_string_t uuid_string;
5162 	switch (result) {
5163 	case NECP_KERNEL_POLICY_RESULT_NONE: {
5164 		snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5165 		break;
5166 	}
5167 	case NECP_KERNEL_POLICY_RESULT_PASS: {
5168 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5169 		break;
5170 	}
5171 	case NECP_KERNEL_POLICY_RESULT_SKIP: {
5172 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5173 		break;
5174 	}
5175 	case NECP_KERNEL_POLICY_RESULT_DROP: {
5176 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5177 		break;
5178 	}
5179 	case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5180 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5181 		break;
5182 	}
5183 	case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5184 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5185 		break;
5186 	}
5187 	case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5188 		ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5189 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5190 		break;
5191 	}
5192 	case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5193 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5194 		break;
5195 	}
5196 	case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5197 		ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5198 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5199 		break;
5200 	}
5201 	case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5202 		snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5203 		break;
5204 	}
5205 	case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5206 		snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5207 		break;
5208 	}
5209 	case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5210 		int index = 0;
5211 		char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5212 		struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5213 		if (route_rule != NULL) {
5214 			for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5215 				if (route_rule->exception_if_indices[index] != 0) {
5216 					ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5217 					snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5218 				} else {
5219 					memset(interface_names[index], 0, IFXNAMSIZ);
5220 				}
5221 			}
5222 			switch (route_rule->default_action) {
5223 			case NECP_ROUTE_RULE_DENY_INTERFACE:
5224 			case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5225 				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%s)",
5226 				    (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5227 				    (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5228 				    (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5229 				    (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5230 				    (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5231 				    (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Ultra-Constrained " : "",
5232 				    (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5233 				    (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5234 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5235 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5236 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5237 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5238 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5239 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5240 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5241 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5242 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5243 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5244 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5245 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5246 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5247 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5248 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5249 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5250 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5251 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5252 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5253 				break;
5254 			case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5255 				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%s)",
5256 				    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5257 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5258 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5259 				    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5260 				    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5261 				    IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action) ? "!Ultra-Constrained " : "",
5262 				    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5263 				    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5264 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5265 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5266 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5267 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5268 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5269 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5270 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5271 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5272 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5273 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5274 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5275 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5276 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5277 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5278 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5279 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5280 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5281 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5282 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5283 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5284 				break;
5285 			case NECP_ROUTE_RULE_QOS_MARKING:
5286 				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%s)",
5287 				    (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5288 				    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5289 				    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5290 				    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5291 				    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5292 				    (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Ultra-Constrained " : "",
5293 				    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5294 				    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5295 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5296 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5297 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5298 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5299 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5300 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5301 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5302 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5303 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5304 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5305 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5306 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5307 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5308 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5309 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5310 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5311 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5312 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5313 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5314 				break;
5315 			default:
5316 				snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5317 				break;
5318 			}
5319 		}
5320 		break;
5321 	}
5322 	case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5323 		bool found_mapping = FALSE;
5324 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5325 		if (mapping != NULL) {
5326 			uuid_unparse(mapping->uuid, uuid_string);
5327 			found_mapping = TRUE;
5328 		}
5329 		snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5330 		break;
5331 	}
5332 	case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5333 		bool found_mapping = FALSE;
5334 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5335 		if (mapping != NULL) {
5336 			uuid_unparse(mapping->uuid, uuid_string);
5337 			found_mapping = TRUE;
5338 		}
5339 		snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5340 		break;
5341 	}
5342 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5343 		bool found_mapping = FALSE;
5344 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5345 		if (mapping != NULL) {
5346 			uuid_unparse(mapping->uuid, uuid_string);
5347 			found_mapping = TRUE;
5348 		}
5349 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5350 		break;
5351 	}
5352 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
5353 		bool found_mapping = FALSE;
5354 		struct necp_agent_type_id_mapping *mapping = necp_lookup_agent_type_with_id_locked(result_parameter.netagent_id);
5355 		if (mapping != NULL) {
5356 			found_mapping = TRUE;
5357 		}
5358 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgentType (%s/%s)", found_mapping ? mapping->agent_type.agent_domain : "Unknown", found_mapping ? mapping->agent_type.agent_type : "Unknown");
5359 		break;
5360 	}
5361 	default: {
5362 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5363 		break;
5364 	}
5365 	}
5366 	return result_string;
5367 }
5368 
5369 static void
necp_kernel_socket_policies_dump_all(void)5370 necp_kernel_socket_policies_dump_all(void)
5371 {
5372 	if (necp_debug) {
5373 		struct necp_kernel_socket_policy *policy = NULL;
5374 		int policy_i;
5375 		int app_i;
5376 		char result_string[MAX_RESULT_STRING_LEN];
5377 		char proc_name_string[MAXCOMLEN + 1];
5378 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
5379 		memset(proc_name_string, 0, MAXCOMLEN + 1);
5380 
5381 		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5382 		NECPLOG0(LOG_DEBUG, "-----------\n");
5383 		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5384 			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5385 			proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5386 			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));
5387 		}
5388 		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5389 			NECPLOG0(LOG_DEBUG, "-----------\n");
5390 		}
5391 
5392 		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5393 		NECPLOG0(LOG_DEBUG, "-----------\n");
5394 		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5395 			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5396 			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5397 				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5398 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5399 				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));
5400 			}
5401 			NECPLOG0(LOG_DEBUG, "-----------\n");
5402 		}
5403 	}
5404 }
5405 
5406 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5407 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5408 {
5409 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5410 		// Drop always cancels out lower policies
5411 		return TRUE;
5412 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5413 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5414 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5415 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5416 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5417 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT ||
5418 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE) {
5419 		// Filters and route rules never cancel out lower policies
5420 		return FALSE;
5421 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5422 		if (upper_policy->session_order != lower_policy->session_order) {
5423 			// A skip cannot override a policy of a different session
5424 			return FALSE;
5425 		} else {
5426 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
5427 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5428 				// This policy is beyond the skip
5429 				return FALSE;
5430 			} else {
5431 				// This policy is inside the skip
5432 				return TRUE;
5433 			}
5434 		}
5435 	}
5436 
5437 	// A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5438 	return TRUE;
5439 }
5440 
5441 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)5442 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5443 {
5444 	bool can_skip = FALSE;
5445 	u_int32_t highest_skip_session_order = 0;
5446 	u_int32_t highest_skip_order = 0;
5447 	int i;
5448 	for (i = 0; i < valid_indices; i++) {
5449 		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5450 
5451 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
5452 		if (can_skip) {
5453 			if (highest_skip_session_order != compared_policy->session_order ||
5454 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5455 				// If we've moved on to the next session, or passed the skip window
5456 				highest_skip_session_order = 0;
5457 				highest_skip_order = 0;
5458 				can_skip = FALSE;
5459 			} else {
5460 				// If this policy is also a skip, in can increase the skip window
5461 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5462 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5463 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5464 					}
5465 				}
5466 				continue;
5467 			}
5468 		}
5469 
5470 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5471 			// This policy is a skip. Set the skip window accordingly
5472 			can_skip = TRUE;
5473 			highest_skip_session_order = compared_policy->session_order;
5474 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5475 		}
5476 
5477 		// The result of the compared policy must be able to block out this policy result
5478 		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5479 			continue;
5480 		}
5481 
5482 		// If new policy matches All Interfaces, compared policy must also
5483 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5484 			continue;
5485 		}
5486 
5487 		// If new policy matches Local Networks, compared policy must also
5488 		if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5489 		    policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5490 			continue;
5491 		}
5492 
5493 		// Default makes lower policies unecessary always
5494 		if (compared_policy->condition_mask == 0) {
5495 			return TRUE;
5496 		}
5497 
5498 		// Compared must be more general than policy, and include only conditions within policy
5499 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5500 			continue;
5501 		}
5502 
5503 		// Negative conditions must match for the overlapping conditions
5504 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5505 			continue;
5506 		}
5507 
5508 		if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5509 		    compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5510 		    strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5511 			continue;
5512 		}
5513 
5514 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5515 		    compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5516 			continue;
5517 		}
5518 
5519 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5520 		    strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5521 			continue;
5522 		}
5523 
5524 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5525 		    strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5526 			continue;
5527 		}
5528 
5529 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5530 		    compared_policy->cond_account_id != policy->cond_account_id) {
5531 			continue;
5532 		}
5533 
5534 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5535 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
5536 			continue;
5537 		}
5538 
5539 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5540 		    compared_policy->cond_app_id != policy->cond_app_id) {
5541 			continue;
5542 		}
5543 
5544 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5545 		    compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5546 			continue;
5547 		}
5548 
5549 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5550 		    (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5551 			continue;
5552 		}
5553 
5554 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5555 		    compared_policy->cond_uid != policy->cond_uid) {
5556 			continue;
5557 		}
5558 
5559 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5560 		    compared_policy->cond_real_uid != policy->cond_real_uid) {
5561 			continue;
5562 		}
5563 
5564 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5565 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5566 			continue;
5567 		}
5568 
5569 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5570 		    compared_policy->cond_protocol != policy->cond_protocol) {
5571 			continue;
5572 		}
5573 
5574 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5575 		    compared_policy->cond_client_flags != policy->cond_client_flags) {
5576 			continue;
5577 		}
5578 
5579 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5580 		    !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5581 		    compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5582 			continue;
5583 		}
5584 
5585 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5586 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5587 				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))) {
5588 					continue;
5589 				}
5590 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5591 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5592 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5593 					continue;
5594 				}
5595 			}
5596 		}
5597 
5598 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5599 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5600 				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))) {
5601 					continue;
5602 				}
5603 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5604 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5605 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5606 					continue;
5607 				}
5608 			}
5609 		}
5610 
5611 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5612 		    memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5613 			continue;
5614 		}
5615 
5616 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5617 		    memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5618 			continue;
5619 		}
5620 
5621 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5622 		    memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5623 			continue;
5624 		}
5625 
5626 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5627 		    memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5628 			continue;
5629 		}
5630 
5631 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5632 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5633 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5634 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5635 			continue;
5636 		}
5637 
5638 		return TRUE;
5639 	}
5640 
5641 	return FALSE;
5642 }
5643 
5644 static bool
necp_kernel_socket_policies_reprocess(void)5645 necp_kernel_socket_policies_reprocess(void)
5646 {
5647 	int app_i;
5648 	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5649 	int app_layer_current_free_index = 0;
5650 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5651 
5652 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5653 
5654 	// Reset mask to 0
5655 	necp_kernel_application_policies_condition_mask = 0;
5656 	necp_kernel_socket_policies_condition_mask = 0;
5657 	necp_kernel_application_policies_count = 0;
5658 	necp_kernel_socket_policies_count = 0;
5659 	necp_kernel_socket_policies_non_app_count = 0;
5660 
5661 	// Reset all maps to NULL
5662 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5663 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5664 			kfree_type(struct necp_kernel_socket_policy *,
5665 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5666 			    necp_kernel_socket_policies_map[app_i]);
5667 			necp_kernel_socket_policies_map[app_i] = NULL;
5668 		}
5669 
5670 		// Init counts
5671 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5672 	}
5673 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5674 		kfree_type(struct necp_kernel_socket_policy *,
5675 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5676 		    necp_kernel_socket_policies_app_layer_map);
5677 	}
5678 	necp_kernel_socket_policies_app_layer_map = NULL;
5679 	necp_kernel_socket_policies_app_layer_map_count = 0;
5680 
5681 	// Create masks and counts
5682 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5683 		// App layer mask/count
5684 		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5685 		necp_kernel_application_policies_count++;
5686 		necp_kernel_socket_policies_app_layer_map_count++;
5687 
5688 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5689 			// Agent type conditions only apply to app layer
5690 			continue;
5691 		}
5692 
5693 		// Update socket layer bucket mask/counts
5694 		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5695 		necp_kernel_socket_policies_count++;
5696 
5697 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5698 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5699 			necp_kernel_socket_policies_non_app_count++;
5700 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5701 				necp_kernel_socket_policies_map_counts[app_i]++;
5702 			}
5703 		} else {
5704 			necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5705 		}
5706 	}
5707 
5708 	// Allocate maps
5709 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5710 		if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5711 			// Allocate a NULL-terminated array of policy pointers for each bucket
5712 			necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5713 			    necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5714 			if (necp_kernel_socket_policies_map[app_i] == NULL) {
5715 				goto fail;
5716 			}
5717 		}
5718 		bucket_current_free_index[app_i] = 0;
5719 	}
5720 	necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5721 	    necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5722 	if (necp_kernel_socket_policies_app_layer_map == NULL) {
5723 		goto fail;
5724 	}
5725 
5726 	// Fill out maps
5727 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5728 		// Add app layer policies
5729 		if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5730 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5731 			app_layer_current_free_index++;
5732 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5733 		}
5734 
5735 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5736 			// Agent type conditions only apply to app layer
5737 			continue;
5738 		}
5739 
5740 		// Add socket policies
5741 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5742 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5743 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5744 				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])) {
5745 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5746 					bucket_current_free_index[app_i]++;
5747 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5748 				}
5749 			}
5750 		} else {
5751 			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5752 			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])) {
5753 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5754 				bucket_current_free_index[app_i]++;
5755 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5756 			}
5757 		}
5758 	}
5759 	necp_kernel_socket_policies_dump_all();
5760 	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5761 	return TRUE;
5762 
5763 fail:
5764 	// Free memory, reset masks to 0
5765 	necp_kernel_application_policies_condition_mask = 0;
5766 	necp_kernel_socket_policies_condition_mask = 0;
5767 	necp_kernel_application_policies_count = 0;
5768 	necp_kernel_socket_policies_count = 0;
5769 	necp_kernel_socket_policies_non_app_count = 0;
5770 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5771 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5772 			kfree_type(struct necp_kernel_socket_policy *,
5773 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5774 			    necp_kernel_socket_policies_map[app_i]);
5775 			necp_kernel_socket_policies_map[app_i] = NULL;
5776 		}
5777 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5778 	}
5779 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5780 		kfree_type(struct necp_kernel_socket_policy *,
5781 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5782 		    necp_kernel_socket_policies_app_layer_map);
5783 		necp_kernel_socket_policies_app_layer_map = NULL;
5784 	}
5785 	necp_kernel_socket_policies_app_layer_map_count = 0;
5786 	return FALSE;
5787 }
5788 
5789 static u_int32_t
necp_get_new_string_id(void)5790 necp_get_new_string_id(void)
5791 {
5792 	static u_int32_t necp_last_string_id = 0;
5793 
5794 	u_int32_t newid = 0;
5795 
5796 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5797 
5798 	bool wrapped = FALSE;
5799 	do {
5800 		necp_last_string_id++;
5801 		if (necp_last_string_id < 1) {
5802 			if (wrapped) {
5803 				// Already wrapped, give up
5804 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5805 				return 0;
5806 			}
5807 			necp_last_string_id = 1;
5808 			wrapped = TRUE;
5809 		}
5810 		newid = necp_last_string_id;
5811 	} while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5812 
5813 	if (newid == 0) {
5814 		NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5815 		return 0;
5816 	}
5817 
5818 	return newid;
5819 }
5820 
5821 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5822 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5823 {
5824 	struct necp_string_id_mapping *searchentry = NULL;
5825 	struct necp_string_id_mapping *foundentry = NULL;
5826 
5827 	LIST_FOREACH(searchentry, list, chain) {
5828 		if (strcmp(searchentry->string, string) == 0) {
5829 			foundentry = searchentry;
5830 			break;
5831 		}
5832 	}
5833 
5834 	return foundentry;
5835 }
5836 
5837 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5838 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5839 {
5840 	struct necp_string_id_mapping *searchentry = NULL;
5841 	struct necp_string_id_mapping *foundentry = NULL;
5842 
5843 	LIST_FOREACH(searchentry, list, chain) {
5844 		if (searchentry->id == local_id) {
5845 			foundentry = searchentry;
5846 			break;
5847 		}
5848 	}
5849 
5850 	return foundentry;
5851 }
5852 
5853 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5854 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5855 {
5856 	u_int32_t string_id = 0;
5857 	struct necp_string_id_mapping *existing_mapping = NULL;
5858 
5859 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5860 
5861 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5862 	if (existing_mapping != NULL) {
5863 		string_id = existing_mapping->id;
5864 		os_ref_retain_locked(&existing_mapping->refcount);
5865 	} else {
5866 		struct necp_string_id_mapping * __single new_mapping = NULL;
5867 		new_mapping = kalloc_type(struct necp_string_id_mapping,
5868 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5869 
5870 		size_t length = strlen(string) + 1;
5871 		char *buffer = kalloc_data(length, Z_WAITOK);
5872 		if (buffer != NULL) {
5873 			strlcpy(buffer, string, length);
5874 			new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5875 			new_mapping->id = necp_get_new_string_id();
5876 			os_ref_init(&new_mapping->refcount, &necp_refgrp);
5877 			LIST_INSERT_HEAD(list, new_mapping, chain);
5878 			string_id = new_mapping->id;
5879 		} else {
5880 			kfree_type(struct necp_string_id_mapping, new_mapping);
5881 			new_mapping = NULL;
5882 		}
5883 	}
5884 	return string_id;
5885 }
5886 
5887 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5888 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5889 {
5890 	struct necp_string_id_mapping * __single existing_mapping = NULL;
5891 	char * __indexable buffer = NULL;
5892 
5893 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5894 
5895 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5896 	if (existing_mapping != NULL) {
5897 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5898 			LIST_REMOVE(existing_mapping, chain);
5899 			buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5900 			kfree_data_addr(buffer);
5901 			kfree_type(struct necp_string_id_mapping, existing_mapping);
5902 		}
5903 		return TRUE;
5904 	}
5905 
5906 	return FALSE;
5907 }
5908 
5909 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5910 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5911 {
5912 	struct necp_domain_filter *searchfilter = NULL;
5913 	struct necp_domain_filter *foundfilter = NULL;
5914 
5915 	LIST_FOREACH(searchfilter, list, chain) {
5916 		if (searchfilter->id == filter_id) {
5917 			foundfilter = searchfilter;
5918 			break;
5919 		}
5920 	}
5921 
5922 	return foundfilter;
5923 }
5924 
5925 static u_int32_t
necp_get_new_domain_filter_id(void)5926 necp_get_new_domain_filter_id(void)
5927 {
5928 	static u_int32_t necp_last_filter_id = 0;
5929 
5930 	u_int32_t newid = 0;
5931 
5932 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5933 
5934 	bool wrapped = FALSE;
5935 	do {
5936 		// Scope id within its space
5937 		if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5938 			necp_last_filter_id = 0;
5939 		}
5940 		if (necp_last_filter_id < 1) {
5941 			if (wrapped) {
5942 				// Already wrapped, give up
5943 				NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5944 				return 0;
5945 			}
5946 			necp_last_filter_id = 1;
5947 			wrapped = TRUE;
5948 		}
5949 		newid = necp_last_filter_id;
5950 	} while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5951 
5952 	if (newid == 0) {
5953 		NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5954 		return 0;
5955 	}
5956 
5957 	return newid;
5958 }
5959 
5960 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)5961 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5962 {
5963 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5964 
5965 	struct necp_domain_filter *new_filter = NULL;
5966 	new_filter = kalloc_type(struct necp_domain_filter,
5967 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5968 
5969 	new_filter->filter = filter;
5970 	new_filter->id = necp_get_new_domain_filter_id();
5971 	LIST_INSERT_HEAD(list, new_filter, chain);
5972 	LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5973 	os_ref_init(&new_filter->refcount, &necp_refgrp);
5974 
5975 	return new_filter->id;
5976 }
5977 
5978 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)5979 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5980 {
5981 	struct necp_domain_filter * __single existing_filter = NULL;
5982 
5983 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5984 
5985 	existing_filter = necp_lookup_domain_filter(list, filter_id);
5986 	if (existing_filter != NULL) {
5987 		if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5988 			LIST_REMOVE(existing_filter, chain);
5989 			LIST_REMOVE(existing_filter, owner_chain);
5990 			net_bloom_filter_destroy(existing_filter->filter);
5991 			kfree_type(struct necp_domain_filter, existing_filter);
5992 		}
5993 		return true;
5994 	}
5995 
5996 	return false;
5997 }
5998 
5999 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6000 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6001 {
6002 	struct necp_domain_trie *searchTrie = NULL;
6003 	struct necp_domain_trie *foundTrie = NULL;
6004 
6005 	LIST_FOREACH(searchTrie, list, chain) {
6006 		if (searchTrie->id == id) {
6007 			foundTrie = searchTrie;
6008 			break;
6009 		}
6010 	}
6011 
6012 	return foundTrie;
6013 }
6014 
6015 static u_int32_t
necp_get_new_domain_trie_id(void)6016 necp_get_new_domain_trie_id(void)
6017 {
6018 	static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6019 	u_int32_t newid = necp_last_trie_id;
6020 
6021 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6022 
6023 	bool wrapped = FALSE;
6024 	do {
6025 		if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6026 			if (wrapped) {
6027 				// Already wrapped, give up
6028 				NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6029 				return 0;
6030 			}
6031 			necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6032 			wrapped = TRUE;
6033 		}
6034 		newid = necp_last_trie_id;
6035 	} while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6036 
6037 	if (newid == NECP_DOMAIN_TRIE_ID_START) {
6038 		NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6039 		return 0;
6040 	}
6041 
6042 	return newid;
6043 }
6044 
6045 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)6046 necp_create_domain_trie(struct necp_domain_trie_list *list,
6047     struct necp_domain_trie_list *owner_list,
6048     struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6049 {
6050 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6051 
6052 	struct necp_domain_trie *new_trie = NULL;
6053 	new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6054 	if (new_trie == NULL) {
6055 		NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6056 		return 0;
6057 	}
6058 
6059 	if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6060 	    trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6061 	    trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6062 		NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6063 		kfree_type(struct necp_domain_trie, new_trie);
6064 		return 0;
6065 	}
6066 	new_trie->trie_request = trie_request;
6067 	new_trie->trie_request_size = trie_request_size;
6068 	new_trie->id = necp_get_new_domain_trie_id();
6069 	new_trie->trie_request->id = new_trie->id;
6070 	LIST_INSERT_HEAD(list, new_trie, chain);
6071 	LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6072 
6073 	os_ref_init(&new_trie->refcount, &necp_refgrp);
6074 	necp_trie_count++;
6075 	return new_trie->id;
6076 }
6077 
6078 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6079 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6080 {
6081 	if (existing_trie != NULL) {
6082 		uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6083 		kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6084 		kfree_type(struct necp_domain_trie, existing_trie);
6085 	}
6086 }
6087 
6088 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6089 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6090 {
6091 	struct necp_domain_trie * __single existing_trie = NULL;
6092 
6093 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6094 
6095 	existing_trie = necp_lookup_domain_trie(list, id);
6096 	if (existing_trie != NULL) {
6097 		if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6098 			LIST_REMOVE(existing_trie, chain);
6099 			LIST_REMOVE(existing_trie, owner_chain);
6100 			necp_free_domain_trie(existing_trie);
6101 			necp_trie_count--;
6102 		}
6103 		return true;
6104 	}
6105 
6106 	return false;
6107 }
6108 
6109 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)6110 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6111 {
6112 	size_t metadata_length = 0;
6113 	const uint8_t * __sized_by(metadata_length) metadata = NULL;
6114 
6115 	struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6116 	if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6117 		return false;
6118 	}
6119 	Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6120 	Boolean allow_partial_match  = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6121 	return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6122 	           &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6123 }
6124 
6125 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6126 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6127 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6128 necp_get_new_route_rule_id(bool aggregate)
6129 {
6130 	static u_int32_t necp_last_route_rule_id = 0;
6131 	static u_int32_t necp_last_aggregate_route_rule_id = 0;
6132 
6133 	u_int32_t newid = 0;
6134 
6135 	if (!aggregate) {
6136 		// Main necp_kernel_policy_lock protects non-aggregate rule IDs
6137 		LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6138 
6139 		bool wrapped = FALSE;
6140 		do {
6141 			necp_last_route_rule_id++;
6142 			if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6143 			    necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6144 				if (wrapped) {
6145 					// Already wrapped, give up
6146 					NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6147 					return 0;
6148 				}
6149 				necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6150 				wrapped = TRUE;
6151 			}
6152 			newid = necp_last_route_rule_id;
6153 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6154 	} else {
6155 		// necp_route_rule_lock protects aggregate rule IDs
6156 		LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6157 
6158 		bool wrapped = FALSE;
6159 		do {
6160 			necp_last_aggregate_route_rule_id++;
6161 			if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6162 				if (wrapped) {
6163 					// Already wrapped, give up
6164 					NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6165 					return 0;
6166 				}
6167 				necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6168 				wrapped = TRUE;
6169 			}
6170 			newid = necp_last_aggregate_route_rule_id;
6171 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6172 	}
6173 
6174 	if (newid == 0) {
6175 		NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6176 		return 0;
6177 	}
6178 
6179 	return newid;
6180 }
6181 
6182 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6183 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6184 {
6185 	struct necp_route_rule *searchentry = NULL;
6186 	struct necp_route_rule *foundentry = NULL;
6187 
6188 	LIST_FOREACH(searchentry, list, chain) {
6189 		if (searchentry->id == route_rule_id) {
6190 			foundentry = searchentry;
6191 			break;
6192 		}
6193 	}
6194 
6195 	return foundentry;
6196 }
6197 
6198 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_int8_t ultra_constrained_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)6199 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_int8_t ultra_constrained_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)
6200 {
6201 	struct necp_route_rule *searchentry = NULL;
6202 	struct necp_route_rule *foundentry = NULL;
6203 
6204 	LIST_FOREACH(searchentry, list, chain) {
6205 		if (searchentry->default_action == default_action &&
6206 		    searchentry->cellular_action == cellular_action &&
6207 		    searchentry->wifi_action == wifi_action &&
6208 		    searchentry->wired_action == wired_action &&
6209 		    searchentry->expensive_action == expensive_action &&
6210 		    searchentry->constrained_action == constrained_action &&
6211 		    searchentry->companion_action == companion_action &&
6212 		    searchentry->vpn_action == vpn_action &&
6213 		    searchentry->ultra_constrained_action == ultra_constrained_action &&
6214 		    searchentry->control_unit == control_unit &&
6215 		    searchentry->effective_type == effective_type) {
6216 			bool match_failed = FALSE;
6217 			size_t index_a = 0;
6218 			size_t index_b = 0;
6219 			size_t count_a = 0;
6220 			size_t count_b = 0;
6221 			for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6222 				bool found_index = FALSE;
6223 				if (searchentry->exception_if_indices[index_a] == 0) {
6224 					break;
6225 				}
6226 				count_a++;
6227 				for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6228 					if (if_indices[index_b] == 0) {
6229 						break;
6230 					}
6231 					if (index_b >= count_b) {
6232 						count_b = index_b + 1;
6233 					}
6234 					if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6235 					    searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6236 						found_index = TRUE;
6237 						break;
6238 					}
6239 				}
6240 				if (!found_index) {
6241 					match_failed = TRUE;
6242 					break;
6243 				}
6244 			}
6245 
6246 			if (match_failed || count_a != count_b) {
6247 				continue;
6248 			}
6249 
6250 			bool has_agent_a = !uuid_is_null(netagent_uuid);
6251 			bool has_agent_b = (searchentry->netagent_id != 0);
6252 			if (has_agent_a != has_agent_b) {
6253 				continue;
6254 			}
6255 
6256 			if (has_agent_a) {
6257 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(searchentry->netagent_id);
6258 				if (mapping == NULL) {
6259 					// Bad mapping, doesn't match
6260 					continue;
6261 				}
6262 				if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6263 					// UUIDs don't match
6264 					continue;
6265 				}
6266 			}
6267 
6268 			bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6269 			bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6270 			if (has_match_agent_a != has_match_agent_b) {
6271 				continue;
6272 			}
6273 
6274 			if (has_match_agent_a) {
6275 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(searchentry->match_netagent_id);
6276 				if (mapping == NULL) {
6277 					// Bad mapping, doesn't match
6278 					continue;
6279 				}
6280 				if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6281 					// UUIDs don't match
6282 					continue;
6283 				}
6284 			}
6285 
6286 			// Rules match!
6287 			foundentry = searchentry;
6288 			break;
6289 		}
6290 	}
6291 
6292 	return foundentry;
6293 }
6294 
6295 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)6296 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,
6297     bool *has_socket_only_actions)
6298 {
6299 	size_t offset = 0;
6300 	u_int32_t route_rule_id = 0;
6301 	struct necp_route_rule *existing_rule = NULL;
6302 	u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6303 	u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6304 	u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6305 	u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6306 	u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6307 	u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6308 	u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6309 	u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6310 	u_int8_t ultra_constrained_action = NECP_ROUTE_RULE_NONE;
6311 	u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6312 	size_t num_valid_indices = 0;
6313 	memset(&if_indices, 0, sizeof(if_indices));
6314 	u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6315 	memset(&if_actions, 0, sizeof(if_actions));
6316 
6317 	uuid_t netagent_uuid = {};
6318 
6319 	uuid_t match_netagent_uuid = {};
6320 	uint32_t control_unit = 0;
6321 	uint32_t effective_type = 0;
6322 
6323 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6324 
6325 	if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6326 		return 0;
6327 	}
6328 
6329 	// Process rules
6330 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6331 		ifnet_t __single rule_interface = NULL;
6332 		char interface_name[IFXNAMSIZ];
6333 		u_int32_t length = 0;
6334 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6335 
6336 		if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6337 			// Invalid TLV goes beyond end of the rules array
6338 			break;
6339 		}
6340 
6341 		// Increment offset for the next time through the loop
6342 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6343 
6344 		u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6345 		u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6346 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6347 		u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6348 
6349 		if (rule_action == NECP_ROUTE_RULE_NONE) {
6350 			// Don't allow an explicit rule to be None action
6351 			continue;
6352 		}
6353 
6354 		if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6355 		    rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6356 			if (rule_length < sizeof(uuid_t)) {
6357 				// Too short, skip
6358 				continue;
6359 			}
6360 
6361 			if (!uuid_is_null(netagent_uuid)) {
6362 				if (uuid_compare(netagent_uuid, rule_value) != 0) {
6363 					// UUIDs don't match, skip
6364 					continue;
6365 				}
6366 			} else {
6367 				// Copy out agent UUID
6368 				memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6369 			}
6370 
6371 			// Adjust remaining length
6372 			rule_value += sizeof(netagent_uuid);
6373 			rule_length -= sizeof(netagent_uuid);
6374 			*has_socket_only_actions = true;
6375 		} else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6376 			if (rule_length < sizeof(control_unit)) {
6377 				// Too short, skip
6378 				continue;
6379 			}
6380 
6381 			memcpy(&control_unit, rule_value, sizeof(control_unit));
6382 
6383 			// Adjust remaining length
6384 			rule_value += sizeof(control_unit);
6385 			rule_length -= sizeof(control_unit);
6386 			*has_socket_only_actions = true;
6387 		} else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6388 			if (rule_length < sizeof(effective_type)) {
6389 				// Too short, skip
6390 				continue;
6391 			}
6392 
6393 			memcpy(&effective_type, rule_value, sizeof(effective_type));
6394 
6395 			// Adjust remaining length
6396 			rule_value += sizeof(effective_type);
6397 			rule_length -= sizeof(effective_type);
6398 		}
6399 
6400 		if (rule_length == 0) {
6401 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6402 				cellular_action = rule_action;
6403 			}
6404 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6405 				wifi_action = rule_action;
6406 			}
6407 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6408 				wired_action = rule_action;
6409 			}
6410 			if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6411 				expensive_action = rule_action;
6412 			}
6413 			if ((rule_flags & NECP_ROUTE_RULE_FLAG_ULTRA_CONSTRAINED) == NECP_ROUTE_RULE_FLAG_ULTRA_CONSTRAINED) {
6414 				ultra_constrained_action = rule_action;
6415 			} else if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6416 				constrained_action = rule_action;
6417 			}
6418 			if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6419 				companion_action = rule_action;
6420 			}
6421 			if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6422 				vpn_action = rule_action;
6423 			}
6424 			if (rule_flags == 0) {
6425 				default_action = rule_action;
6426 			}
6427 			continue;
6428 		} else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6429 			if (rule_length < sizeof(uuid_t)) {
6430 				// Too short, skip
6431 				continue;
6432 			}
6433 
6434 			// Store the netagent UUID to match
6435 			memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6436 			// If the data is exactly a UUID, this is the default action
6437 			if (rule_length == sizeof(uuid_t)) {
6438 				default_action = rule_action;
6439 				continue;
6440 			}
6441 
6442 			// If the data is longer than a UUID, this also includes an interface name
6443 			// Adjust remaining length to make sure the interface name is picked up below
6444 			rule_value += sizeof(uuid_t);
6445 			rule_length -= sizeof(uuid_t);
6446 		}
6447 
6448 		if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6449 			continue;
6450 		}
6451 
6452 		if (rule_length <= IFXNAMSIZ) {
6453 			memcpy(interface_name, rule_value, rule_length);
6454 			interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6455 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6456 				if_actions[num_valid_indices] = rule_action;
6457 				if_indices[num_valid_indices++] = rule_interface->if_index;
6458 				ifnet_release(rule_interface);
6459 			}
6460 		}
6461 	}
6462 
6463 	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, ultra_constrained_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6464 	if (existing_rule != NULL) {
6465 		route_rule_id = existing_rule->id;
6466 		os_ref_retain_locked(&existing_rule->refcount);
6467 	} else {
6468 		struct necp_route_rule *new_rule = NULL;
6469 		new_rule = kalloc_type(struct necp_route_rule,
6470 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6471 		route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6472 		if (!uuid_is_null(netagent_uuid)) {
6473 			new_rule->netagent_id = necp_create_agent_uuid_id_mapping(netagent_uuid);
6474 		}
6475 		if (!uuid_is_null(match_netagent_uuid)) {
6476 			new_rule->match_netagent_id = necp_create_agent_uuid_id_mapping(match_netagent_uuid);
6477 		}
6478 		new_rule->effective_type = effective_type;
6479 		new_rule->control_unit = control_unit;
6480 		new_rule->default_action = default_action;
6481 		new_rule->cellular_action = cellular_action;
6482 		new_rule->wifi_action = wifi_action;
6483 		new_rule->wired_action = wired_action;
6484 		new_rule->expensive_action = expensive_action;
6485 		new_rule->constrained_action = constrained_action;
6486 		new_rule->companion_action = companion_action;
6487 		new_rule->vpn_action = vpn_action;
6488 		new_rule->ultra_constrained_action = ultra_constrained_action;
6489 		memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6490 		memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6491 		os_ref_init(&new_rule->refcount, &necp_refgrp);
6492 		LIST_INSERT_HEAD(list, new_rule, chain);
6493 	}
6494 	return route_rule_id;
6495 }
6496 
6497 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6498 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6499 {
6500 	if (rule_id) {
6501 		lck_rw_lock_exclusive(&necp_route_rule_lock);
6502 
6503 		struct necp_aggregate_route_rule * __single existing_rule = NULL;
6504 		struct necp_aggregate_route_rule *tmp_rule = NULL;
6505 
6506 		LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6507 			int index = 0;
6508 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6509 				u_int32_t route_rule_id = existing_rule->rule_ids[index];
6510 				if (route_rule_id == rule_id) {
6511 					LIST_REMOVE(existing_rule, chain);
6512 					kfree_type(struct necp_aggregate_route_rule, existing_rule);
6513 					break;
6514 				}
6515 			}
6516 		}
6517 
6518 		lck_rw_done(&necp_route_rule_lock);
6519 	}
6520 }
6521 
6522 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6523 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6524 {
6525 	struct necp_route_rule * __single existing_rule = NULL;
6526 
6527 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6528 
6529 	existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6530 	if (existing_rule != NULL) {
6531 		if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6532 			necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6533 			necp_remove_agent_uuid_id_mapping_with_agent_id(existing_rule->netagent_id);
6534 			necp_remove_agent_uuid_id_mapping_with_agent_id(existing_rule->match_netagent_id);
6535 			LIST_REMOVE(existing_rule, chain);
6536 			kfree_type(struct necp_route_rule, existing_rule);
6537 		}
6538 		return TRUE;
6539 	}
6540 
6541 	return FALSE;
6542 }
6543 
6544 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6545 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6546 {
6547 	struct necp_aggregate_route_rule *searchentry = NULL;
6548 	struct necp_aggregate_route_rule *foundentry = NULL;
6549 
6550 	lck_rw_lock_shared(&necp_route_rule_lock);
6551 
6552 	LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6553 		if (searchentry->id == route_rule_id) {
6554 			foundentry = searchentry;
6555 			break;
6556 		}
6557 	}
6558 
6559 	lck_rw_done(&necp_route_rule_lock);
6560 
6561 	return foundentry;
6562 }
6563 
6564 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6565 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6566 {
6567 	u_int32_t aggregate_route_rule_id = 0;
6568 	struct necp_aggregate_route_rule *new_rule = NULL;
6569 	struct necp_aggregate_route_rule *existing_rule = NULL;
6570 
6571 	lck_rw_lock_exclusive(&necp_route_rule_lock);
6572 
6573 	// Check if the rule already exists
6574 	LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6575 		if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6576 			lck_rw_done(&necp_route_rule_lock);
6577 			return existing_rule->id;
6578 		}
6579 	}
6580 
6581 	new_rule = kalloc_type(struct necp_aggregate_route_rule,
6582 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6583 	aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6584 	new_rule->id = aggregate_route_rule_id;
6585 	memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6586 	LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6587 	lck_rw_done(&necp_route_rule_lock);
6588 
6589 	return aggregate_route_rule_id;
6590 }
6591 
6592 static u_int32_t
necp_get_new_app_uuid_id(void)6593 necp_get_new_app_uuid_id(void)
6594 {
6595 	static u_int32_t necp_last_app_uuid_id = 0;
6596 
6597 	u_int32_t newid = 0;
6598 
6599 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6600 
6601 	bool wrapped = FALSE;
6602 	do {
6603 		necp_last_app_uuid_id++;
6604 		if (necp_last_app_uuid_id < 1) {
6605 			if (wrapped) {
6606 				// Already wrapped, give up
6607 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID ID.\n");
6608 				return 0;
6609 			}
6610 			necp_last_app_uuid_id = 1;
6611 			wrapped = TRUE;
6612 		}
6613 		newid = necp_last_app_uuid_id;
6614 	} while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6615 
6616 	if (newid == 0) {
6617 		NECPLOG0(LOG_ERR, "Allocate app UUID ID failed.\n");
6618 		return 0;
6619 	}
6620 
6621 	return newid;
6622 }
6623 
6624 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6625 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6626 {
6627 	struct necp_uuid_id_mapping *searchentry = NULL;
6628 	struct necp_uuid_id_mapping *foundentry = NULL;
6629 
6630 	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6631 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6632 			foundentry = searchentry;
6633 			break;
6634 		}
6635 	}
6636 
6637 	return foundentry;
6638 }
6639 
6640 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6641 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6642 {
6643 	struct necp_uuid_id_mapping *searchentry = NULL;
6644 	struct necp_uuid_id_mapping *foundentry = NULL;
6645 
6646 	struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6647 	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--) {
6648 		LIST_FOREACH(searchentry, uuid_list_head, chain) {
6649 			if (searchentry->id == local_id) {
6650 				foundentry = searchentry;
6651 				break;
6652 			}
6653 		}
6654 	}
6655 
6656 	return foundentry;
6657 }
6658 
6659 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6660 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6661 {
6662 	u_int32_t local_id = 0;
6663 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6664 
6665 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6666 
6667 	if (allocated_mapping) {
6668 		*allocated_mapping = FALSE;
6669 	}
6670 
6671 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6672 	if (existing_mapping != NULL) {
6673 		local_id = existing_mapping->id;
6674 		os_ref_retain_locked(&existing_mapping->refcount);
6675 		if (uuid_policy_table) {
6676 			existing_mapping->table_usecount++;
6677 		}
6678 	} else {
6679 		struct necp_uuid_id_mapping *new_mapping = NULL;
6680 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6681 		    Z_WAITOK | Z_NOFAIL);
6682 		uuid_copy(new_mapping->uuid, uuid);
6683 		new_mapping->id = necp_get_new_app_uuid_id();
6684 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6685 		if (uuid_policy_table) {
6686 			new_mapping->table_usecount = 1;
6687 		} else {
6688 			new_mapping->table_usecount = 0;
6689 		}
6690 
6691 		LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6692 
6693 		if (allocated_mapping) {
6694 			*allocated_mapping = TRUE;
6695 		}
6696 
6697 		local_id = new_mapping->id;
6698 	}
6699 
6700 	return local_id;
6701 }
6702 
6703 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6704 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6705 {
6706 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6707 
6708 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6709 
6710 	if (removed_mapping) {
6711 		*removed_mapping = FALSE;
6712 	}
6713 
6714 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6715 	if (existing_mapping != NULL) {
6716 		if (uuid_policy_table) {
6717 			existing_mapping->table_usecount--;
6718 		}
6719 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6720 			LIST_REMOVE(existing_mapping, chain);
6721 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6722 			if (removed_mapping) {
6723 				*removed_mapping = TRUE;
6724 			}
6725 		}
6726 		return TRUE;
6727 	}
6728 
6729 	return FALSE;
6730 }
6731 
6732 #define NECP_NULL_AGENT_ID 1
6733 #define NECP_FIRST_VALID_AGENT_UUID_ID  2
6734 #define NECP_FIRST_VALID_AGENT_TYPE_ID  UINT16_MAX
6735 
6736 static bool
necp_agent_id_is_uuid(u_int32_t agent_id)6737 necp_agent_id_is_uuid(u_int32_t agent_id)
6738 {
6739 	return agent_id < NECP_FIRST_VALID_AGENT_TYPE_ID;
6740 }
6741 
6742 static u_int32_t
necp_get_new_agent_id(bool uuid)6743 necp_get_new_agent_id(bool uuid)
6744 {
6745 	static u_int32_t necp_last_agent_id = 0;
6746 	static u_int32_t necp_last_agent_type_id = 0;
6747 
6748 	u_int32_t newid = 0;
6749 
6750 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6751 
6752 	if (uuid) {
6753 		bool wrapped = FALSE;
6754 		do {
6755 			necp_last_agent_id++;
6756 			if (necp_last_agent_id < NECP_FIRST_VALID_AGENT_UUID_ID ||
6757 			    necp_last_agent_id >= NECP_FIRST_VALID_AGENT_TYPE_ID) {
6758 				if (wrapped) {
6759 					// Already wrapped, give up
6760 					NECPLOG0(LOG_ERR, "Failed to find a free agent UUID ID.\n");
6761 					return NECP_NULL_AGENT_ID;
6762 				}
6763 				necp_last_agent_id = NECP_FIRST_VALID_AGENT_UUID_ID;
6764 				wrapped = TRUE;
6765 			}
6766 			newid = necp_last_agent_id;
6767 		} while (necp_uuid_lookup_uuid_with_agent_id_locked(newid) != NULL); // If already used, keep trying
6768 	} else {
6769 		bool wrapped = FALSE;
6770 		do {
6771 			necp_last_agent_type_id++;
6772 			if (necp_last_agent_type_id < NECP_FIRST_VALID_AGENT_TYPE_ID) {
6773 				if (wrapped) {
6774 					// Already wrapped, give up
6775 					NECPLOG0(LOG_ERR, "Failed to find a free agent type ID.\n");
6776 					return NECP_NULL_AGENT_ID;
6777 				}
6778 				necp_last_agent_type_id = NECP_FIRST_VALID_AGENT_TYPE_ID;
6779 				wrapped = TRUE;
6780 			}
6781 			newid = necp_last_agent_type_id;
6782 		} while (necp_lookup_agent_type_with_id_locked(newid) != NULL); // If already used, keep trying
6783 	}
6784 
6785 	if (newid == NECP_NULL_AGENT_ID) {
6786 		NECPLOG0(LOG_ERR, "Allocate agent ID failed.\n");
6787 		return NECP_NULL_AGENT_ID;
6788 	}
6789 
6790 	return newid;
6791 }
6792 
6793 static struct necp_uuid_id_mapping *
necp_uuid_get_null_agent_id_mapping(void)6794 necp_uuid_get_null_agent_id_mapping(void)
6795 {
6796 	static struct necp_uuid_id_mapping null_mapping;
6797 	uuid_clear(null_mapping.uuid);
6798 	null_mapping.id = NECP_NULL_AGENT_ID;
6799 
6800 	return &null_mapping;
6801 }
6802 
6803 static struct necp_uuid_id_mapping *
necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid)6804 necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid)
6805 {
6806 	struct necp_uuid_id_mapping *searchentry = NULL;
6807 	struct necp_uuid_id_mapping *foundentry = NULL;
6808 
6809 	if (uuid_is_null(uuid)) {
6810 		return necp_uuid_get_null_agent_id_mapping();
6811 	}
6812 
6813 	LIST_FOREACH(searchentry, &necp_agent_uuid_id_list, chain) {
6814 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6815 			foundentry = searchentry;
6816 			break;
6817 		}
6818 	}
6819 
6820 	return foundentry;
6821 }
6822 
6823 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id)6824 necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id)
6825 {
6826 	struct necp_uuid_id_mapping *searchentry = NULL;
6827 	struct necp_uuid_id_mapping *foundentry = NULL;
6828 
6829 	if (agent_id == NECP_NULL_AGENT_ID) {
6830 		return necp_uuid_get_null_agent_id_mapping();
6831 	}
6832 
6833 	LIST_FOREACH(searchentry, &necp_agent_uuid_id_list, chain) {
6834 		if (searchentry->id == agent_id) {
6835 			foundentry = searchentry;
6836 			break;
6837 		}
6838 	}
6839 
6840 	return foundentry;
6841 }
6842 
6843 static u_int32_t
necp_create_agent_uuid_id_mapping(uuid_t uuid)6844 necp_create_agent_uuid_id_mapping(uuid_t uuid)
6845 {
6846 	u_int32_t agent_id = 0;
6847 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6848 
6849 	if (uuid_is_null(uuid)) {
6850 		return NECP_NULL_AGENT_ID;
6851 	}
6852 
6853 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6854 
6855 	existing_mapping = necp_uuid_lookup_agent_id_with_uuid_locked(uuid);
6856 	if (existing_mapping != NULL) {
6857 		agent_id = existing_mapping->id;
6858 		os_ref_retain_locked(&existing_mapping->refcount);
6859 	} else {
6860 		struct necp_uuid_id_mapping *new_mapping = NULL;
6861 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6862 		    Z_WAITOK | Z_NOFAIL);
6863 		uuid_copy(new_mapping->uuid, uuid);
6864 		new_mapping->id = necp_get_new_agent_id(true);
6865 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6866 
6867 		LIST_INSERT_HEAD(&necp_agent_uuid_id_list, new_mapping, chain);
6868 
6869 		agent_id = new_mapping->id;
6870 	}
6871 
6872 	return agent_id;
6873 }
6874 
6875 static bool
necp_remove_agent_uuid_id_mapping(uuid_t uuid)6876 necp_remove_agent_uuid_id_mapping(uuid_t uuid)
6877 {
6878 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6879 
6880 	if (uuid_is_null(uuid)) {
6881 		return TRUE;
6882 	}
6883 
6884 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6885 
6886 	existing_mapping = necp_uuid_lookup_agent_id_with_uuid_locked(uuid);
6887 	if (existing_mapping != NULL) {
6888 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6889 			LIST_REMOVE(existing_mapping, chain);
6890 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6891 		}
6892 		return TRUE;
6893 	}
6894 
6895 	return FALSE;
6896 }
6897 
6898 static bool
necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id)6899 necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id)
6900 {
6901 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6902 
6903 	if (agent_id == 0) {
6904 		return TRUE;
6905 	}
6906 
6907 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6908 
6909 	existing_mapping = necp_uuid_lookup_uuid_with_agent_id_locked(agent_id);
6910 	if (existing_mapping != NULL) {
6911 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6912 			LIST_REMOVE(existing_mapping, chain);
6913 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6914 		}
6915 		return TRUE;
6916 	}
6917 
6918 	return FALSE;
6919 }
6920 
6921 static struct necp_agent_type_id_mapping *
necp_lookup_agent_type_to_id_locked(struct necp_policy_condition_agent_type * agent_type)6922 necp_lookup_agent_type_to_id_locked(struct necp_policy_condition_agent_type *agent_type)
6923 {
6924 	struct necp_agent_type_id_mapping *searchentry = NULL;
6925 	struct necp_agent_type_id_mapping *foundentry = NULL;
6926 
6927 	LIST_FOREACH(searchentry, &necp_agent_type_id_list, chain) {
6928 		if (strlcmp(searchentry->agent_type.agent_domain, __unsafe_null_terminated_from_indexable(agent_type->agent_domain), NETAGENT_DOMAINSIZE) == 0 &&
6929 		    strlcmp(searchentry->agent_type.agent_type, __unsafe_null_terminated_from_indexable(agent_type->agent_type), NETAGENT_TYPESIZE) == 0) {
6930 			foundentry = searchentry;
6931 			break;
6932 		}
6933 	}
6934 
6935 	return foundentry;
6936 }
6937 
6938 static struct necp_agent_type_id_mapping *
necp_lookup_agent_type_with_id_locked(u_int32_t agent_id)6939 necp_lookup_agent_type_with_id_locked(u_int32_t agent_id)
6940 {
6941 	struct necp_agent_type_id_mapping *searchentry = NULL;
6942 	struct necp_agent_type_id_mapping *foundentry = NULL;
6943 
6944 	LIST_FOREACH(searchentry, &necp_agent_type_id_list, chain) {
6945 		if (searchentry->id == agent_id) {
6946 			foundentry = searchentry;
6947 			break;
6948 		}
6949 	}
6950 
6951 	return foundentry;
6952 }
6953 
6954 static u_int32_t
necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type * agent_type)6955 necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type *agent_type)
6956 {
6957 	u_int32_t agent_type_id = 0;
6958 	struct necp_agent_type_id_mapping *existing_mapping = NULL;
6959 
6960 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6961 
6962 	existing_mapping = necp_lookup_agent_type_to_id_locked(agent_type);
6963 	if (existing_mapping != NULL) {
6964 		agent_type_id = existing_mapping->id;
6965 		os_ref_retain_locked(&existing_mapping->refcount);
6966 	} else {
6967 		struct necp_agent_type_id_mapping * __single new_mapping = NULL;
6968 		new_mapping = kalloc_type(struct necp_agent_type_id_mapping,
6969 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6970 		strlcpy(new_mapping->agent_type.agent_domain, __unsafe_null_terminated_from_indexable(agent_type->agent_domain), NETAGENT_DOMAINSIZE);
6971 		strlcpy(new_mapping->agent_type.agent_type, __unsafe_null_terminated_from_indexable(agent_type->agent_type), NETAGENT_TYPESIZE);
6972 		new_mapping->id = necp_get_new_agent_id(false);
6973 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6974 		LIST_INSERT_HEAD(&necp_agent_type_id_list, new_mapping, chain);
6975 		agent_type_id = new_mapping->id;
6976 	}
6977 	return agent_type_id;
6978 }
6979 
6980 static bool
necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id)6981 necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id)
6982 {
6983 	struct necp_agent_type_id_mapping * __single existing_mapping = NULL;
6984 
6985 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6986 
6987 	existing_mapping = necp_lookup_agent_type_with_id_locked(agent_type_id);
6988 	if (existing_mapping != NULL) {
6989 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6990 			LIST_REMOVE(existing_mapping, chain);
6991 			kfree_type(struct necp_agent_type_id_mapping, existing_mapping);
6992 		}
6993 		return true;
6994 	}
6995 
6996 	return false;
6997 }
6998 
6999 static bool
necp_kernel_socket_policies_update_uuid_table(void)7000 necp_kernel_socket_policies_update_uuid_table(void)
7001 {
7002 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7003 
7004 	if (necp_uuid_app_id_mappings_dirty) {
7005 		uuid_t dummy_uuid = {};
7006 		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
7007 			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
7008 			return FALSE;
7009 		}
7010 
7011 		if (necp_num_uuid_app_id_mappings > 0) {
7012 			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
7013 			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--) {
7014 				struct necp_uuid_id_mapping *mapping = NULL;
7015 				LIST_FOREACH(mapping, uuid_list_head, chain) {
7016 					if (mapping->table_usecount > 0 &&
7017 					    proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
7018 						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
7019 					}
7020 				}
7021 			}
7022 		}
7023 
7024 		necp_uuid_app_id_mappings_dirty = FALSE;
7025 	}
7026 
7027 	return TRUE;
7028 }
7029 
7030 #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)
7031 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)7032 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)
7033 {
7034 	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
7035 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7036 
7037 	new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
7038 	new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
7039 	new_kernel_policy->suborder = suborder;
7040 	new_kernel_policy->order = order;
7041 	new_kernel_policy->session_order = session_order;
7042 	new_kernel_policy->session_pid = session_pid;
7043 
7044 	// Sanitize condition mask
7045 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
7046 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
7047 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
7048 	}
7049 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
7050 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
7051 	}
7052 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
7053 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
7054 	}
7055 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
7056 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
7057 	}
7058 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
7059 
7060 	// Set condition values
7061 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
7062 		new_kernel_policy->cond_policy_id = cond_policy_id;
7063 	}
7064 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
7065 		if (cond_bound_interface) {
7066 			ifnet_reference(cond_bound_interface);
7067 		}
7068 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
7069 	}
7070 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
7071 		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
7072 	}
7073 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
7074 		new_kernel_policy->cond_protocol = cond_protocol;
7075 	}
7076 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7077 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
7078 	}
7079 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7080 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
7081 	}
7082 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7083 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
7084 	}
7085 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7086 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
7087 	}
7088 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7089 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7090 	}
7091 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7092 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7093 	}
7094 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7095 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7096 	}
7097 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7098 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
7099 	}
7100 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7101 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7102 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7103 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7104 	}
7105 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7106 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7107 	}
7108 
7109 	new_kernel_policy->result = result;
7110 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7111 
7112 	if (necp_debug) {
7113 		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7114 	}
7115 	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7116 
7117 	return new_kernel_policy ? new_kernel_policy->id : 0;
7118 }
7119 
7120 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7121 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7122 {
7123 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7124 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7125 
7126 	if (policy_id == 0) {
7127 		return NULL;
7128 	}
7129 
7130 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7131 		if (kernel_policy->id == policy_id) {
7132 			return kernel_policy;
7133 		}
7134 	}
7135 
7136 	return NULL;
7137 }
7138 
7139 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7140 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7141 {
7142 	struct necp_kernel_ip_output_policy * __single policy = NULL;
7143 
7144 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7145 
7146 	policy = necp_kernel_ip_output_policy_find(policy_id);
7147 	if (policy) {
7148 		LIST_REMOVE(policy, chain);
7149 
7150 		if (policy->cond_bound_interface) {
7151 			ifnet_release(policy->cond_bound_interface);
7152 			policy->cond_bound_interface = NULL;
7153 		}
7154 
7155 		zfree(necp_ip_policy_zone, policy);
7156 		return TRUE;
7157 	}
7158 
7159 	return FALSE;
7160 }
7161 
7162 static void
necp_kernel_ip_output_policies_dump_all(void)7163 necp_kernel_ip_output_policies_dump_all(void)
7164 {
7165 	if (necp_debug) {
7166 		struct necp_kernel_ip_output_policy *policy = NULL;
7167 		int policy_i;
7168 		int id_i;
7169 		char result_string[MAX_RESULT_STRING_LEN];
7170 		char proc_name_string[MAXCOMLEN + 1];
7171 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
7172 		memset(proc_name_string, 0, MAXCOMLEN + 1);
7173 
7174 		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7175 		NECPLOG0(LOG_DEBUG, "-----------\n");
7176 		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7177 			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7178 			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++) {
7179 				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7180 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7181 				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));
7182 			}
7183 			NECPLOG0(LOG_DEBUG, "-----------\n");
7184 		}
7185 	}
7186 }
7187 
7188 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)7189 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7190 {
7191 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7192 		if (upper_policy->session_order != lower_policy->session_order) {
7193 			// A skip cannot override a policy of a different session
7194 			return FALSE;
7195 		} else {
7196 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
7197 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7198 				// This policy is beyond the skip
7199 				return FALSE;
7200 			} else {
7201 				// This policy is inside the skip
7202 				return TRUE;
7203 			}
7204 		}
7205 	}
7206 
7207 	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7208 	return TRUE;
7209 }
7210 
7211 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)7212 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)
7213 {
7214 	bool can_skip = FALSE;
7215 	u_int32_t highest_skip_session_order = 0;
7216 	u_int32_t highest_skip_order = 0;
7217 	int i;
7218 	for (i = 0; i < valid_indices; i++) {
7219 		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7220 
7221 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
7222 		if (can_skip) {
7223 			if (highest_skip_session_order != compared_policy->session_order ||
7224 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7225 				// If we've moved on to the next session, or passed the skip window
7226 				highest_skip_session_order = 0;
7227 				highest_skip_order = 0;
7228 				can_skip = FALSE;
7229 			} else {
7230 				// If this policy is also a skip, in can increase the skip window
7231 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7232 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7233 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7234 					}
7235 				}
7236 				continue;
7237 			}
7238 		}
7239 
7240 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7241 			// This policy is a skip. Set the skip window accordingly
7242 			can_skip = TRUE;
7243 			highest_skip_session_order = compared_policy->session_order;
7244 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7245 		}
7246 
7247 		// The result of the compared policy must be able to block out this policy result
7248 		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7249 			continue;
7250 		}
7251 
7252 		// If new policy matches All Interfaces, compared policy must also
7253 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7254 			continue;
7255 		}
7256 
7257 		// If new policy matches Local Networks, compared policy must also
7258 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7259 			continue;
7260 		}
7261 
7262 		// Default makes lower policies unnecessary always
7263 		if (compared_policy->condition_mask == 0) {
7264 			return TRUE;
7265 		}
7266 
7267 		// Compared must be more general than policy, and include only conditions within policy
7268 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7269 			continue;
7270 		}
7271 
7272 		// Negative conditions must match for the overlapping conditions
7273 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7274 			continue;
7275 		}
7276 
7277 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7278 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
7279 			continue;
7280 		}
7281 
7282 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7283 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7284 			continue;
7285 		}
7286 
7287 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7288 		    compared_policy->cond_protocol != policy->cond_protocol) {
7289 			continue;
7290 		}
7291 
7292 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7293 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7294 				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))) {
7295 					continue;
7296 				}
7297 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7298 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7299 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7300 					continue;
7301 				}
7302 			}
7303 		}
7304 
7305 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7306 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7307 				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))) {
7308 					continue;
7309 				}
7310 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7311 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7312 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7313 					continue;
7314 				}
7315 			}
7316 		}
7317 
7318 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7319 		    compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7320 			continue;
7321 		}
7322 
7323 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7324 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7325 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7326 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7327 			continue;
7328 		}
7329 
7330 		return TRUE;
7331 	}
7332 
7333 	return FALSE;
7334 }
7335 
7336 static bool
necp_kernel_ip_output_policies_reprocess(void)7337 necp_kernel_ip_output_policies_reprocess(void)
7338 {
7339 	int i;
7340 	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7341 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7342 
7343 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7344 
7345 	// Reset mask to 0
7346 	necp_kernel_ip_output_policies_condition_mask = 0;
7347 	necp_kernel_ip_output_policies_count = 0;
7348 	necp_kernel_ip_output_policies_non_id_count = 0;
7349 
7350 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7351 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7352 			kfree_type(struct necp_kernel_ip_output_policy *,
7353 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7354 			    necp_kernel_ip_output_policies_map[i]);
7355 			necp_kernel_ip_output_policies_map[i] = NULL;
7356 		}
7357 
7358 		// Init counts
7359 		necp_kernel_ip_output_policies_map_counts[i] = 0;
7360 	}
7361 
7362 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7363 		// Update mask
7364 		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7365 		necp_kernel_ip_output_policies_count++;
7366 
7367 		/* Update bucket counts:
7368 		 * Non-id and SKIP policies will be added to all buckets
7369 		 * Add local networks policy to all buckets for incoming IP
7370 		 */
7371 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7372 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7373 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7374 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7375 				necp_kernel_ip_output_policies_map_counts[i]++;
7376 			}
7377 		}
7378 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7379 			necp_kernel_ip_output_policies_non_id_count++;
7380 		} else {
7381 			necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7382 		}
7383 	}
7384 
7385 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7386 		if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7387 			// Allocate a NULL-terminated array of policy pointers for each bucket
7388 			necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7389 			    necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7390 			if (necp_kernel_ip_output_policies_map[i] == NULL) {
7391 				goto fail;
7392 			}
7393 		}
7394 		bucket_current_free_index[i] = 0;
7395 	}
7396 
7397 	u_int32_t current_session_order = 0;
7398 	u_int32_t current_session_last_non_skip_policy = 0;
7399 
7400 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7401 		// For each new session, find the last non-skip policy. We can
7402 		// avoid adding any skip policies that don't actually skip over
7403 		// any non-skip policies.
7404 		if (current_session_order != kernel_policy->session_order) {
7405 			current_session_order = kernel_policy->session_order;
7406 			current_session_last_non_skip_policy = 0;
7407 
7408 			struct necp_kernel_ip_output_policy *inner_policy = NULL;
7409 			LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7410 				if (inner_policy->session_order < current_session_order) {
7411 					continue;
7412 				}
7413 				if (inner_policy->session_order > current_session_order) {
7414 					break;
7415 				}
7416 				if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7417 					continue;
7418 				}
7419 
7420 				current_session_last_non_skip_policy = inner_policy->order;
7421 			}
7422 		}
7423 
7424 		if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7425 			if (current_session_last_non_skip_policy == 0) {
7426 				// No useful policies to skip over, don't add
7427 				continue;
7428 			}
7429 			if (kernel_policy->order >= current_session_last_non_skip_policy) {
7430 				// Skip policy is after the last useful policy, don't add
7431 				continue;
7432 			}
7433 		}
7434 
7435 		// Insert pointers into map
7436 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7437 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7438 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7439 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7440 				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])) {
7441 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7442 					bucket_current_free_index[i]++;
7443 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7444 				}
7445 			}
7446 		} else {
7447 			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7448 			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])) {
7449 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7450 				bucket_current_free_index[i]++;
7451 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7452 			}
7453 		}
7454 	}
7455 
7456 	if (bucket_current_free_index[0] == 0) {
7457 		// No non-id policies were actually added
7458 		necp_kernel_ip_output_policies_non_id_count = 0;
7459 
7460 		// Also check if no policies at all were added
7461 		bool policies_added = FALSE;
7462 		for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7463 			if (bucket_current_free_index[i] != 0) {
7464 				policies_added = TRUE;
7465 				break;
7466 			}
7467 		}
7468 		if (!policies_added) {
7469 			necp_kernel_ip_output_policies_condition_mask = 0;
7470 			necp_kernel_ip_output_policies_count = 0;
7471 		}
7472 	}
7473 
7474 	necp_kernel_ip_output_policies_dump_all();
7475 	return TRUE;
7476 
7477 fail:
7478 	// Free memory, reset mask to 0
7479 	necp_kernel_ip_output_policies_condition_mask = 0;
7480 	necp_kernel_ip_output_policies_count = 0;
7481 	necp_kernel_ip_output_policies_non_id_count = 0;
7482 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7483 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7484 			kfree_type(struct necp_kernel_ip_output_policy *,
7485 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7486 			    necp_kernel_ip_output_policies_map[i]);
7487 			necp_kernel_ip_output_policies_map[i] = NULL;
7488 		}
7489 	}
7490 	return FALSE;
7491 }
7492 
7493 // Outbound Policy Matching
7494 // ---------------------
7495 struct substring {
7496 	size_t length;
7497 	char * __sized_by(length) string;
7498 };
7499 
7500 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7501 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7502 {
7503 	struct substring sub = {};
7504 	char * __indexable ptr = string;
7505 	size_t len = string ? length : 0;
7506 
7507 	while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7508 		ptr++;
7509 		len--;
7510 	}
7511 
7512 	while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7513 		len--;
7514 	}
7515 
7516 	sub.string = ptr;
7517 	sub.length = len;
7518 	return sub;
7519 }
7520 
7521 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7522 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7523 {
7524 	size_t trimmed_domain_length = 0;
7525 	char *trimmed_domain = NULL;
7526 	struct substring sub = necp_trim_dots_and_stars(string, length);
7527 
7528 	trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7529 	trimmed_domain_length = sub.length + 1;
7530 	if (trimmed_domain == NULL) {
7531 		return NULL;
7532 	}
7533 
7534 	strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7535 	trimmed_domain[sub.length] = 0;
7536 
7537 	return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7538 }
7539 
7540 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7541 necp_count_dots(char * __sized_by(length)string, size_t length)
7542 {
7543 	int dot_count = 0;
7544 	size_t i = 0;
7545 
7546 	for (i = 0; i < length; i++) {
7547 		if (string[i] == '.') {
7548 			dot_count++;
7549 		}
7550 	}
7551 
7552 	return dot_count;
7553 }
7554 
7555 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7556 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7557 {
7558 	if (parent.length <= suffix.length) {
7559 		return FALSE;
7560 	}
7561 
7562 	size_t length_difference = (parent.length - suffix.length);
7563 
7564 	if (require_dot_before_suffix) {
7565 		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7566 			return FALSE;
7567 		}
7568 	}
7569 
7570 	// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7571 	return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7572 }
7573 
7574 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)7575 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7576 {
7577 	if (hostname_substring.string == NULL || domain == NULL) {
7578 		return hostname_substring.string == domain;
7579 	}
7580 
7581 	struct substring domain_substring;
7582 	domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7583 	domain_substring.length = strlen(domain);
7584 
7585 	if (hostname_dot_count == domain_dot_count) {
7586 		// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7587 		if (hostname_substring.length == domain_substring.length &&
7588 		    strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7589 			return TRUE;
7590 		}
7591 	} else if (domain_dot_count < hostname_dot_count) {
7592 		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7593 			return TRUE;
7594 		}
7595 	}
7596 
7597 	return FALSE;
7598 }
7599 
7600 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7601 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7602 {
7603 	if (hostname_string == NULL ||
7604 	    domain_string == NULL) {
7605 		return false;
7606 	}
7607 
7608 	struct substring hostname_substring;
7609 	hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7610 	hostname_substring.length = strlen(hostname_string);
7611 
7612 	return necp_hostname_matches_domain(hostname_substring,
7613 	           necp_count_dots(hostname_substring.string, hostname_substring.length),
7614 	           domain_string,
7615 	           necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7616 }
7617 
7618 #define NECP_MAX_STRING_LEN 1024
7619 
7620 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7621 necp_copy_string(char * __sized_by(length)string, size_t length)
7622 {
7623 	size_t copied_string_length = 0;
7624 	char * __sized_by(copied_string_length) copied_string = NULL;
7625 
7626 	if (length > NECP_MAX_STRING_LEN) {
7627 		return NULL;
7628 	}
7629 
7630 	copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7631 	copied_string_length = length + 1;
7632 	if (copied_string == NULL) {
7633 		return NULL;
7634 	}
7635 
7636 	memcpy(copied_string, string, length);
7637 	copied_string[length] = 0;
7638 
7639 	return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7640 }
7641 
7642 static u_int32_t
necp_get_primary_direct_interface_index(void)7643 necp_get_primary_direct_interface_index(void)
7644 {
7645 	u_int32_t interface_index = IFSCOPE_NONE;
7646 
7647 	ifnet_head_lock_shared();
7648 	struct ifnet *ordered_interface = NULL;
7649 	TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7650 		const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7651 		if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7652 		    functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7653 			// All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7654 			interface_index = ordered_interface->if_index;
7655 			break;
7656 		}
7657 	}
7658 	ifnet_head_done();
7659 
7660 	return interface_index;
7661 }
7662 
7663 static inline bool
necp_task_has_match_entitlement(task_t task)7664 necp_task_has_match_entitlement(task_t task)
7665 {
7666 	return task != NULL &&
7667 	       (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7668 	       IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7669 }
7670 
7671 // Loopback traffic from certain entitled process will be dropped
7672 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7673 necp_task_has_loopback_drop_entitlement(task_t task)
7674 {
7675 	bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7676 	if (drop) {
7677 		necp_drop_loopback_count++;
7678 	}
7679 	return drop;
7680 }
7681 
7682 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7683 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7684 {
7685 	coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7686 
7687 	if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7688 		// No parent, nothing to do
7689 		return;
7690 	}
7691 
7692 	task_t __single lead_task = coalition_get_leader(coal);
7693 	if (lead_task != NULL) {
7694 		info->is_entitled = necp_task_has_match_entitlement(lead_task);
7695 		task_deallocate(lead_task);
7696 	}
7697 }
7698 
7699 // Some processes, due to particular entitlements, require using an NECP client to
7700 // access networking. Returns true if the result should be a Drop.
7701 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7702 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7703 {
7704 	if (necp_is_platform_binary(proc)) {
7705 		// This check is currently for the "on-demand-install-capable"
7706 		// entitlement, which by definition cannot be a built-in platform
7707 		// binary.
7708 		return false;
7709 	}
7710 
7711 	task_t __single task = proc_task(proc ? proc : current_proc());
7712 
7713 	if (!info->has_client &&
7714 	    task != NULL &&
7715 	    IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7716 		// Drop connections that don't use NECP clients and have the
7717 		// com.apple.developer.on-demand-install-capable entitlement.
7718 		// This effectively restricts those processes to only using
7719 		// an NECP-aware path for networking.
7720 		return true;
7721 	} else {
7722 		return false;
7723 	}
7724 }
7725 
7726 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7727 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7728 {
7729 	if (!necp_restrict_multicast || proc == NULL) {
7730 		return false;
7731 	}
7732 
7733 	// Check for multicast/broadcast here
7734 	if (info->remote_addr.sa.sa_family == AF_INET) {
7735 		if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7736 		    info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7737 			return false;
7738 		}
7739 	} else if (info->remote_addr.sa.sa_family == AF_INET6) {
7740 		if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7741 			return false;
7742 		}
7743 	} else {
7744 		// Not IPv4/IPv6
7745 		return false;
7746 	}
7747 
7748 	if (necp_is_platform_binary(proc)) {
7749 		return false;
7750 	}
7751 
7752 	const uint32_t platform = proc_platform(proc);
7753 	const uint32_t sdk = proc_sdk(proc);
7754 
7755 	// Enforce for iOS, linked on or after version 14
7756 	// If the caller set `check_minor_version`, only enforce starting at 14.5
7757 	if ((platform != PLATFORM_IOS ||
7758 	    sdk == 0 ||
7759 	    (sdk >> 16) < 14 ||
7760 	    (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7761 		return false;
7762 	}
7763 
7764 	// Allow entitled processes to use multicast
7765 	task_t __single task = proc_task(proc);
7766 	if (task != NULL &&
7767 	    IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7768 		return false;
7769 	}
7770 
7771 	const uint32_t min_sdk = proc_min_sdk(proc);
7772 	NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7773 
7774 	return true;
7775 }
7776 
7777 #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)
7778 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)7779 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)
7780 {
7781 	memset(info, 0, sizeof(struct necp_socket_info));
7782 
7783 	info->pid = pid;
7784 	info->pid_version = pid_version;
7785 	info->uid = uid;
7786 	info->real_uid = real_uid;
7787 	info->protocol = protocol;
7788 	info->bound_interface_index = bound_interface_index;
7789 	info->traffic_class = traffic_class;
7790 	info->has_client = has_client;
7791 	info->has_system_signed_result = has_system_signed_result;
7792 	info->drop_order = drop_order;
7793 	info->client_flags = client_flags;
7794 	info->is_loopback = is_loopback;
7795 	info->is_delegated = is_delegated;
7796 
7797 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7798 	    info->bound_interface_index != IFSCOPE_NONE) {
7799 		ifnet_head_lock_shared();
7800 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7801 		if (interface != NULL) {
7802 			info->bound_interface_flags = interface->if_flags;
7803 			info->bound_interface_eflags = interface->if_eflags;
7804 			info->bound_interface_xflags = interface->if_xflags;
7805 		}
7806 		ifnet_head_done();
7807 	}
7808 
7809 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7810 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7811 		if (existing_mapping) {
7812 			info->application_id = existing_mapping->id;
7813 		}
7814 	}
7815 
7816 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7817 		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7818 			info->real_application_id = info->application_id;
7819 		} else {
7820 			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7821 			if (existing_mapping) {
7822 				info->real_application_id = existing_mapping->id;
7823 			}
7824 		}
7825 	}
7826 
7827 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7828 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7829 		if (existing_mapping != NULL) {
7830 			info->real_application_id = info->application_id;
7831 			info->application_id = existing_mapping->id;
7832 			info->used_responsible_pid = true;
7833 		}
7834 	}
7835 
7836 	if (info->used_responsible_pid) {
7837 		proc = responsible_proc;
7838 	}
7839 
7840 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7841 		info->is_entitled = necp_task_has_match_entitlement(task);
7842 		if (!info->is_entitled) {
7843 			// Task does not have entitlement, check the parent task
7844 			necp_get_parent_is_entitled(task, info);
7845 		}
7846 	}
7847 
7848 	if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7849 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7850 		if (necp_is_platform_binary(proc)) {
7851 			info->is_platform_binary = true;
7852 		} else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7853 			info->is_platform_binary = true;
7854 			info->used_responsible_pid = true;
7855 		} else {
7856 			info->is_platform_binary = false;
7857 		}
7858 	}
7859 
7860 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7861 		info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7862 	}
7863 
7864 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7865 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7866 		if (existing_mapping) {
7867 			info->account_id = existing_mapping->id;
7868 		}
7869 	}
7870 
7871 	if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7872 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7873 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7874 		info->domain = domain;
7875 	}
7876 
7877 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7878 		info->url = url;
7879 	}
7880 
7881 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
7882 	    necp_restrict_multicast ||
7883 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7884 		if (local_addr && local_addr->sa.sa_len > 0) {
7885 			SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7886 			if (local_port != 0) {
7887 				info->local_addr.sin6.sin6_port = local_port;
7888 			}
7889 		} else {
7890 			if (remote_addr && remote_addr->sa.sa_len > 0) {
7891 				info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7892 				info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7893 			} else {
7894 				info->local_addr.sin6.sin6_family = AF_INET6;
7895 				info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7896 			}
7897 			if (local_port != 0) {
7898 				info->local_addr.sin6.sin6_port = local_port;
7899 			}
7900 		}
7901 		if (remote_addr && remote_addr->sa.sa_len > 0) {
7902 			SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7903 			if (remote_port != 0) {
7904 				info->remote_addr.sin6.sin6_port = remote_port;
7905 			}
7906 		} else if (remote_port != 0) {
7907 			info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7908 			info->remote_addr.sin6.sin6_family = AF_INET6;
7909 			info->remote_addr.sin6.sin6_port = remote_port;
7910 		}
7911 	}
7912 
7913 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7914 		info->scheme_port = scheme_port;
7915 	}
7916 }
7917 
7918 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7919 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7920 {
7921 	struct kev_netpolicy_ifdenied ev_ifdenied;
7922 
7923 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7924 
7925 	ev_ifdenied.ev_data.epid = pid;
7926 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7927 	ev_ifdenied.ev_if_functional_type = if_functional_type;
7928 
7929 	netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7930 }
7931 
7932 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7933 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7934 {
7935 	struct kev_netpolicy_netdenied ev_netdenied = {};
7936 
7937 	bzero(&ev_netdenied, sizeof(ev_netdenied));
7938 
7939 	ev_netdenied.ev_data.epid = pid;
7940 	uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7941 	ev_netdenied.ev_network_type = network_type;
7942 
7943 	netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7944 }
7945 
7946 extern char *proc_name_address(void *p);
7947 
7948 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7949 	if (!has_checked_delegation_entitlement) { \
7950 	        has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7951 	        has_checked_delegation_entitlement = TRUE; \
7952 	} \
7953 	if (!has_delegation_entitlement) { \
7954 	        NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7955 	                                          proc_name_address(_p), proc_pid(_p), _d); \
7956 	        break; \
7957 	}
7958 
7959 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)7960 necp_application_find_policy_match_internal(proc_t proc,
7961     u_int8_t * __sized_by(parameters_size)parameters,
7962     u_int32_t parameters_size,
7963     struct necp_aggregate_result *returned_result,
7964     u_int32_t *flags,
7965     u_int32_t *reason,
7966     u_int required_interface_index,
7967     const union necp_sockaddr_union *override_local_addr,
7968     const union necp_sockaddr_union *override_remote_addr,
7969     struct necp_client_endpoint *returned_v4_gateway,
7970     struct necp_client_endpoint *returned_v6_gateway,
7971     struct rtentry **returned_route, bool ignore_address,
7972     bool has_client,
7973     uuid_t *returned_override_euuid)
7974 {
7975 	int error = 0;
7976 	size_t offset = 0;
7977 
7978 	struct necp_kernel_socket_policy *matched_policy = NULL;
7979 	struct necp_socket_info info = {};
7980 	necp_kernel_policy_filter filter_control_unit = 0;
7981 
7982 	u_int64_t extended_client_flags = 0;
7983 	u_int16_t protocol = 0;
7984 	u_int32_t bound_interface_index = required_interface_index;
7985 	u_int32_t traffic_class = 0;
7986 	u_int32_t client_flags = 0;
7987 	u_int16_t scheme_port = 0;
7988 	union necp_sockaddr_union local_addr;
7989 	union necp_sockaddr_union remote_addr;
7990 	bool no_remote_addr = FALSE;
7991 	u_int8_t remote_family = 0;
7992 	bool no_local_addr = FALSE;
7993 	u_int16_t local_port = 0;
7994 	u_int16_t remote_port = 0;
7995 	u_int32_t remote_endpoint_type = 0;
7996 	bool remote_address_is_empty = false;
7997 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7998 	bool is_delegated = false;
7999 
8000 	if (override_local_addr) {
8001 		memcpy(&local_addr, override_local_addr, sizeof(local_addr));
8002 	} else {
8003 		memset(&local_addr, 0, sizeof(local_addr));
8004 	}
8005 	if (override_remote_addr) {
8006 		memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
8007 	} else {
8008 		memset(&remote_addr, 0, sizeof(remote_addr));
8009 	}
8010 
8011 	// Initialize UID, PID, and UUIDs to the current process
8012 	uid_t uid = 0;
8013 	uid_t real_uid = 0;
8014 	kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
8015 	if (cred != NULL) {
8016 		uid = kauth_cred_getuid(cred);
8017 		real_uid = uid;
8018 	}
8019 	task_t __single task = proc_task(proc);
8020 	pid_t pid = proc_pid(proc);
8021 	int32_t pid_version = proc_pidversion(proc);
8022 	uuid_t application_uuid;
8023 	uuid_clear(application_uuid);
8024 	uuid_t real_application_uuid;
8025 	uuid_clear(real_application_uuid);
8026 	proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
8027 	uuid_copy(application_uuid, real_application_uuid);
8028 	uuid_t responsible_application_uuid;
8029 	uuid_clear(responsible_application_uuid);
8030 
8031 	char *domain __null_terminated = NULL;
8032 	char *url __null_terminated = NULL;
8033 	char *account __null_terminated = NULL;
8034 
8035 #define NECP_MAX_REQUIRED_AGENTS 16
8036 	u_int32_t num_required_agent_types = 0;
8037 	struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
8038 	memset(&required_agent_types, 0, sizeof(required_agent_types));
8039 
8040 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
8041 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
8042 	memset(&netagent_ids, 0, sizeof(netagent_ids));
8043 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
8044 	int netagent_cursor;
8045 
8046 	bool has_checked_delegation_entitlement = false;
8047 	bool has_delegation_entitlement = false;
8048 	bool has_system_signed_result = false;
8049 
8050 	proc_t responsible_proc = PROC_NULL;
8051 	proc_t effective_proc = proc;
8052 	bool release_eproc = false;
8053 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
8054 
8055 	u_int32_t flow_divert_aggregate_unit = 0;
8056 
8057 	if (returned_result == NULL) {
8058 		if (cred != NULL) {
8059 			kauth_cred_unref(&cred);
8060 		}
8061 		return EINVAL;
8062 	}
8063 
8064 	if (returned_v4_gateway != NULL) {
8065 		memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
8066 	}
8067 
8068 	if (returned_v6_gateway != NULL) {
8069 		memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
8070 	}
8071 
8072 	if (returned_override_euuid != NULL) {
8073 		uuid_clear(*returned_override_euuid);
8074 	}
8075 
8076 	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
8077 
8078 	u_int32_t drop_order = necp_process_drop_order(cred);
8079 
8080 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
8081 
8082 	lck_rw_lock_shared(&necp_kernel_policy_lock);
8083 	if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
8084 		if (necp_drop_all_order > 0 || drop_order > 0) {
8085 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8086 			lck_rw_done(&necp_kernel_policy_lock);
8087 			if (cred != NULL) {
8088 				kauth_cred_unref(&cred);
8089 			}
8090 			return 0;
8091 		}
8092 	}
8093 	lck_rw_done(&necp_kernel_policy_lock);
8094 
8095 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8096 		u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8097 		u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8098 
8099 		if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8100 			// If the length is larger than what can fit in the remaining parameters size, bail
8101 			NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8102 			break;
8103 		}
8104 
8105 		if (length > 0) {
8106 			u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8107 			if (value != NULL) {
8108 				switch (type) {
8109 				case NECP_CLIENT_PARAMETER_APPLICATION: {
8110 					if (length >= sizeof(uuid_t)) {
8111 						if (uuid_compare(application_uuid, value) == 0) {
8112 							// No delegation
8113 							break;
8114 						}
8115 
8116 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8117 
8118 						is_delegated = true;
8119 						uuid_copy(application_uuid, value);
8120 					}
8121 					break;
8122 				}
8123 				case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8124 					if (length >= sizeof(uuid_t)) {
8125 						if (uuid_compare(real_application_uuid, value) == 0) {
8126 							// No delegation
8127 							break;
8128 						}
8129 
8130 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8131 
8132 						is_delegated = true;
8133 						uuid_copy(real_application_uuid, value);
8134 					}
8135 					break;
8136 				}
8137 				case NECP_CLIENT_PARAMETER_PID: {
8138 					if (length >= sizeof(pid_t)) {
8139 						if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8140 							// No delegation
8141 							break;
8142 						}
8143 
8144 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8145 
8146 						is_delegated = true;
8147 						memcpy(&pid, value, sizeof(pid_t));
8148 					}
8149 					break;
8150 				}
8151 				case NECP_CLIENT_PARAMETER_UID: {
8152 					if (length >= sizeof(uid_t)) {
8153 						if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8154 							// No delegation
8155 							break;
8156 						}
8157 
8158 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8159 
8160 						is_delegated = true;
8161 						memcpy(&uid, value, sizeof(uid_t));
8162 					}
8163 					break;
8164 				}
8165 				case NECP_CLIENT_PARAMETER_DOMAIN: {
8166 					char *ptr = (char *)value;
8167 					ptr[length - 1] = 0;
8168 					domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8169 					break;
8170 				}
8171 				case NECP_CLIENT_PARAMETER_URL: {
8172 					char *ptr = (char *)value;
8173 					ptr[length - 1] = 0;
8174 					url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8175 					break;
8176 				}
8177 				case NECP_CLIENT_PARAMETER_ACCOUNT: {
8178 					char *ptr = (char *)value;
8179 					ptr[length - 1] = 0;
8180 					account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8181 					break;
8182 				}
8183 				case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8184 					if (length >= sizeof(u_int32_t)) {
8185 						memcpy(&traffic_class, value, sizeof(u_int32_t));
8186 					}
8187 					break;
8188 				}
8189 				case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8190 					if (length >= sizeof(u_int16_t)) {
8191 						memcpy(&protocol, value, sizeof(u_int16_t));
8192 					} else if (length >= sizeof(u_int8_t)) {
8193 						memcpy(&protocol, value, sizeof(u_int8_t));
8194 					}
8195 					break;
8196 				}
8197 				case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8198 					if (length <= IFXNAMSIZ && length > 0) {
8199 						ifnet_t __single bound_interface = NULL;
8200 						char interface_name[IFXNAMSIZ];
8201 						memcpy(interface_name, value, length);
8202 						interface_name[length - 1] = 0;         // Make sure the string is NULL terminated
8203 						if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8204 							bound_interface_index = bound_interface->if_index;
8205 							ifnet_release(bound_interface);
8206 						}
8207 					}
8208 					break;
8209 				}
8210 				case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8211 					if (ignore_address || override_local_addr) {
8212 						break;
8213 					}
8214 
8215 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8216 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8217 						if (necp_address_is_valid(&address_struct->address.sa)) {
8218 							memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8219 						}
8220 					}
8221 					break;
8222 				}
8223 				case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8224 					if (ignore_address || override_remote_addr) {
8225 						break;
8226 					}
8227 
8228 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8229 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8230 						if (necp_address_is_valid(&address_struct->address.sa)) {
8231 							memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8232 						}
8233 					}
8234 					break;
8235 				}
8236 				case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8237 					if (ignore_address || override_local_addr) {
8238 						break;
8239 					}
8240 
8241 					if (length >= sizeof(struct necp_client_endpoint)) {
8242 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8243 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8244 						    endpoint->u.endpoint.endpoint_port != 0) {
8245 							// Save port
8246 							local_port = endpoint->u.endpoint.endpoint_port;
8247 						}
8248 					}
8249 					break;
8250 				}
8251 				case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8252 					if (ignore_address || override_remote_addr) {
8253 						break;
8254 					}
8255 
8256 					if (length >= sizeof(struct necp_client_endpoint)) {
8257 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8258 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8259 							remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8260 							if (endpoint->u.endpoint.endpoint_port != 0) {
8261 								// Save port
8262 								remote_port = endpoint->u.endpoint.endpoint_port;
8263 							}
8264 						} else if (necp_addr_is_empty(&endpoint->u.sa)) {
8265 							remote_address_is_empty = true;
8266 						}
8267 					}
8268 					break;
8269 				}
8270 				case NECP_CLIENT_PARAMETER_FLAGS: {
8271 					if (length >= sizeof(client_flags)) {
8272 						memcpy(&client_flags, value, sizeof(client_flags));
8273 					}
8274 					break;
8275 				}
8276 				case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8277 				case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8278 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8279 						break;
8280 					}
8281 					if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8282 						memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8283 						num_required_agent_types++;
8284 					}
8285 					break;
8286 				}
8287 				case NECP_CLIENT_PARAMETER_PREFER_AGENT: {
8288 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8289 						break;
8290 					}
8291 					if (length >= sizeof(uuid_t)) {
8292 						if (netagent_get_agent_domain_and_type(value,
8293 						    required_agent_types[num_required_agent_types].netagent_domain,
8294 						    required_agent_types[num_required_agent_types].netagent_type)) {
8295 							num_required_agent_types++;
8296 						}
8297 					}
8298 					break;
8299 				}
8300 				case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8301 					if (length >= sizeof(scheme_port)) {
8302 						memcpy(&scheme_port, value, sizeof(scheme_port));
8303 					}
8304 					break;
8305 				}
8306 				case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8307 					has_system_signed_result = true;
8308 					struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8309 					if (length >= sizeof(struct necp_client_validatable)) {
8310 						// Check for system-signed sign_type values
8311 						if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8312 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8313 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8314 							has_system_signed_result = true;
8315 						}
8316 					}
8317 					break;
8318 				}
8319 				case NECP_CLIENT_PARAMETER_EXTENDED_FLAGS: {
8320 					if (length >= sizeof(extended_client_flags)) {
8321 						memcpy(&extended_client_flags, value, sizeof(extended_client_flags));
8322 					}
8323 					break;
8324 				}
8325 				default: {
8326 					break;
8327 				}
8328 				}
8329 			}
8330 		}
8331 
8332 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8333 	}
8334 
8335 	// Check for loopback exception
8336 	if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8337 		if (necp_task_has_loopback_drop_entitlement(task)) {
8338 			// Disallow certain entitled processes to send loopback traffic
8339 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8340 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8341 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8342 			if (cred != NULL) {
8343 				kauth_cred_unref(&cred);
8344 			}
8345 			return 0;
8346 		}
8347 		if (necp_pass_loopback > 0) {
8348 			bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8349 		}
8350 	} else if (bound_interface_index != IFSCOPE_NONE) {
8351 		// Check for inter-process exception
8352 		struct sockaddr *dst = SA(&remote_addr.sa);
8353 		if (dst->sa_family == AF_INET6) {
8354 			struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8355 			if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8356 				ifnet_head_lock_shared();
8357 				ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8358 				if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8359 					bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8360 				}
8361 				ifnet_head_done();
8362 			}
8363 		}
8364 	}
8365 
8366 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8367 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8368 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8369 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8370 		if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8371 			returned_result->routed_interface_index = lo_ifp->if_index;
8372 			*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8373 		} else {
8374 			returned_result->routed_interface_index = bound_interface_index;
8375 		}
8376 		if (cred != NULL) {
8377 			kauth_cred_unref(&cred);
8378 		}
8379 		return 0;
8380 	}
8381 
8382 	if (drop_order != 0) {
8383 		if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8384 		    client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8385 		    ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8386 			// Allow listeners, inbound connections without remote addresses, and
8387 			// application service connections to bypass the unentitled drop order,
8388 			// to allow them to connect to application services (not directly over
8389 			// physical networking interfaces)
8390 			drop_order = 0;
8391 		}
8392 	}
8393 
8394 	if (proc_pid(effective_proc) != pid) {
8395 		proc_t found_proc = proc_find(pid);
8396 		if (found_proc != PROC_NULL) {
8397 			effective_proc = found_proc;
8398 			pid_version = proc_pidversion(effective_proc);
8399 			release_eproc = true;
8400 		}
8401 	}
8402 #if defined(XNU_TARGET_OS_OSX)
8403 	if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8404 		proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8405 		responsible_proc = proc_find(effective_proc->p_responsible_pid);
8406 	}
8407 #endif /* defined(XNU_TARGET_OS_OSX) */
8408 
8409 	// Lock
8410 	lck_rw_lock_shared(&necp_kernel_policy_lock);
8411 
8412 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8413 	size_t route_rule_id_array_count = 0;
8414 	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);
8415 
8416 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8417 	NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8418 
8419 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8420 	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8421 	    &info,
8422 	    &filter_control_unit,
8423 	    route_rule_id_array,
8424 	    &route_rule_id_array_count,
8425 	    MAX_AGGREGATE_ROUTE_RULES,
8426 	    netagent_ids,
8427 	    NECP_MAX_NETAGENTS,
8428 	    netagent_use_flags,
8429 	    NECP_MAX_NETAGENTS,
8430 	    required_agent_types,
8431 	    num_required_agent_types,
8432 	    info.used_responsible_pid ? responsible_proc : effective_proc,
8433 	    0,
8434 	    &skip_policy_id,
8435 	    NULL,
8436 	    &drop_dest_policy_result,
8437 	    &drop_all_bypass,
8438 	    &flow_divert_aggregate_unit,
8439 	    NULL,
8440 	    debug);
8441 
8442 	// Check for loopback exception again after the policy match
8443 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8444 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8445 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8446 		if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8447 			returned_result->filter_control_unit = 0;
8448 		} else {
8449 			returned_result->filter_control_unit = filter_control_unit;
8450 		}
8451 
8452 		if (flow_divert_aggregate_unit > 0) {
8453 			returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8454 		}
8455 
8456 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8457 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8458 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8459 		returned_result->routed_interface_index = lo_ifp->if_index;
8460 		*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8461 		error = 0;
8462 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8463 		goto done;
8464 	}
8465 
8466 	if (matched_policy) {
8467 		returned_result->policy_id = matched_policy->id;
8468 		returned_result->skip_policy_id = skip_policy_id;
8469 		returned_result->routing_result = matched_policy->result;
8470 		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8471 		if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8472 			uuid_copy(*returned_override_euuid, responsible_application_uuid);
8473 		}
8474 	} else {
8475 		bool drop_all = false;
8476 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8477 			// Mark socket as a drop if drop_all is set
8478 			drop_all = true;
8479 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8480 				drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8481 			}
8482 		}
8483 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8484 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8485 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8486 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8487 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8488 		} else {
8489 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8490 			returned_result->skip_policy_id = skip_policy_id;
8491 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8492 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8493 		}
8494 	}
8495 	if (necp_check_missing_client_drop(proc, &info) ||
8496 	    necp_check_restricted_multicast_drop(proc, &info, false)) {
8497 		// Mark as drop
8498 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8499 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8500 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8501 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8502 	}
8503 	if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8504 		returned_result->filter_control_unit = 0;
8505 	} else {
8506 		returned_result->filter_control_unit = filter_control_unit;
8507 	}
8508 
8509 	if (flow_divert_aggregate_unit > 0) {
8510 		returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8511 	}
8512 
8513 	// Handle netagents
8514 	size_t netagent_i = 0;
8515 	size_t removed_netagent_type_i = 0;
8516 	for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8517 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
8518 		if (netagent_id == 0) {
8519 			continue;
8520 		}
8521 
8522 		if (necp_agent_id_is_uuid(netagent_id)) {
8523 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
8524 			if (mapping != NULL) {
8525 				uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8526 				returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8527 				netagent_i++;
8528 			}
8529 		} else {
8530 			struct necp_agent_type_id_mapping *mapping = necp_lookup_agent_type_with_id_locked(netagent_id);
8531 			if (mapping != NULL && removed_netagent_type_i < NECP_MAX_REMOVE_NETAGENT_TYPES &&
8532 			    netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8533 				memcpy(&returned_result->remove_netagent_types[removed_netagent_type_i], &mapping->agent_type, sizeof(mapping->agent_type));
8534 				removed_netagent_type_i++;
8535 			}
8536 		}
8537 
8538 		// If the flags say to remove, clear the local copy
8539 		if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8540 			netagent_ids[netagent_cursor] = 0;
8541 		}
8542 	}
8543 
8544 	// Do routing evaluation
8545 	u_int output_bound_interface = bound_interface_index;
8546 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8547 		output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8548 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8549 		output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8550 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8551 		output_bound_interface = necp_get_primary_direct_interface_index();
8552 		if (output_bound_interface == IFSCOPE_NONE) {
8553 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8554 		} else {
8555 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8556 			returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8557 		}
8558 	}
8559 
8560 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8561 	    returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8562 		if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8563 			// Trigger the event that we dropped due to a local network policy
8564 #if defined(XNU_TARGET_OS_OSX)
8565 			bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8566 			necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8567 			    should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8568 			    NETPOLICY_NETWORKTYPE_LOCAL);
8569 #else
8570 			necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8571 #endif
8572 		}
8573 		if (reason != NULL) {
8574 			*reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8575 		}
8576 	}
8577 
8578 	if (local_addr.sa.sa_len == 0 ||
8579 	    (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8580 	    (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8581 		no_local_addr = TRUE;
8582 	}
8583 
8584 	if (remote_addr.sa.sa_len == 0 ||
8585 	    (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8586 	    (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8587 		no_remote_addr = TRUE;
8588 		remote_family = remote_addr.sa.sa_family;
8589 	}
8590 
8591 	returned_result->routed_interface_index = 0;
8592 	struct rtentry *rt = NULL;
8593 	if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8594 		// Treat the output bound interface as the routed interface for local address
8595 		// validation later.
8596 		returned_result->routed_interface_index = output_bound_interface;
8597 	} else {
8598 		if (no_remote_addr) {
8599 			memset(&remote_addr, 0, sizeof(remote_addr));
8600 			if (remote_family == AF_INET6) {
8601 				// Reset address to ::
8602 				remote_addr.sa.sa_family = AF_INET6;
8603 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8604 			} else {
8605 				// Reset address to 0.0.0.0
8606 				remote_addr.sa.sa_family = AF_INET;
8607 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8608 			}
8609 		}
8610 
8611 		rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8612 		    output_bound_interface);
8613 
8614 		if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8615 		    IS_INTF_CLAT46(rt->rt_ifp)) {
8616 			rtfree(rt);
8617 			rt = NULL;
8618 			returned_result->routed_interface_index = 0;
8619 		}
8620 
8621 		if (no_remote_addr && remote_family == AF_UNSPEC &&
8622 		    (rt == NULL || rt->rt_ifp == NULL)) {
8623 			// Route lookup for default IPv4 failed, try IPv6
8624 
8625 			// Cleanup old route if necessary
8626 			if (rt != NULL) {
8627 				rtfree(rt);
8628 				rt = NULL;
8629 			}
8630 
8631 			// Reset address to ::
8632 			memset(&remote_addr, 0, sizeof(remote_addr));
8633 			remote_addr.sa.sa_family = AF_INET6;
8634 			remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8635 
8636 			// Get route
8637 			rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8638 			    output_bound_interface);
8639 		}
8640 
8641 		if (rt != NULL &&
8642 		    rt->rt_ifp != NULL) {
8643 			returned_result->routed_interface_index = rt->rt_ifp->if_index;
8644 			/*
8645 			 * For local addresses, we allow the interface scope to be
8646 			 * either the loopback interface or the interface hosting the
8647 			 * local address.
8648 			 */
8649 			if (bound_interface_index != IFSCOPE_NONE &&
8650 			    rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8651 			    (output_bound_interface == lo_ifp->if_index ||
8652 			    rt->rt_ifp->if_index == lo_ifp->if_index ||
8653 			    rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8654 				struct sockaddr_storage dst;
8655 				unsigned int ifscope = bound_interface_index;
8656 
8657 				/*
8658 				 * Transform dst into the internal routing table form
8659 				 */
8660 				(void) sa_copy(SA(&remote_addr),
8661 				    &dst, &ifscope);
8662 
8663 				if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8664 				    rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8665 					returned_result->routed_interface_index =
8666 					    bound_interface_index;
8667 				}
8668 			}
8669 		}
8670 	}
8671 
8672 	if (returned_result->routed_interface_index != 0 &&
8673 	    returned_result->routed_interface_index != lo_ifp->if_index &&     // Loopback can accept any local address
8674 	    !no_local_addr) {
8675 		// Transform local_addr into the ifaddr form
8676 		// IPv6 Scope IDs are always embedded in the ifaddr list
8677 		struct sockaddr_storage local_address_sanitized;
8678 		u_int ifscope = IFSCOPE_NONE;
8679 		(void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8680 		SIN(&local_address_sanitized)->sin_port = 0;
8681 		if (local_address_sanitized.ss_family == AF_INET6) {
8682 			if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8683 				SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8684 			}
8685 		}
8686 
8687 		// Validate local address on routed interface
8688 		struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8689 		if (ifa == NULL) {
8690 			// Interface address not found, reject route
8691 			returned_result->routed_interface_index = 0;
8692 			if (rt != NULL) {
8693 				rtfree(rt);
8694 				rt = NULL;
8695 			}
8696 		} else {
8697 			ifaddr_release(ifa);
8698 			ifa = NULL;
8699 		}
8700 	}
8701 
8702 	if (flags != NULL) {
8703 #if SKYWALK
8704 		if (kernel_is_macos_or_server()) {
8705 			enum net_filter_event_subsystems filters = net_filter_event_get_state();
8706 
8707 			if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8708 				*flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8709 			}
8710 			if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8711 				*flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8712 			}
8713 			if (filters & NET_FILTER_EVENT_ALF) {
8714 				*flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8715 			}
8716 			if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8717 				*flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8718 			}
8719 		}
8720 #endif /* SKYWALK */
8721 		if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8722 			// Check for local/direct
8723 			bool is_local = FALSE;
8724 			if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8725 				is_local = TRUE;
8726 			} else if (returned_result->routed_interface_index != 0 &&
8727 			    !no_remote_addr) {
8728 				// Clean up the address before comparison with interface addresses
8729 
8730 				// Transform remote_addr into the ifaddr form
8731 				// IPv6 Scope IDs are always embedded in the ifaddr list
8732 				struct sockaddr_storage remote_address_sanitized;
8733 				u_int ifscope = IFSCOPE_NONE;
8734 				(void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8735 				SIN(&remote_address_sanitized)->sin_port = 0;
8736 				if (remote_address_sanitized.ss_family == AF_INET6) {
8737 					if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8738 						SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8739 					}
8740 				}
8741 
8742 				// Check if remote address is an interface address
8743 				struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8744 				if (ifa != NULL && ifa->ifa_ifp != NULL) {
8745 					u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8746 					if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8747 					    if_index_for_remote_addr == lo_ifp->if_index) {
8748 						is_local = TRUE;
8749 					}
8750 				}
8751 				if (ifa != NULL) {
8752 					ifaddr_release(ifa);
8753 					ifa = NULL;
8754 				}
8755 			}
8756 
8757 			if (is_local) {
8758 				*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8759 			} else if (rt != NULL) {
8760 				if (rt->rt_flags & RTF_GLOBAL) {
8761 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8762 				} else if (!(rt->rt_flags & RTF_GATEWAY) &&
8763 				    (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8764 					// Route is directly accessible
8765 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8766 				}
8767 			}
8768 
8769 			if (rt != NULL &&
8770 			    rt->rt_ifp != NULL) {
8771 				// Check probe status
8772 				if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8773 					*flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8774 				}
8775 
8776 				if (if_link_heuristics_enabled(rt->rt_ifp)) {
8777 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_HEURISTICS;
8778 				}
8779 
8780 				if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8781 					struct if_cellular_status_v1 *ifsr;
8782 
8783 					ifnet_lock_shared(rt->rt_ifp);
8784 					lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8785 
8786 					if (rt->rt_ifp->if_link_status != NULL) {
8787 						ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8788 
8789 						if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8790 							if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8791 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8792 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8793 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8794 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8795 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8796 							}
8797 						}
8798 					}
8799 					lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8800 					ifnet_lock_done(rt->rt_ifp);
8801 				}
8802 
8803 				// Check link quality
8804 				if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8805 				    (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8806 				    rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8807 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8808 				}
8809 
8810 				// Check QoS marking (fastlane)
8811 				for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8812 					if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8813 						*flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8814 						// If the route can use QoS markings, stop iterating route rules
8815 						break;
8816 					}
8817 				}
8818 
8819 				if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8820 					*flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8821 				}
8822 
8823 				if (traffic_class == SO_TC_BK_SYS) {
8824 					// Block BK_SYS traffic if interface is throttled
8825 					u_int32_t throttle_level = 0;
8826 					if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8827 						if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8828 							returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8829 							memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8830 						}
8831 					}
8832 				}
8833 			}
8834 		}
8835 
8836 		u_int interface_to_check = returned_result->routed_interface_index;
8837 		if (interface_to_check == 0) {
8838 			interface_to_check = output_bound_interface;
8839 		}
8840 		union necp_sockaddr_union default_address;
8841 		struct rtentry *v4Route = NULL;
8842 		struct rtentry *v6Route = NULL;
8843 
8844 		memset(&default_address, 0, sizeof(default_address));
8845 
8846 		// Reset address to 0.0.0.0
8847 		default_address.sa.sa_family = AF_INET;
8848 		default_address.sa.sa_len = sizeof(struct sockaddr_in);
8849 		v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8850 		    returned_result->routed_interface_index);
8851 
8852 		// Reset address to ::
8853 		default_address.sa.sa_family = AF_INET6;
8854 		default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8855 		v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8856 		    returned_result->routed_interface_index);
8857 
8858 		if (v4Route != NULL) {
8859 			if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8860 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8861 			}
8862 			if (returned_v4_gateway != NULL &&
8863 			    v4Route->rt_gateway != NULL &&
8864 			    v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8865 				memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8866 				memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8867 			}
8868 			rtfree(v4Route);
8869 			v4Route = NULL;
8870 		}
8871 
8872 		if (v6Route != NULL) {
8873 			if (v6Route->rt_ifp != NULL) {
8874 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8875 
8876 				if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8877 					*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8878 				}
8879 			}
8880 			if (returned_v6_gateway != NULL &&
8881 			    v6Route->rt_gateway != NULL &&
8882 			    v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8883 				SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8884 			}
8885 			rtfree(v6Route);
8886 			v6Route = NULL;
8887 		}
8888 	}
8889 
8890 	// Take two passes through the rule list: first for rules that don't match based on agents,
8891 	// second for rules that match based on agents. Since rules can modify the agent list itself,
8892 	// this makes the logic more deterministic. This allows a non-agent matching rule to remove
8893 	// an agent before it is used for matching later.
8894 	size_t route_rule_index = 0;
8895 	bool second_pass = false;
8896 	while (route_rule_index < route_rule_id_array_count) {
8897 		bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8898 		if (rule_matches_agents != second_pass) {
8899 			// Process rules that match based on agents only in the second pass
8900 			route_rule_index++;
8901 			if (route_rule_index == route_rule_id_array_count && !second_pass) {
8902 				route_rule_index = 0;
8903 				second_pass = true;
8904 			}
8905 			continue;
8906 		}
8907 
8908 		u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8909 		bool ultra_constrained_denied = false;
8910 		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, &ultra_constrained_denied);
8911 		if (!route_is_allowed) {
8912 			// If the route is blocked, treat the lookup as a drop
8913 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8914 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8915 
8916 			if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8917 				if (reason != NULL) {
8918 					if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8919 						*reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8920 					} else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8921 						*reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8922 					}
8923 				}
8924 				necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8925 			} else if (ultra_constrained_denied) {
8926 				if (reason != NULL) {
8927 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8928 				}
8929 				necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
8930 			}
8931 
8932 			// If the route gets denied, stop matching rules
8933 			break;
8934 		}
8935 
8936 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8937 		if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8938 			u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8939 			    route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8940 			if (flow_divert_control_unit != 0) {
8941 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8942 				returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8943 			}
8944 			if (flow_divert_aggregate_unit != 0) {
8945 				returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8946 			}
8947 		}
8948 
8949 		// Check if there is a route rule that adds or removes an agent
8950 		bool remove = false;
8951 		u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8952 		if (netagent_id != 0) {
8953 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
8954 			if (mapping != NULL) {
8955 				bool agent_already_present = false;
8956 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8957 					if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8958 						// Found the agent already present
8959 						agent_already_present = true;
8960 						if (remove) {
8961 							// Mark as remove if necessary
8962 							returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8963 						}
8964 					} else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8965 						// Found open slot
8966 						if (!agent_already_present) {
8967 							uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8968 							if (remove) {
8969 								returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8970 							} else {
8971 								returned_result->netagent_use_flags[netagent_cursor] = 0;
8972 							}
8973 						}
8974 						break;
8975 					}
8976 				}
8977 			}
8978 
8979 			// Update the local netagent_ids array for future evaluations
8980 			if (remove) {
8981 				// Check if the agent ID is in the array, and remove it
8982 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8983 					if (netagent_id == netagent_ids[netagent_cursor]) {
8984 						netagent_ids[netagent_cursor] = 0;
8985 					}
8986 				}
8987 			} else {
8988 				// Check if the agent ID is not yet in the array, and add it
8989 				bool found = false;
8990 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8991 					if (netagent_id == netagent_ids[netagent_cursor]) {
8992 						found = true;
8993 						break;
8994 					}
8995 				}
8996 				if (!found) {
8997 					for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8998 						if (netagent_ids[netagent_cursor] == 0) {
8999 							// Empty slot, add the agent
9000 							netagent_ids[netagent_cursor] = netagent_id;
9001 							break;
9002 						}
9003 					}
9004 				}
9005 			}
9006 		}
9007 
9008 		route_rule_index++;
9009 		if (route_rule_index == route_rule_id_array_count && !second_pass) {
9010 			route_rule_index = 0;
9011 			second_pass = true;
9012 		}
9013 	}
9014 
9015 	if (rt != NULL && rt->rt_ifp != NULL) {
9016 		const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
9017 		const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
9018 		const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
9019 		    IFNET_IS_EXPENSIVE(rt->rt_ifp));
9020 		const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
9021 		    IFNET_IS_CONSTRAINED(rt->rt_ifp));
9022 		const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
9023 		    IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
9024 		    (!if_ultra_constrained_default_allowed && !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT))));
9025 
9026 		const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
9027 		if (!is_listener && !is_browser) {
9028 			if (reason != NULL) {
9029 				if (expensive_prohibited) {
9030 					*reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
9031 				} else if (constrained_prohibited) {
9032 					*reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
9033 				} else if (ultra_constrained_not_allowed) {
9034 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
9035 					necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
9036 				}
9037 			}
9038 			if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
9039 				// If a property of the interface was not allowed, treat it as a drop
9040 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
9041 				memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
9042 			}
9043 		}
9044 
9045 		if ((extended_client_flags & NECP_CLIENT_PARAMETER_EXTENDED_FLAG_AOP2_OFFLOAD) &&
9046 		    ((rt->rt_ifp->if_xflags & IFXF_RX_FLOW_STEERING) == 0)) {
9047 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
9048 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
9049 		}
9050 	}
9051 
9052 	if (rt != NULL) {
9053 		if (returned_route != NULL) {
9054 			*returned_route = rt;
9055 		} else {
9056 			rtfree(rt);
9057 		}
9058 		rt = NULL;
9059 	}
9060 
9061 done:
9062 	// Unlock
9063 	lck_rw_done(&necp_kernel_policy_lock);
9064 
9065 	if (release_eproc && effective_proc != PROC_NULL) {
9066 		proc_rele(effective_proc);
9067 	}
9068 #if defined(XNU_TARGET_OS_OSX)
9069 	if (responsible_proc != PROC_NULL) {
9070 		proc_rele(responsible_proc);
9071 	}
9072 #endif
9073 
9074 	if (cred != NULL) {
9075 		kauth_cred_unref(&cred);
9076 	}
9077 
9078 	return error;
9079 }
9080 
9081 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)9082 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
9083 {
9084 	struct rtentry *rt = NULL;
9085 	bool is_local = FALSE;
9086 
9087 	if (remote_addr == NULL) {
9088 		return NULL;
9089 	}
9090 
9091 	if (remote_addr->sa.sa_len == 0 ||
9092 	    (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
9093 	    (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
9094 		return FALSE;
9095 	}
9096 
9097 	// Lookup route regardless of the scoped interface to check if
9098 	// remote address is in a local network.
9099 	rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
9100 
9101 	if (rt == NULL) {
9102 		goto done;
9103 	}
9104 	if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
9105 		goto free_rt;
9106 	}
9107 	is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9108 
9109 free_rt:
9110 	rtfree(rt);
9111 
9112 done:
9113 	return is_local;
9114 }
9115 
9116 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)9117 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9118     necp_app_id app_id,
9119     necp_app_id real_app_id,
9120     uint8_t is_entitled,
9121     u_int32_t account_id,
9122     struct substring domain,
9123     u_int8_t domain_dot_count,
9124     const char *url __null_terminated,
9125     pid_t pid,
9126     int32_t pid_version,
9127     uid_t uid,
9128     uid_t real_uid,
9129     u_int32_t bound_interface_index,
9130     u_int32_t traffic_class,
9131     u_int16_t protocol,
9132     union necp_sockaddr_union *local,
9133     union necp_sockaddr_union *remote,
9134     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9135     u_int32_t num_required_agent_types,
9136     bool has_client,
9137     uint32_t client_flags,
9138     int is_platform_binary,
9139     bool has_signed_result,
9140     proc_t proc,
9141     u_int16_t pf_tag,
9142     u_int16_t scheme_port,
9143     struct rtentry *rt,
9144     bool is_loopback,
9145     int debug,
9146     bool real_is_platform_binary,
9147     u_int32_t bound_interface_flags,
9148     u_int32_t bound_interface_eflags,
9149     u_int32_t bound_interface_xflags,
9150     struct necp_socket_info *info,
9151     bool is_delegated,
9152     struct socket *socket)
9153 {
9154 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9155 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9156 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9157 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9158 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9159 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9160 				if (bound_interface_index == cond_bound_interface_index) {
9161 					// No match, matches forbidden interface
9162 					return FALSE;
9163 				}
9164 			} else {
9165 				if (bound_interface_index != cond_bound_interface_index) {
9166 					// No match, does not match required interface
9167 					return FALSE;
9168 				}
9169 			}
9170 		}
9171 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9172 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9173 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9174 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9175 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9176 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9177 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9178 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9179 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9180 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9181 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9182 					// No match, matches some forbidden interface flags
9183 					return FALSE;
9184 				}
9185 			} else {
9186 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9187 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9188 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9189 					// No match, does not match some required interface xflags
9190 					return FALSE;
9191 				}
9192 			}
9193 		}
9194 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9195 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9196 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9197 			if (bound_interface_index != 0) {
9198 				// No match, requires a non-bound packet
9199 				return FALSE;
9200 			}
9201 		}
9202 	}
9203 
9204 	if (kernel_policy->condition_mask == 0) {
9205 		return TRUE;
9206 	}
9207 
9208 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9209 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9210 		    "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9211 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9212 			if (app_id == kernel_policy->cond_app_id) {
9213 				// No match, matches forbidden application
9214 				return FALSE;
9215 			}
9216 		} else {
9217 			if (app_id != kernel_policy->cond_app_id) {
9218 				// No match, does not match required application
9219 				return FALSE;
9220 			}
9221 		}
9222 
9223 		// Check signing identifier only after APP ID matched
9224 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9225 		    kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9226 			u_int8_t matched = necp_boolean_state_false;
9227 			const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9228 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9229 			    "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9230 			    kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9231 			    signing_id ? signing_id : "<n/a>");
9232 			if (signing_id != NULL) {
9233 				if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9234 					matched = necp_boolean_state_true;
9235 				}
9236 			}
9237 
9238 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9239 				if (matched == necp_boolean_state_true) {
9240 					return FALSE;
9241 				}
9242 			} else {
9243 				if (matched != necp_boolean_state_true) {
9244 					return FALSE;
9245 				}
9246 			}
9247 		}
9248 	}
9249 
9250 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9251 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9252 		    "NECP_KERNEL_CONDITION_REAL_APP_ID",
9253 		    kernel_policy->cond_real_app_id, real_app_id);
9254 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9255 			if (real_app_id == kernel_policy->cond_real_app_id) {
9256 				// No match, matches forbidden application
9257 				return FALSE;
9258 			}
9259 		} else {
9260 			if (real_app_id != kernel_policy->cond_real_app_id) {
9261 				// No match, does not match required application
9262 				return FALSE;
9263 			}
9264 		}
9265 	}
9266 
9267 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9268 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9269 		if (!has_client) {
9270 			return FALSE;
9271 		}
9272 	}
9273 
9274 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9275 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9276 		if (!is_entitled) {
9277 			// Process is missing entitlement
9278 			return FALSE;
9279 		}
9280 	}
9281 
9282 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9283 		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);
9284 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9285 			if (is_platform_binary) {
9286 				// Process is platform binary
9287 				return FALSE;
9288 			}
9289 		} else {
9290 			if (!is_platform_binary) {
9291 				// Process is not platform binary
9292 				return FALSE;
9293 			}
9294 		}
9295 	}
9296 
9297 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9298 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9299 		if (has_signed_result == 0) {
9300 			// Client did not have a system-signed result
9301 			return FALSE;
9302 		}
9303 	}
9304 
9305 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9306 		if (proc != NULL) {
9307 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9308 			    kernel_policy->cond_sdk_version.platform,
9309 			    kernel_policy->cond_sdk_version.min_version,
9310 			    kernel_policy->cond_sdk_version.version,
9311 			    proc_platform(proc),
9312 			    proc_min_sdk(proc),
9313 			    proc_sdk(proc));
9314 			if (kernel_policy->cond_sdk_version.platform != 0) {
9315 				if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9316 					// Process does not match platform
9317 					return FALSE;
9318 				}
9319 			}
9320 
9321 			if (kernel_policy->cond_sdk_version.min_version != 0) {
9322 				if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9323 					// Process min version is older than required min version
9324 					return FALSE;
9325 				}
9326 			}
9327 
9328 			if (kernel_policy->cond_sdk_version.version != 0) {
9329 				if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9330 					// Process SDK version is older than required version
9331 					return FALSE;
9332 				}
9333 			}
9334 		}
9335 	}
9336 
9337 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9338 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9339 		if (kernel_policy->cond_custom_entitlement != NULL) {
9340 			if (proc == NULL) {
9341 				// No process found, cannot check entitlement
9342 				return FALSE;
9343 			}
9344 			task_t __single task = proc_task(proc);
9345 			if (task == NULL ||
9346 			    !IOTaskHasEntitlementAsBooleanOrObject(task, kernel_policy->cond_custom_entitlement)) {
9347 				// Process is missing custom entitlement
9348 				return FALSE;
9349 			}
9350 		}
9351 	}
9352 
9353 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9354 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9355 		    "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9356 		// Exact match requires the number of dots to match (no suffix matching allowed)
9357 		bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9358 		    necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9359 		if (domain_matches && socket != NULL) {
9360 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9361 		}
9362 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9363 			if (domain_matches) {
9364 				// No match, matches forbidden domain
9365 				return FALSE;
9366 			}
9367 		} else {
9368 			if (!domain_matches) {
9369 				// No match, does not match required domain
9370 				return FALSE;
9371 			}
9372 		}
9373 	} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9374 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9375 		    "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9376 		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9377 		if (domain_matches && socket != NULL) {
9378 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9379 		}
9380 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9381 			if (domain_matches) {
9382 				// No match, matches forbidden domain
9383 				return FALSE;
9384 			}
9385 		} else {
9386 			if (!domain_matches) {
9387 				// No match, does not match required domain
9388 				return FALSE;
9389 			}
9390 		}
9391 	}
9392 
9393 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9394 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9395 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9396 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9397 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9398 		bool domain_matches = false;
9399 		if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9400 			struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9401 			if (filter != NULL && filter->filter != NULL) {
9402 				domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9403 			}
9404 		} else {
9405 			domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9406 			if (debug) {
9407 				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);
9408 			}
9409 		}
9410 		if (domain_matches && socket != NULL) {
9411 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9412 		}
9413 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9414 			if (domain_matches) {
9415 				// No match, matches forbidden domain
9416 				return FALSE;
9417 			}
9418 		} else {
9419 			if (!domain_matches) {
9420 				// No match, does not match required domain
9421 				return FALSE;
9422 			}
9423 		}
9424 	}
9425 
9426 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9427 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9428 		    "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9429 		bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9430 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9431 			if (url_matches) {
9432 				// No match, matches forbidden url
9433 				return FALSE;
9434 			}
9435 		} else {
9436 			if (!url_matches) {
9437 				// No match, does not match required url
9438 				return FALSE;
9439 			}
9440 		}
9441 	}
9442 
9443 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9444 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9445 		    "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9446 		    kernel_policy->cond_account_id, account_id);
9447 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9448 			if (account_id == kernel_policy->cond_account_id) {
9449 				// No match, matches forbidden account
9450 				return FALSE;
9451 			}
9452 		} else {
9453 			if (account_id != kernel_policy->cond_account_id) {
9454 				// No match, does not match required account
9455 				return FALSE;
9456 			}
9457 		}
9458 	}
9459 
9460 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9461 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9462 		    "NECP_KERNEL_CONDITION_PID",
9463 		    kernel_policy->cond_pid, pid);
9464 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9465 			if (pid == kernel_policy->cond_pid) {
9466 				// No match, matches forbidden pid
9467 				return FALSE;
9468 			}
9469 			if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9470 				return FALSE;
9471 			}
9472 		} else {
9473 			if (pid != kernel_policy->cond_pid) {
9474 				// No match, does not match required pid
9475 				return FALSE;
9476 			}
9477 			if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9478 				return FALSE;
9479 			}
9480 		}
9481 	}
9482 
9483 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9484 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9485 		    "NECP_KERNEL_CONDITION_UID",
9486 		    kernel_policy->cond_uid, uid);
9487 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9488 			if (uid == kernel_policy->cond_uid) {
9489 				// No match, matches forbidden uid
9490 				return FALSE;
9491 			}
9492 		} else {
9493 			if (uid != kernel_policy->cond_uid) {
9494 				// No match, does not match required uid
9495 				return FALSE;
9496 			}
9497 		}
9498 	}
9499 
9500 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9501 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9502 		    "NECP_KERNEL_CONDITION_REAL_UID",
9503 		    kernel_policy->cond_real_uid, real_uid);
9504 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9505 			if (real_uid == kernel_policy->cond_real_uid) {
9506 				// No match, matches forbidden uid
9507 				return FALSE;
9508 			}
9509 		} else {
9510 			if (real_uid != kernel_policy->cond_real_uid) {
9511 				// No match, does not match required uid
9512 				return FALSE;
9513 			}
9514 		}
9515 	}
9516 
9517 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9518 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9519 		    kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9520 		    traffic_class, 0, 0);
9521 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9522 			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9523 			    traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9524 				// No match, matches forbidden traffic class
9525 				return FALSE;
9526 			}
9527 		} else {
9528 			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9529 			    traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9530 				// No match, does not match required traffic class
9531 				return FALSE;
9532 			}
9533 		}
9534 	}
9535 
9536 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9537 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9538 		    "NECP_KERNEL_CONDITION_PROTOCOL",
9539 		    kernel_policy->cond_protocol, protocol);
9540 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9541 			if (protocol == kernel_policy->cond_protocol) {
9542 				// No match, matches forbidden protocol
9543 				return FALSE;
9544 			}
9545 		} else {
9546 			if (protocol != kernel_policy->cond_protocol) {
9547 				// No match, does not match required protocol
9548 				return FALSE;
9549 			}
9550 		}
9551 	}
9552 
9553 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9554 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9555 		    kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9556 		    "n/a", "n/a", "n/a");
9557 		bool matches_agent_type = FALSE;
9558 		for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9559 			struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9560 			if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9561 			    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) &&
9562 			    (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9563 			    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)) {
9564 				// Found a required agent that matches
9565 				matches_agent_type = TRUE;
9566 				break;
9567 			}
9568 		}
9569 		if (!matches_agent_type) {
9570 			return FALSE;
9571 		}
9572 	}
9573 
9574 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9575 		bool is_local = FALSE;
9576 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9577 
9578 		if (rt != NULL) {
9579 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9580 		} else {
9581 			is_local = necp_is_route_local(remote, include_local_addresses);
9582 		}
9583 		if (info != NULL) {
9584 			info->is_local = is_local;
9585 		}
9586 
9587 		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);
9588 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9589 			if (is_local) {
9590 				// Match local-networks, fail
9591 				return FALSE;
9592 			}
9593 		} else {
9594 			if (!is_local) {
9595 				// Either no route to validate or no match for local networks
9596 				return FALSE;
9597 			}
9598 		}
9599 	}
9600 
9601 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9602 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9603 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9604 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9605 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9606 				if (inRange) {
9607 					return FALSE;
9608 				}
9609 			} else {
9610 				if (!inRange) {
9611 					return FALSE;
9612 				}
9613 			}
9614 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9615 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9616 			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);
9617 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9618 				if (inSubnet) {
9619 					return FALSE;
9620 				}
9621 			} else {
9622 				if (!inSubnet) {
9623 					return FALSE;
9624 				}
9625 			}
9626 		}
9627 	}
9628 
9629 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9630 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9631 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9632 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9633 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9634 				if (inRange) {
9635 					return FALSE;
9636 				}
9637 			} else {
9638 				if (!inRange) {
9639 					return FALSE;
9640 				}
9641 			}
9642 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9643 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9644 			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);
9645 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9646 				if (inSubnet) {
9647 					return FALSE;
9648 				}
9649 			} else {
9650 				if (!inSubnet) {
9651 					return FALSE;
9652 				}
9653 			}
9654 		}
9655 	}
9656 
9657 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9658 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9659 		    "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9660 		    kernel_policy->cond_client_flags, client_flags);
9661 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9662 			if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9663 				// Flags do match, and condition is negative, fail.
9664 				return FALSE;
9665 			}
9666 		} else {
9667 			if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9668 				// Flags do not match, fail.
9669 				return FALSE;
9670 			}
9671 		}
9672 	}
9673 
9674 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9675 		bool isEmpty = necp_addr_is_empty(SA(local));
9676 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9677 		    "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9678 		    0, isEmpty);
9679 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9680 			if (isEmpty) {
9681 				return FALSE;
9682 			}
9683 		} else {
9684 			if (!isEmpty) {
9685 				return FALSE;
9686 			}
9687 		}
9688 	}
9689 
9690 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9691 		bool isEmpty = necp_addr_is_empty(SA(remote));
9692 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9693 		    "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9694 		    0, isEmpty);
9695 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9696 			if (isEmpty) {
9697 				return FALSE;
9698 			}
9699 		} else {
9700 			if (!isEmpty) {
9701 				return FALSE;
9702 			}
9703 		}
9704 	}
9705 
9706 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9707 		u_int16_t remote_port = 0;
9708 		if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9709 			remote_port = SIN(remote)->sin_port;
9710 		}
9711 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9712 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
9713 		    scheme_port, remote_port);
9714 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9715 			if (kernel_policy->cond_scheme_port == scheme_port ||
9716 			    kernel_policy->cond_scheme_port == remote_port) {
9717 				return FALSE;
9718 			}
9719 		} else {
9720 			if (kernel_policy->cond_scheme_port != scheme_port &&
9721 			    kernel_policy->cond_scheme_port != remote_port) {
9722 				return FALSE;
9723 			}
9724 		}
9725 	}
9726 
9727 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9728 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9729 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9730 		    kernel_policy->cond_packet_filter_tags,
9731 		    pf_tag);
9732 		bool tags_matched = false;
9733 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9734 			if (pf_tag == PF_TAG_ID_STACK_DROP) {
9735 				tags_matched = true;
9736 			}
9737 		}
9738 
9739 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9740 			if (tags_matched) {
9741 				return FALSE;
9742 			}
9743 		} else {
9744 			if (!tags_matched) {
9745 				return FALSE;
9746 			}
9747 		}
9748 	}
9749 
9750 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9751 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9752 		    "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9753 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9754 			if (is_loopback) {
9755 				return FALSE;
9756 			}
9757 		} else {
9758 			if (!is_loopback) {
9759 				return FALSE;
9760 			}
9761 		}
9762 	}
9763 
9764 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9765 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9766 		    "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9767 		if (is_delegated) {
9768 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9769 				if (real_is_platform_binary) {
9770 					return FALSE;
9771 				}
9772 			} else {
9773 				if (!real_is_platform_binary) {
9774 					return FALSE;
9775 				}
9776 			}
9777 		} else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9778 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9779 			// If the connection is not delegated, and the policy did not specify a particular effective process UUID
9780 			// or PID, check the process directly
9781 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9782 				if (is_platform_binary) {
9783 					return FALSE;
9784 				}
9785 			} else {
9786 				if (!is_platform_binary) {
9787 					return FALSE;
9788 				}
9789 			}
9790 		}
9791 	}
9792 
9793 	return TRUE;
9794 }
9795 
9796 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9797 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9798 {
9799 	return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9800 }
9801 
9802 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)9803 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)
9804 {
9805 	struct socket *so = NULL;
9806 	proc_t sock_proc = NULL;
9807 	proc_t curr_proc = current_proc();
9808 
9809 	memset(info, 0, sizeof(struct necp_socket_info));
9810 
9811 	so = inp->inp_socket;
9812 
9813 	info->drop_order = drop_order;
9814 	info->is_loopback = is_loopback;
9815 	info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9816 
9817 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9818 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9819 		info->uid = kauth_cred_getuid(so->so_cred);
9820 		info->real_uid = info->uid;
9821 	}
9822 
9823 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9824 		info->traffic_class = so->so_traffic_class;
9825 	}
9826 
9827 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9828 		info->has_client = !uuid_is_null(inp->necp_client_uuid);
9829 	}
9830 
9831 	if (inp->inp_ip_p) {
9832 		info->protocol = inp->inp_ip_p;
9833 	} else {
9834 		info->protocol = SOCK_PROTO(so);
9835 	}
9836 
9837 	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9838 		u_int32_t responsible_application_id = 0;
9839 
9840 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9841 		if (existing_mapping) {
9842 			info->application_id = existing_mapping->id;
9843 		}
9844 
9845 #if defined(XNU_TARGET_OS_OSX)
9846 		if (so->so_rpid > 0) {
9847 			existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9848 			if (existing_mapping != NULL) {
9849 				responsible_application_id = existing_mapping->id;
9850 			}
9851 		}
9852 #endif
9853 
9854 		if (responsible_application_id > 0) {
9855 			info->real_application_id = info->application_id;
9856 			info->application_id = responsible_application_id;
9857 			info->used_responsible_pid = true;
9858 		} else if (!(so->so_flags & SOF_DELEGATED)) {
9859 			info->real_application_id = info->application_id;
9860 		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9861 			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9862 			if (real_existing_mapping) {
9863 				info->real_application_id = real_existing_mapping->id;
9864 			}
9865 		}
9866 	}
9867 
9868 	pid_t socket_pid =
9869 #if defined(XNU_TARGET_OS_OSX)
9870 	    info->used_responsible_pid ? so->so_rpid :
9871 #endif
9872 	    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9873 	if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9874 		sock_proc = proc_find(socket_pid);
9875 		if (socket_proc) {
9876 			*socket_proc = sock_proc;
9877 		}
9878 	}
9879 
9880 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9881 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9882 		info->is_entitled = necp_task_has_match_entitlement(task);
9883 		if (!info->is_entitled) {
9884 			// Task does not have entitlement, check the parent task
9885 			necp_get_parent_is_entitled(task, info);
9886 		}
9887 	}
9888 
9889 	info->pid = socket_pid;
9890 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9891 		info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9892 	}
9893 
9894 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9895 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9896 		if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9897 			info->is_platform_binary = true;
9898 		} else if (so->so_rpid != 0) {
9899 			proc_t responsible_proc = proc_find(so->so_rpid);
9900 			if (responsible_proc != NULL) {
9901 				if (necp_is_platform_binary(responsible_proc)) {
9902 					info->is_platform_binary = true;
9903 					info->used_responsible_pid = true;
9904 				}
9905 				proc_rele(responsible_proc);
9906 			}
9907 		}
9908 	}
9909 
9910 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9911 		proc_t real_proc = curr_proc;
9912 		bool release_real_proc = false;
9913 		if (so->last_pid != proc_pid(real_proc)) {
9914 			if (so->last_pid == socket_pid && sock_proc != NULL) {
9915 				real_proc = sock_proc;
9916 			} else {
9917 				proc_t last_proc = proc_find(so->last_pid);
9918 				if (last_proc != NULL) {
9919 					real_proc = last_proc;
9920 					release_real_proc = true;
9921 				}
9922 			}
9923 		}
9924 		if (real_proc != NULL) {
9925 			if (real_proc == kernproc) {
9926 				info->real_is_platform_binary = true;
9927 			} else {
9928 				info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9929 			}
9930 			if (release_real_proc) {
9931 				proc_rele(real_proc);
9932 			}
9933 		}
9934 	}
9935 
9936 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9937 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9938 		if (existing_mapping) {
9939 			info->account_id = existing_mapping->id;
9940 		}
9941 	}
9942 
9943 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9944 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9945 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9946 		info->domain = inp->inp_necp_attributes.inp_domain;
9947 	}
9948 
9949 	if (override_bound_interface) {
9950 		info->bound_interface_index = override_bound_interface;
9951 	} else {
9952 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9953 			info->bound_interface_index = inp->inp_boundifp->if_index;
9954 		}
9955 	}
9956 
9957 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9958 	    info->bound_interface_index != IFSCOPE_NONE) {
9959 		ifnet_head_lock_shared();
9960 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9961 		if (interface != NULL) {
9962 			info->bound_interface_flags = interface->if_flags;
9963 			info->bound_interface_eflags = interface->if_eflags;
9964 			info->bound_interface_xflags = interface->if_xflags;
9965 		}
9966 		ifnet_head_done();
9967 	}
9968 
9969 	bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9970 	    uuid_is_null(inp->necp_client_uuid) &&
9971 	    necp_socket_has_resolver_signature(inp));
9972 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
9973 	    necp_restrict_multicast ||
9974 	    needs_address_for_signature ||
9975 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9976 	    NEED_DGRAM_FLOW_TRACKING(so)) {
9977 		if (override_local_addr != NULL) {
9978 			if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9979 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9980 				if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9981 					struct sockaddr_in sin;
9982 					in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9983 					memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9984 					memcpy(&info->local_addr, &sin, sin.sin_len);
9985 				}
9986 			} else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9987 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9988 			}
9989 		} else {
9990 			if (inp->inp_vflag & INP_IPV6) {
9991 				SIN6(&info->local_addr)->sin6_family = AF_INET6;
9992 				SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9993 				SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9994 				memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9995 			} else if (inp->inp_vflag & INP_IPV4) {
9996 				SIN(&info->local_addr)->sin_family = AF_INET;
9997 				SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9998 				SIN(&info->local_addr)->sin_port = inp->inp_lport;
9999 				memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
10000 			}
10001 		}
10002 
10003 		if (override_remote_addr != NULL) {
10004 			if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
10005 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
10006 				if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
10007 					struct sockaddr_in sin;
10008 					in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
10009 					memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
10010 					memcpy(&info->remote_addr, &sin, sin.sin_len);
10011 				}
10012 			} else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
10013 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
10014 			}
10015 		} else {
10016 			if (inp->inp_vflag & INP_IPV6) {
10017 				SIN6(&info->remote_addr)->sin6_family = AF_INET6;
10018 				SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
10019 				SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
10020 				memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
10021 			} else if (inp->inp_vflag & INP_IPV4) {
10022 				SIN(&info->remote_addr)->sin_family = AF_INET;
10023 				SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
10024 				SIN(&info->remote_addr)->sin_port = inp->inp_fport;
10025 				memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
10026 			}
10027 		}
10028 		// Clear the embedded scope id from v6 addresses
10029 		if (info->local_addr.sa.sa_family == AF_INET6) {
10030 			struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
10031 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
10032 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
10033 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
10034 					sin6->sin6_addr.s6_addr16[1] = 0;
10035 				}
10036 			}
10037 		}
10038 		if (info->remote_addr.sa.sa_family == AF_INET6) {
10039 			struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
10040 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
10041 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
10042 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
10043 					sin6->sin6_addr.s6_addr16[1] = 0;
10044 				}
10045 			}
10046 		}
10047 	}
10048 
10049 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
10050 		// For checking sockets, only validate that there is an NECP client present. It will have
10051 		// already checked for the signature.
10052 		if (!uuid_is_null(inp->necp_client_uuid)) {
10053 			info->has_system_signed_result = true;
10054 		} else {
10055 			info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
10056 		}
10057 	}
10058 
10059 	if (NEED_DGRAM_FLOW_TRACKING(so)) {
10060 		info->soflow_entry = soflow_get_flow(so, NULL, &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
10061 	} else {
10062 		info->soflow_entry = NULL;
10063 	}
10064 
10065 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
10066 		info->client_flags = 0;
10067 		if (INP_NO_CONSTRAINED(inp)) {
10068 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
10069 		}
10070 		if (INP_NO_EXPENSIVE(inp)) {
10071 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
10072 		}
10073 		if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
10074 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
10075 		}
10076 		if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
10077 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
10078 		}
10079 		if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
10080 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
10081 		}
10082 		if (NEED_DGRAM_FLOW_TRACKING(so)) {
10083 			// If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
10084 			// and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
10085 			if (info->soflow_entry != NULL) {
10086 				if (!info->soflow_entry->soflow_outgoing) {
10087 					info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10088 				}
10089 			} else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
10090 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10091 			}
10092 		} else {
10093 			// If the socket is explicitly marked as inbound then set the inbound flag.
10094 			if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
10095 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10096 			}
10097 		}
10098 		if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
10099 		    inp->inp_flags2 & INP2_EXTERNAL_PORT) {
10100 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
10101 		}
10102 		if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
10103 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
10104 		}
10105 		if (inp->inp_socket->so_options & SO_REUSEPORT) {
10106 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
10107 		}
10108 	}
10109 }
10110 
10111 #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)
10112 
10113 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,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)10114 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
10115     struct necp_socket_info *info,
10116     necp_kernel_policy_filter *return_filter,
10117     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10118     size_t *return_route_rule_id_array_count,
10119     size_t route_rule_id_array_count,
10120     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10121     size_t netagent_array_count,
10122     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10123     size_t netagent_use_flags_array_count,
10124     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10125     u_int32_t num_required_agent_types,
10126     proc_t proc,
10127     u_int16_t pf_tag,
10128     necp_kernel_policy_id *skip_policy_id,
10129     struct rtentry *rt,
10130     necp_kernel_policy_result *return_drop_dest_policy_result,
10131     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10132     u_int32_t *return_flow_divert_aggregate_unit,
10133     struct socket *so,
10134     int debug)
10135 {
10136 	struct necp_kernel_socket_policy *matched_policy = NULL;
10137 	u_int32_t skip_order = 0;
10138 	u_int32_t skip_session_order = 0;
10139 	bool skipped_ip_result = false;
10140 	size_t route_rule_id_count = 0;
10141 	int i;
10142 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10143 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10144 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10145 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10146 	size_t netagent_cursor = 0;
10147 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10148 	size_t netagent_array_count_adjusted = netagent_array_count;
10149 	if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10150 		netagent_array_count_adjusted = netagent_use_flags_array_count;
10151 	}
10152 
10153 	if (return_drop_all_bypass != NULL) {
10154 		*return_drop_all_bypass = drop_all_bypass;
10155 	}
10156 
10157 	if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10158 		netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10159 	}
10160 
10161 	// Pre-process domain for quick matching
10162 	struct substring domain_substring = {};
10163 	u_int8_t domain_dot_count = 0;
10164 	if (info->domain != NULL) {
10165 		domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10166 		domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10167 	}
10168 
10169 	if (return_filter != NULL) {
10170 		*return_filter = 0;
10171 	}
10172 
10173 	if (return_route_rule_id_array_count != NULL) {
10174 		*return_route_rule_id_array_count = 0;
10175 	}
10176 
10177 	// Do not subject layer-2 filter to NECP policies, return a PASS policy
10178 	if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10179 		return &pass_policy;
10180 	}
10181 
10182 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10183 
10184 	if (policy_search_array != NULL) {
10185 		for (i = 0; policy_search_array[i] != NULL; i++) {
10186 			NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10187 
10188 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10189 				// We've hit a drop all rule
10190 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10191 					drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10192 					if (return_drop_all_bypass != NULL) {
10193 						*return_drop_all_bypass = drop_all_bypass;
10194 					}
10195 				}
10196 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10197 					NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10198 					break;
10199 				}
10200 			}
10201 			if (necp_drop_dest_policy.entry_count != 0 &&
10202 			    necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10203 				// We've hit a drop by destination address rule
10204 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10205 				break;
10206 			}
10207 			if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10208 				// We've hit a drop order for this socket
10209 				break;
10210 			}
10211 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10212 				// Done skipping
10213 				skip_order = 0;
10214 				skip_session_order = 0;
10215 				// If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10216 				if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10217 					*skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10218 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10219 				}
10220 			}
10221 			if (skip_order) {
10222 				if (policy_search_array[i]->order < skip_order) {
10223 					// Skip this policy
10224 					// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10225 					// didn't, clear out the return value for skip ID when we are done with each session.'
10226 					if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10227 						skipped_ip_result = true;
10228 						NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10229 					}
10230 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10231 					continue;
10232 				} else {
10233 					// Done skipping
10234 					skip_order = 0;
10235 					skip_session_order = 0;
10236 				}
10237 			} else if (skip_session_order) {
10238 				// Skip this policy
10239 				// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10240 				// didn't, clear out the return value for skip ID when we are done with each session.'
10241 				if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10242 					skipped_ip_result = true;
10243 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10244 				}
10245 				NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10246 				continue;
10247 			}
10248 
10249 			if (necp_socket_check_policy(policy_search_array[i],
10250 			    info->application_id,
10251 			    info->real_application_id,
10252 			    info->is_entitled,
10253 			    info->account_id,
10254 			    domain_substring,
10255 			    domain_dot_count,
10256 			    info->url,
10257 			    info->pid,
10258 			    info->pid_version,
10259 			    info->uid,
10260 			    info->real_uid,
10261 			    info->bound_interface_index,
10262 			    info->traffic_class,
10263 			    info->protocol,
10264 			    &info->local_addr,
10265 			    &info->remote_addr,
10266 			    required_agent_types,
10267 			    num_required_agent_types,
10268 			    info->has_client,
10269 			    info->client_flags,
10270 			    info->is_platform_binary,
10271 			    info->has_system_signed_result,
10272 			    proc,
10273 			    pf_tag,
10274 			    info->scheme_port,
10275 			    rt,
10276 			    info->is_loopback,
10277 			    debug,
10278 			    info->real_is_platform_binary,
10279 			    info->bound_interface_flags,
10280 			    info->bound_interface_eflags,
10281 			    info->bound_interface_xflags,
10282 			    info,
10283 			    info->is_delegated,
10284 			    so)) {
10285 				if (!debug && necp_data_tracing_session_order) {
10286 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10287 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10288 						NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10289 					}
10290 				}
10291 
10292 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10293 					if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10294 						necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10295 						if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10296 							*return_filter = control_unit;
10297 						} else {
10298 							// Preserve pre-existing connections only if all filters preserve.
10299 							bool preserve_bit_off = false;
10300 							if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10301 							    (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10302 								preserve_bit_off = true;
10303 							}
10304 							*return_filter |= control_unit;
10305 							if (preserve_bit_off == true) {
10306 								*return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10307 							}
10308 						}
10309 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10310 							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);
10311 						}
10312 					}
10313 					continue;
10314 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10315 					if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10316 						return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10317 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10318 							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);
10319 						}
10320 					}
10321 					continue;
10322 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10323 				    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10324 					if (netagent_cursor < netagent_array_count_adjusted) {
10325 						bool agent_already_present = false;
10326 						for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10327 							if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10328 								// Already present. Mark the "SCOPED" flag if flags are necessary.
10329 								agent_already_present = true;
10330 								if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10331 								    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10332 									netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10333 								}
10334 							}
10335 						}
10336 
10337 						if (!agent_already_present) {
10338 							netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10339 							if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10340 								netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10341 							}
10342 							netagent_cursor++;
10343 						}
10344 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10345 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10346 							    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10347 							    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10348 							    policy_search_array[i]->result_parameter.netagent_id);
10349 						}
10350 					}
10351 					continue;
10352 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10353 					bool agent_already_present = false;
10354 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10355 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10356 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10357 							agent_already_present = true;
10358 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10359 						}
10360 					}
10361 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10362 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
10363 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10364 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10365 						netagent_cursor++;
10366 					}
10367 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10368 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10369 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10370 						    policy_search_array[i]->result_parameter.netagent_id);
10371 					}
10372 					continue;
10373 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE) {
10374 					bool agent_already_present = false;
10375 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10376 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10377 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10378 							agent_already_present = true;
10379 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10380 						}
10381 					}
10382 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10383 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
10384 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10385 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10386 						netagent_cursor++;
10387 					}
10388 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10389 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove NetagentType %d",
10390 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10391 						    policy_search_array[i]->result_parameter.netagent_id);
10392 					}
10393 					continue;
10394 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10395 					u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10396 					if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10397 						/* For transparent proxies, accumulate the control unit and continue to the next policy */
10398 						if (return_flow_divert_aggregate_unit != NULL) {
10399 							*return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10400 							if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10401 								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);
10402 							}
10403 						}
10404 						continue;
10405 					}
10406 				}
10407 
10408 				// Matched policy is a skip. Do skip and continue.
10409 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10410 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10411 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10412 					skip_session_order = policy_search_array[i]->session_order + 1;
10413 					if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10414 						*skip_policy_id = policy_search_array[i]->id;
10415 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10416 							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);
10417 						}
10418 					}
10419 					continue;
10420 				}
10421 
10422 				// Matched an allow unentitled, which clears any drop order
10423 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10424 					info->drop_order = 0;
10425 					continue;
10426 				}
10427 
10428 				// Passed all tests, found a match
10429 				matched_policy = policy_search_array[i];
10430 				NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10431 				break;
10432 			}
10433 		}
10434 	}
10435 
10436 	if (return_netagent_array != NULL) {
10437 		if (return_netagent_use_flags_array != NULL) {
10438 			memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10439 			memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10440 		} else {
10441 			for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10442 				if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10443 					return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10444 				} else {
10445 					return_netagent_array[netagent_i] = 0;
10446 				}
10447 			}
10448 		}
10449 	}
10450 
10451 	if (return_route_rule_id_array_count != NULL) {
10452 		*return_route_rule_id_array_count = route_rule_id_count;
10453 	}
10454 	return matched_policy;
10455 }
10456 
10457 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10458 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10459 {
10460 	bool found_match = FALSE;
10461 	ifaddr_t ifa;
10462 	union necp_sockaddr_union address_storage;
10463 	int family = AF_INET;
10464 
10465 	ifnet_head_lock_shared();
10466 	ifnet_t interface = ifindex2ifnet[interface_index];
10467 	ifnet_head_done();
10468 
10469 	if (inp == NULL || interface == NULL) {
10470 		return FALSE;
10471 	}
10472 
10473 	if (inp->inp_vflag & INP_IPV4) {
10474 		family = AF_INET;
10475 	} else if (inp->inp_vflag & INP_IPV6) {
10476 		family = AF_INET6;
10477 	} else {
10478 		return FALSE;
10479 	}
10480 
10481 	// Match socket address against interface addresses
10482 	ifnet_lock_shared(interface);
10483 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10484 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10485 			if (address_storage.sa.sa_family != family) {
10486 				continue;
10487 			}
10488 
10489 			if (family == AF_INET) {
10490 				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10491 					found_match = TRUE;
10492 					break;
10493 				}
10494 			} else if (family == AF_INET6) {
10495 				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10496 					found_match = TRUE;
10497 					break;
10498 				}
10499 			}
10500 		}
10501 	}
10502 	ifnet_lock_done(interface);
10503 
10504 	return found_match;
10505 }
10506 
10507 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10508 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10509 {
10510 	if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10511 		proc_t curr_proc = current_proc();
10512 		proc_t sock_proc = NULL;
10513 		struct socket *so = inp ? inp->inp_socket : NULL;
10514 		pid_t socket_pid = (so == NULL) ? 0 :
10515 #if defined(XNU_TARGET_OS_OSX)
10516 		    so->so_rpid ? so->so_rpid :
10517 #endif
10518 		    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10519 		if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10520 			sock_proc = proc_find(socket_pid);
10521 		}
10522 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10523 		if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10524 			if (sock_proc) {
10525 				proc_rele(sock_proc);
10526 			}
10527 			return NECP_BYPASS_TYPE_DROP;
10528 		}
10529 		if (sock_proc) {
10530 			proc_rele(sock_proc);
10531 		}
10532 
10533 		if (necp_pass_loopback > 0) {
10534 			return NECP_BYPASS_TYPE_LOOPBACK;
10535 		}
10536 	} else if (necp_is_intcoproc(inp, NULL)) {
10537 		return NECP_BYPASS_TYPE_INTCOPROC;
10538 	}
10539 
10540 	return NECP_BYPASS_TYPE_NONE;
10541 }
10542 
10543 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10544 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10545 {
10546 	u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10547 	ifnet_t tunnel_interface = NULL;
10548 
10549 	ifnet_head_lock_shared();
10550 	tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10551 	ifnet_head_done();
10552 
10553 	if (tunnel_interface != NULL) {
10554 		tcp_set_tso(intotcpcb(inp), tunnel_interface);
10555 	}
10556 }
10557 
10558 static inline void
necp_unscope(struct inpcb * inp)10559 necp_unscope(struct inpcb *inp)
10560 {
10561 	// If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10562 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10563 		inp->inp_flags &= ~INP_BOUND_IF;
10564 		inp->inp_boundifp = NULL;
10565 	}
10566 }
10567 
10568 static inline void
necp_clear_tunnel(struct inpcb * inp)10569 necp_clear_tunnel(struct inpcb *inp)
10570 {
10571 	if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10572 		inp->inp_flags &= ~INP_BOUND_IF;
10573 		inp->inp_boundifp = NULL;
10574 	}
10575 }
10576 
10577 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10578 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10579 {
10580 	// Verify netagents
10581 	for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10582 		struct necp_uuid_id_mapping *mapping = NULL;
10583 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
10584 		if (netagent_id == 0) {
10585 			continue;
10586 		}
10587 		mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
10588 		if (mapping != NULL) {
10589 			u_int32_t agent_flags = 0;
10590 			agent_flags = netagent_get_flags(mapping->uuid);
10591 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10592 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10593 					continue;
10594 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10595 					if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10596 						int trigger_error = 0;
10597 						trigger_error = netagent_kernel_trigger(mapping->uuid);
10598 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10599 							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);
10600 						}
10601 					}
10602 					return false;
10603 				}
10604 			}
10605 		}
10606 	}
10607 	return true;
10608 }
10609 
10610 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)10611 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10612 {
10613 	struct socket *so = NULL;
10614 	necp_kernel_policy_filter filter_control_unit = 0;
10615 	struct necp_kernel_socket_policy *matched_policy = NULL;
10616 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10617 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10618 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10619 	proc_t __single socket_proc = NULL;
10620 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10621 
10622 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10623 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10624 
10625 	struct necp_socket_info info = {};
10626 
10627 	u_int32_t flow_divert_aggregate_unit = 0;
10628 
10629 	if (inp == NULL) {
10630 		return NECP_KERNEL_POLICY_ID_NONE;
10631 	}
10632 
10633 	// Ignore invalid addresses
10634 	if (override_local_addr != NULL &&
10635 	    !necp_address_is_valid(override_local_addr)) {
10636 		override_local_addr = NULL;
10637 	}
10638 	if (override_remote_addr != NULL &&
10639 	    !necp_address_is_valid(override_remote_addr)) {
10640 		override_remote_addr = NULL;
10641 	}
10642 
10643 	so = inp->inp_socket;
10644 
10645 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10646 
10647 	// Don't lock. Possible race condition, but we don't want the performance hit.
10648 	if (necp_drop_management_order == 0 &&
10649 	    (necp_kernel_socket_policies_count == 0 ||
10650 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10651 		if (necp_drop_all_order > 0 || drop_order > 0) {
10652 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10653 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10654 			inp->inp_policyresult.policy_gencount = 0;
10655 			inp->inp_policyresult.app_id = 0;
10656 			inp->inp_policyresult.flowhash = 0;
10657 			inp->inp_policyresult.results.filter_control_unit = 0;
10658 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10659 			inp->inp_policyresult.results.route_rule_id = 0;
10660 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10661 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10662 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10663 			} else {
10664 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10665 			}
10666 		}
10667 		return NECP_KERNEL_POLICY_ID_NONE;
10668 	}
10669 
10670 	// Check for loopback exception
10671 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10672 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10673 		// Mark socket as a drop
10674 		necp_unscope(inp);
10675 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10676 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10677 		inp->inp_policyresult.policy_gencount = 0;
10678 		inp->inp_policyresult.app_id = 0;
10679 		inp->inp_policyresult.flowhash = 0;
10680 		inp->inp_policyresult.results.filter_control_unit = 0;
10681 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10682 		inp->inp_policyresult.results.route_rule_id = 0;
10683 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10684 		return NECP_KERNEL_POLICY_ID_NONE;
10685 	}
10686 
10687 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10688 		// Mark socket as a pass
10689 		necp_unscope(inp);
10690 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10691 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10692 		inp->inp_policyresult.policy_gencount = 0;
10693 		inp->inp_policyresult.app_id = 0;
10694 		inp->inp_policyresult.flowhash = 0;
10695 		inp->inp_policyresult.results.filter_control_unit = 0;
10696 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10697 		inp->inp_policyresult.results.route_rule_id = 0;
10698 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10699 		return NECP_KERNEL_POLICY_ID_NONE;
10700 	}
10701 
10702 	// Lock
10703 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10704 	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);
10705 
10706 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10707 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10708 
10709 	// Check info
10710 	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10711 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10712 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10713 	    inp->inp_policyresult.flowhash == flowhash) {
10714 		// If already matched this socket on this generation of table, skip
10715 
10716 		if (info.soflow_entry != NULL) {
10717 			soflow_free_flow(info.soflow_entry);
10718 		}
10719 
10720 		// Unlock
10721 		lck_rw_done(&necp_kernel_policy_lock);
10722 
10723 		if (socket_proc) {
10724 			proc_rele(socket_proc);
10725 		}
10726 
10727 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10728 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10729 			    inp->inp_socket, info.bound_interface_index, info.protocol,
10730 			    inp->inp_policyresult.policy_id,
10731 			    inp->inp_policyresult.results.result,
10732 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10733 		}
10734 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10735 		return inp->inp_policyresult.policy_id;
10736 	}
10737 
10738 	inp->inp_policyresult.app_id = info.application_id;
10739 
10740 	// Match socket to policy
10741 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10742 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10743 	size_t route_rule_id_array_count = 0;
10744 
10745 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10746 	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)],
10747 	    &info,
10748 	    &filter_control_unit,
10749 	    route_rule_id_array,
10750 	    &route_rule_id_array_count,
10751 	    MAX_AGGREGATE_ROUTE_RULES,
10752 	    netagent_ids,
10753 	    NECP_MAX_NETAGENTS,
10754 	    NULL,
10755 	    0,
10756 	    NULL,
10757 	    0,
10758 	    effective_proc,
10759 	    0,
10760 	    &skip_policy_id,
10761 	    inp->inp_route.ro_rt,
10762 	    &drop_dest_policy_result,
10763 	    &drop_all_bypass,
10764 	    &flow_divert_aggregate_unit,
10765 	    so,
10766 	    debug);
10767 
10768 	// Check for loopback exception again after the policy match
10769 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10770 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10771 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10772 		// Mark socket as a pass
10773 		necp_unscope(inp);
10774 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10775 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10776 		inp->inp_policyresult.policy_gencount = 0;
10777 		inp->inp_policyresult.app_id = 0;
10778 		inp->inp_policyresult.flowhash = 0;
10779 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10780 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10781 		inp->inp_policyresult.results.route_rule_id = 0;
10782 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10783 		if (info.soflow_entry != NULL) {
10784 			info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10785 			info.soflow_entry->soflow_policies_gencount = 0;
10786 			soflow_free_flow(info.soflow_entry);
10787 		}
10788 
10789 		// Unlock
10790 		lck_rw_done(&necp_kernel_policy_lock);
10791 
10792 		if (socket_proc) {
10793 			proc_rele(socket_proc);
10794 		}
10795 
10796 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10797 		return NECP_KERNEL_POLICY_ID_NONE;
10798 	}
10799 
10800 	// Verify netagents
10801 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10802 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10803 			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);
10804 		}
10805 
10806 		// Mark socket as a drop if required agent is not active
10807 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10808 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10809 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10810 		inp->inp_policyresult.flowhash = flowhash;
10811 		inp->inp_policyresult.results.filter_control_unit = 0;
10812 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10813 		inp->inp_policyresult.results.route_rule_id = 0;
10814 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10815 		if (info.soflow_entry != NULL) {
10816 			info.soflow_entry->soflow_filter_control_unit = 0;
10817 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10818 			soflow_free_flow(info.soflow_entry);
10819 		}
10820 
10821 		// Unlock
10822 		lck_rw_done(&necp_kernel_policy_lock);
10823 
10824 		if (socket_proc) {
10825 			proc_rele(socket_proc);
10826 		}
10827 
10828 		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);
10829 		return NECP_KERNEL_POLICY_ID_NONE;
10830 	}
10831 
10832 	u_int32_t route_rule_id = 0;
10833 	if (route_rule_id_array_count == 1) {
10834 		route_rule_id = route_rule_id_array[0];
10835 	} else if (route_rule_id_array_count > 1) {
10836 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10837 	}
10838 
10839 	bool reset_tcp_tunnel_interface = false;
10840 	bool send_local_network_denied_event = false;
10841 	if (matched_policy) {
10842 		// For PASS policy result, clear previous rescope / tunnel inteface
10843 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10844 		    (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10845 			necp_unscope(inp);
10846 			necp_clear_tunnel(inp);
10847 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10848 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10849 			}
10850 		}
10851 		matched_policy_id = matched_policy->id;
10852 		inp->inp_policyresult.policy_id = matched_policy->id;
10853 		inp->inp_policyresult.skip_policy_id = skip_policy_id;
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 = filter_control_unit;
10857 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10858 		inp->inp_policyresult.results.route_rule_id = route_rule_id;
10859 		inp->inp_policyresult.results.result = matched_policy->result;
10860 		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10861 		if (info.soflow_entry != NULL) {
10862 			info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10863 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10864 		}
10865 
10866 		if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10867 			inp->inp_policyresult.app_id = info.real_application_id;
10868 		}
10869 
10870 		if (necp_socket_is_connected(inp) &&
10871 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10872 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10873 			NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10874 			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10875 		} else if (necp_socket_is_connected(inp) &&
10876 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10877 		    info.protocol == IPPROTO_TCP) {
10878 			// Reset TCP socket interface based parameters if tunnel policy changes
10879 			reset_tcp_tunnel_interface = true;
10880 		}
10881 
10882 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10883 			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);
10884 		}
10885 
10886 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10887 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10888 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10889 			// Trigger the event that we dropped due to a local network policy
10890 			send_local_network_denied_event = true;
10891 		}
10892 	} else {
10893 		bool drop_all = false;
10894 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10895 			// Mark socket as a drop if set
10896 			drop_all = true;
10897 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10898 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10899 			}
10900 		}
10901 
10902 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10903 		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);
10904 		if (flow_divert_control_unit != 0) {
10905 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10906 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10907 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10908 			inp->inp_policyresult.flowhash = flowhash;
10909 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10910 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10911 			inp->inp_policyresult.results.route_rule_id = route_rule_id;
10912 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10913 			inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10914 			if (info.soflow_entry != NULL) {
10915 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10916 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10917 			}
10918 			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);
10919 		} else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10920 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10921 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10922 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10923 			inp->inp_policyresult.flowhash = flowhash;
10924 			inp->inp_policyresult.results.filter_control_unit = 0;
10925 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10926 			inp->inp_policyresult.results.route_rule_id = 0;
10927 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10928 			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);
10929 			if (info.soflow_entry != NULL) {
10930 				info.soflow_entry->soflow_filter_control_unit = 0;
10931 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10932 			}
10933 		} else {
10934 			// Mark non-matching socket so we don't re-check it
10935 			necp_unscope(inp);
10936 			if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10937 				necp_clear_tunnel(inp);
10938 			}
10939 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10940 				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);
10941 			}
10942 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10943 			inp->inp_policyresult.skip_policy_id = skip_policy_id;
10944 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10945 			inp->inp_policyresult.flowhash = flowhash;
10946 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10947 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10948 			inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10949 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10950 			if (info.soflow_entry != NULL) {
10951 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10952 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10953 			}
10954 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10955 		}
10956 	}
10957 
10958 	if (necp_check_missing_client_drop(effective_proc, &info) ||
10959 	    necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10960 		// Mark as drop
10961 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10962 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10963 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10964 		inp->inp_policyresult.flowhash = flowhash;
10965 		inp->inp_policyresult.results.filter_control_unit = 0;
10966 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10967 		inp->inp_policyresult.results.route_rule_id = 0;
10968 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10969 		if (info.soflow_entry != NULL) {
10970 			info.soflow_entry->soflow_filter_control_unit = 0;
10971 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10972 		}
10973 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10974 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10975 		}
10976 	}
10977 
10978 	if (info.soflow_entry != NULL) {
10979 		soflow_free_flow(info.soflow_entry);
10980 	}
10981 
10982 	// Unlock
10983 	lck_rw_done(&necp_kernel_policy_lock);
10984 
10985 	if (reset_tcp_tunnel_interface) {
10986 		// Update MSS when not holding the policy lock to avoid recursive locking
10987 		tcp_mtudisc(inp, 0);
10988 
10989 		// Update TSO flag based on the tunnel interface
10990 		necp_socket_ip_tunnel_tso(inp);
10991 	}
10992 
10993 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10994 		inp->inp_policyresult.network_denied_notifies++;
10995 #if defined(XNU_TARGET_OS_OSX)
10996 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10997 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10998 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10999 		    NETPOLICY_NETWORKTYPE_LOCAL);
11000 #else
11001 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
11002 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
11003 		    NETPOLICY_NETWORKTYPE_LOCAL);
11004 #endif
11005 	}
11006 
11007 	if (socket_proc) {
11008 		proc_rele(socket_proc);
11009 	}
11010 
11011 	return matched_policy_id;
11012 }
11013 
11014 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)11015 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)
11016 {
11017 	u_int32_t bound_interface_flags = 0;
11018 	u_int32_t bound_interface_eflags = 0;
11019 	u_int32_t bound_interface_xflags = 0;
11020 
11021 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
11022 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
11023 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
11024 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
11025 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
11026 			    cond_bound_interface_index, bound_interface_index);
11027 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
11028 				if (bound_interface_index == cond_bound_interface_index) {
11029 					// No match, matches forbidden interface
11030 					return FALSE;
11031 				}
11032 			} else {
11033 				if (bound_interface_index != cond_bound_interface_index) {
11034 					// No match, does not match required interface
11035 					return FALSE;
11036 				}
11037 			}
11038 		}
11039 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
11040 			if (bound_interface_index != IFSCOPE_NONE) {
11041 				ifnet_head_lock_shared();
11042 				ifnet_t interface = ifindex2ifnet[bound_interface_index];
11043 				if (interface != NULL) {
11044 					bound_interface_flags = interface->if_flags;
11045 					bound_interface_eflags = interface->if_eflags;
11046 					bound_interface_xflags = interface->if_xflags;
11047 				}
11048 				ifnet_head_done();
11049 			}
11050 
11051 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11052 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
11053 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11054 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
11055 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11056 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
11057 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
11058 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
11059 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
11060 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
11061 					// No match, matches some forbidden interface flags
11062 					return FALSE;
11063 				}
11064 			} else {
11065 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
11066 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
11067 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
11068 					// No match, does not match some required interface xflags
11069 					return FALSE;
11070 				}
11071 			}
11072 		}
11073 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
11074 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
11075 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
11076 			if (bound_interface_index != 0) {
11077 				// No match, requires a non-bound packet
11078 				return FALSE;
11079 			}
11080 		}
11081 	}
11082 
11083 	if (kernel_policy->condition_mask == 0) {
11084 		return TRUE;
11085 	}
11086 
11087 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
11088 		necp_kernel_policy_id matched_policy_id =
11089 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
11090 		NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
11091 		    "NECP_KERNEL_CONDITION_POLICY_ID",
11092 		    kernel_policy->cond_policy_id, 0, 0,
11093 		    matched_policy_id, socket_policy_id, socket_skip_policy_id);
11094 		if (matched_policy_id != kernel_policy->cond_policy_id) {
11095 			// No match, does not match required id
11096 			return FALSE;
11097 		}
11098 	}
11099 
11100 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
11101 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
11102 		    "NECP_KERNEL_CONDITION_LAST_INTERFACE",
11103 		    kernel_policy->cond_last_interface_index, last_interface_index);
11104 		if (last_interface_index != kernel_policy->cond_last_interface_index) {
11105 			return FALSE;
11106 		}
11107 	}
11108 
11109 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11110 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
11111 		    "NECP_KERNEL_CONDITION_PROTOCOL",
11112 		    kernel_policy->cond_protocol, protocol);
11113 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11114 			if (protocol == kernel_policy->cond_protocol) {
11115 				// No match, matches forbidden protocol
11116 				return FALSE;
11117 			}
11118 		} else {
11119 			if (protocol != kernel_policy->cond_protocol) {
11120 				// No match, does not match required protocol
11121 				return FALSE;
11122 			}
11123 		}
11124 	}
11125 
11126 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11127 		bool is_local = FALSE;
11128 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11129 
11130 		if (rt != NULL) {
11131 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11132 		} else {
11133 			is_local = necp_is_route_local(remote, include_local_addresses);
11134 		}
11135 		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);
11136 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11137 			if (is_local) {
11138 				// Match local-networks, fail
11139 				return FALSE;
11140 			}
11141 		} else {
11142 			if (!is_local) {
11143 				// Either no route to validate or no match for local networks
11144 				return FALSE;
11145 			}
11146 		}
11147 	}
11148 
11149 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11150 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11151 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11152 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11153 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11154 				if (inRange) {
11155 					return FALSE;
11156 				}
11157 			} else {
11158 				if (!inRange) {
11159 					return FALSE;
11160 				}
11161 			}
11162 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11163 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11164 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11165 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11166 				if (inSubnet) {
11167 					return FALSE;
11168 				}
11169 			} else {
11170 				if (!inSubnet) {
11171 					return FALSE;
11172 				}
11173 			}
11174 		}
11175 	}
11176 
11177 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11178 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11179 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11180 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11181 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11182 				if (inRange) {
11183 					return FALSE;
11184 				}
11185 			} else {
11186 				if (!inRange) {
11187 					return FALSE;
11188 				}
11189 			}
11190 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11191 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11192 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11193 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11194 				if (inSubnet) {
11195 					return FALSE;
11196 				}
11197 			} else {
11198 				if (!inSubnet) {
11199 					return FALSE;
11200 				}
11201 			}
11202 		}
11203 	}
11204 
11205 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11206 		u_int16_t remote_port = 0;
11207 		if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11208 			remote_port = SIN(remote)->sin_port;
11209 		}
11210 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11211 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
11212 		    0, remote_port);
11213 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11214 			if (kernel_policy->cond_scheme_port == remote_port) {
11215 				return FALSE;
11216 			}
11217 		} else {
11218 			if (kernel_policy->cond_scheme_port != remote_port) {
11219 				return FALSE;
11220 			}
11221 		}
11222 	}
11223 
11224 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11225 		bool tags_matched = false;
11226 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11227 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11228 		    kernel_policy->cond_packet_filter_tags, pf_tag);
11229 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11230 			if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11231 				tags_matched = true;
11232 			}
11233 
11234 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11235 				if (tags_matched) {
11236 					return FALSE;
11237 				}
11238 			} else {
11239 				if (!tags_matched) {
11240 					return FALSE;
11241 				}
11242 			}
11243 		}
11244 	}
11245 
11246 	return TRUE;
11247 }
11248 
11249 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)11250 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)
11251 {
11252 	u_int32_t skip_order = 0;
11253 	u_int32_t skip_session_order = 0;
11254 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11255 	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)];
11256 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11257 	size_t route_rule_id_count = 0;
11258 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11259 	if (return_drop_all_bypass != NULL) {
11260 		*return_drop_all_bypass = drop_all_bypass;
11261 	}
11262 
11263 	if (return_route_rule_id != NULL) {
11264 		*return_route_rule_id = 0;
11265 	}
11266 
11267 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11268 
11269 	if (policy_search_array != NULL) {
11270 		for (int i = 0; policy_search_array[i] != NULL; i++) {
11271 			NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11272 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11273 				// We've hit a drop all rule
11274 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11275 					drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11276 					if (return_drop_all_bypass != NULL) {
11277 						*return_drop_all_bypass = drop_all_bypass;
11278 					}
11279 				}
11280 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11281 					NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11282 					break;
11283 				}
11284 			}
11285 			if (necp_drop_dest_policy.entry_count > 0 &&
11286 			    necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11287 				// We've hit a drop by destination address rule
11288 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11289 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11290 				break;
11291 			}
11292 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11293 				// Done skipping
11294 				skip_order = 0;
11295 				skip_session_order = 0;
11296 			}
11297 			if (skip_order) {
11298 				if (policy_search_array[i]->order < skip_order) {
11299 					// Skip this policy
11300 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11301 					continue;
11302 				} else {
11303 					// Done skipping
11304 					skip_order = 0;
11305 					skip_session_order = 0;
11306 				}
11307 			} else if (skip_session_order) {
11308 				// Skip this policy
11309 				NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11310 				continue;
11311 			}
11312 
11313 			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)) {
11314 				if (!debug && necp_data_tracing_session_order) {
11315 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11316 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11317 						NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11318 					}
11319 				}
11320 
11321 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11322 					if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11323 						route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11324 					}
11325 					continue;
11326 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11327 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11328 					skip_session_order = policy_search_array[i]->session_order + 1;
11329 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11330 					continue;
11331 				}
11332 
11333 				// Passed all tests, found a match
11334 				matched_policy = policy_search_array[i];
11335 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11336 				break;
11337 			}
11338 		}
11339 	}
11340 
11341 	if (route_rule_id_count == 1) {
11342 		*return_route_rule_id = route_rule_id_array[0];
11343 	} else if (route_rule_id_count > 1) {
11344 		*return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11345 	}
11346 
11347 	return matched_policy;
11348 }
11349 
11350 static inline bool
necp_output_bypass(struct mbuf * packet)11351 necp_output_bypass(struct mbuf *packet)
11352 {
11353 	if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11354 		return true;
11355 	}
11356 	if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11357 		return true;
11358 	}
11359 	if (necp_is_intcoproc(NULL, packet)) {
11360 		return true;
11361 	}
11362 	return false;
11363 }
11364 
11365 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)11366 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11367     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11368 {
11369 	struct ip *ip = NULL;
11370 	int hlen = sizeof(struct ip);
11371 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11372 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11373 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11374 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11375 	u_int16_t protocol = 0;
11376 	u_int32_t bound_interface_index = 0;
11377 	u_int32_t last_interface_index = 0;
11378 	union necp_sockaddr_union local_addr = { };
11379 	union necp_sockaddr_union remote_addr = { };
11380 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11381 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11382 	u_int16_t pf_tag = 0;
11383 
11384 	if (result) {
11385 		*result = 0;
11386 	}
11387 
11388 	if (result_parameter) {
11389 		memset(result_parameter, 0, sizeof(*result_parameter));
11390 	}
11391 
11392 	if (packet == NULL) {
11393 		return NECP_KERNEL_POLICY_ID_NONE;
11394 	}
11395 
11396 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11397 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11398 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11399 
11400 	// Exit early for an empty list
11401 	// Don't lock. Possible race condition, but we don't want the performance hit.
11402 	if (necp_kernel_ip_output_policies_count == 0 ||
11403 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11404 		if (necp_drop_all_order > 0) {
11405 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11406 			if (result) {
11407 				if (necp_output_bypass(packet)) {
11408 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11409 				} else {
11410 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11411 				}
11412 			}
11413 		}
11414 
11415 		return matched_policy_id;
11416 	}
11417 
11418 	// Check for loopback exception
11419 	if (necp_output_bypass(packet)) {
11420 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11421 		if (result) {
11422 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11423 		}
11424 		return matched_policy_id;
11425 	}
11426 
11427 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11428 
11429 	// Process packet to get relevant fields
11430 	ip = mtod(packet, struct ip *);
11431 #ifdef _IP_VHL
11432 	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11433 #else
11434 	hlen = ip->ip_hl << 2;
11435 #endif
11436 
11437 	protocol = ip->ip_p;
11438 
11439 	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11440 	    (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11441 	    ipoa->ipoa_boundif != IFSCOPE_NONE) {
11442 		bound_interface_index = ipoa->ipoa_boundif;
11443 	}
11444 
11445 	local_addr.sin.sin_family = AF_INET;
11446 	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11447 	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11448 
11449 	remote_addr.sin.sin_family = AF_INET;
11450 	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11451 	memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11452 
11453 	switch (protocol) {
11454 	case IPPROTO_TCP: {
11455 		struct tcphdr th;
11456 		if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11457 			m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11458 			SIN(&local_addr)->sin_port = th.th_sport;
11459 			SIN(&remote_addr)->sin_port = th.th_dport;
11460 		}
11461 		break;
11462 	}
11463 	case IPPROTO_UDP: {
11464 		struct udphdr uh;
11465 		if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11466 			m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11467 			SIN(&local_addr)->sin_port = uh.uh_sport;
11468 			SIN(&remote_addr)->sin_port = uh.uh_dport;
11469 		}
11470 		break;
11471 	}
11472 	default: {
11473 		SIN(&local_addr)->sin_port = 0;
11474 		SIN(&remote_addr)->sin_port = 0;
11475 		break;
11476 	}
11477 	}
11478 
11479 	// Match packet to policy
11480 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11481 	u_int32_t route_rule_id = 0;
11482 
11483 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11484 	NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11485 
11486 	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);
11487 	if (matched_policy) {
11488 		matched_policy_id = matched_policy->id;
11489 		if (result) {
11490 			*result = matched_policy->result;
11491 		}
11492 
11493 		if (result_parameter) {
11494 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11495 		}
11496 
11497 		if (route_rule_id != 0 &&
11498 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11499 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11500 		}
11501 
11502 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11503 			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);
11504 		}
11505 	} else {
11506 		bool drop_all = false;
11507 		/*
11508 		 * Apply drop-all only to packets which have never matched a primary policy (check
11509 		 * if the packet saved policy id is none or falls within the socket policy id range).
11510 		 */
11511 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11512 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11513 			drop_all = true;
11514 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11515 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11516 			}
11517 		}
11518 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11519 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11520 			if (result) {
11521 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11522 				NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11523 			}
11524 		} else if (route_rule_id != 0 &&
11525 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11526 			// If we matched a route rule, mark it
11527 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11528 		}
11529 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11530 			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);
11531 		}
11532 	}
11533 
11534 	lck_rw_done(&necp_kernel_policy_lock);
11535 
11536 	return matched_policy_id;
11537 }
11538 
11539 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)11540 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11541     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11542 {
11543 	struct ip6_hdr *ip6 = NULL;
11544 	int next = -1;
11545 	int offset = 0;
11546 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11547 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11548 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11549 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11550 	u_int16_t protocol = 0;
11551 	u_int32_t bound_interface_index = 0;
11552 	u_int32_t last_interface_index = 0;
11553 	union necp_sockaddr_union local_addr = { };
11554 	union necp_sockaddr_union remote_addr = { };
11555 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11556 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11557 	u_int16_t pf_tag = 0;
11558 
11559 	if (result) {
11560 		*result = 0;
11561 	}
11562 
11563 	if (result_parameter) {
11564 		memset(result_parameter, 0, sizeof(*result_parameter));
11565 	}
11566 
11567 	if (packet == NULL) {
11568 		return NECP_KERNEL_POLICY_ID_NONE;
11569 	}
11570 
11571 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11572 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11573 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11574 
11575 	// Exit early for an empty list
11576 	// Don't lock. Possible race condition, but we don't want the performance hit.
11577 	if (necp_drop_management_order == 0 &&
11578 	    (necp_kernel_ip_output_policies_count == 0 ||
11579 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11580 		if (necp_drop_all_order > 0) {
11581 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11582 			if (result) {
11583 				if (necp_output_bypass(packet)) {
11584 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11585 				} else {
11586 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11587 				}
11588 			}
11589 		}
11590 
11591 		return matched_policy_id;
11592 	}
11593 
11594 	// Check for loopback exception
11595 	if (necp_output_bypass(packet)) {
11596 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11597 		if (result) {
11598 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11599 		}
11600 		return matched_policy_id;
11601 	}
11602 
11603 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11604 
11605 	// Process packet to get relevant fields
11606 	ip6 = mtod(packet, struct ip6_hdr *);
11607 
11608 	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11609 	    (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11610 	    ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11611 		bound_interface_index = ip6oa->ip6oa_boundif;
11612 	}
11613 
11614 	SIN6(&local_addr)->sin6_family = AF_INET6;
11615 	SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11616 	memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11617 
11618 	SIN6(&remote_addr)->sin6_family = AF_INET6;
11619 	SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11620 	memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11621 
11622 	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11623 	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11624 		protocol = next;
11625 		switch (protocol) {
11626 		case IPPROTO_TCP: {
11627 			struct tcphdr th;
11628 			if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11629 				m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11630 				SIN6(&local_addr)->sin6_port = th.th_sport;
11631 				SIN6(&remote_addr)->sin6_port = th.th_dport;
11632 			}
11633 			break;
11634 		}
11635 		case IPPROTO_UDP: {
11636 			struct udphdr uh;
11637 			if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11638 				m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11639 				SIN6(&local_addr)->sin6_port = uh.uh_sport;
11640 				SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11641 			}
11642 			break;
11643 		}
11644 		default: {
11645 			SIN6(&local_addr)->sin6_port = 0;
11646 			SIN6(&remote_addr)->sin6_port = 0;
11647 			break;
11648 		}
11649 		}
11650 	}
11651 
11652 	// Match packet to policy
11653 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11654 	u_int32_t route_rule_id = 0;
11655 
11656 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11657 	NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11658 
11659 	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);
11660 	if (matched_policy) {
11661 		matched_policy_id = matched_policy->id;
11662 		if (result) {
11663 			*result = matched_policy->result;
11664 		}
11665 
11666 		if (result_parameter) {
11667 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11668 		}
11669 
11670 		if (route_rule_id != 0 &&
11671 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11672 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11673 		}
11674 
11675 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11676 			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);
11677 		}
11678 	} else {
11679 		bool drop_all = false;
11680 		/*
11681 		 * Apply drop-all only to packets which have never matched a primary policy (check
11682 		 * if the packet saved policy id is none or falls within the socket policy id range).
11683 		 */
11684 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11685 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11686 			drop_all = true;
11687 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11688 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11689 			}
11690 		}
11691 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11692 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11693 			if (result) {
11694 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11695 				NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11696 			}
11697 		} else if (route_rule_id != 0 &&
11698 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11699 			// If we matched a route rule, mark it
11700 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11701 		}
11702 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11703 			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);
11704 		}
11705 	}
11706 
11707 	lck_rw_done(&necp_kernel_policy_lock);
11708 
11709 	return matched_policy_id;
11710 }
11711 
11712 // Utilities
11713 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11714 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11715 {
11716 	int cmp = 0;
11717 
11718 	if (addr == NULL || range_start == NULL || range_end == NULL) {
11719 		return FALSE;
11720 	}
11721 
11722 	/* Must be greater than or equal to start */
11723 	cmp = necp_addr_compare(addr, range_start, 1);
11724 	if (cmp != 0 && cmp != 1) {
11725 		return FALSE;
11726 	}
11727 
11728 	/* Must be less than or equal to end */
11729 	cmp = necp_addr_compare(addr, range_end, 1);
11730 	if (cmp != 0 && cmp != -1) {
11731 		return FALSE;
11732 	}
11733 
11734 	return TRUE;
11735 }
11736 
11737 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)11738 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11739 {
11740 	int cmp = 0;
11741 
11742 	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11743 		return FALSE;
11744 	}
11745 
11746 	/* Must be greater than or equal to start */
11747 	cmp = necp_addr_compare(inner_range_start, range_start, 1);
11748 	if (cmp != 0 && cmp != 1) {
11749 		return FALSE;
11750 	}
11751 
11752 	/* Must be less than or equal to end */
11753 	cmp = necp_addr_compare(inner_range_end, range_end, 1);
11754 	if (cmp != 0 && cmp != -1) {
11755 		return FALSE;
11756 	}
11757 
11758 	return TRUE;
11759 }
11760 
11761 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11762 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11763 {
11764 	if (addr == NULL || subnet_addr == NULL) {
11765 		return FALSE;
11766 	}
11767 
11768 	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11769 		return FALSE;
11770 	}
11771 
11772 	switch (addr->sa_family) {
11773 	case AF_INET: {
11774 		if (satosin(subnet_addr)->sin_port != 0 &&
11775 		    satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11776 			return FALSE;
11777 		}
11778 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11779 	}
11780 	case AF_INET6: {
11781 		if (satosin6(subnet_addr)->sin6_port != 0 &&
11782 		    satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11783 			return FALSE;
11784 		}
11785 		if (satosin6(addr)->sin6_scope_id &&
11786 		    satosin6(subnet_addr)->sin6_scope_id &&
11787 		    satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11788 			return FALSE;
11789 		}
11790 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11791 	}
11792 	default: {
11793 		return FALSE;
11794 	}
11795 	}
11796 
11797 	return FALSE;
11798 }
11799 
11800 /*
11801  * Return values:
11802  * -1: sa1 < sa2
11803  * 0: sa1 == sa2
11804  * 1: sa1 > sa2
11805  * 2: Not comparable or error
11806  */
11807 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11808 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11809 {
11810 	int result = 0;
11811 	int port_result = 0;
11812 
11813 	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11814 		return 2;
11815 	}
11816 
11817 	if (sa1->sa_len == 0) {
11818 		return 0;
11819 	}
11820 
11821 	switch (sa1->sa_family) {
11822 	case AF_INET: {
11823 		if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11824 			return 2;
11825 		}
11826 
11827 		result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11828 
11829 		if (check_port) {
11830 			if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11831 				port_result = -1;
11832 			} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11833 				port_result = 1;
11834 			}
11835 
11836 			if (result == 0) {
11837 				result = port_result;
11838 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11839 				return 2;
11840 			}
11841 		}
11842 
11843 		break;
11844 	}
11845 	case AF_INET6: {
11846 		if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11847 			return 2;
11848 		}
11849 
11850 		if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11851 			return 2;
11852 		}
11853 
11854 		result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11855 
11856 		if (check_port) {
11857 			if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11858 				port_result = -1;
11859 			} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11860 				port_result = 1;
11861 			}
11862 
11863 			if (result == 0) {
11864 				result = port_result;
11865 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11866 				return 2;
11867 			}
11868 		}
11869 
11870 		break;
11871 	}
11872 	default: {
11873 		result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11874 		break;
11875 	}
11876 	}
11877 
11878 	if (result < 0) {
11879 		result = (-1);
11880 	} else if (result > 0) {
11881 		result = (1);
11882 	}
11883 
11884 	return result;
11885 }
11886 
11887 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11888 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11889 {
11890 	u_int8_t mask;
11891 
11892 	/* Handle null pointers */
11893 	if (p1 == NULL || p2 == NULL) {
11894 		return p1 == p2;
11895 	}
11896 
11897 	while (bits >= 8) {
11898 		if (*p1++ != *p2++) {
11899 			return FALSE;
11900 		}
11901 		bits -= 8;
11902 	}
11903 
11904 	if (bits > 0) {
11905 		mask = ~((1 << (8 - bits)) - 1);
11906 		if ((*p1 & mask) != (*p2 & mask)) {
11907 			return FALSE;
11908 		}
11909 	}
11910 	return TRUE;
11911 }
11912 
11913 static bool
necp_addr_is_empty(struct sockaddr * addr)11914 necp_addr_is_empty(struct sockaddr *addr)
11915 {
11916 	if (addr == NULL) {
11917 		return TRUE;
11918 	}
11919 
11920 	if (addr->sa_len == 0) {
11921 		return TRUE;
11922 	}
11923 
11924 	switch (addr->sa_family) {
11925 	case AF_INET: {
11926 		static struct sockaddr_in ipv4_empty_address = {
11927 			.sin_len = sizeof(struct sockaddr_in),
11928 			.sin_family = AF_INET,
11929 			.sin_port = 0,
11930 			.sin_addr = { .s_addr = 0 }, // 0.0.0.0
11931 			.sin_zero = {0},
11932 		};
11933 		if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11934 			return TRUE;
11935 		} else {
11936 			return FALSE;
11937 		}
11938 	}
11939 	case AF_INET6: {
11940 		static struct sockaddr_in6 ipv6_empty_address = {
11941 			.sin6_len = sizeof(struct sockaddr_in6),
11942 			.sin6_family = AF_INET6,
11943 			.sin6_port = 0,
11944 			.sin6_flowinfo = 0,
11945 			.sin6_addr = IN6ADDR_ANY_INIT, // ::
11946 			.sin6_scope_id = 0,
11947 		};
11948 		if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11949 			return TRUE;
11950 		} else {
11951 			return FALSE;
11952 		}
11953 	}
11954 	default:
11955 		return FALSE;
11956 	}
11957 
11958 	return FALSE;
11959 }
11960 
11961 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)11962 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)
11963 {
11964 	bool qos_marking = FALSE;
11965 	int exception_index = 0;
11966 	struct necp_route_rule *route_rule = NULL;
11967 
11968 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11969 	if (route_rule == NULL) {
11970 		qos_marking = FALSE;
11971 		goto done;
11972 	}
11973 
11974 	if (route_rule->match_netagent_id != 0) {
11975 		if (netagent_array == NULL || netagent_array_count == 0) {
11976 			// No agents, ignore rule
11977 			goto done;
11978 		}
11979 		bool found_match = FALSE;
11980 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11981 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11982 				found_match = TRUE;
11983 				break;
11984 			}
11985 		}
11986 		if (!found_match) {
11987 			// Agents don't match, ignore rule
11988 			goto done;
11989 		}
11990 	}
11991 
11992 	qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11993 
11994 	if (ifp == NULL) {
11995 		goto done;
11996 	}
11997 
11998 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11999 		if (route_rule->exception_if_indices[exception_index] == 0) {
12000 			break;
12001 		}
12002 		if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
12003 			continue;
12004 		}
12005 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
12006 			qos_marking = TRUE;
12007 			if (necp_debug > 2) {
12008 				NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
12009 				    route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
12010 			}
12011 			goto done;
12012 		}
12013 	}
12014 
12015 	if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
12016 	    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
12017 	    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
12018 	    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
12019 	    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
12020 	    (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_ULTRA_CONSTRAINED(ifp)) ||
12021 	    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
12022 	    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
12023 		qos_marking = TRUE;
12024 		if (necp_debug > 2) {
12025 			NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d UlCn:%d for Rule %d Allowed %d",
12026 			    route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
12027 			    route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action,
12028 			    route_rule->ultra_constrained_action, route_rule_id, qos_marking);
12029 		}
12030 		goto done;
12031 	}
12032 done:
12033 	if (necp_debug > 1) {
12034 		NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
12035 		    route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
12036 	}
12037 	return qos_marking;
12038 }
12039 
12040 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)12041 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)
12042 {
12043 	bool new_qos_marking = old_qos_marking;
12044 	struct ifnet *ifp = interface;
12045 
12046 	if (net_qos_policy_restricted == 0) {
12047 		return new_qos_marking;
12048 	}
12049 
12050 	/*
12051 	 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
12052 	 */
12053 	if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
12054 		return new_qos_marking;
12055 	}
12056 
12057 	lck_rw_lock_shared(&necp_kernel_policy_lock);
12058 
12059 	if (ifp == NULL && route != NULL) {
12060 		ifp = route->rt_ifp;
12061 	}
12062 	/*
12063 	 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
12064 	 */
12065 	if (ifp == NULL || route_rule_id == 0) {
12066 		new_qos_marking = FALSE;
12067 		goto done;
12068 	}
12069 
12070 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12071 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12072 		if (aggregate_route_rule != NULL) {
12073 			int index = 0;
12074 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12075 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12076 				if (sub_route_rule_id == 0) {
12077 					break;
12078 				}
12079 				new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
12080 				if (new_qos_marking == TRUE) {
12081 					break;
12082 				}
12083 			}
12084 		}
12085 	} else {
12086 		new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
12087 	}
12088 	/*
12089 	 * Now that we have an interface we remember the gencount
12090 	 */
12091 	*qos_marking_gencount = necp_kernel_socket_policies_gencount;
12092 
12093 done:
12094 	lck_rw_done(&necp_kernel_policy_lock);
12095 	return new_qos_marking;
12096 }
12097 
12098 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)12099 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
12100 {
12101 	bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
12102 
12103 	if (net_qos_policy_restricted == 0) {
12104 		return;
12105 	}
12106 	if (inp->inp_socket == NULL) {
12107 		return;
12108 	}
12109 	if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
12110 		return;
12111 	}
12112 
12113 	qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
12114 
12115 	if (qos_marking == TRUE) {
12116 		inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
12117 	} else {
12118 		inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
12119 	}
12120 }
12121 
12122 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)12123 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
12124 {
12125 	if (ifp != NULL &&
12126 	    (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12127 	    ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12128 		return true;
12129 	}
12130 	if (delegated_ifp != NULL &&
12131 	    (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12132 	    delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12133 		return true;
12134 	}
12135 	return false;
12136 }
12137 
12138 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,bool * ultra_constrained_denied)12139 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,
12140     u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied)
12141 {
12142 	bool default_is_allowed = TRUE;
12143 	u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12144 	int exception_index = 0;
12145 	struct ifnet *delegated_ifp = NULL;
12146 	struct necp_route_rule *route_rule = NULL;
12147 
12148 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12149 	if (route_rule == NULL) {
12150 		return TRUE;
12151 	}
12152 
12153 	if (route_rule->match_netagent_id != 0) {
12154 		if (netagent_array == NULL || netagent_array_count == 0) {
12155 			// No agents, ignore rule
12156 			return TRUE;
12157 		}
12158 		bool found_match = FALSE;
12159 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12160 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12161 				found_match = TRUE;
12162 				break;
12163 			}
12164 		}
12165 		if (!found_match) {
12166 			// Agents don't match, ignore rule
12167 			return TRUE;
12168 		}
12169 	}
12170 
12171 	default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12172 	if (ifp == NULL && route != NULL) {
12173 		ifp = route->rt_ifp;
12174 	}
12175 	if (ifp == NULL) {
12176 		if (necp_debug > 1 && !default_is_allowed) {
12177 			NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12178 		}
12179 		return default_is_allowed;
12180 	}
12181 
12182 	delegated_ifp = ifp->if_delegated.ifp;
12183 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12184 		if (route_rule->exception_if_indices[exception_index] == 0) {
12185 			break;
12186 		}
12187 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12188 		    (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12189 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12190 				const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12191 				if (necp_debug > 1 && lqm_abort) {
12192 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12193 					    route_rule->exception_if_indices[exception_index], route_rule_id);
12194 				}
12195 				return false;
12196 			} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12197 				if (necp_debug > 1) {
12198 					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));
12199 				}
12200 				if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12201 					*interface_type_denied = route_rule->effective_type;
12202 				}
12203 				return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12204 			}
12205 		}
12206 	}
12207 
12208 	if (IFNET_IS_CELLULAR(ifp)) {
12209 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12210 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12211 				if (interface_type_denied != NULL) {
12212 					*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12213 					if (route_rule->effective_type != 0) {
12214 						*interface_type_denied = route_rule->effective_type;
12215 					}
12216 				}
12217 				// Mark aggregate action as deny
12218 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12219 			}
12220 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12221 			if (interface_type_denied != NULL) {
12222 				*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12223 				if (route_rule->effective_type != 0) {
12224 					*interface_type_denied = route_rule->effective_type;
12225 				}
12226 			}
12227 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12228 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12229 			    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12230 				// Deny wins if there is a conflict
12231 				type_aggregate_action = route_rule->cellular_action;
12232 			}
12233 		}
12234 	}
12235 
12236 	if (IFNET_IS_WIFI(ifp)) {
12237 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12238 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12239 				if (interface_type_denied != NULL) {
12240 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12241 					if (route_rule->effective_type != 0) {
12242 						*interface_type_denied = route_rule->effective_type;
12243 					}
12244 				}
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->wifi_action)) {
12249 			if (interface_type_denied != NULL) {
12250 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12251 				if (route_rule->effective_type != 0) {
12252 					*interface_type_denied = route_rule->effective_type;
12253 				}
12254 			}
12255 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12256 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12257 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12258 				// Deny wins if there is a conflict
12259 				type_aggregate_action = route_rule->wifi_action;
12260 			}
12261 		}
12262 	}
12263 
12264 	if (IFNET_IS_COMPANION_LINK(ifp) ||
12265 	    (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12266 		if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12267 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12268 				if (interface_type_denied != NULL) {
12269 					*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12270 					if (route_rule->effective_type != 0) {
12271 						*interface_type_denied = route_rule->effective_type;
12272 					}
12273 				}
12274 				// Mark aggregate action as deny
12275 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12276 			}
12277 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12278 			if (interface_type_denied != NULL) {
12279 				*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12280 				if (route_rule->effective_type != 0) {
12281 					*interface_type_denied = route_rule->effective_type;
12282 				}
12283 			}
12284 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12285 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12286 			    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12287 				// Deny wins if there is a conflict
12288 				type_aggregate_action = route_rule->companion_action;
12289 			}
12290 		}
12291 	}
12292 
12293 	if (IFNET_IS_WIRED(ifp)) {
12294 		if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12295 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12296 				if (interface_type_denied != NULL) {
12297 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12298 					if (route_rule->effective_type != 0) {
12299 						*interface_type_denied = route_rule->effective_type;
12300 					}
12301 				}
12302 				// Mark aggregate action as deny
12303 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12304 			}
12305 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12306 			if (interface_type_denied != NULL) {
12307 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12308 				if (route_rule->effective_type != 0) {
12309 					*interface_type_denied = route_rule->effective_type;
12310 				}
12311 			}
12312 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12313 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12314 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12315 				// Deny wins if there is a conflict
12316 				type_aggregate_action = route_rule->wired_action;
12317 			}
12318 		}
12319 	}
12320 
12321 	if (IFNET_IS_EXPENSIVE(ifp)) {
12322 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12323 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12324 				// Mark aggregate action as deny
12325 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12326 			}
12327 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12328 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12329 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12330 			    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12331 				// Deny wins if there is a conflict
12332 				type_aggregate_action = route_rule->expensive_action;
12333 			}
12334 		}
12335 	}
12336 
12337 	if (IFNET_IS_CONSTRAINED(ifp)) {
12338 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12339 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12340 				// Mark aggregate action as deny
12341 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12342 			}
12343 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12344 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12345 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12346 			    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12347 				// Deny wins if there is a conflict
12348 				type_aggregate_action = route_rule->constrained_action;
12349 			}
12350 		}
12351 	}
12352 
12353 	if (IFNET_IS_VPN(ifp)) {
12354 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12355 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12356 				// Mark aggregate action as deny
12357 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12358 			}
12359 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12360 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12361 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12362 			    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12363 				// Deny wins if there is a conflict
12364 				type_aggregate_action = route_rule->vpn_action;
12365 			}
12366 		}
12367 	}
12368 
12369 	if (IFNET_IS_ULTRA_CONSTRAINED(ifp)) {
12370 		if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12371 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12372 				// Mark aggregate action as deny
12373 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12374 			}
12375 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->ultra_constrained_action)) {
12376 			if (ultra_constrained_denied != NULL && IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action)) {
12377 				*ultra_constrained_denied = true;
12378 			}
12379 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12380 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12381 			    IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action))) {
12382 				// Deny wins if there is a conflict
12383 				type_aggregate_action = route_rule->ultra_constrained_action;
12384 			}
12385 		}
12386 	}
12387 
12388 	if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12389 		if (necp_debug > 1) {
12390 			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));
12391 		}
12392 		return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12393 	}
12394 
12395 	if (necp_debug > 1 && !default_is_allowed) {
12396 		NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12397 	}
12398 	return default_is_allowed;
12399 }
12400 
12401 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12402 necp_proc_is_allowed_on_management_interface(proc_t proc)
12403 {
12404 	bool allowed = false;
12405 	const task_t __single task = proc_task(proc);
12406 
12407 	if (task != NULL) {
12408 		if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12409 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12410 #if DEBUG || DEVELOPMENT
12411 		    || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12412 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12413 #endif /* DEBUG || DEVELOPMENT */
12414 		    ) {
12415 			allowed = true;
12416 		}
12417 	}
12418 	return allowed;
12419 }
12420 
12421 __attribute__((noinline))
12422 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12423 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12424 {
12425 	char buf[128];
12426 
12427 	if (inp != NULL) {
12428 		inp_snprintf_tuple(inp, buf, sizeof(buf));
12429 	} else {
12430 		*buf = 0;
12431 	}
12432 	os_log(OS_LOG_DEFAULT,
12433 	    "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12434 	    proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12435 	    proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12436 	    inp != NULL ? buf : "",
12437 	    ifp->if_xname);
12438 }
12439 
12440 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12441 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12442 {
12443 	if (if_management_interface_check_needed == false) {
12444 		return true;
12445 	}
12446 	if (necp_drop_management_order == 0) {
12447 		return true;
12448 	}
12449 	if (ifp == NULL && route != NULL) {
12450 		ifp = route->rt_ifp;
12451 	}
12452 	if (ifp == NULL) {
12453 		return true;
12454 	}
12455 
12456 	if (IFNET_IS_MANAGEMENT(ifp)) {
12457 		bool allowed = true;
12458 
12459 		if (inp != NULL) {
12460 			/*
12461 			 * The entitlement check is already performed for socket flows
12462 			 */
12463 			allowed = INP_MANAGEMENT_ALLOWED(inp);
12464 		} else if (proc != NULL) {
12465 			allowed = necp_proc_is_allowed_on_management_interface(proc);
12466 		}
12467 		if (__improbable(if_management_verbose > 1 && allowed == false)) {
12468 			necp_log_interface_not_allowed(ifp, proc, inp);
12469 		}
12470 		return allowed;
12471 	}
12472 	return true;
12473 }
12474 
12475 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,bool * ultra_constrained_denied)12476 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,
12477     u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied)
12478 {
12479 	if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12480 		if (necp_debug > 1) {
12481 			NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12482 		}
12483 		return TRUE;
12484 	}
12485 
12486 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12487 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12488 		if (aggregate_route_rule != NULL) {
12489 			int index = 0;
12490 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12491 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12492 				if (sub_route_rule_id == 0) {
12493 					break;
12494 				}
12495 				if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied, ultra_constrained_denied)) {
12496 					return FALSE;
12497 				}
12498 			}
12499 		}
12500 	} else {
12501 		return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied, ultra_constrained_denied);
12502 	}
12503 
12504 	return TRUE;
12505 }
12506 
12507 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12508 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12509 {
12510 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12511 	if (route_rule == NULL) {
12512 		return false;
12513 	}
12514 
12515 	return route_rule->match_netagent_id != 0;
12516 }
12517 
12518 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)12519 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)
12520 {
12521 	if (remove == NULL) {
12522 		return 0;
12523 	}
12524 
12525 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12526 	if (route_rule == NULL) {
12527 		return 0;
12528 	}
12529 
12530 	// No netagent, skip
12531 	if (route_rule->netagent_id == 0) {
12532 		return 0;
12533 	}
12534 
12535 	if (route_rule->match_netagent_id != 0) {
12536 		if (netagent_array == NULL || netagent_array_count == 0) {
12537 			// No agents, ignore rule
12538 			return 0;
12539 		}
12540 		bool found_match = FALSE;
12541 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12542 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12543 				found_match = TRUE;
12544 				break;
12545 			}
12546 		}
12547 		if (!found_match) {
12548 			// Agents don't match, ignore rule
12549 			return 0;
12550 		}
12551 	}
12552 
12553 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12554 	if (ifp == NULL) {
12555 		// No interface, apply the default action
12556 		if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12557 		    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12558 			*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12559 			return route_rule->netagent_id;
12560 		}
12561 		return 0;
12562 	}
12563 
12564 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12565 		if (route_rule->exception_if_indices[exception_index] == 0) {
12566 			break;
12567 		}
12568 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12569 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12570 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12571 			    route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12572 				*remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12573 				return route_rule->netagent_id;
12574 			}
12575 			return 0;
12576 		}
12577 	}
12578 
12579 	if (ifp->if_type == IFT_CELLULAR &&
12580 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12581 		if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12582 		    route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12583 			*remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12584 			return route_rule->netagent_id;
12585 		}
12586 		return 0;
12587 	}
12588 
12589 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12590 	    route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12591 		if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12592 		    route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12593 			*remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12594 			return route_rule->netagent_id;
12595 		}
12596 		return 0;
12597 	}
12598 
12599 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12600 	    route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12601 		if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12602 		    route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12603 			*remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12604 			return route_rule->netagent_id;
12605 		}
12606 		return 0;
12607 	}
12608 
12609 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12610 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12611 		if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12612 		    route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12613 			*remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12614 			return route_rule->netagent_id;
12615 		}
12616 		return 0;
12617 	}
12618 
12619 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12620 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12621 		if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12622 		    route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12623 			*remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12624 			return route_rule->netagent_id;
12625 		}
12626 		return 0;
12627 	}
12628 
12629 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12630 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12631 		if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12632 		    route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12633 			*remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12634 			return route_rule->netagent_id;
12635 		}
12636 		return 0;
12637 	}
12638 
12639 	if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12640 	    route_rule->ultra_constrained_action != NECP_ROUTE_RULE_NONE) {
12641 		if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12642 		    route_rule->ultra_constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12643 			*remove = (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12644 			return route_rule->netagent_id;
12645 		}
12646 		return 0;
12647 	}
12648 
12649 	if (ifp->if_xflags & IFXF_IS_VPN &&
12650 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12651 		if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12652 		    route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12653 			*remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12654 			return route_rule->netagent_id;
12655 		}
12656 		return 0;
12657 	}
12658 
12659 	// No more specific case matched, apply the default action
12660 	if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12661 	    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12662 		*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12663 		return route_rule->netagent_id;
12664 	}
12665 
12666 	return 0;
12667 }
12668 
12669 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)12670 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)
12671 {
12672 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12673 	if (route_rule == NULL) {
12674 		return 0;
12675 	}
12676 
12677 	// No control unit, skip
12678 	if (route_rule->control_unit == 0) {
12679 		return 0;
12680 	}
12681 
12682 	if (route_rule->match_netagent_id != 0) {
12683 		if (netagent_array == NULL || netagent_array_count == 0) {
12684 			// No agents, ignore rule
12685 			return 0;
12686 		}
12687 		bool found_match = FALSE;
12688 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12689 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12690 				found_match = TRUE;
12691 				break;
12692 			}
12693 		}
12694 		if (!found_match) {
12695 			// Agents don't match, ignore rule
12696 			return 0;
12697 		}
12698 	}
12699 
12700 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12701 	if (ifp == NULL) {
12702 		// No interface, apply the default action
12703 		if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12704 			return route_rule->control_unit;
12705 		}
12706 		return 0;
12707 	}
12708 
12709 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12710 		if (route_rule->exception_if_indices[exception_index] == 0) {
12711 			break;
12712 		}
12713 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12714 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12715 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12716 				return route_rule->control_unit;
12717 			}
12718 			return 0;
12719 		}
12720 	}
12721 
12722 	if (ifp->if_type == IFT_CELLULAR &&
12723 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12724 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12725 			return route_rule->control_unit;
12726 		}
12727 		return 0;
12728 	}
12729 
12730 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12731 	    route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12732 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12733 			return route_rule->control_unit;
12734 		}
12735 		return 0;
12736 	}
12737 
12738 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12739 	    route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12740 		if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12741 			return route_rule->control_unit;
12742 		}
12743 		return 0;
12744 	}
12745 
12746 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12747 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12748 		if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12749 			return route_rule->control_unit;
12750 		}
12751 		return 0;
12752 	}
12753 
12754 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12755 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12756 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12757 			return route_rule->control_unit;
12758 		}
12759 		return 0;
12760 	}
12761 
12762 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12763 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12764 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12765 			return route_rule->control_unit;
12766 		}
12767 		return 0;
12768 	}
12769 
12770 	if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12771 	    route_rule->ultra_constrained_action != NECP_ROUTE_RULE_NONE) {
12772 		if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12773 			return route_rule->control_unit;
12774 		}
12775 		return 0;
12776 	}
12777 
12778 	if (ifp->if_xflags & IFXF_IS_VPN &&
12779 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12780 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12781 			return route_rule->control_unit;
12782 		}
12783 		return 0;
12784 	}
12785 
12786 	// No more specific case matched, apply the default action
12787 	if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12788 		return route_rule->control_unit;
12789 	}
12790 	return 0;
12791 }
12792 
12793 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)12794 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,
12795     u_int32_t *flow_divert_aggregate_unit)
12796 {
12797 	if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12798 		return 0;
12799 	}
12800 
12801 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12802 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12803 		if (aggregate_route_rule != NULL) {
12804 			int index = 0;
12805 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12806 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12807 				if (sub_route_rule_id == 0) {
12808 					break;
12809 				}
12810 				uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12811 				if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12812 					// For transparent proxies, accumulate the control unit and continue to the next route rule
12813 					*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12814 					continue;
12815 				}
12816 
12817 				if (control_unit != 0) {
12818 					return control_unit;
12819 				}
12820 			}
12821 		}
12822 	} else {
12823 		uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12824 		if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12825 			// For transparent proxies, accumulate the control unit and let the caller continue
12826 			*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12827 			return 0;
12828 		}
12829 		return control_unit;
12830 	}
12831 
12832 	return 0;
12833 }
12834 
12835 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12836 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12837 {
12838 	bool is_allowed = true;
12839 	u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12840 	if (route_rule_id != 0 &&
12841 	    interface != NULL) {
12842 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12843 		is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL, NULL);
12844 		lck_rw_done(&necp_kernel_policy_lock);
12845 	}
12846 	return is_allowed;
12847 }
12848 
12849 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12850 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12851 {
12852 	size_t netagent_cursor;
12853 	for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12854 		struct necp_uuid_id_mapping *mapping = NULL;
12855 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
12856 		if (netagent_id == 0) {
12857 			continue;
12858 		}
12859 		mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
12860 		if (mapping != NULL) {
12861 			u_int32_t agent_flags = 0;
12862 			agent_flags = netagent_get_flags(mapping->uuid);
12863 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12864 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12865 					continue;
12866 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12867 					return FALSE;
12868 				}
12869 			}
12870 		}
12871 	}
12872 	return TRUE;
12873 }
12874 
12875 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12876 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12877 {
12878 	bool allowed_to_receive = TRUE;
12879 
12880 	if (pf_tag == PF_TAG_ID_STACK_DROP &&
12881 	    (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12882 		allowed_to_receive = FALSE;
12883 	}
12884 
12885 	return allowed_to_receive;
12886 }
12887 
12888 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)12889 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)
12890 {
12891 	u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12892 	bool allowed_to_receive = TRUE;
12893 	struct necp_socket_info info = {};
12894 	u_int32_t flowhash = 0;
12895 	u_int32_t route_rule_id = 0;
12896 	struct rtentry *route = NULL;
12897 	u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12898 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12899 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12900 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12901 	proc_t __single socket_proc = NULL;
12902 	necp_kernel_policy_filter filter_control_unit = 0;
12903 	u_int32_t pass_flags = 0;
12904 	u_int32_t flow_divert_aggregate_unit = 0;
12905 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12906 	int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12907 
12908 	memset(&netagent_ids, 0, sizeof(netagent_ids));
12909 
12910 	if (return_policy_id) {
12911 		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12912 	}
12913 	if (return_skip_policy_id) {
12914 		*return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12915 	}
12916 	if (return_route_rule_id) {
12917 		*return_route_rule_id = 0;
12918 	}
12919 	if (return_pass_flags) {
12920 		*return_pass_flags = 0;
12921 	}
12922 
12923 	if (inp == NULL) {
12924 		goto done;
12925 	}
12926 
12927 	route = inp->inp_route.ro_rt;
12928 
12929 	struct socket *so = inp->inp_socket;
12930 
12931 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12932 
12933 	// Don't lock. Possible race condition, but we don't want the performance hit.
12934 	if (necp_drop_management_order == 0 &&
12935 	    (necp_kernel_socket_policies_count == 0 ||
12936 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12937 		if (necp_drop_all_order > 0 || drop_order > 0) {
12938 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12939 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12940 				allowed_to_receive = TRUE;
12941 			} else {
12942 				allowed_to_receive = FALSE;
12943 			}
12944 		}
12945 		goto done;
12946 	}
12947 
12948 	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
12949 	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12950 		bool policies_have_changed = FALSE;
12951 		bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12952 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12953 			policies_have_changed = TRUE;
12954 		} else {
12955 			if (inp->inp_policyresult.results.route_rule_id != 0) {
12956 				lck_rw_lock_shared(&necp_kernel_policy_lock);
12957 				if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied, NULL)) {
12958 					route_allowed = FALSE;
12959 				}
12960 				lck_rw_done(&necp_kernel_policy_lock);
12961 			}
12962 		}
12963 
12964 		if (!policies_have_changed) {
12965 			if (debug) {
12966 				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);
12967 				debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12968 			}
12969 
12970 			if (!route_allowed ||
12971 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12972 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12973 			    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12974 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12975 				allowed_to_receive = FALSE;
12976 				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);
12977 			} else {
12978 				if (return_policy_id) {
12979 					*return_policy_id = inp->inp_policyresult.policy_id;
12980 				}
12981 				if (return_skip_policy_id) {
12982 					*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12983 				}
12984 				if (return_route_rule_id) {
12985 					*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12986 				}
12987 				if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12988 					pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12989 				}
12990 				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);
12991 			}
12992 			goto done;
12993 		}
12994 	}
12995 
12996 	// Check for loopback exception
12997 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12998 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12999 		allowed_to_receive = FALSE;
13000 		goto done;
13001 	}
13002 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
13003 		allowed_to_receive = TRUE;
13004 		goto done;
13005 	}
13006 
13007 	// Actually calculate policy result
13008 	lck_rw_lock_shared(&necp_kernel_policy_lock);
13009 	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);
13010 
13011 	debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
13012 	NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
13013 
13014 	flowhash = necp_socket_calc_flowhash_locked(&info);
13015 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13016 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
13017 	    inp->inp_policyresult.flowhash == flowhash) {
13018 		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
13019 		    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13020 		    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13021 		    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
13022 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13023 		    (inp->inp_policyresult.results.route_rule_id != 0 &&
13024 		    !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied, NULL))) {
13025 			allowed_to_receive = FALSE;
13026 			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);
13027 		} else {
13028 			if (return_policy_id) {
13029 				*return_policy_id = inp->inp_policyresult.policy_id;
13030 			}
13031 			if (return_route_rule_id) {
13032 				*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13033 			}
13034 			if (return_skip_policy_id) {
13035 				*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13036 			}
13037 			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
13038 				pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
13039 			}
13040 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
13041 				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",
13042 				    inp->inp_socket, info.bound_interface_index, info.protocol,
13043 				    inp->inp_policyresult.policy_id,
13044 				    inp->inp_policyresult.skip_policy_id,
13045 				    inp->inp_policyresult.results.result,
13046 				    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
13047 			}
13048 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
13049 			    return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
13050 		}
13051 		lck_rw_done(&necp_kernel_policy_lock);
13052 		goto done;
13053 	}
13054 
13055 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
13056 	size_t route_rule_id_array_count = 0;
13057 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
13058 	struct necp_kernel_socket_policy *matched_policy =
13059 	    necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
13060 	    &info,
13061 	    &filter_control_unit,
13062 	    route_rule_id_array,
13063 	    &route_rule_id_array_count,
13064 	    MAX_AGGREGATE_ROUTE_RULES,
13065 	    netagent_ids,
13066 	    NECP_MAX_NETAGENTS,
13067 	    NULL,
13068 	    0,
13069 	    NULL,
13070 	    0,
13071 	    effective_proc,
13072 	    pf_tag,
13073 	    return_skip_policy_id,
13074 	    inp->inp_route.ro_rt,
13075 	    &drop_dest_policy_result,
13076 	    &drop_all_bypass,
13077 	    &flow_divert_aggregate_unit,
13078 	    so,
13079 	    debug);
13080 
13081 	// Check for loopback exception again after the policy match
13082 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
13083 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
13084 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
13085 		// If policies haven't changed since last evaluation, do not update filter result in order to
13086 		// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13087 		// allow content filter to detect and drop pre-existing flows.
13088 		uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13089 		int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13090 		if (info.soflow_entry != NULL) {
13091 			current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13092 			current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13093 		}
13094 		if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13095 		    current_filter_control_unit != filter_control_unit) {
13096 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13097 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13098 			if (info.soflow_entry != NULL) {
13099 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13100 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13101 			}
13102 		}
13103 		if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13104 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13105 		}
13106 		allowed_to_receive = TRUE;
13107 		lck_rw_done(&necp_kernel_policy_lock);
13108 
13109 		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);
13110 		goto done;
13111 	}
13112 
13113 	if (info.protocol != IPPROTO_UDP) {
13114 		goto skip_agent_check;
13115 	}
13116 
13117 	// Verify netagents
13118 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
13119 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
13120 			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);
13121 		}
13122 
13123 		// Mark socket as a drop if required agent is not active
13124 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13125 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13126 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13127 		inp->inp_policyresult.flowhash = flowhash;
13128 		inp->inp_policyresult.results.filter_control_unit = 0;
13129 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
13130 		inp->inp_policyresult.results.route_rule_id = 0;
13131 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
13132 		if (info.soflow_entry != NULL) {
13133 			info.soflow_entry->soflow_filter_control_unit = 0;
13134 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13135 		}
13136 
13137 		// Unlock
13138 		allowed_to_receive = FALSE;
13139 		lck_rw_done(&necp_kernel_policy_lock);
13140 
13141 		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);
13142 
13143 		goto done;
13144 	}
13145 
13146 skip_agent_check:
13147 
13148 	if (route_rule_id_array_count == 1) {
13149 		route_rule_id = route_rule_id_array[0];
13150 	} else if (route_rule_id_array_count > 1) {
13151 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
13152 	}
13153 
13154 	bool send_local_network_denied_event = false;
13155 	if (matched_policy != NULL) {
13156 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
13157 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13158 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13159 			// Trigger the event that we dropped due to a local network policy
13160 			send_local_network_denied_event = true;
13161 		}
13162 
13163 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13164 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13165 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13166 		    matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13167 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13168 		    (route_rule_id != 0 &&
13169 		    !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied, NULL)) ||
13170 		    !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13171 			allowed_to_receive = FALSE;
13172 		} else {
13173 			if (return_policy_id) {
13174 				*return_policy_id = matched_policy->id;
13175 			}
13176 			if (return_route_rule_id) {
13177 				*return_route_rule_id = route_rule_id;
13178 			}
13179 			if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13180 				pass_flags = matched_policy->result_parameter.pass_flags;
13181 			}
13182 			// If policies haven't changed since last evaluation, do not update filter result in order to
13183 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13184 			// allow content filter to detect and drop pre-existing flows.
13185 			uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13186 			int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13187 			if (info.soflow_entry != NULL) {
13188 				current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13189 				current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13190 			}
13191 			if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13192 			    current_filter_control_unit != filter_control_unit) {
13193 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13194 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13195 				if (info.soflow_entry != NULL) {
13196 					info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13197 					info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13198 				}
13199 			}
13200 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13201 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13202 			}
13203 		}
13204 
13205 		if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13206 			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>",
13207 			    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);
13208 		}
13209 	} else {
13210 		bool drop_all = false;
13211 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13212 			drop_all = true;
13213 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13214 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13215 			}
13216 		}
13217 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13218 			allowed_to_receive = FALSE;
13219 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13220 		} else {
13221 			if (return_policy_id) {
13222 				*return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13223 			}
13224 			if (return_route_rule_id) {
13225 				*return_route_rule_id = route_rule_id;
13226 			}
13227 
13228 			// If policies haven't changed since last evaluation, do not update filter result in order to
13229 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13230 			// allow content filter to detect and drop pre-existing flows.
13231 			uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13232 			int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13233 			if (info.soflow_entry != NULL) {
13234 				current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13235 				current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13236 			}
13237 			if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13238 			    current_filter_control_unit != filter_control_unit) {
13239 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13240 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13241 				if (info.soflow_entry != NULL) {
13242 					info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13243 					info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13244 				}
13245 			}
13246 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13247 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13248 			}
13249 			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);
13250 		}
13251 	}
13252 
13253 	if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13254 		allowed_to_receive = FALSE;
13255 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13256 	}
13257 
13258 	lck_rw_done(&necp_kernel_policy_lock);
13259 
13260 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13261 		inp->inp_policyresult.network_denied_notifies++;
13262 #if defined(XNU_TARGET_OS_OSX)
13263 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13264 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13265 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13266 		    NETPOLICY_NETWORKTYPE_LOCAL);
13267 #else
13268 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13269 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13270 		    NETPOLICY_NETWORKTYPE_LOCAL);
13271 #endif
13272 	}
13273 
13274 done:
13275 	if (return_pass_flags != NULL) {
13276 		*return_pass_flags = pass_flags;
13277 	}
13278 
13279 	if (pf_tag != 0 && allowed_to_receive) {
13280 		allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13281 	}
13282 
13283 	if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13284 		soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13285 	}
13286 
13287 	if (socket_proc) {
13288 		proc_rele(socket_proc);
13289 	}
13290 
13291 	if (info.soflow_entry != NULL) {
13292 		soflow_free_flow(info.soflow_entry);
13293 	}
13294 
13295 	return allowed_to_receive;
13296 }
13297 
13298 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)13299 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)
13300 {
13301 	struct sockaddr_in local = {};
13302 	struct sockaddr_in remote = {};
13303 	local.sin_family = remote.sin_family = AF_INET;
13304 	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13305 	local.sin_port = local_port;
13306 	remote.sin_port = remote_port;
13307 	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13308 	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13309 
13310 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13311 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13312 }
13313 
13314 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)13315 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)
13316 {
13317 	struct sockaddr_in6 local = {};
13318 	struct sockaddr_in6 remote = {};
13319 	local.sin6_family = remote.sin6_family = AF_INET6;
13320 	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13321 	local.sin6_port = local_port;
13322 	remote.sin6_port = remote_port;
13323 	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13324 	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13325 
13326 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13327 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13328 }
13329 
13330 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)13331 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,
13332     u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13333 {
13334 	return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13335 	           return_policy_id, return_route_rule_id,
13336 	           return_skip_policy_id, return_pass_flags);
13337 }
13338 
13339 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)13340 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13341     necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13342 {
13343 	if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13344 		return EINVAL;
13345 	}
13346 
13347 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13348 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13349 		    policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13350 	}
13351 
13352 	// Mark ID for Pass and IP Tunnel
13353 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13354 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13355 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13356 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13357 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13358 	} else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13359 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13360 		// This case is same as a PASS
13361 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13362 	} else {
13363 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13364 	}
13365 	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13366 	if (route_rule_id != 0) {
13367 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13368 	} else {
13369 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13370 	}
13371 	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);
13372 
13373 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13374 	    skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13375 		// Only mark the skip policy if it is a valid policy ID
13376 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13377 	} else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13378 	    inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13379 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13380 	} else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13381 		// Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13382 		// to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13383 		// See necp_get_skip_policy_id_from_packet() and
13384 		// necp_packet_should_skip_filters().
13385 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13386 	} else {
13387 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13388 	}
13389 
13390 	if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13391 	    ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13392 		m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13393 	}
13394 
13395 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13396 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13397 		    packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13398 	}
13399 
13400 	return 0;
13401 }
13402 
13403 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13404 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13405 {
13406 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13407 		return EINVAL;
13408 	}
13409 
13410 	// Mark ID for Pass and IP Tunnel
13411 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13412 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13413 	} else {
13414 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13415 	}
13416 
13417 	return 0;
13418 }
13419 
13420 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13421 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13422 {
13423 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13424 		return EINVAL;
13425 	}
13426 
13427 	// Mark ID for Pass and IP Tunnel
13428 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13429 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13430 	} else {
13431 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13432 	}
13433 
13434 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13435 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13436 	} else {
13437 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13438 	}
13439 	return 0;
13440 }
13441 
13442 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13443 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13444 {
13445 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13446 		return EINVAL;
13447 	}
13448 
13449 	// Mark ID for Pass and IP Tunnel
13450 	if (interface != NULL) {
13451 		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13452 	}
13453 
13454 	return 0;
13455 }
13456 
13457 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13458 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13459 {
13460 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13461 		return EINVAL;
13462 	}
13463 
13464 	if (is_keepalive) {
13465 		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13466 	} else {
13467 		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13468 	}
13469 
13470 	return 0;
13471 }
13472 
13473 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13474 necp_get_policy_id_from_packet(struct mbuf *packet)
13475 {
13476 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13477 		return NECP_KERNEL_POLICY_ID_NONE;
13478 	}
13479 
13480 	return packet->m_pkthdr.necp_mtag.necp_policy_id;
13481 }
13482 
13483 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13484 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13485 {
13486 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13487 		return NECP_KERNEL_POLICY_ID_NONE;
13488 	}
13489 
13490 	// Check for overloaded value. See necp_mark_packet_from_socket().
13491 	if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13492 		return NECP_KERNEL_POLICY_ID_NONE;
13493 	}
13494 
13495 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13496 }
13497 
13498 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13499 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13500 {
13501 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13502 		return 0;
13503 	}
13504 
13505 	return m_pftag(packet)->pftag_tag;
13506 }
13507 
13508 bool
necp_packet_should_skip_filters(struct mbuf * packet)13509 necp_packet_should_skip_filters(struct mbuf *packet)
13510 {
13511 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13512 		return false;
13513 	}
13514 
13515 	// Check for overloaded value. See necp_mark_packet_from_socket().
13516 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13517 }
13518 
13519 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13520 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13521 {
13522 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13523 		return 0;
13524 	}
13525 
13526 	return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13527 }
13528 
13529 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13530 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13531 {
13532 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13533 		return 0;
13534 	}
13535 
13536 	return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13537 }
13538 
13539 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13540 necp_get_app_uuid_from_packet(struct mbuf *packet,
13541     uuid_t app_uuid)
13542 {
13543 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13544 		return EINVAL;
13545 	}
13546 
13547 	bool found_mapping = FALSE;
13548 	if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13549 		lck_rw_lock_shared(&necp_kernel_policy_lock);
13550 		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);
13551 		struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13552 		if (entry != NULL) {
13553 			uuid_copy(app_uuid, entry->uuid);
13554 			found_mapping = true;
13555 		}
13556 		lck_rw_done(&necp_kernel_policy_lock);
13557 	}
13558 	if (!found_mapping) {
13559 		uuid_clear(app_uuid);
13560 	}
13561 	return 0;
13562 }
13563 
13564 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13565 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13566 {
13567 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13568 		return FALSE;
13569 	}
13570 
13571 	return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13572 }
13573 
13574 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13575 necp_socket_get_content_filter_control_unit(struct socket *so)
13576 {
13577 	struct inpcb *inp = sotoinpcb(so);
13578 
13579 	if (inp == NULL) {
13580 		return 0;
13581 	}
13582 	return inp->inp_policyresult.results.filter_control_unit;
13583 }
13584 
13585 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13586 necp_socket_get_policy_gencount(struct socket *so)
13587 {
13588 	struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13589 
13590 	if (inp == NULL) {
13591 		return 0;
13592 	}
13593 	return inp->inp_policyresult.policy_gencount;
13594 }
13595 
13596 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13597 necp_socket_should_use_flow_divert(struct inpcb *inp)
13598 {
13599 	if (inp == NULL) {
13600 		return FALSE;
13601 	}
13602 
13603 	return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13604 	       (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13605 	       (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13606 }
13607 
13608 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13609 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13610 {
13611 	if (inp == NULL) {
13612 		return 0;
13613 	}
13614 
13615 	if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13616 		return 0;
13617 	}
13618 
13619 	if (aggregate_unit != NULL &&
13620 	    inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13621 		*aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13622 	}
13623 
13624 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13625 		return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13626 	}
13627 
13628 	return 0;
13629 }
13630 
13631 bool
necp_socket_should_rescope(struct inpcb * inp)13632 necp_socket_should_rescope(struct inpcb *inp)
13633 {
13634 	if (inp == NULL) {
13635 		return FALSE;
13636 	}
13637 
13638 	return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13639 	       inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13640 }
13641 
13642 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13643 necp_socket_get_rescope_if_index(struct inpcb *inp)
13644 {
13645 	if (inp == NULL) {
13646 		return 0;
13647 	}
13648 
13649 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13650 		return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13651 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13652 		return necp_get_primary_direct_interface_index();
13653 	}
13654 
13655 	return 0;
13656 }
13657 
13658 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13659 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13660 {
13661 	if (inp == NULL) {
13662 		return current_mtu;
13663 	}
13664 
13665 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13666 	    (inp->inp_flags & INP_BOUND_IF) &&
13667 	    inp->inp_boundifp) {
13668 		u_int bound_interface_index = inp->inp_boundifp->if_index;
13669 		u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13670 
13671 		// The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13672 		if (bound_interface_index != tunnel_interface_index) {
13673 			ifnet_t tunnel_interface = NULL;
13674 
13675 			ifnet_head_lock_shared();
13676 			tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13677 			ifnet_head_done();
13678 
13679 			if (tunnel_interface != NULL) {
13680 				u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13681 				u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13682 				const char ipsec_prefix[] = "ipsec";
13683 				if (delegate_tunnel_mtu != 0 &&
13684 				    strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13685 					// For ipsec interfaces, calculate the overhead from the delegate interface
13686 					u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13687 					if (delegate_tunnel_mtu > tunnel_overhead) {
13688 						delegate_tunnel_mtu -= tunnel_overhead;
13689 					}
13690 
13691 					if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13692 						// If the (delegate - overhead) < direct, return (delegate - overhead)
13693 						return delegate_tunnel_mtu;
13694 					} else {
13695 						// Otherwise return direct
13696 						return direct_tunnel_mtu;
13697 					}
13698 				} else {
13699 					// For non-ipsec interfaces, just return the tunnel MTU
13700 					return direct_tunnel_mtu;
13701 				}
13702 			}
13703 		}
13704 	}
13705 
13706 	// By default, just return the MTU passed in
13707 	return current_mtu;
13708 }
13709 
13710 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13711 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13712 {
13713 	if (result_parameter == NULL) {
13714 		return NULL;
13715 	}
13716 
13717 	return ifindex2ifnet[result_parameter->tunnel_interface_index];
13718 }
13719 
13720 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13721 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13722 {
13723 	bool found_match = FALSE;
13724 	bool can_rebind = FALSE;
13725 	ifaddr_t ifa;
13726 	union necp_sockaddr_union address_storage;
13727 
13728 	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13729 		return FALSE;
13730 	}
13731 
13732 	// Match source address against interface addresses
13733 	ifnet_lock_shared(interface);
13734 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13735 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13736 			if (address_storage.sa.sa_family != family) {
13737 				continue;
13738 			}
13739 
13740 			if (family == AF_INET) {
13741 				struct ip *ip = mtod(packet, struct ip *);
13742 				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13743 					found_match = TRUE;
13744 					break;
13745 				}
13746 			} else if (family == AF_INET6) {
13747 				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13748 				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13749 					found_match = TRUE;
13750 					break;
13751 				}
13752 			}
13753 		}
13754 	}
13755 	const uint32_t if_idx = interface->if_index;
13756 	ifnet_lock_done(interface);
13757 
13758 	// If source address matched, attempt to construct a route to the destination address
13759 	if (found_match) {
13760 		ROUTE_RELEASE(new_route);
13761 
13762 		if (family == AF_INET) {
13763 			struct ip *ip = mtod(packet, struct ip *);
13764 			struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13765 			dst4->sin_family = AF_INET;
13766 			dst4->sin_len = sizeof(struct sockaddr_in);
13767 			dst4->sin_addr = ip->ip_dst;
13768 			rtalloc_scoped(new_route, if_idx);
13769 			if (!ROUTE_UNUSABLE(new_route)) {
13770 				can_rebind = TRUE;
13771 			}
13772 		} else if (family == AF_INET6) {
13773 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13774 			struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13775 			dst6->sin6_family = AF_INET6;
13776 			dst6->sin6_len = sizeof(struct sockaddr_in6);
13777 			dst6->sin6_addr = ip6->ip6_dst;
13778 			rtalloc_scoped(new_route, if_idx);
13779 			if (!ROUTE_UNUSABLE(new_route)) {
13780 				can_rebind = TRUE;
13781 			}
13782 		}
13783 	}
13784 
13785 	return can_rebind;
13786 }
13787 
13788 static bool
necp_addr_is_loopback(struct sockaddr * address)13789 necp_addr_is_loopback(struct sockaddr *address)
13790 {
13791 	if (address == NULL) {
13792 		return FALSE;
13793 	}
13794 
13795 	if (address->sa_family == AF_INET) {
13796 		return IN_LOOPBACK(ntohl(SIN(address)->sin_addr.s_addr));
13797 	} else if (address->sa_family == AF_INET6) {
13798 		if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13799 			return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13800 		} else {
13801 			// Match ::ffff:127.0.0.1 loopback address
13802 			in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13803 			return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13804 		}
13805 	}
13806 
13807 	return FALSE;
13808 }
13809 
13810 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)13811 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13812 {
13813 	// Note: This function only checks for the loopback addresses.
13814 	// In the future, we may want to expand to also allow any traffic
13815 	// going through the loopback interface, but until then, this
13816 	// check is cheaper.
13817 
13818 	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13819 		return TRUE;
13820 	}
13821 
13822 	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13823 		return TRUE;
13824 	}
13825 
13826 	if (inp != NULL) {
13827 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13828 			return TRUE;
13829 		}
13830 		if (inp->inp_vflag & INP_IPV4) {
13831 			if (IN_LOOPBACK(ntohl(inp->inp_laddr.s_addr)) ||
13832 			    IN_LOOPBACK(ntohl(inp->inp_faddr.s_addr))) {
13833 				return TRUE;
13834 			}
13835 		} else if (inp->inp_vflag & INP_IPV6) {
13836 			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13837 			    IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13838 				return TRUE;
13839 			}
13840 		}
13841 	} else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13842 		return TRUE;
13843 	}
13844 
13845 	if (packet != NULL) {
13846 		struct ip *ip = mtod(packet, struct ip *);
13847 		if (ip->ip_v == 4) {
13848 			if (IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) {
13849 				return TRUE;
13850 			}
13851 			if (IN_LOOPBACK(ntohl(ip->ip_dst.s_addr))) {
13852 				return TRUE;
13853 			}
13854 		} else if (ip->ip_v == 6) {
13855 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13856 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13857 				return TRUE;
13858 			}
13859 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13860 				return TRUE;
13861 			}
13862 		}
13863 	}
13864 
13865 	return FALSE;
13866 }
13867 
13868 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13869 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13870 {
13871 	if (inp != NULL) {
13872 		if (!(inp->inp_vflag & INP_IPV6)) {
13873 			return false;
13874 		}
13875 		if (INP_INTCOPROC_ALLOWED(inp)) {
13876 			return true;
13877 		}
13878 		if ((inp->inp_flags & INP_BOUND_IF) &&
13879 		    IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13880 			return true;
13881 		}
13882 		return false;
13883 	}
13884 	if (packet != NULL) {
13885 		struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13886 		struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13887 		if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13888 		    NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13889 			return true;
13890 		}
13891 	}
13892 
13893 	return false;
13894 }
13895 
13896 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13897 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13898 {
13899 	char dest_str[MAX_IPv6_STR_LEN];
13900 
13901 	if (necp_drop_dest_debug > 0) {
13902 		if (sau->sa.sa_family == AF_INET) {
13903 			(void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13904 		} else if (sau->sa.sa_family == AF_INET6) {
13905 			(void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13906 		} else {
13907 			dest_str[0] = 0;
13908 		}
13909 	}
13910 	for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13911 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13912 		struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13913 
13914 		if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13915 			if (necp_drop_dest_debug > 0) {
13916 				char subnet_str[MAX_IPv6_STR_LEN];
13917 				struct proc *p = current_proc();
13918 				pid_t pid = proc_pid(p);
13919 
13920 				if (sau->sa.sa_family == AF_INET) {
13921 					(void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13922 					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);
13923 				} else if (sau->sa.sa_family == AF_INET6) {
13924 					(void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13925 					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);
13926 				}
13927 			}
13928 			return true;
13929 		}
13930 	}
13931 	if (necp_drop_dest_debug > 1) {
13932 		struct proc *p = current_proc();
13933 		pid_t pid = proc_pid(p);
13934 
13935 		os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13936 	}
13937 	return false;
13938 }
13939 
13940 static int
13941 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13942 {
13943 #pragma unused(arg1, arg2, oidp)
13944 	int changed = 0;
13945 	int error = 0;
13946 	struct necp_drop_dest_policy tmp_drop_dest_policy;
13947 	struct proc *p = current_proc();
13948 	pid_t pid = proc_pid(p);
13949 
13950 	if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13951 	    priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13952 		NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13953 		return EPERM;
13954 	}
13955 	if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13956 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13957 		return EINVAL;
13958 	}
13959 
13960 	memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13961 	error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13962 	if (error != 0) {
13963 		NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13964 		return error;
13965 	}
13966 	if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13967 		return error;
13968 	}
13969 
13970 	//
13971 	// Validate the passed parameters
13972 	//
13973 	if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13974 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13975 		return EINVAL;
13976 	}
13977 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13978 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13979 		struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13980 
13981 		switch (tmp_drop_dest_entry->level) {
13982 		case NECP_SESSION_PRIORITY_UNKNOWN:
13983 			if (tmp_drop_dest_policy.entry_count != 0) {
13984 				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);
13985 				return EINVAL;
13986 			}
13987 			break;
13988 		case NECP_SESSION_PRIORITY_CONTROL:
13989 		case NECP_SESSION_PRIORITY_CONTROL_1:
13990 		case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13991 		case NECP_SESSION_PRIORITY_HIGH:
13992 		case NECP_SESSION_PRIORITY_HIGH_1:
13993 		case NECP_SESSION_PRIORITY_HIGH_2:
13994 		case NECP_SESSION_PRIORITY_HIGH_3:
13995 		case NECP_SESSION_PRIORITY_HIGH_4:
13996 		case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13997 		case NECP_SESSION_PRIORITY_DEFAULT:
13998 		case NECP_SESSION_PRIORITY_LOW:
13999 			if (tmp_drop_dest_policy.entry_count == 0) {
14000 				NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
14001 				return EINVAL;
14002 			}
14003 			break;
14004 		default: {
14005 			NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
14006 			return EINVAL;
14007 		}
14008 		}
14009 
14010 		switch (npca->address.sa.sa_family) {
14011 		case AF_INET: {
14012 			if (npca->prefix > 32) {
14013 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
14014 				return EINVAL;
14015 			}
14016 			if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
14017 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
14018 				return EINVAL;
14019 			}
14020 			if (npca->address.sin.sin_port != 0) {
14021 				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);
14022 				return EINVAL;
14023 			}
14024 			break;
14025 		}
14026 		case AF_INET6: {
14027 			if (npca->prefix > 128) {
14028 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
14029 				return EINVAL;
14030 			}
14031 			if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
14032 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
14033 				return EINVAL;
14034 			}
14035 			if (npca->address.sin6.sin6_port != 0) {
14036 				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);
14037 				return EINVAL;
14038 			}
14039 			if (npca->address.sin6.sin6_flowinfo != 0) {
14040 				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);
14041 				return EINVAL;
14042 			}
14043 			if (npca->address.sin6.sin6_scope_id != 0) {
14044 				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);
14045 				return EINVAL;
14046 			}
14047 			break;
14048 		}
14049 		default: {
14050 			return EINVAL;
14051 		}
14052 		}
14053 	}
14054 
14055 	//
14056 	// Commit the changed policy
14057 	//
14058 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
14059 	memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
14060 
14061 	necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
14062 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
14063 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
14064 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
14065 
14066 		memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
14067 
14068 		necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
14069 	}
14070 	lck_rw_done(&necp_kernel_policy_lock);
14071 
14072 	return 0;
14073 }
14074 
14075 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])14076 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
14077 {
14078 	uint16_t fam = address->sa.sa_family;
14079 	memset(addr_str, 0, MAX_IPv6_STR_LEN);
14080 	if (fam == AF_INET) {
14081 		(void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
14082 	} else if (fam == AF_INET6) {
14083 		(void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
14084 	}
14085 	return __unsafe_null_terminated_from_indexable(addr_str);
14086 }
14087