xref: /xnu-12377.81.4/bsd/net/necp.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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)4077 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
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 			}
4628 		}
4629 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4630 			socket_layer_non_id_conditions = TRUE;
4631 		} else if (socket_ip_conditions) {
4632 			socket_layer_non_id_conditions = TRUE;
4633 			ip_output_layer_non_id_conditions = TRUE;
4634 			ip_output_layer_non_id_only = TRUE;         // Only apply drop to packets that didn't go through socket layer
4635 		}
4636 		break;
4637 	}
4638 	case NECP_POLICY_RESULT_SKIP: {
4639 		u_int32_t skip_policy_order = 0;
4640 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4641 			ultimate_result_parameter.skip_policy_order = skip_policy_order;
4642 		}
4643 
4644 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4645 			socket_layer_non_id_conditions = TRUE;
4646 			ip_output_layer_id_condition = TRUE;
4647 		} else if (socket_ip_conditions) {
4648 			socket_layer_non_id_conditions = TRUE;
4649 			ip_output_layer_non_id_conditions = TRUE;
4650 		}
4651 		break;
4652 	}
4653 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
4654 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
4655 		u_int32_t control_unit = 0;
4656 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4657 			ultimate_result_parameter.flow_divert_control_unit = control_unit;
4658 		}
4659 		socket_layer_non_id_conditions = TRUE;
4660 		break;
4661 	}
4662 	case NECP_POLICY_RESULT_IP_TUNNEL: {
4663 		struct necp_policy_result_ip_tunnel tunnel_parameters;
4664 		u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4665 		if (tunnel_parameters_length > sizeof(u_int32_t) &&
4666 		    tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4667 		    necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4668 			ifnet_t __single tunnel_interface = NULL;
4669 			tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0;         // Make sure the string is NULL terminated
4670 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4671 				ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4672 				ifnet_release(tunnel_interface);
4673 			}
4674 
4675 			secondary_result = tunnel_parameters.secondary_result;
4676 			if (secondary_result) {
4677 				cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4678 			}
4679 		}
4680 
4681 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4682 			socket_layer_non_id_conditions = TRUE;
4683 			ip_output_layer_id_condition = TRUE;
4684 			if (secondary_result) {
4685 				ip_output_layer_tunnel_condition_from_id = TRUE;
4686 			}
4687 		} else if (socket_ip_conditions) {
4688 			socket_layer_non_id_conditions = TRUE;
4689 			ip_output_layer_id_condition = TRUE;
4690 			ip_output_layer_non_id_conditions = TRUE;
4691 			if (secondary_result) {
4692 				ip_output_layer_tunnel_condition_from_id = TRUE;
4693 				ip_output_layer_tunnel_condition_from_non_id = TRUE;
4694 			}
4695 		}
4696 		break;
4697 	}
4698 	case NECP_POLICY_RESULT_USE_NETAGENT:
4699 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4700 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4701 		uuid_t netagent_uuid;
4702 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4703 			ultimate_result_parameter.netagent_id = necp_create_agent_uuid_id_mapping(netagent_uuid);
4704 			if (ultimate_result_parameter.netagent_id != 0) {
4705 				uuid_copy(policy->applied_result_uuid, netagent_uuid);
4706 				socket_layer_non_id_conditions = TRUE;
4707 			}
4708 		}
4709 		break;
4710 	}
4711 	case NECP_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
4712 		struct necp_policy_condition_agent_type netagent_type = {};
4713 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_type, sizeof(netagent_type))) {
4714 			ultimate_result_parameter.netagent_id = necp_create_agent_type_to_id_mapping(&netagent_type);
4715 			if (ultimate_result_parameter.netagent_id != 0) {
4716 				policy->applied_agent_type_id = ultimate_result_parameter.netagent_id;
4717 				socket_layer_non_id_conditions = TRUE;
4718 			}
4719 		}
4720 		break;
4721 	}
4722 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4723 		u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4724 		if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4725 			char interface_name[IFXNAMSIZ];
4726 			ifnet_t __single scope_interface = NULL;
4727 			necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4728 			interface_name[interface_name_length - 1] = 0;         // Make sure the string is NULL terminated
4729 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4730 				ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4731 				socket_layer_non_id_conditions = TRUE;
4732 				ifnet_release(scope_interface);
4733 			}
4734 		}
4735 		break;
4736 	}
4737 	case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4738 		socket_layer_non_id_conditions = TRUE;
4739 		break;
4740 	}
4741 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4742 		socket_layer_non_id_conditions = TRUE;
4743 		break;
4744 	}
4745 	case NECP_POLICY_RESULT_ROUTE_RULES: {
4746 		if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4747 			bool has_socket_only_actions = FALSE;
4748 			u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4749 			if (route_rule_id > 0) {
4750 				policy->applied_route_rules_id = route_rule_id;
4751 				ultimate_result_parameter.route_rule_id = route_rule_id;
4752 				if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4753 					socket_layer_non_id_conditions = TRUE;
4754 				} else if (socket_ip_conditions) {
4755 					socket_layer_non_id_conditions = TRUE;
4756 					ip_output_layer_non_id_conditions = TRUE;
4757 					ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4758 				}
4759 			}
4760 		}
4761 		break;
4762 	}
4763 	default: {
4764 		break;
4765 	}
4766 	}
4767 
4768 	if (socket_layer_non_id_conditions) {
4769 		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);
4770 
4771 		if (policy_id == 0) {
4772 			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4773 			goto fail;
4774 		}
4775 
4776 		cond_ip_output_layer_id = policy_id;
4777 		policy->kernel_socket_policies[0] = policy_id;
4778 	}
4779 
4780 	if (ip_output_layer_non_id_conditions) {
4781 		u_int64_t condition_mask = master_condition_mask;
4782 		if (ip_output_layer_non_id_only) {
4783 			condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4784 		}
4785 
4786 		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);
4787 
4788 		if (policy_id == 0) {
4789 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4790 			goto fail;
4791 		}
4792 
4793 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4794 	}
4795 
4796 	if (ip_output_layer_id_condition) {
4797 		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);
4798 
4799 		if (policy_id == 0) {
4800 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4801 			goto fail;
4802 		}
4803 
4804 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4805 	}
4806 
4807 	// Extra policies for IP Output tunnels for when packets loop back
4808 	if (ip_output_layer_tunnel_condition_from_id) {
4809 		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);
4810 
4811 		if (policy_id == 0) {
4812 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4813 			goto fail;
4814 		}
4815 
4816 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4817 	}
4818 
4819 	if (ip_output_layer_tunnel_condition_from_id) {
4820 		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);
4821 
4822 		if (policy_id == 0) {
4823 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4824 			goto fail;
4825 		}
4826 
4827 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4828 	}
4829 
4830 	policy->applied = TRUE;
4831 	policy->pending_update = FALSE;
4832 	return TRUE;
4833 
4834 fail:
4835 	return FALSE;
4836 }
4837 
4838 static void
necp_policy_apply_all(struct necp_session * session)4839 necp_policy_apply_all(struct necp_session *session)
4840 {
4841 	struct necp_session_policy *policy = NULL;
4842 	struct necp_session_policy *temp_policy = NULL;
4843 	struct kev_necp_policies_changed_data kev_data;
4844 	kev_data.changed_count = 0;
4845 
4846 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4847 
4848 	// Remove exisiting applied policies
4849 	if (session->dirty) {
4850 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4851 			if (policy->pending_deletion) {
4852 				if (policy->applied) {
4853 					necp_policy_unapply(policy);
4854 				}
4855 				// Delete the policy
4856 				necp_policy_delete(session, policy);
4857 			} else if (!policy->applied) {
4858 				necp_policy_apply(session, policy);
4859 			} else if (policy->pending_update) {
4860 				// Must have been applied, but needs an update. Remove and re-add.
4861 				necp_policy_unapply(policy);
4862 				necp_policy_apply(session, policy);
4863 			}
4864 		}
4865 
4866 		necp_kernel_socket_policies_update_uuid_table();
4867 		necp_kernel_socket_policies_reprocess();
4868 		necp_kernel_ip_output_policies_reprocess();
4869 
4870 		// Clear dirty bit flags
4871 		session->dirty = FALSE;
4872 	}
4873 
4874 	lck_rw_done(&necp_kernel_policy_lock);
4875 
4876 	necp_update_all_clients();
4877 	necp_post_change_event(&kev_data);
4878 
4879 	if (necp_debug) {
4880 		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4881 	}
4882 }
4883 
4884 // Kernel Policy Management
4885 // ---------------------
4886 // Kernel policies are derived from session policies
4887 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4888 necp_kernel_policy_get_new_id(bool socket_level)
4889 {
4890 	static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4891 	static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4892 
4893 	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4894 
4895 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4896 
4897 	if (socket_level) {
4898 		bool wrapped = FALSE;
4899 		do {
4900 			necp_last_kernel_socket_policy_id++;
4901 			if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4902 			    necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4903 				if (wrapped) {
4904 					// Already wrapped, give up
4905 					NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4906 					return NECP_KERNEL_POLICY_ID_NONE;
4907 				}
4908 				necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4909 				wrapped = TRUE;
4910 			}
4911 			newid = necp_last_kernel_socket_policy_id;
4912 		} while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4913 	} else {
4914 		bool wrapped = FALSE;
4915 		do {
4916 			necp_last_kernel_ip_policy_id++;
4917 			if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4918 				if (wrapped) {
4919 					// Already wrapped, give up
4920 					NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4921 					return NECP_KERNEL_POLICY_ID_NONE;
4922 				}
4923 				necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4924 				wrapped = TRUE;
4925 			}
4926 			newid = necp_last_kernel_ip_policy_id;
4927 		} while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4928 	}
4929 
4930 	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4931 		NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4932 		return NECP_KERNEL_POLICY_ID_NONE;
4933 	}
4934 
4935 	return newid;
4936 }
4937 
4938 #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)
4939 
4940 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)4941 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)
4942 {
4943 	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4944 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4945 
4946 	new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4947 
4948 	new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4949 	new_kernel_policy->order = order;
4950 	new_kernel_policy->session_order = session_order;
4951 	new_kernel_policy->session_pid = session_pid;
4952 
4953 	// Sanitize condition mask
4954 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4955 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4956 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4957 	}
4958 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4959 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4960 	}
4961 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4962 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4963 	}
4964 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4965 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4966 	}
4967 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4968 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4969 	}
4970 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4971 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4972 	}
4973 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4974 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4975 	}
4976 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4977 
4978 	// Set condition values
4979 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4980 		new_kernel_policy->cond_app_id = cond_app_id;
4981 	}
4982 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4983 		new_kernel_policy->cond_real_app_id = cond_real_app_id;
4984 	}
4985 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4986 		new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4987 	}
4988 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4989 		new_kernel_policy->cond_account_id = cond_account_id;
4990 	}
4991 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
4992 	    (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
4993 		new_kernel_policy->cond_domain = cond_domain;
4994 		new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
4995 	}
4996 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
4997 		new_kernel_policy->cond_domain_filter = cond_domain_filter;
4998 	}
4999 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5000 		new_kernel_policy->cond_url = cond_url;
5001 	}
5002 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5003 		new_kernel_policy->cond_pid = cond_pid;
5004 		new_kernel_policy->cond_pid_version = cond_pid_version;
5005 	}
5006 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5007 		new_kernel_policy->cond_uid = cond_uid;
5008 	}
5009 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5010 		new_kernel_policy->cond_real_uid = cond_real_uid;
5011 	}
5012 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5013 		if (cond_bound_interface) {
5014 			ifnet_reference(cond_bound_interface);
5015 		}
5016 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
5017 	}
5018 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5019 		new_kernel_policy->cond_traffic_class = cond_traffic_class;
5020 	}
5021 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5022 		new_kernel_policy->cond_protocol = cond_protocol;
5023 	}
5024 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5025 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5026 	}
5027 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5028 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5029 	}
5030 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5031 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
5032 	}
5033 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5034 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5035 	}
5036 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5037 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5038 	}
5039 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5040 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5041 	}
5042 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5043 		memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5044 	}
5045 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5046 		memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5047 	}
5048 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5049 		new_kernel_policy->cond_client_flags = cond_client_flags;
5050 	}
5051 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5052 		new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5053 	}
5054 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5055 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5056 	}
5057 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5058 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
5059 	}
5060 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5061 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5062 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5063 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5064 	}
5065 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5066 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5067 	}
5068 
5069 	new_kernel_policy->result = result;
5070 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5071 
5072 	if (necp_debug) {
5073 		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5074 	}
5075 	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5076 
5077 	return new_kernel_policy ? new_kernel_policy->id : 0;
5078 }
5079 
5080 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5081 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5082 {
5083 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5084 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5085 
5086 	if (policy_id == 0) {
5087 		return NULL;
5088 	}
5089 
5090 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5091 		if (kernel_policy->id == policy_id) {
5092 			return kernel_policy;
5093 		}
5094 	}
5095 
5096 	return NULL;
5097 }
5098 
5099 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5100 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5101 {
5102 	struct necp_kernel_socket_policy * __single policy = NULL;
5103 	char * __indexable buffer = NULL;
5104 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5105 
5106 	policy = necp_kernel_socket_policy_find(policy_id);
5107 	if (policy) {
5108 		LIST_REMOVE(policy, chain);
5109 
5110 		if (policy->cond_bound_interface) {
5111 			ifnet_release(policy->cond_bound_interface);
5112 			policy->cond_bound_interface = NULL;
5113 		}
5114 
5115 		if (policy->cond_domain) {
5116 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5117 			kfree_data_addr(buffer);
5118 			policy->cond_domain = NULL;
5119 		}
5120 
5121 		if (policy->cond_url) {
5122 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5123 			kfree_data_addr(buffer);
5124 			policy->cond_url = NULL;
5125 		}
5126 
5127 		if (policy->cond_custom_entitlement) {
5128 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5129 			kfree_data_addr(buffer);
5130 			policy->cond_custom_entitlement = NULL;
5131 		}
5132 
5133 		if (policy->cond_signing_identifier) {
5134 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5135 			kfree_data_addr(buffer);
5136 			policy->cond_signing_identifier = NULL;
5137 		}
5138 
5139 		zfree(necp_socket_policy_zone, policy);
5140 		return TRUE;
5141 	}
5142 
5143 	return FALSE;
5144 }
5145 
5146 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5147 __sized_by(MAX_RESULT_STRING_LEN)
5148 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)
5149 {
5150 	uuid_string_t uuid_string;
5151 	switch (result) {
5152 	case NECP_KERNEL_POLICY_RESULT_NONE: {
5153 		snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5154 		break;
5155 	}
5156 	case NECP_KERNEL_POLICY_RESULT_PASS: {
5157 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5158 		break;
5159 	}
5160 	case NECP_KERNEL_POLICY_RESULT_SKIP: {
5161 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5162 		break;
5163 	}
5164 	case NECP_KERNEL_POLICY_RESULT_DROP: {
5165 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5166 		break;
5167 	}
5168 	case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5169 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5170 		break;
5171 	}
5172 	case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5173 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5174 		break;
5175 	}
5176 	case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5177 		ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5178 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5179 		break;
5180 	}
5181 	case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5182 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5183 		break;
5184 	}
5185 	case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5186 		ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5187 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5188 		break;
5189 	}
5190 	case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5191 		snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5192 		break;
5193 	}
5194 	case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5195 		snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5196 		break;
5197 	}
5198 	case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5199 		int index = 0;
5200 		char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5201 		struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5202 		if (route_rule != NULL) {
5203 			for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5204 				if (route_rule->exception_if_indices[index] != 0) {
5205 					ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5206 					snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5207 				} else {
5208 					memset(interface_names[index], 0, IFXNAMSIZ);
5209 				}
5210 			}
5211 			switch (route_rule->default_action) {
5212 			case NECP_ROUTE_RULE_DENY_INTERFACE:
5213 			case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5214 				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)",
5215 				    (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5216 				    (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5217 				    (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5218 				    (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5219 				    (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5220 				    (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Ultra-Constrained " : "",
5221 				    (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5222 				    (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5223 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5224 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5225 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5226 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5227 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5228 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5229 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5230 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5231 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5232 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5233 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5234 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5235 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5236 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5237 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5238 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5239 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5240 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5241 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5242 				break;
5243 			case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5244 				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)",
5245 				    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5246 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5247 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5248 				    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5249 				    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5250 				    IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action) ? "!Ultra-Constrained " : "",
5251 				    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5252 				    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5253 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5254 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5255 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5256 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5257 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5258 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5259 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5260 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5261 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5262 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5263 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5264 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5265 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5266 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5267 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5268 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5269 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5270 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5271 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5272 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5273 				break;
5274 			case NECP_ROUTE_RULE_QOS_MARKING:
5275 				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)",
5276 				    (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5277 				    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5278 				    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5279 				    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5280 				    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5281 				    (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Ultra-Constrained " : "",
5282 				    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5283 				    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5284 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5285 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5286 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5287 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5288 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5289 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5290 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5291 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5292 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5293 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5294 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5295 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5296 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5297 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5298 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5299 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5300 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5301 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5302 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5303 				break;
5304 			default:
5305 				snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5306 				break;
5307 			}
5308 		}
5309 		break;
5310 	}
5311 	case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5312 		bool found_mapping = FALSE;
5313 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5314 		if (mapping != NULL) {
5315 			uuid_unparse(mapping->uuid, uuid_string);
5316 			found_mapping = TRUE;
5317 		}
5318 		snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5319 		break;
5320 	}
5321 	case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5322 		bool found_mapping = FALSE;
5323 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5324 		if (mapping != NULL) {
5325 			uuid_unparse(mapping->uuid, uuid_string);
5326 			found_mapping = TRUE;
5327 		}
5328 		snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5329 		break;
5330 	}
5331 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5332 		bool found_mapping = FALSE;
5333 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(result_parameter.netagent_id);
5334 		if (mapping != NULL) {
5335 			uuid_unparse(mapping->uuid, uuid_string);
5336 			found_mapping = TRUE;
5337 		}
5338 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5339 		break;
5340 	}
5341 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE: {
5342 		bool found_mapping = FALSE;
5343 		struct necp_agent_type_id_mapping *mapping = necp_lookup_agent_type_with_id_locked(result_parameter.netagent_id);
5344 		if (mapping != NULL) {
5345 			found_mapping = TRUE;
5346 		}
5347 		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");
5348 		break;
5349 	}
5350 	default: {
5351 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5352 		break;
5353 	}
5354 	}
5355 	return result_string;
5356 }
5357 
5358 static void
necp_kernel_socket_policies_dump_all(void)5359 necp_kernel_socket_policies_dump_all(void)
5360 {
5361 	if (necp_debug) {
5362 		struct necp_kernel_socket_policy *policy = NULL;
5363 		int policy_i;
5364 		int app_i;
5365 		char result_string[MAX_RESULT_STRING_LEN];
5366 		char proc_name_string[MAXCOMLEN + 1];
5367 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
5368 		memset(proc_name_string, 0, MAXCOMLEN + 1);
5369 
5370 		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5371 		NECPLOG0(LOG_DEBUG, "-----------\n");
5372 		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5373 			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5374 			proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5375 			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));
5376 		}
5377 		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5378 			NECPLOG0(LOG_DEBUG, "-----------\n");
5379 		}
5380 
5381 		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5382 		NECPLOG0(LOG_DEBUG, "-----------\n");
5383 		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5384 			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5385 			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5386 				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5387 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5388 				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));
5389 			}
5390 			NECPLOG0(LOG_DEBUG, "-----------\n");
5391 		}
5392 	}
5393 }
5394 
5395 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5396 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5397 {
5398 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5399 		// Drop always cancels out lower policies
5400 		return TRUE;
5401 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5402 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5403 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5404 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5405 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5406 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT ||
5407 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE) {
5408 		// Filters and route rules never cancel out lower policies
5409 		return FALSE;
5410 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5411 		if (upper_policy->session_order != lower_policy->session_order) {
5412 			// A skip cannot override a policy of a different session
5413 			return FALSE;
5414 		} else {
5415 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
5416 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5417 				// This policy is beyond the skip
5418 				return FALSE;
5419 			} else {
5420 				// This policy is inside the skip
5421 				return TRUE;
5422 			}
5423 		}
5424 	}
5425 
5426 	// A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5427 	return TRUE;
5428 }
5429 
5430 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)5431 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5432 {
5433 	bool can_skip = FALSE;
5434 	u_int32_t highest_skip_session_order = 0;
5435 	u_int32_t highest_skip_order = 0;
5436 	int i;
5437 	for (i = 0; i < valid_indices; i++) {
5438 		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5439 
5440 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
5441 		if (can_skip) {
5442 			if (highest_skip_session_order != compared_policy->session_order ||
5443 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5444 				// If we've moved on to the next session, or passed the skip window
5445 				highest_skip_session_order = 0;
5446 				highest_skip_order = 0;
5447 				can_skip = FALSE;
5448 			} else {
5449 				// If this policy is also a skip, in can increase the skip window
5450 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5451 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5452 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5453 					}
5454 				}
5455 				continue;
5456 			}
5457 		}
5458 
5459 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5460 			// This policy is a skip. Set the skip window accordingly
5461 			can_skip = TRUE;
5462 			highest_skip_session_order = compared_policy->session_order;
5463 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5464 		}
5465 
5466 		// The result of the compared policy must be able to block out this policy result
5467 		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5468 			continue;
5469 		}
5470 
5471 		// If new policy matches All Interfaces, compared policy must also
5472 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5473 			continue;
5474 		}
5475 
5476 		// If new policy matches Local Networks, compared policy must also
5477 		if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5478 		    policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5479 			continue;
5480 		}
5481 
5482 		// Default makes lower policies unecessary always
5483 		if (compared_policy->condition_mask == 0) {
5484 			return TRUE;
5485 		}
5486 
5487 		// Compared must be more general than policy, and include only conditions within policy
5488 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5489 			continue;
5490 		}
5491 
5492 		// Negative conditions must match for the overlapping conditions
5493 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5494 			continue;
5495 		}
5496 
5497 		if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5498 		    compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5499 		    strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5500 			continue;
5501 		}
5502 
5503 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5504 		    compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5505 			continue;
5506 		}
5507 
5508 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5509 		    strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5510 			continue;
5511 		}
5512 
5513 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5514 		    strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5515 			continue;
5516 		}
5517 
5518 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5519 		    compared_policy->cond_account_id != policy->cond_account_id) {
5520 			continue;
5521 		}
5522 
5523 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5524 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
5525 			continue;
5526 		}
5527 
5528 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5529 		    compared_policy->cond_app_id != policy->cond_app_id) {
5530 			continue;
5531 		}
5532 
5533 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5534 		    compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5535 			continue;
5536 		}
5537 
5538 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5539 		    (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5540 			continue;
5541 		}
5542 
5543 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5544 		    compared_policy->cond_uid != policy->cond_uid) {
5545 			continue;
5546 		}
5547 
5548 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5549 		    compared_policy->cond_real_uid != policy->cond_real_uid) {
5550 			continue;
5551 		}
5552 
5553 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5554 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5555 			continue;
5556 		}
5557 
5558 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5559 		    compared_policy->cond_protocol != policy->cond_protocol) {
5560 			continue;
5561 		}
5562 
5563 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5564 		    compared_policy->cond_client_flags != policy->cond_client_flags) {
5565 			continue;
5566 		}
5567 
5568 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5569 		    !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5570 		    compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5571 			continue;
5572 		}
5573 
5574 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5575 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5576 				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))) {
5577 					continue;
5578 				}
5579 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5580 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5581 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5582 					continue;
5583 				}
5584 			}
5585 		}
5586 
5587 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5588 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5589 				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))) {
5590 					continue;
5591 				}
5592 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5593 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5594 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5595 					continue;
5596 				}
5597 			}
5598 		}
5599 
5600 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5601 		    memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5602 			continue;
5603 		}
5604 
5605 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5606 		    memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5607 			continue;
5608 		}
5609 
5610 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5611 		    memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5612 			continue;
5613 		}
5614 
5615 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5616 		    memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5617 			continue;
5618 		}
5619 
5620 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5621 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5622 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5623 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5624 			continue;
5625 		}
5626 
5627 		return TRUE;
5628 	}
5629 
5630 	return FALSE;
5631 }
5632 
5633 static bool
necp_kernel_socket_policies_reprocess(void)5634 necp_kernel_socket_policies_reprocess(void)
5635 {
5636 	int app_i;
5637 	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5638 	int app_layer_current_free_index = 0;
5639 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5640 
5641 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5642 
5643 	// Reset mask to 0
5644 	necp_kernel_application_policies_condition_mask = 0;
5645 	necp_kernel_socket_policies_condition_mask = 0;
5646 	necp_kernel_application_policies_count = 0;
5647 	necp_kernel_socket_policies_count = 0;
5648 	necp_kernel_socket_policies_non_app_count = 0;
5649 
5650 	// Reset all maps to NULL
5651 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5652 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5653 			kfree_type(struct necp_kernel_socket_policy *,
5654 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5655 			    necp_kernel_socket_policies_map[app_i]);
5656 			necp_kernel_socket_policies_map[app_i] = NULL;
5657 		}
5658 
5659 		// Init counts
5660 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5661 	}
5662 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5663 		kfree_type(struct necp_kernel_socket_policy *,
5664 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5665 		    necp_kernel_socket_policies_app_layer_map);
5666 	}
5667 	necp_kernel_socket_policies_app_layer_map = NULL;
5668 	necp_kernel_socket_policies_app_layer_map_count = 0;
5669 
5670 	// Create masks and counts
5671 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5672 		// App layer mask/count
5673 		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5674 		necp_kernel_application_policies_count++;
5675 		necp_kernel_socket_policies_app_layer_map_count++;
5676 
5677 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5678 			// Agent type conditions only apply to app layer
5679 			continue;
5680 		}
5681 
5682 		// Update socket layer bucket mask/counts
5683 		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5684 		necp_kernel_socket_policies_count++;
5685 
5686 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5687 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5688 			necp_kernel_socket_policies_non_app_count++;
5689 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5690 				necp_kernel_socket_policies_map_counts[app_i]++;
5691 			}
5692 		} else {
5693 			necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5694 		}
5695 	}
5696 
5697 	// Allocate maps
5698 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5699 		if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5700 			// Allocate a NULL-terminated array of policy pointers for each bucket
5701 			necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5702 			    necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5703 			if (necp_kernel_socket_policies_map[app_i] == NULL) {
5704 				goto fail;
5705 			}
5706 		}
5707 		bucket_current_free_index[app_i] = 0;
5708 	}
5709 	necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5710 	    necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5711 	if (necp_kernel_socket_policies_app_layer_map == NULL) {
5712 		goto fail;
5713 	}
5714 
5715 	// Fill out maps
5716 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5717 		// Add app layer policies
5718 		if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5719 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5720 			app_layer_current_free_index++;
5721 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5722 		}
5723 
5724 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5725 			// Agent type conditions only apply to app layer
5726 			continue;
5727 		}
5728 
5729 		// Add socket policies
5730 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5731 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5732 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5733 				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])) {
5734 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5735 					bucket_current_free_index[app_i]++;
5736 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5737 				}
5738 			}
5739 		} else {
5740 			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5741 			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])) {
5742 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5743 				bucket_current_free_index[app_i]++;
5744 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5745 			}
5746 		}
5747 	}
5748 	necp_kernel_socket_policies_dump_all();
5749 	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5750 	return TRUE;
5751 
5752 fail:
5753 	// Free memory, reset masks to 0
5754 	necp_kernel_application_policies_condition_mask = 0;
5755 	necp_kernel_socket_policies_condition_mask = 0;
5756 	necp_kernel_application_policies_count = 0;
5757 	necp_kernel_socket_policies_count = 0;
5758 	necp_kernel_socket_policies_non_app_count = 0;
5759 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5760 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5761 			kfree_type(struct necp_kernel_socket_policy *,
5762 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5763 			    necp_kernel_socket_policies_map[app_i]);
5764 			necp_kernel_socket_policies_map[app_i] = NULL;
5765 		}
5766 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5767 	}
5768 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5769 		kfree_type(struct necp_kernel_socket_policy *,
5770 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5771 		    necp_kernel_socket_policies_app_layer_map);
5772 		necp_kernel_socket_policies_app_layer_map = NULL;
5773 	}
5774 	necp_kernel_socket_policies_app_layer_map_count = 0;
5775 	return FALSE;
5776 }
5777 
5778 static u_int32_t
necp_get_new_string_id(void)5779 necp_get_new_string_id(void)
5780 {
5781 	static u_int32_t necp_last_string_id = 0;
5782 
5783 	u_int32_t newid = 0;
5784 
5785 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5786 
5787 	bool wrapped = FALSE;
5788 	do {
5789 		necp_last_string_id++;
5790 		if (necp_last_string_id < 1) {
5791 			if (wrapped) {
5792 				// Already wrapped, give up
5793 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5794 				return 0;
5795 			}
5796 			necp_last_string_id = 1;
5797 			wrapped = TRUE;
5798 		}
5799 		newid = necp_last_string_id;
5800 	} while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5801 
5802 	if (newid == 0) {
5803 		NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5804 		return 0;
5805 	}
5806 
5807 	return newid;
5808 }
5809 
5810 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5811 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5812 {
5813 	struct necp_string_id_mapping *searchentry = NULL;
5814 	struct necp_string_id_mapping *foundentry = NULL;
5815 
5816 	LIST_FOREACH(searchentry, list, chain) {
5817 		if (strcmp(searchentry->string, string) == 0) {
5818 			foundentry = searchentry;
5819 			break;
5820 		}
5821 	}
5822 
5823 	return foundentry;
5824 }
5825 
5826 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5827 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5828 {
5829 	struct necp_string_id_mapping *searchentry = NULL;
5830 	struct necp_string_id_mapping *foundentry = NULL;
5831 
5832 	LIST_FOREACH(searchentry, list, chain) {
5833 		if (searchentry->id == local_id) {
5834 			foundentry = searchentry;
5835 			break;
5836 		}
5837 	}
5838 
5839 	return foundentry;
5840 }
5841 
5842 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5843 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5844 {
5845 	u_int32_t string_id = 0;
5846 	struct necp_string_id_mapping *existing_mapping = NULL;
5847 
5848 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5849 
5850 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5851 	if (existing_mapping != NULL) {
5852 		string_id = existing_mapping->id;
5853 		os_ref_retain_locked(&existing_mapping->refcount);
5854 	} else {
5855 		struct necp_string_id_mapping * __single new_mapping = NULL;
5856 		new_mapping = kalloc_type(struct necp_string_id_mapping,
5857 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5858 
5859 		size_t length = strlen(string) + 1;
5860 		char *buffer = kalloc_data(length, Z_WAITOK);
5861 		if (buffer != NULL) {
5862 			strlcpy(buffer, string, length);
5863 			new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5864 			new_mapping->id = necp_get_new_string_id();
5865 			os_ref_init(&new_mapping->refcount, &necp_refgrp);
5866 			LIST_INSERT_HEAD(list, new_mapping, chain);
5867 			string_id = new_mapping->id;
5868 		} else {
5869 			kfree_type(struct necp_string_id_mapping, new_mapping);
5870 			new_mapping = NULL;
5871 		}
5872 	}
5873 	return string_id;
5874 }
5875 
5876 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5877 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5878 {
5879 	struct necp_string_id_mapping * __single existing_mapping = NULL;
5880 	char * __indexable buffer = NULL;
5881 
5882 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5883 
5884 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5885 	if (existing_mapping != NULL) {
5886 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5887 			LIST_REMOVE(existing_mapping, chain);
5888 			buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5889 			kfree_data_addr(buffer);
5890 			kfree_type(struct necp_string_id_mapping, existing_mapping);
5891 		}
5892 		return TRUE;
5893 	}
5894 
5895 	return FALSE;
5896 }
5897 
5898 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5899 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5900 {
5901 	struct necp_domain_filter *searchfilter = NULL;
5902 	struct necp_domain_filter *foundfilter = NULL;
5903 
5904 	LIST_FOREACH(searchfilter, list, chain) {
5905 		if (searchfilter->id == filter_id) {
5906 			foundfilter = searchfilter;
5907 			break;
5908 		}
5909 	}
5910 
5911 	return foundfilter;
5912 }
5913 
5914 static u_int32_t
necp_get_new_domain_filter_id(void)5915 necp_get_new_domain_filter_id(void)
5916 {
5917 	static u_int32_t necp_last_filter_id = 0;
5918 
5919 	u_int32_t newid = 0;
5920 
5921 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5922 
5923 	bool wrapped = FALSE;
5924 	do {
5925 		// Scope id within its space
5926 		if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5927 			necp_last_filter_id = 0;
5928 		}
5929 		if (necp_last_filter_id < 1) {
5930 			if (wrapped) {
5931 				// Already wrapped, give up
5932 				NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5933 				return 0;
5934 			}
5935 			necp_last_filter_id = 1;
5936 			wrapped = TRUE;
5937 		}
5938 		newid = necp_last_filter_id;
5939 	} while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5940 
5941 	if (newid == 0) {
5942 		NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5943 		return 0;
5944 	}
5945 
5946 	return newid;
5947 }
5948 
5949 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)5950 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5951 {
5952 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5953 
5954 	struct necp_domain_filter *new_filter = NULL;
5955 	new_filter = kalloc_type(struct necp_domain_filter,
5956 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5957 
5958 	new_filter->filter = filter;
5959 	new_filter->id = necp_get_new_domain_filter_id();
5960 	LIST_INSERT_HEAD(list, new_filter, chain);
5961 	LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5962 	os_ref_init(&new_filter->refcount, &necp_refgrp);
5963 
5964 	return new_filter->id;
5965 }
5966 
5967 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)5968 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5969 {
5970 	struct necp_domain_filter * __single existing_filter = NULL;
5971 
5972 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5973 
5974 	existing_filter = necp_lookup_domain_filter(list, filter_id);
5975 	if (existing_filter != NULL) {
5976 		if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5977 			LIST_REMOVE(existing_filter, chain);
5978 			LIST_REMOVE(existing_filter, owner_chain);
5979 			net_bloom_filter_destroy(existing_filter->filter);
5980 			kfree_type(struct necp_domain_filter, existing_filter);
5981 		}
5982 		return true;
5983 	}
5984 
5985 	return false;
5986 }
5987 
5988 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)5989 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
5990 {
5991 	struct necp_domain_trie *searchTrie = NULL;
5992 	struct necp_domain_trie *foundTrie = NULL;
5993 
5994 	LIST_FOREACH(searchTrie, list, chain) {
5995 		if (searchTrie->id == id) {
5996 			foundTrie = searchTrie;
5997 			break;
5998 		}
5999 	}
6000 
6001 	return foundTrie;
6002 }
6003 
6004 static u_int32_t
necp_get_new_domain_trie_id(void)6005 necp_get_new_domain_trie_id(void)
6006 {
6007 	static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6008 	u_int32_t newid = necp_last_trie_id;
6009 
6010 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6011 
6012 	bool wrapped = FALSE;
6013 	do {
6014 		if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6015 			if (wrapped) {
6016 				// Already wrapped, give up
6017 				NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6018 				return 0;
6019 			}
6020 			necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6021 			wrapped = TRUE;
6022 		}
6023 		newid = necp_last_trie_id;
6024 	} while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6025 
6026 	if (newid == NECP_DOMAIN_TRIE_ID_START) {
6027 		NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6028 		return 0;
6029 	}
6030 
6031 	return newid;
6032 }
6033 
6034 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)6035 necp_create_domain_trie(struct necp_domain_trie_list *list,
6036     struct necp_domain_trie_list *owner_list,
6037     struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6038 {
6039 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6040 
6041 	struct necp_domain_trie *new_trie = NULL;
6042 	new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6043 	if (new_trie == NULL) {
6044 		NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6045 		return 0;
6046 	}
6047 
6048 	if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6049 	    trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6050 	    trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6051 		NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6052 		kfree_type(struct necp_domain_trie, new_trie);
6053 		return 0;
6054 	}
6055 	new_trie->trie_request = trie_request;
6056 	new_trie->trie_request_size = trie_request_size;
6057 	new_trie->id = necp_get_new_domain_trie_id();
6058 	new_trie->trie_request->id = new_trie->id;
6059 	LIST_INSERT_HEAD(list, new_trie, chain);
6060 	LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6061 
6062 	os_ref_init(&new_trie->refcount, &necp_refgrp);
6063 	necp_trie_count++;
6064 	return new_trie->id;
6065 }
6066 
6067 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6068 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6069 {
6070 	if (existing_trie != NULL) {
6071 		uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6072 		kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6073 		kfree_type(struct necp_domain_trie, existing_trie);
6074 	}
6075 }
6076 
6077 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6078 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6079 {
6080 	struct necp_domain_trie * __single existing_trie = NULL;
6081 
6082 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6083 
6084 	existing_trie = necp_lookup_domain_trie(list, id);
6085 	if (existing_trie != NULL) {
6086 		if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6087 			LIST_REMOVE(existing_trie, chain);
6088 			LIST_REMOVE(existing_trie, owner_chain);
6089 			necp_free_domain_trie(existing_trie);
6090 			necp_trie_count--;
6091 		}
6092 		return true;
6093 	}
6094 
6095 	return false;
6096 }
6097 
6098 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)6099 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6100 {
6101 	size_t metadata_length = 0;
6102 	const uint8_t * __sized_by(metadata_length) metadata = NULL;
6103 
6104 	struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6105 	if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6106 		return false;
6107 	}
6108 	Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6109 	Boolean allow_partial_match  = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6110 	return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6111 	           &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6112 }
6113 
6114 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6115 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6116 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6117 necp_get_new_route_rule_id(bool aggregate)
6118 {
6119 	static u_int32_t necp_last_route_rule_id = 0;
6120 	static u_int32_t necp_last_aggregate_route_rule_id = 0;
6121 
6122 	u_int32_t newid = 0;
6123 
6124 	if (!aggregate) {
6125 		// Main necp_kernel_policy_lock protects non-aggregate rule IDs
6126 		LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6127 
6128 		bool wrapped = FALSE;
6129 		do {
6130 			necp_last_route_rule_id++;
6131 			if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6132 			    necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6133 				if (wrapped) {
6134 					// Already wrapped, give up
6135 					NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6136 					return 0;
6137 				}
6138 				necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6139 				wrapped = TRUE;
6140 			}
6141 			newid = necp_last_route_rule_id;
6142 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6143 	} else {
6144 		// necp_route_rule_lock protects aggregate rule IDs
6145 		LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6146 
6147 		bool wrapped = FALSE;
6148 		do {
6149 			necp_last_aggregate_route_rule_id++;
6150 			if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6151 				if (wrapped) {
6152 					// Already wrapped, give up
6153 					NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6154 					return 0;
6155 				}
6156 				necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6157 				wrapped = TRUE;
6158 			}
6159 			newid = necp_last_aggregate_route_rule_id;
6160 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6161 	}
6162 
6163 	if (newid == 0) {
6164 		NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6165 		return 0;
6166 	}
6167 
6168 	return newid;
6169 }
6170 
6171 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6172 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6173 {
6174 	struct necp_route_rule *searchentry = NULL;
6175 	struct necp_route_rule *foundentry = NULL;
6176 
6177 	LIST_FOREACH(searchentry, list, chain) {
6178 		if (searchentry->id == route_rule_id) {
6179 			foundentry = searchentry;
6180 			break;
6181 		}
6182 	}
6183 
6184 	return foundentry;
6185 }
6186 
6187 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)6188 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)
6189 {
6190 	struct necp_route_rule *searchentry = NULL;
6191 	struct necp_route_rule *foundentry = NULL;
6192 
6193 	LIST_FOREACH(searchentry, list, chain) {
6194 		if (searchentry->default_action == default_action &&
6195 		    searchentry->cellular_action == cellular_action &&
6196 		    searchentry->wifi_action == wifi_action &&
6197 		    searchentry->wired_action == wired_action &&
6198 		    searchentry->expensive_action == expensive_action &&
6199 		    searchentry->constrained_action == constrained_action &&
6200 		    searchentry->companion_action == companion_action &&
6201 		    searchentry->vpn_action == vpn_action &&
6202 		    searchentry->ultra_constrained_action == ultra_constrained_action &&
6203 		    searchentry->control_unit == control_unit &&
6204 		    searchentry->effective_type == effective_type) {
6205 			bool match_failed = FALSE;
6206 			size_t index_a = 0;
6207 			size_t index_b = 0;
6208 			size_t count_a = 0;
6209 			size_t count_b = 0;
6210 			for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6211 				bool found_index = FALSE;
6212 				if (searchentry->exception_if_indices[index_a] == 0) {
6213 					break;
6214 				}
6215 				count_a++;
6216 				for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6217 					if (if_indices[index_b] == 0) {
6218 						break;
6219 					}
6220 					if (index_b >= count_b) {
6221 						count_b = index_b + 1;
6222 					}
6223 					if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6224 					    searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6225 						found_index = TRUE;
6226 						break;
6227 					}
6228 				}
6229 				if (!found_index) {
6230 					match_failed = TRUE;
6231 					break;
6232 				}
6233 			}
6234 
6235 			if (match_failed || count_a != count_b) {
6236 				continue;
6237 			}
6238 
6239 			bool has_agent_a = !uuid_is_null(netagent_uuid);
6240 			bool has_agent_b = (searchentry->netagent_id != 0);
6241 			if (has_agent_a != has_agent_b) {
6242 				continue;
6243 			}
6244 
6245 			if (has_agent_a) {
6246 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(searchentry->netagent_id);
6247 				if (mapping == NULL) {
6248 					// Bad mapping, doesn't match
6249 					continue;
6250 				}
6251 				if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6252 					// UUIDs don't match
6253 					continue;
6254 				}
6255 			}
6256 
6257 			bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6258 			bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6259 			if (has_match_agent_a != has_match_agent_b) {
6260 				continue;
6261 			}
6262 
6263 			if (has_match_agent_a) {
6264 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(searchentry->match_netagent_id);
6265 				if (mapping == NULL) {
6266 					// Bad mapping, doesn't match
6267 					continue;
6268 				}
6269 				if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6270 					// UUIDs don't match
6271 					continue;
6272 				}
6273 			}
6274 
6275 			// Rules match!
6276 			foundentry = searchentry;
6277 			break;
6278 		}
6279 	}
6280 
6281 	return foundentry;
6282 }
6283 
6284 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)6285 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,
6286     bool *has_socket_only_actions)
6287 {
6288 	size_t offset = 0;
6289 	u_int32_t route_rule_id = 0;
6290 	struct necp_route_rule *existing_rule = NULL;
6291 	u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6292 	u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6293 	u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6294 	u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6295 	u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6296 	u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6297 	u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6298 	u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6299 	u_int8_t ultra_constrained_action = NECP_ROUTE_RULE_NONE;
6300 	u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6301 	size_t num_valid_indices = 0;
6302 	memset(&if_indices, 0, sizeof(if_indices));
6303 	u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6304 	memset(&if_actions, 0, sizeof(if_actions));
6305 
6306 	uuid_t netagent_uuid = {};
6307 
6308 	uuid_t match_netagent_uuid = {};
6309 	uint32_t control_unit = 0;
6310 	uint32_t effective_type = 0;
6311 
6312 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6313 
6314 	if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6315 		return 0;
6316 	}
6317 
6318 	// Process rules
6319 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6320 		ifnet_t __single rule_interface = NULL;
6321 		char interface_name[IFXNAMSIZ];
6322 		u_int32_t length = 0;
6323 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6324 
6325 		if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6326 			// Invalid TLV goes beyond end of the rules array
6327 			break;
6328 		}
6329 
6330 		// Increment offset for the next time through the loop
6331 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6332 
6333 		u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6334 		u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6335 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6336 		u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6337 
6338 		if (rule_action == NECP_ROUTE_RULE_NONE) {
6339 			// Don't allow an explicit rule to be None action
6340 			continue;
6341 		}
6342 
6343 		if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6344 		    rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6345 			if (rule_length < sizeof(uuid_t)) {
6346 				// Too short, skip
6347 				continue;
6348 			}
6349 
6350 			if (!uuid_is_null(netagent_uuid)) {
6351 				if (uuid_compare(netagent_uuid, rule_value) != 0) {
6352 					// UUIDs don't match, skip
6353 					continue;
6354 				}
6355 			} else {
6356 				// Copy out agent UUID
6357 				memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6358 			}
6359 
6360 			// Adjust remaining length
6361 			rule_value += sizeof(netagent_uuid);
6362 			rule_length -= sizeof(netagent_uuid);
6363 			*has_socket_only_actions = true;
6364 		} else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6365 			if (rule_length < sizeof(control_unit)) {
6366 				// Too short, skip
6367 				continue;
6368 			}
6369 
6370 			memcpy(&control_unit, rule_value, sizeof(control_unit));
6371 
6372 			// Adjust remaining length
6373 			rule_value += sizeof(control_unit);
6374 			rule_length -= sizeof(control_unit);
6375 			*has_socket_only_actions = true;
6376 		} else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6377 			if (rule_length < sizeof(effective_type)) {
6378 				// Too short, skip
6379 				continue;
6380 			}
6381 
6382 			memcpy(&effective_type, rule_value, sizeof(effective_type));
6383 
6384 			// Adjust remaining length
6385 			rule_value += sizeof(effective_type);
6386 			rule_length -= sizeof(effective_type);
6387 		}
6388 
6389 		if (rule_length == 0) {
6390 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6391 				cellular_action = rule_action;
6392 			}
6393 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6394 				wifi_action = rule_action;
6395 			}
6396 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6397 				wired_action = rule_action;
6398 			}
6399 			if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6400 				expensive_action = rule_action;
6401 			}
6402 			if ((rule_flags & NECP_ROUTE_RULE_FLAG_ULTRA_CONSTRAINED) == NECP_ROUTE_RULE_FLAG_ULTRA_CONSTRAINED) {
6403 				ultra_constrained_action = rule_action;
6404 			} else if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6405 				constrained_action = rule_action;
6406 			}
6407 			if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6408 				companion_action = rule_action;
6409 			}
6410 			if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6411 				vpn_action = rule_action;
6412 			}
6413 			if (rule_flags == 0) {
6414 				default_action = rule_action;
6415 			}
6416 			continue;
6417 		} else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6418 			if (rule_length < sizeof(uuid_t)) {
6419 				// Too short, skip
6420 				continue;
6421 			}
6422 
6423 			// Store the netagent UUID to match
6424 			memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6425 			// If the data is exactly a UUID, this is the default action
6426 			if (rule_length == sizeof(uuid_t)) {
6427 				default_action = rule_action;
6428 				continue;
6429 			}
6430 
6431 			// If the data is longer than a UUID, this also includes an interface name
6432 			// Adjust remaining length to make sure the interface name is picked up below
6433 			rule_value += sizeof(uuid_t);
6434 			rule_length -= sizeof(uuid_t);
6435 		}
6436 
6437 		if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6438 			continue;
6439 		}
6440 
6441 		if (rule_length <= IFXNAMSIZ) {
6442 			memcpy(interface_name, rule_value, rule_length);
6443 			interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6444 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6445 				if_actions[num_valid_indices] = rule_action;
6446 				if_indices[num_valid_indices++] = rule_interface->if_index;
6447 				ifnet_release(rule_interface);
6448 			}
6449 		}
6450 	}
6451 
6452 	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);
6453 	if (existing_rule != NULL) {
6454 		route_rule_id = existing_rule->id;
6455 		os_ref_retain_locked(&existing_rule->refcount);
6456 	} else {
6457 		struct necp_route_rule *new_rule = NULL;
6458 		new_rule = kalloc_type(struct necp_route_rule,
6459 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6460 		route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6461 		if (!uuid_is_null(netagent_uuid)) {
6462 			new_rule->netagent_id = necp_create_agent_uuid_id_mapping(netagent_uuid);
6463 		}
6464 		if (!uuid_is_null(match_netagent_uuid)) {
6465 			new_rule->match_netagent_id = necp_create_agent_uuid_id_mapping(match_netagent_uuid);
6466 		}
6467 		new_rule->effective_type = effective_type;
6468 		new_rule->control_unit = control_unit;
6469 		new_rule->default_action = default_action;
6470 		new_rule->cellular_action = cellular_action;
6471 		new_rule->wifi_action = wifi_action;
6472 		new_rule->wired_action = wired_action;
6473 		new_rule->expensive_action = expensive_action;
6474 		new_rule->constrained_action = constrained_action;
6475 		new_rule->companion_action = companion_action;
6476 		new_rule->vpn_action = vpn_action;
6477 		new_rule->ultra_constrained_action = ultra_constrained_action;
6478 		memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6479 		memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6480 		os_ref_init(&new_rule->refcount, &necp_refgrp);
6481 		LIST_INSERT_HEAD(list, new_rule, chain);
6482 	}
6483 	return route_rule_id;
6484 }
6485 
6486 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6487 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6488 {
6489 	if (rule_id) {
6490 		lck_rw_lock_exclusive(&necp_route_rule_lock);
6491 
6492 		struct necp_aggregate_route_rule * __single existing_rule = NULL;
6493 		struct necp_aggregate_route_rule *tmp_rule = NULL;
6494 
6495 		LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6496 			int index = 0;
6497 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6498 				u_int32_t route_rule_id = existing_rule->rule_ids[index];
6499 				if (route_rule_id == rule_id) {
6500 					LIST_REMOVE(existing_rule, chain);
6501 					kfree_type(struct necp_aggregate_route_rule, existing_rule);
6502 					break;
6503 				}
6504 			}
6505 		}
6506 
6507 		lck_rw_done(&necp_route_rule_lock);
6508 	}
6509 }
6510 
6511 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6512 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6513 {
6514 	struct necp_route_rule * __single existing_rule = NULL;
6515 
6516 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6517 
6518 	existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6519 	if (existing_rule != NULL) {
6520 		if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6521 			necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6522 			necp_remove_agent_uuid_id_mapping_with_agent_id(existing_rule->netagent_id);
6523 			necp_remove_agent_uuid_id_mapping_with_agent_id(existing_rule->match_netagent_id);
6524 			LIST_REMOVE(existing_rule, chain);
6525 			kfree_type(struct necp_route_rule, existing_rule);
6526 		}
6527 		return TRUE;
6528 	}
6529 
6530 	return FALSE;
6531 }
6532 
6533 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6534 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6535 {
6536 	struct necp_aggregate_route_rule *searchentry = NULL;
6537 	struct necp_aggregate_route_rule *foundentry = NULL;
6538 
6539 	lck_rw_lock_shared(&necp_route_rule_lock);
6540 
6541 	LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6542 		if (searchentry->id == route_rule_id) {
6543 			foundentry = searchentry;
6544 			break;
6545 		}
6546 	}
6547 
6548 	lck_rw_done(&necp_route_rule_lock);
6549 
6550 	return foundentry;
6551 }
6552 
6553 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6554 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6555 {
6556 	u_int32_t aggregate_route_rule_id = 0;
6557 	struct necp_aggregate_route_rule *new_rule = NULL;
6558 	struct necp_aggregate_route_rule *existing_rule = NULL;
6559 
6560 	lck_rw_lock_exclusive(&necp_route_rule_lock);
6561 
6562 	// Check if the rule already exists
6563 	LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6564 		if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6565 			lck_rw_done(&necp_route_rule_lock);
6566 			return existing_rule->id;
6567 		}
6568 	}
6569 
6570 	new_rule = kalloc_type(struct necp_aggregate_route_rule,
6571 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6572 	aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6573 	new_rule->id = aggregate_route_rule_id;
6574 	memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6575 	LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6576 	lck_rw_done(&necp_route_rule_lock);
6577 
6578 	return aggregate_route_rule_id;
6579 }
6580 
6581 static u_int32_t
necp_get_new_app_uuid_id(void)6582 necp_get_new_app_uuid_id(void)
6583 {
6584 	static u_int32_t necp_last_app_uuid_id = 0;
6585 
6586 	u_int32_t newid = 0;
6587 
6588 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6589 
6590 	bool wrapped = FALSE;
6591 	do {
6592 		necp_last_app_uuid_id++;
6593 		if (necp_last_app_uuid_id < 1) {
6594 			if (wrapped) {
6595 				// Already wrapped, give up
6596 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID ID.\n");
6597 				return 0;
6598 			}
6599 			necp_last_app_uuid_id = 1;
6600 			wrapped = TRUE;
6601 		}
6602 		newid = necp_last_app_uuid_id;
6603 	} while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6604 
6605 	if (newid == 0) {
6606 		NECPLOG0(LOG_ERR, "Allocate app UUID ID failed.\n");
6607 		return 0;
6608 	}
6609 
6610 	return newid;
6611 }
6612 
6613 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6614 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6615 {
6616 	struct necp_uuid_id_mapping *searchentry = NULL;
6617 	struct necp_uuid_id_mapping *foundentry = NULL;
6618 
6619 	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6620 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6621 			foundentry = searchentry;
6622 			break;
6623 		}
6624 	}
6625 
6626 	return foundentry;
6627 }
6628 
6629 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6630 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6631 {
6632 	struct necp_uuid_id_mapping *searchentry = NULL;
6633 	struct necp_uuid_id_mapping *foundentry = NULL;
6634 
6635 	struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6636 	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--) {
6637 		LIST_FOREACH(searchentry, uuid_list_head, chain) {
6638 			if (searchentry->id == local_id) {
6639 				foundentry = searchentry;
6640 				break;
6641 			}
6642 		}
6643 	}
6644 
6645 	return foundentry;
6646 }
6647 
6648 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6649 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6650 {
6651 	u_int32_t local_id = 0;
6652 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6653 
6654 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6655 
6656 	if (allocated_mapping) {
6657 		*allocated_mapping = FALSE;
6658 	}
6659 
6660 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6661 	if (existing_mapping != NULL) {
6662 		local_id = existing_mapping->id;
6663 		os_ref_retain_locked(&existing_mapping->refcount);
6664 		if (uuid_policy_table) {
6665 			existing_mapping->table_usecount++;
6666 		}
6667 	} else {
6668 		struct necp_uuid_id_mapping *new_mapping = NULL;
6669 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6670 		    Z_WAITOK | Z_NOFAIL);
6671 		uuid_copy(new_mapping->uuid, uuid);
6672 		new_mapping->id = necp_get_new_app_uuid_id();
6673 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6674 		if (uuid_policy_table) {
6675 			new_mapping->table_usecount = 1;
6676 		} else {
6677 			new_mapping->table_usecount = 0;
6678 		}
6679 
6680 		LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6681 
6682 		if (allocated_mapping) {
6683 			*allocated_mapping = TRUE;
6684 		}
6685 
6686 		local_id = new_mapping->id;
6687 	}
6688 
6689 	return local_id;
6690 }
6691 
6692 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6693 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6694 {
6695 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6696 
6697 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6698 
6699 	if (removed_mapping) {
6700 		*removed_mapping = FALSE;
6701 	}
6702 
6703 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6704 	if (existing_mapping != NULL) {
6705 		if (uuid_policy_table) {
6706 			existing_mapping->table_usecount--;
6707 		}
6708 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6709 			LIST_REMOVE(existing_mapping, chain);
6710 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6711 			if (removed_mapping) {
6712 				*removed_mapping = TRUE;
6713 			}
6714 		}
6715 		return TRUE;
6716 	}
6717 
6718 	return FALSE;
6719 }
6720 
6721 #define NECP_NULL_AGENT_ID 1
6722 #define NECP_FIRST_VALID_AGENT_UUID_ID  2
6723 #define NECP_FIRST_VALID_AGENT_TYPE_ID  UINT16_MAX
6724 
6725 static bool
necp_agent_id_is_uuid(u_int32_t agent_id)6726 necp_agent_id_is_uuid(u_int32_t agent_id)
6727 {
6728 	return agent_id < NECP_FIRST_VALID_AGENT_TYPE_ID;
6729 }
6730 
6731 static u_int32_t
necp_get_new_agent_id(bool uuid)6732 necp_get_new_agent_id(bool uuid)
6733 {
6734 	static u_int32_t necp_last_agent_id = 0;
6735 	static u_int32_t necp_last_agent_type_id = 0;
6736 
6737 	u_int32_t newid = 0;
6738 
6739 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6740 
6741 	if (uuid) {
6742 		bool wrapped = FALSE;
6743 		do {
6744 			necp_last_agent_id++;
6745 			if (necp_last_agent_id < NECP_FIRST_VALID_AGENT_UUID_ID ||
6746 			    necp_last_agent_id >= NECP_FIRST_VALID_AGENT_TYPE_ID) {
6747 				if (wrapped) {
6748 					// Already wrapped, give up
6749 					NECPLOG0(LOG_ERR, "Failed to find a free agent UUID ID.\n");
6750 					return NECP_NULL_AGENT_ID;
6751 				}
6752 				necp_last_agent_id = NECP_FIRST_VALID_AGENT_UUID_ID;
6753 				wrapped = TRUE;
6754 			}
6755 			newid = necp_last_agent_id;
6756 		} while (necp_uuid_lookup_uuid_with_agent_id_locked(newid) != NULL); // If already used, keep trying
6757 	} else {
6758 		bool wrapped = FALSE;
6759 		do {
6760 			necp_last_agent_type_id++;
6761 			if (necp_last_agent_type_id < NECP_FIRST_VALID_AGENT_TYPE_ID) {
6762 				if (wrapped) {
6763 					// Already wrapped, give up
6764 					NECPLOG0(LOG_ERR, "Failed to find a free agent type ID.\n");
6765 					return NECP_NULL_AGENT_ID;
6766 				}
6767 				necp_last_agent_type_id = NECP_FIRST_VALID_AGENT_TYPE_ID;
6768 				wrapped = TRUE;
6769 			}
6770 			newid = necp_last_agent_type_id;
6771 		} while (necp_lookup_agent_type_with_id_locked(newid) != NULL); // If already used, keep trying
6772 	}
6773 
6774 	if (newid == NECP_NULL_AGENT_ID) {
6775 		NECPLOG0(LOG_ERR, "Allocate agent ID failed.\n");
6776 		return NECP_NULL_AGENT_ID;
6777 	}
6778 
6779 	return newid;
6780 }
6781 
6782 static struct necp_uuid_id_mapping *
necp_uuid_get_null_agent_id_mapping(void)6783 necp_uuid_get_null_agent_id_mapping(void)
6784 {
6785 	static struct necp_uuid_id_mapping null_mapping;
6786 	uuid_clear(null_mapping.uuid);
6787 	null_mapping.id = NECP_NULL_AGENT_ID;
6788 
6789 	return &null_mapping;
6790 }
6791 
6792 static struct necp_uuid_id_mapping *
necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid)6793 necp_uuid_lookup_agent_id_with_uuid_locked(uuid_t uuid)
6794 {
6795 	struct necp_uuid_id_mapping *searchentry = NULL;
6796 	struct necp_uuid_id_mapping *foundentry = NULL;
6797 
6798 	if (uuid_is_null(uuid)) {
6799 		return necp_uuid_get_null_agent_id_mapping();
6800 	}
6801 
6802 	LIST_FOREACH(searchentry, &necp_agent_uuid_id_list, chain) {
6803 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6804 			foundentry = searchentry;
6805 			break;
6806 		}
6807 	}
6808 
6809 	return foundentry;
6810 }
6811 
6812 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id)6813 necp_uuid_lookup_uuid_with_agent_id_locked(u_int32_t agent_id)
6814 {
6815 	struct necp_uuid_id_mapping *searchentry = NULL;
6816 	struct necp_uuid_id_mapping *foundentry = NULL;
6817 
6818 	if (agent_id == NECP_NULL_AGENT_ID) {
6819 		return necp_uuid_get_null_agent_id_mapping();
6820 	}
6821 
6822 	LIST_FOREACH(searchentry, &necp_agent_uuid_id_list, chain) {
6823 		if (searchentry->id == agent_id) {
6824 			foundentry = searchentry;
6825 			break;
6826 		}
6827 	}
6828 
6829 	return foundentry;
6830 }
6831 
6832 static u_int32_t
necp_create_agent_uuid_id_mapping(uuid_t uuid)6833 necp_create_agent_uuid_id_mapping(uuid_t uuid)
6834 {
6835 	u_int32_t agent_id = 0;
6836 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6837 
6838 	if (uuid_is_null(uuid)) {
6839 		return NECP_NULL_AGENT_ID;
6840 	}
6841 
6842 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6843 
6844 	existing_mapping = necp_uuid_lookup_agent_id_with_uuid_locked(uuid);
6845 	if (existing_mapping != NULL) {
6846 		agent_id = existing_mapping->id;
6847 		os_ref_retain_locked(&existing_mapping->refcount);
6848 	} else {
6849 		struct necp_uuid_id_mapping *new_mapping = NULL;
6850 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6851 		    Z_WAITOK | Z_NOFAIL);
6852 		uuid_copy(new_mapping->uuid, uuid);
6853 		new_mapping->id = necp_get_new_agent_id(true);
6854 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6855 
6856 		LIST_INSERT_HEAD(&necp_agent_uuid_id_list, new_mapping, chain);
6857 
6858 		agent_id = new_mapping->id;
6859 	}
6860 
6861 	return agent_id;
6862 }
6863 
6864 static bool
necp_remove_agent_uuid_id_mapping(uuid_t uuid)6865 necp_remove_agent_uuid_id_mapping(uuid_t uuid)
6866 {
6867 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6868 
6869 	if (uuid_is_null(uuid)) {
6870 		return TRUE;
6871 	}
6872 
6873 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6874 
6875 	existing_mapping = necp_uuid_lookup_agent_id_with_uuid_locked(uuid);
6876 	if (existing_mapping != NULL) {
6877 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6878 			LIST_REMOVE(existing_mapping, chain);
6879 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6880 		}
6881 		return TRUE;
6882 	}
6883 
6884 	return FALSE;
6885 }
6886 
6887 static bool
necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id)6888 necp_remove_agent_uuid_id_mapping_with_agent_id(u_int32_t agent_id)
6889 {
6890 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6891 
6892 	if (agent_id == 0) {
6893 		return TRUE;
6894 	}
6895 
6896 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6897 
6898 	existing_mapping = necp_uuid_lookup_uuid_with_agent_id_locked(agent_id);
6899 	if (existing_mapping != NULL) {
6900 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6901 			LIST_REMOVE(existing_mapping, chain);
6902 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6903 		}
6904 		return TRUE;
6905 	}
6906 
6907 	return FALSE;
6908 }
6909 
6910 static struct necp_agent_type_id_mapping *
necp_lookup_agent_type_to_id_locked(struct necp_policy_condition_agent_type * agent_type)6911 necp_lookup_agent_type_to_id_locked(struct necp_policy_condition_agent_type *agent_type)
6912 {
6913 	struct necp_agent_type_id_mapping *searchentry = NULL;
6914 	struct necp_agent_type_id_mapping *foundentry = NULL;
6915 
6916 	LIST_FOREACH(searchentry, &necp_agent_type_id_list, chain) {
6917 		if (strlcmp(searchentry->agent_type.agent_domain, __unsafe_null_terminated_from_indexable(agent_type->agent_domain), NETAGENT_DOMAINSIZE) == 0 &&
6918 		    strlcmp(searchentry->agent_type.agent_type, __unsafe_null_terminated_from_indexable(agent_type->agent_type), NETAGENT_TYPESIZE) == 0) {
6919 			foundentry = searchentry;
6920 			break;
6921 		}
6922 	}
6923 
6924 	return foundentry;
6925 }
6926 
6927 static struct necp_agent_type_id_mapping *
necp_lookup_agent_type_with_id_locked(u_int32_t agent_id)6928 necp_lookup_agent_type_with_id_locked(u_int32_t agent_id)
6929 {
6930 	struct necp_agent_type_id_mapping *searchentry = NULL;
6931 	struct necp_agent_type_id_mapping *foundentry = NULL;
6932 
6933 	LIST_FOREACH(searchentry, &necp_agent_type_id_list, chain) {
6934 		if (searchentry->id == agent_id) {
6935 			foundentry = searchentry;
6936 			break;
6937 		}
6938 	}
6939 
6940 	return foundentry;
6941 }
6942 
6943 static u_int32_t
necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type * agent_type)6944 necp_create_agent_type_to_id_mapping(struct necp_policy_condition_agent_type *agent_type)
6945 {
6946 	u_int32_t agent_type_id = 0;
6947 	struct necp_agent_type_id_mapping *existing_mapping = NULL;
6948 
6949 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6950 
6951 	existing_mapping = necp_lookup_agent_type_to_id_locked(agent_type);
6952 	if (existing_mapping != NULL) {
6953 		agent_type_id = existing_mapping->id;
6954 		os_ref_retain_locked(&existing_mapping->refcount);
6955 	} else {
6956 		struct necp_agent_type_id_mapping * __single new_mapping = NULL;
6957 		new_mapping = kalloc_type(struct necp_agent_type_id_mapping,
6958 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6959 		strlcpy(new_mapping->agent_type.agent_domain, __unsafe_null_terminated_from_indexable(agent_type->agent_domain), NETAGENT_DOMAINSIZE);
6960 		strlcpy(new_mapping->agent_type.agent_type, __unsafe_null_terminated_from_indexable(agent_type->agent_type), NETAGENT_TYPESIZE);
6961 		new_mapping->id = necp_get_new_agent_id(false);
6962 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6963 		LIST_INSERT_HEAD(&necp_agent_type_id_list, new_mapping, chain);
6964 		agent_type_id = new_mapping->id;
6965 	}
6966 	return agent_type_id;
6967 }
6968 
6969 static bool
necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id)6970 necp_remove_agent_type_to_id_mapping(u_int32_t agent_type_id)
6971 {
6972 	struct necp_agent_type_id_mapping * __single existing_mapping = NULL;
6973 
6974 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6975 
6976 	existing_mapping = necp_lookup_agent_type_with_id_locked(agent_type_id);
6977 	if (existing_mapping != NULL) {
6978 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6979 			LIST_REMOVE(existing_mapping, chain);
6980 			kfree_type(struct necp_agent_type_id_mapping, existing_mapping);
6981 		}
6982 		return true;
6983 	}
6984 
6985 	return false;
6986 }
6987 
6988 static bool
necp_kernel_socket_policies_update_uuid_table(void)6989 necp_kernel_socket_policies_update_uuid_table(void)
6990 {
6991 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6992 
6993 	if (necp_uuid_app_id_mappings_dirty) {
6994 		uuid_t dummy_uuid = {};
6995 		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6996 			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6997 			return FALSE;
6998 		}
6999 
7000 		if (necp_num_uuid_app_id_mappings > 0) {
7001 			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
7002 			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--) {
7003 				struct necp_uuid_id_mapping *mapping = NULL;
7004 				LIST_FOREACH(mapping, uuid_list_head, chain) {
7005 					if (mapping->table_usecount > 0 &&
7006 					    proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
7007 						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
7008 					}
7009 				}
7010 			}
7011 		}
7012 
7013 		necp_uuid_app_id_mappings_dirty = FALSE;
7014 	}
7015 
7016 	return TRUE;
7017 }
7018 
7019 #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)
7020 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)7021 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)
7022 {
7023 	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
7024 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7025 
7026 	new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
7027 	new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
7028 	new_kernel_policy->suborder = suborder;
7029 	new_kernel_policy->order = order;
7030 	new_kernel_policy->session_order = session_order;
7031 	new_kernel_policy->session_pid = session_pid;
7032 
7033 	// Sanitize condition mask
7034 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
7035 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
7036 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
7037 	}
7038 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
7039 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
7040 	}
7041 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
7042 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
7043 	}
7044 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
7045 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
7046 	}
7047 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
7048 
7049 	// Set condition values
7050 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
7051 		new_kernel_policy->cond_policy_id = cond_policy_id;
7052 	}
7053 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
7054 		if (cond_bound_interface) {
7055 			ifnet_reference(cond_bound_interface);
7056 		}
7057 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
7058 	}
7059 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
7060 		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
7061 	}
7062 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
7063 		new_kernel_policy->cond_protocol = cond_protocol;
7064 	}
7065 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7066 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
7067 	}
7068 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7069 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
7070 	}
7071 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7072 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
7073 	}
7074 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7075 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
7076 	}
7077 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7078 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7079 	}
7080 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7081 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7082 	}
7083 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7084 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7085 	}
7086 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7087 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
7088 	}
7089 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7090 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7091 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7092 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7093 	}
7094 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7095 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7096 	}
7097 
7098 	new_kernel_policy->result = result;
7099 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7100 
7101 	if (necp_debug) {
7102 		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7103 	}
7104 	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7105 
7106 	return new_kernel_policy ? new_kernel_policy->id : 0;
7107 }
7108 
7109 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7110 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7111 {
7112 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7113 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7114 
7115 	if (policy_id == 0) {
7116 		return NULL;
7117 	}
7118 
7119 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7120 		if (kernel_policy->id == policy_id) {
7121 			return kernel_policy;
7122 		}
7123 	}
7124 
7125 	return NULL;
7126 }
7127 
7128 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7129 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7130 {
7131 	struct necp_kernel_ip_output_policy * __single policy = NULL;
7132 
7133 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7134 
7135 	policy = necp_kernel_ip_output_policy_find(policy_id);
7136 	if (policy) {
7137 		LIST_REMOVE(policy, chain);
7138 
7139 		if (policy->cond_bound_interface) {
7140 			ifnet_release(policy->cond_bound_interface);
7141 			policy->cond_bound_interface = NULL;
7142 		}
7143 
7144 		zfree(necp_ip_policy_zone, policy);
7145 		return TRUE;
7146 	}
7147 
7148 	return FALSE;
7149 }
7150 
7151 static void
necp_kernel_ip_output_policies_dump_all(void)7152 necp_kernel_ip_output_policies_dump_all(void)
7153 {
7154 	if (necp_debug) {
7155 		struct necp_kernel_ip_output_policy *policy = NULL;
7156 		int policy_i;
7157 		int id_i;
7158 		char result_string[MAX_RESULT_STRING_LEN];
7159 		char proc_name_string[MAXCOMLEN + 1];
7160 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
7161 		memset(proc_name_string, 0, MAXCOMLEN + 1);
7162 
7163 		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7164 		NECPLOG0(LOG_DEBUG, "-----------\n");
7165 		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7166 			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7167 			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++) {
7168 				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7169 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7170 				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));
7171 			}
7172 			NECPLOG0(LOG_DEBUG, "-----------\n");
7173 		}
7174 	}
7175 }
7176 
7177 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)7178 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7179 {
7180 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7181 		if (upper_policy->session_order != lower_policy->session_order) {
7182 			// A skip cannot override a policy of a different session
7183 			return FALSE;
7184 		} else {
7185 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
7186 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7187 				// This policy is beyond the skip
7188 				return FALSE;
7189 			} else {
7190 				// This policy is inside the skip
7191 				return TRUE;
7192 			}
7193 		}
7194 	}
7195 
7196 	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7197 	return TRUE;
7198 }
7199 
7200 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)7201 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)
7202 {
7203 	bool can_skip = FALSE;
7204 	u_int32_t highest_skip_session_order = 0;
7205 	u_int32_t highest_skip_order = 0;
7206 	int i;
7207 	for (i = 0; i < valid_indices; i++) {
7208 		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7209 
7210 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
7211 		if (can_skip) {
7212 			if (highest_skip_session_order != compared_policy->session_order ||
7213 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7214 				// If we've moved on to the next session, or passed the skip window
7215 				highest_skip_session_order = 0;
7216 				highest_skip_order = 0;
7217 				can_skip = FALSE;
7218 			} else {
7219 				// If this policy is also a skip, in can increase the skip window
7220 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7221 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7222 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7223 					}
7224 				}
7225 				continue;
7226 			}
7227 		}
7228 
7229 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7230 			// This policy is a skip. Set the skip window accordingly
7231 			can_skip = TRUE;
7232 			highest_skip_session_order = compared_policy->session_order;
7233 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7234 		}
7235 
7236 		// The result of the compared policy must be able to block out this policy result
7237 		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7238 			continue;
7239 		}
7240 
7241 		// If new policy matches All Interfaces, compared policy must also
7242 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7243 			continue;
7244 		}
7245 
7246 		// If new policy matches Local Networks, compared policy must also
7247 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7248 			continue;
7249 		}
7250 
7251 		// Default makes lower policies unnecessary always
7252 		if (compared_policy->condition_mask == 0) {
7253 			return TRUE;
7254 		}
7255 
7256 		// Compared must be more general than policy, and include only conditions within policy
7257 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7258 			continue;
7259 		}
7260 
7261 		// Negative conditions must match for the overlapping conditions
7262 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7263 			continue;
7264 		}
7265 
7266 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7267 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
7268 			continue;
7269 		}
7270 
7271 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7272 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7273 			continue;
7274 		}
7275 
7276 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7277 		    compared_policy->cond_protocol != policy->cond_protocol) {
7278 			continue;
7279 		}
7280 
7281 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7282 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7283 				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))) {
7284 					continue;
7285 				}
7286 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7287 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7288 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7289 					continue;
7290 				}
7291 			}
7292 		}
7293 
7294 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7295 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7296 				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))) {
7297 					continue;
7298 				}
7299 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7300 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7301 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7302 					continue;
7303 				}
7304 			}
7305 		}
7306 
7307 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7308 		    compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7309 			continue;
7310 		}
7311 
7312 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7313 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7314 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7315 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7316 			continue;
7317 		}
7318 
7319 		return TRUE;
7320 	}
7321 
7322 	return FALSE;
7323 }
7324 
7325 static bool
necp_kernel_ip_output_policies_reprocess(void)7326 necp_kernel_ip_output_policies_reprocess(void)
7327 {
7328 	int i;
7329 	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7330 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7331 
7332 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7333 
7334 	// Reset mask to 0
7335 	necp_kernel_ip_output_policies_condition_mask = 0;
7336 	necp_kernel_ip_output_policies_count = 0;
7337 	necp_kernel_ip_output_policies_non_id_count = 0;
7338 
7339 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7340 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7341 			kfree_type(struct necp_kernel_ip_output_policy *,
7342 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7343 			    necp_kernel_ip_output_policies_map[i]);
7344 			necp_kernel_ip_output_policies_map[i] = NULL;
7345 		}
7346 
7347 		// Init counts
7348 		necp_kernel_ip_output_policies_map_counts[i] = 0;
7349 	}
7350 
7351 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7352 		// Update mask
7353 		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7354 		necp_kernel_ip_output_policies_count++;
7355 
7356 		/* Update bucket counts:
7357 		 * Non-id and SKIP policies will be added to all buckets
7358 		 * Add local networks policy to all buckets for incoming IP
7359 		 */
7360 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7361 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7362 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7363 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7364 				necp_kernel_ip_output_policies_map_counts[i]++;
7365 			}
7366 		}
7367 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7368 			necp_kernel_ip_output_policies_non_id_count++;
7369 		} else {
7370 			necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7371 		}
7372 	}
7373 
7374 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7375 		if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7376 			// Allocate a NULL-terminated array of policy pointers for each bucket
7377 			necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7378 			    necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7379 			if (necp_kernel_ip_output_policies_map[i] == NULL) {
7380 				goto fail;
7381 			}
7382 		}
7383 		bucket_current_free_index[i] = 0;
7384 	}
7385 
7386 	u_int32_t current_session_order = 0;
7387 	u_int32_t current_session_last_non_skip_policy = 0;
7388 
7389 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7390 		// For each new session, find the last non-skip policy. We can
7391 		// avoid adding any skip policies that don't actually skip over
7392 		// any non-skip policies.
7393 		if (current_session_order != kernel_policy->session_order) {
7394 			current_session_order = kernel_policy->session_order;
7395 			current_session_last_non_skip_policy = 0;
7396 
7397 			struct necp_kernel_ip_output_policy *inner_policy = NULL;
7398 			LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7399 				if (inner_policy->session_order < current_session_order) {
7400 					continue;
7401 				}
7402 				if (inner_policy->session_order > current_session_order) {
7403 					break;
7404 				}
7405 				if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7406 					continue;
7407 				}
7408 
7409 				current_session_last_non_skip_policy = inner_policy->order;
7410 			}
7411 		}
7412 
7413 		if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7414 			if (current_session_last_non_skip_policy == 0) {
7415 				// No useful policies to skip over, don't add
7416 				continue;
7417 			}
7418 			if (kernel_policy->order >= current_session_last_non_skip_policy) {
7419 				// Skip policy is after the last useful policy, don't add
7420 				continue;
7421 			}
7422 		}
7423 
7424 		// Insert pointers into map
7425 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7426 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7427 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7428 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7429 				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])) {
7430 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7431 					bucket_current_free_index[i]++;
7432 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7433 				}
7434 			}
7435 		} else {
7436 			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7437 			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])) {
7438 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7439 				bucket_current_free_index[i]++;
7440 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7441 			}
7442 		}
7443 	}
7444 
7445 	if (bucket_current_free_index[0] == 0) {
7446 		// No non-id policies were actually added
7447 		necp_kernel_ip_output_policies_non_id_count = 0;
7448 
7449 		// Also check if no policies at all were added
7450 		bool policies_added = FALSE;
7451 		for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7452 			if (bucket_current_free_index[i] != 0) {
7453 				policies_added = TRUE;
7454 				break;
7455 			}
7456 		}
7457 		if (!policies_added) {
7458 			necp_kernel_ip_output_policies_condition_mask = 0;
7459 			necp_kernel_ip_output_policies_count = 0;
7460 		}
7461 	}
7462 
7463 	necp_kernel_ip_output_policies_dump_all();
7464 	return TRUE;
7465 
7466 fail:
7467 	// Free memory, reset mask to 0
7468 	necp_kernel_ip_output_policies_condition_mask = 0;
7469 	necp_kernel_ip_output_policies_count = 0;
7470 	necp_kernel_ip_output_policies_non_id_count = 0;
7471 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7472 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7473 			kfree_type(struct necp_kernel_ip_output_policy *,
7474 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7475 			    necp_kernel_ip_output_policies_map[i]);
7476 			necp_kernel_ip_output_policies_map[i] = NULL;
7477 		}
7478 	}
7479 	return FALSE;
7480 }
7481 
7482 // Outbound Policy Matching
7483 // ---------------------
7484 struct substring {
7485 	size_t length;
7486 	char * __sized_by(length) string;
7487 };
7488 
7489 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7490 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7491 {
7492 	struct substring sub = {};
7493 	char * __indexable ptr = string;
7494 	size_t len = string ? length : 0;
7495 
7496 	while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7497 		ptr++;
7498 		len--;
7499 	}
7500 
7501 	while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7502 		len--;
7503 	}
7504 
7505 	sub.string = ptr;
7506 	sub.length = len;
7507 	return sub;
7508 }
7509 
7510 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7511 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7512 {
7513 	size_t trimmed_domain_length = 0;
7514 	char *trimmed_domain = NULL;
7515 	struct substring sub = necp_trim_dots_and_stars(string, length);
7516 
7517 	trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7518 	trimmed_domain_length = sub.length + 1;
7519 	if (trimmed_domain == NULL) {
7520 		return NULL;
7521 	}
7522 
7523 	strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7524 	trimmed_domain[sub.length] = 0;
7525 
7526 	return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7527 }
7528 
7529 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7530 necp_count_dots(char * __sized_by(length)string, size_t length)
7531 {
7532 	int dot_count = 0;
7533 	size_t i = 0;
7534 
7535 	for (i = 0; i < length; i++) {
7536 		if (string[i] == '.') {
7537 			dot_count++;
7538 		}
7539 	}
7540 
7541 	return dot_count;
7542 }
7543 
7544 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7545 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7546 {
7547 	if (parent.length <= suffix.length) {
7548 		return FALSE;
7549 	}
7550 
7551 	size_t length_difference = (parent.length - suffix.length);
7552 
7553 	if (require_dot_before_suffix) {
7554 		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7555 			return FALSE;
7556 		}
7557 	}
7558 
7559 	// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7560 	return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7561 }
7562 
7563 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)7564 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7565 {
7566 	if (hostname_substring.string == NULL || domain == NULL) {
7567 		return hostname_substring.string == domain;
7568 	}
7569 
7570 	struct substring domain_substring;
7571 	domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7572 	domain_substring.length = strlen(domain);
7573 
7574 	if (hostname_dot_count == domain_dot_count) {
7575 		// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7576 		if (hostname_substring.length == domain_substring.length &&
7577 		    strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7578 			return TRUE;
7579 		}
7580 	} else if (domain_dot_count < hostname_dot_count) {
7581 		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7582 			return TRUE;
7583 		}
7584 	}
7585 
7586 	return FALSE;
7587 }
7588 
7589 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7590 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7591 {
7592 	if (hostname_string == NULL ||
7593 	    domain_string == NULL) {
7594 		return false;
7595 	}
7596 
7597 	struct substring hostname_substring;
7598 	hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7599 	hostname_substring.length = strlen(hostname_string);
7600 
7601 	return necp_hostname_matches_domain(hostname_substring,
7602 	           necp_count_dots(hostname_substring.string, hostname_substring.length),
7603 	           domain_string,
7604 	           necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7605 }
7606 
7607 #define NECP_MAX_STRING_LEN 1024
7608 
7609 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7610 necp_copy_string(char * __sized_by(length)string, size_t length)
7611 {
7612 	size_t copied_string_length = 0;
7613 	char * __sized_by(copied_string_length) copied_string = NULL;
7614 
7615 	if (length > NECP_MAX_STRING_LEN) {
7616 		return NULL;
7617 	}
7618 
7619 	copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7620 	copied_string_length = length + 1;
7621 	if (copied_string == NULL) {
7622 		return NULL;
7623 	}
7624 
7625 	memcpy(copied_string, string, length);
7626 	copied_string[length] = 0;
7627 
7628 	return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7629 }
7630 
7631 static u_int32_t
necp_get_primary_direct_interface_index(void)7632 necp_get_primary_direct_interface_index(void)
7633 {
7634 	u_int32_t interface_index = IFSCOPE_NONE;
7635 
7636 	ifnet_head_lock_shared();
7637 	struct ifnet *ordered_interface = NULL;
7638 	TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7639 		const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7640 		if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7641 		    functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7642 			// All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7643 			interface_index = ordered_interface->if_index;
7644 			break;
7645 		}
7646 	}
7647 	ifnet_head_done();
7648 
7649 	return interface_index;
7650 }
7651 
7652 static inline bool
necp_task_has_match_entitlement(task_t task)7653 necp_task_has_match_entitlement(task_t task)
7654 {
7655 	return task != NULL &&
7656 	       (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7657 	       IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7658 }
7659 
7660 // Loopback traffic from certain entitled process will be dropped
7661 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7662 necp_task_has_loopback_drop_entitlement(task_t task)
7663 {
7664 	bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7665 	if (drop) {
7666 		necp_drop_loopback_count++;
7667 	}
7668 	return drop;
7669 }
7670 
7671 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7672 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7673 {
7674 	coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7675 
7676 	if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7677 		// No parent, nothing to do
7678 		return;
7679 	}
7680 
7681 	task_t __single lead_task = coalition_get_leader(coal);
7682 	if (lead_task != NULL) {
7683 		info->is_entitled = necp_task_has_match_entitlement(lead_task);
7684 		task_deallocate(lead_task);
7685 	}
7686 }
7687 
7688 // Some processes, due to particular entitlements, require using an NECP client to
7689 // access networking. Returns true if the result should be a Drop.
7690 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7691 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7692 {
7693 	if (necp_is_platform_binary(proc)) {
7694 		// This check is currently for the "on-demand-install-capable"
7695 		// entitlement, which by definition cannot be a built-in platform
7696 		// binary.
7697 		return false;
7698 	}
7699 
7700 	task_t __single task = proc_task(proc ? proc : current_proc());
7701 
7702 	if (!info->has_client &&
7703 	    task != NULL &&
7704 	    IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7705 		// Drop connections that don't use NECP clients and have the
7706 		// com.apple.developer.on-demand-install-capable entitlement.
7707 		// This effectively restricts those processes to only using
7708 		// an NECP-aware path for networking.
7709 		return true;
7710 	} else {
7711 		return false;
7712 	}
7713 }
7714 
7715 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7716 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7717 {
7718 	if (!necp_restrict_multicast || proc == NULL) {
7719 		return false;
7720 	}
7721 
7722 	// Check for multicast/broadcast here
7723 	if (info->remote_addr.sa.sa_family == AF_INET) {
7724 		if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7725 		    info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7726 			return false;
7727 		}
7728 	} else if (info->remote_addr.sa.sa_family == AF_INET6) {
7729 		if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7730 			return false;
7731 		}
7732 	} else {
7733 		// Not IPv4/IPv6
7734 		return false;
7735 	}
7736 
7737 	if (necp_is_platform_binary(proc)) {
7738 		return false;
7739 	}
7740 
7741 	const uint32_t platform = proc_platform(proc);
7742 	const uint32_t sdk = proc_sdk(proc);
7743 
7744 	// Enforce for iOS, linked on or after version 14
7745 	// If the caller set `check_minor_version`, only enforce starting at 14.5
7746 	if ((platform != PLATFORM_IOS ||
7747 	    sdk == 0 ||
7748 	    (sdk >> 16) < 14 ||
7749 	    (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7750 		return false;
7751 	}
7752 
7753 	// Allow entitled processes to use multicast
7754 	task_t __single task = proc_task(proc);
7755 	if (task != NULL &&
7756 	    IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7757 		return false;
7758 	}
7759 
7760 	const uint32_t min_sdk = proc_min_sdk(proc);
7761 	NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7762 
7763 	return true;
7764 }
7765 
7766 #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)
7767 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)7768 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)
7769 {
7770 	memset(info, 0, sizeof(struct necp_socket_info));
7771 
7772 	info->pid = pid;
7773 	info->pid_version = pid_version;
7774 	info->uid = uid;
7775 	info->real_uid = real_uid;
7776 	info->protocol = protocol;
7777 	info->bound_interface_index = bound_interface_index;
7778 	info->traffic_class = traffic_class;
7779 	info->has_client = has_client;
7780 	info->has_system_signed_result = has_system_signed_result;
7781 	info->drop_order = drop_order;
7782 	info->client_flags = client_flags;
7783 	info->is_loopback = is_loopback;
7784 	info->is_delegated = is_delegated;
7785 
7786 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7787 	    info->bound_interface_index != IFSCOPE_NONE) {
7788 		ifnet_head_lock_shared();
7789 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7790 		if (interface != NULL) {
7791 			info->bound_interface_flags = interface->if_flags;
7792 			info->bound_interface_eflags = interface->if_eflags;
7793 			info->bound_interface_xflags = interface->if_xflags;
7794 		}
7795 		ifnet_head_done();
7796 	}
7797 
7798 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7799 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7800 		if (existing_mapping) {
7801 			info->application_id = existing_mapping->id;
7802 		}
7803 	}
7804 
7805 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7806 		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7807 			info->real_application_id = info->application_id;
7808 		} else {
7809 			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7810 			if (existing_mapping) {
7811 				info->real_application_id = existing_mapping->id;
7812 			}
7813 		}
7814 	}
7815 
7816 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7817 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7818 		if (existing_mapping != NULL) {
7819 			info->real_application_id = info->application_id;
7820 			info->application_id = existing_mapping->id;
7821 			info->used_responsible_pid = true;
7822 		}
7823 	}
7824 
7825 	if (info->used_responsible_pid) {
7826 		proc = responsible_proc;
7827 	}
7828 
7829 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7830 		info->is_entitled = necp_task_has_match_entitlement(task);
7831 		if (!info->is_entitled) {
7832 			// Task does not have entitlement, check the parent task
7833 			necp_get_parent_is_entitled(task, info);
7834 		}
7835 	}
7836 
7837 	if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7838 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7839 		if (necp_is_platform_binary(proc)) {
7840 			info->is_platform_binary = true;
7841 		} else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7842 			info->is_platform_binary = true;
7843 			info->used_responsible_pid = true;
7844 		} else {
7845 			info->is_platform_binary = false;
7846 		}
7847 	}
7848 
7849 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7850 		info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7851 	}
7852 
7853 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7854 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7855 		if (existing_mapping) {
7856 			info->account_id = existing_mapping->id;
7857 		}
7858 	}
7859 
7860 	if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7861 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7862 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7863 		info->domain = domain;
7864 	}
7865 
7866 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7867 		info->url = url;
7868 	}
7869 
7870 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
7871 	    necp_restrict_multicast ||
7872 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7873 		if (local_addr && local_addr->sa.sa_len > 0) {
7874 			SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7875 			if (local_port != 0) {
7876 				info->local_addr.sin6.sin6_port = local_port;
7877 			}
7878 		} else {
7879 			if (remote_addr && remote_addr->sa.sa_len > 0) {
7880 				info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7881 				info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7882 			} else {
7883 				info->local_addr.sin6.sin6_family = AF_INET6;
7884 				info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7885 			}
7886 			if (local_port != 0) {
7887 				info->local_addr.sin6.sin6_port = local_port;
7888 			}
7889 		}
7890 		if (remote_addr && remote_addr->sa.sa_len > 0) {
7891 			SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7892 			if (remote_port != 0) {
7893 				info->remote_addr.sin6.sin6_port = remote_port;
7894 			}
7895 		} else if (remote_port != 0) {
7896 			info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7897 			info->remote_addr.sin6.sin6_family = AF_INET6;
7898 			info->remote_addr.sin6.sin6_port = remote_port;
7899 		}
7900 	}
7901 
7902 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7903 		info->scheme_port = scheme_port;
7904 	}
7905 }
7906 
7907 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7908 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7909 {
7910 	struct kev_netpolicy_ifdenied ev_ifdenied;
7911 
7912 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7913 
7914 	ev_ifdenied.ev_data.epid = pid;
7915 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7916 	ev_ifdenied.ev_if_functional_type = if_functional_type;
7917 
7918 	netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7919 }
7920 
7921 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7922 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7923 {
7924 	struct kev_netpolicy_netdenied ev_netdenied = {};
7925 
7926 	bzero(&ev_netdenied, sizeof(ev_netdenied));
7927 
7928 	ev_netdenied.ev_data.epid = pid;
7929 	uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7930 	ev_netdenied.ev_network_type = network_type;
7931 
7932 	netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7933 }
7934 
7935 extern char *proc_name_address(void *p);
7936 
7937 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7938 	if (!has_checked_delegation_entitlement) { \
7939 	        has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7940 	        has_checked_delegation_entitlement = TRUE; \
7941 	} \
7942 	if (!has_delegation_entitlement) { \
7943 	        NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7944 	                                          proc_name_address(_p), proc_pid(_p), _d); \
7945 	        break; \
7946 	}
7947 
7948 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)7949 necp_application_find_policy_match_internal(proc_t proc,
7950     u_int8_t * __sized_by(parameters_size)parameters,
7951     u_int32_t parameters_size,
7952     struct necp_aggregate_result *returned_result,
7953     u_int32_t *flags,
7954     u_int32_t *reason,
7955     u_int required_interface_index,
7956     const union necp_sockaddr_union *override_local_addr,
7957     const union necp_sockaddr_union *override_remote_addr,
7958     struct necp_client_endpoint *returned_v4_gateway,
7959     struct necp_client_endpoint *returned_v6_gateway,
7960     struct rtentry **returned_route, bool ignore_address,
7961     bool has_client,
7962     uuid_t *returned_override_euuid)
7963 {
7964 	int error = 0;
7965 	size_t offset = 0;
7966 
7967 	struct necp_kernel_socket_policy *matched_policy = NULL;
7968 	struct necp_socket_info info = {};
7969 	necp_kernel_policy_filter filter_control_unit = 0;
7970 
7971 	u_int64_t extended_client_flags = 0;
7972 	u_int16_t protocol = 0;
7973 	u_int32_t bound_interface_index = required_interface_index;
7974 	u_int32_t traffic_class = 0;
7975 	u_int32_t client_flags = 0;
7976 	u_int16_t scheme_port = 0;
7977 	union necp_sockaddr_union local_addr;
7978 	union necp_sockaddr_union remote_addr;
7979 	bool no_remote_addr = FALSE;
7980 	u_int8_t remote_family = 0;
7981 	bool no_local_addr = FALSE;
7982 	u_int16_t local_port = 0;
7983 	u_int16_t remote_port = 0;
7984 	u_int32_t remote_endpoint_type = 0;
7985 	bool remote_address_is_empty = false;
7986 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7987 	bool is_delegated = false;
7988 
7989 	if (override_local_addr) {
7990 		memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7991 	} else {
7992 		memset(&local_addr, 0, sizeof(local_addr));
7993 	}
7994 	if (override_remote_addr) {
7995 		memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7996 	} else {
7997 		memset(&remote_addr, 0, sizeof(remote_addr));
7998 	}
7999 
8000 	// Initialize UID, PID, and UUIDs to the current process
8001 	uid_t uid = 0;
8002 	uid_t real_uid = 0;
8003 	kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
8004 	if (cred != NULL) {
8005 		uid = kauth_cred_getuid(cred);
8006 		real_uid = uid;
8007 	}
8008 	task_t __single task = proc_task(proc);
8009 	pid_t pid = proc_pid(proc);
8010 	int32_t pid_version = proc_pidversion(proc);
8011 	uuid_t application_uuid;
8012 	uuid_clear(application_uuid);
8013 	uuid_t real_application_uuid;
8014 	uuid_clear(real_application_uuid);
8015 	proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
8016 	uuid_copy(application_uuid, real_application_uuid);
8017 	uuid_t responsible_application_uuid;
8018 	uuid_clear(responsible_application_uuid);
8019 
8020 	char *domain __null_terminated = NULL;
8021 	char *url __null_terminated = NULL;
8022 	char *account __null_terminated = NULL;
8023 
8024 #define NECP_MAX_REQUIRED_AGENTS 16
8025 	u_int32_t num_required_agent_types = 0;
8026 	struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
8027 	memset(&required_agent_types, 0, sizeof(required_agent_types));
8028 
8029 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
8030 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
8031 	memset(&netagent_ids, 0, sizeof(netagent_ids));
8032 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
8033 	int netagent_cursor;
8034 
8035 	bool has_checked_delegation_entitlement = false;
8036 	bool has_delegation_entitlement = false;
8037 	bool has_system_signed_result = false;
8038 
8039 	proc_t responsible_proc = PROC_NULL;
8040 	proc_t effective_proc = proc;
8041 	bool release_eproc = false;
8042 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
8043 
8044 	u_int32_t flow_divert_aggregate_unit = 0;
8045 
8046 	if (returned_result == NULL) {
8047 		if (cred != NULL) {
8048 			kauth_cred_unref(&cred);
8049 		}
8050 		return EINVAL;
8051 	}
8052 
8053 	if (returned_v4_gateway != NULL) {
8054 		memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
8055 	}
8056 
8057 	if (returned_v6_gateway != NULL) {
8058 		memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
8059 	}
8060 
8061 	if (returned_override_euuid != NULL) {
8062 		uuid_clear(*returned_override_euuid);
8063 	}
8064 
8065 	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
8066 
8067 	u_int32_t drop_order = necp_process_drop_order(cred);
8068 
8069 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
8070 
8071 	lck_rw_lock_shared(&necp_kernel_policy_lock);
8072 	if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
8073 		if (necp_drop_all_order > 0 || drop_order > 0) {
8074 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8075 			lck_rw_done(&necp_kernel_policy_lock);
8076 			if (cred != NULL) {
8077 				kauth_cred_unref(&cred);
8078 			}
8079 			return 0;
8080 		}
8081 	}
8082 	lck_rw_done(&necp_kernel_policy_lock);
8083 
8084 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8085 		u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8086 		u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8087 
8088 		if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8089 			// If the length is larger than what can fit in the remaining parameters size, bail
8090 			NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8091 			break;
8092 		}
8093 
8094 		if (length > 0) {
8095 			u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8096 			if (value != NULL) {
8097 				switch (type) {
8098 				case NECP_CLIENT_PARAMETER_APPLICATION: {
8099 					if (length >= sizeof(uuid_t)) {
8100 						if (uuid_compare(application_uuid, value) == 0) {
8101 							// No delegation
8102 							break;
8103 						}
8104 
8105 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8106 
8107 						is_delegated = true;
8108 						uuid_copy(application_uuid, value);
8109 					}
8110 					break;
8111 				}
8112 				case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8113 					if (length >= sizeof(uuid_t)) {
8114 						if (uuid_compare(real_application_uuid, value) == 0) {
8115 							// No delegation
8116 							break;
8117 						}
8118 
8119 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8120 
8121 						is_delegated = true;
8122 						uuid_copy(real_application_uuid, value);
8123 					}
8124 					break;
8125 				}
8126 				case NECP_CLIENT_PARAMETER_PID: {
8127 					if (length >= sizeof(pid_t)) {
8128 						if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8129 							// No delegation
8130 							break;
8131 						}
8132 
8133 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8134 
8135 						is_delegated = true;
8136 						memcpy(&pid, value, sizeof(pid_t));
8137 					}
8138 					break;
8139 				}
8140 				case NECP_CLIENT_PARAMETER_UID: {
8141 					if (length >= sizeof(uid_t)) {
8142 						if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8143 							// No delegation
8144 							break;
8145 						}
8146 
8147 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8148 
8149 						is_delegated = true;
8150 						memcpy(&uid, value, sizeof(uid_t));
8151 					}
8152 					break;
8153 				}
8154 				case NECP_CLIENT_PARAMETER_DOMAIN: {
8155 					char *ptr = (char *)value;
8156 					ptr[length - 1] = 0;
8157 					domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8158 					break;
8159 				}
8160 				case NECP_CLIENT_PARAMETER_URL: {
8161 					char *ptr = (char *)value;
8162 					ptr[length - 1] = 0;
8163 					url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8164 					break;
8165 				}
8166 				case NECP_CLIENT_PARAMETER_ACCOUNT: {
8167 					char *ptr = (char *)value;
8168 					ptr[length - 1] = 0;
8169 					account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8170 					break;
8171 				}
8172 				case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8173 					if (length >= sizeof(u_int32_t)) {
8174 						memcpy(&traffic_class, value, sizeof(u_int32_t));
8175 					}
8176 					break;
8177 				}
8178 				case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8179 					if (length >= sizeof(u_int16_t)) {
8180 						memcpy(&protocol, value, sizeof(u_int16_t));
8181 					} else if (length >= sizeof(u_int8_t)) {
8182 						memcpy(&protocol, value, sizeof(u_int8_t));
8183 					}
8184 					break;
8185 				}
8186 				case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8187 					if (length <= IFXNAMSIZ && length > 0) {
8188 						ifnet_t __single bound_interface = NULL;
8189 						char interface_name[IFXNAMSIZ];
8190 						memcpy(interface_name, value, length);
8191 						interface_name[length - 1] = 0;         // Make sure the string is NULL terminated
8192 						if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8193 							bound_interface_index = bound_interface->if_index;
8194 							ifnet_release(bound_interface);
8195 						}
8196 					}
8197 					break;
8198 				}
8199 				case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8200 					if (ignore_address || override_local_addr) {
8201 						break;
8202 					}
8203 
8204 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8205 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8206 						if (necp_address_is_valid(&address_struct->address.sa)) {
8207 							memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8208 						}
8209 					}
8210 					break;
8211 				}
8212 				case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8213 					if (ignore_address || override_remote_addr) {
8214 						break;
8215 					}
8216 
8217 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8218 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8219 						if (necp_address_is_valid(&address_struct->address.sa)) {
8220 							memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8221 						}
8222 					}
8223 					break;
8224 				}
8225 				case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8226 					if (ignore_address || override_local_addr) {
8227 						break;
8228 					}
8229 
8230 					if (length >= sizeof(struct necp_client_endpoint)) {
8231 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8232 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8233 						    endpoint->u.endpoint.endpoint_port != 0) {
8234 							// Save port
8235 							local_port = endpoint->u.endpoint.endpoint_port;
8236 						}
8237 					}
8238 					break;
8239 				}
8240 				case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8241 					if (ignore_address || override_remote_addr) {
8242 						break;
8243 					}
8244 
8245 					if (length >= sizeof(struct necp_client_endpoint)) {
8246 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8247 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8248 							remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8249 							if (endpoint->u.endpoint.endpoint_port != 0) {
8250 								// Save port
8251 								remote_port = endpoint->u.endpoint.endpoint_port;
8252 							}
8253 						} else if (necp_addr_is_empty(&endpoint->u.sa)) {
8254 							remote_address_is_empty = true;
8255 						}
8256 					}
8257 					break;
8258 				}
8259 				case NECP_CLIENT_PARAMETER_FLAGS: {
8260 					if (length >= sizeof(client_flags)) {
8261 						memcpy(&client_flags, value, sizeof(client_flags));
8262 					}
8263 					break;
8264 				}
8265 				case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8266 				case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8267 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8268 						break;
8269 					}
8270 					if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8271 						memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8272 						num_required_agent_types++;
8273 					}
8274 					break;
8275 				}
8276 				case NECP_CLIENT_PARAMETER_PREFER_AGENT: {
8277 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8278 						break;
8279 					}
8280 					if (length >= sizeof(uuid_t)) {
8281 						if (netagent_get_agent_domain_and_type(value,
8282 						    required_agent_types[num_required_agent_types].netagent_domain,
8283 						    required_agent_types[num_required_agent_types].netagent_type)) {
8284 							num_required_agent_types++;
8285 						}
8286 					}
8287 					break;
8288 				}
8289 				case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8290 					if (length >= sizeof(scheme_port)) {
8291 						memcpy(&scheme_port, value, sizeof(scheme_port));
8292 					}
8293 					break;
8294 				}
8295 				case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8296 					has_system_signed_result = true;
8297 					struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8298 					if (length >= sizeof(struct necp_client_validatable)) {
8299 						// Check for system-signed sign_type values
8300 						if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8301 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8302 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8303 							has_system_signed_result = true;
8304 						}
8305 					}
8306 					break;
8307 				}
8308 				case NECP_CLIENT_PARAMETER_EXTENDED_FLAGS: {
8309 					if (length >= sizeof(extended_client_flags)) {
8310 						memcpy(&extended_client_flags, value, sizeof(extended_client_flags));
8311 					}
8312 					break;
8313 				}
8314 				default: {
8315 					break;
8316 				}
8317 				}
8318 			}
8319 		}
8320 
8321 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8322 	}
8323 
8324 	// Check for loopback exception
8325 	if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8326 		if (necp_task_has_loopback_drop_entitlement(task)) {
8327 			// Disallow certain entitled processes to send loopback traffic
8328 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8329 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8330 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8331 			if (cred != NULL) {
8332 				kauth_cred_unref(&cred);
8333 			}
8334 			return 0;
8335 		}
8336 		if (necp_pass_loopback > 0) {
8337 			bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8338 		}
8339 	} else if (bound_interface_index != IFSCOPE_NONE) {
8340 		// Check for inter-process exception
8341 		struct sockaddr *dst = SA(&remote_addr.sa);
8342 		if (dst->sa_family == AF_INET6) {
8343 			struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8344 			if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8345 				ifnet_head_lock_shared();
8346 				ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8347 				if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8348 					bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8349 				}
8350 				ifnet_head_done();
8351 			}
8352 		}
8353 	}
8354 
8355 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8356 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8357 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8358 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8359 		if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8360 			returned_result->routed_interface_index = lo_ifp->if_index;
8361 			*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8362 		} else {
8363 			returned_result->routed_interface_index = bound_interface_index;
8364 		}
8365 		if (cred != NULL) {
8366 			kauth_cred_unref(&cred);
8367 		}
8368 		return 0;
8369 	}
8370 
8371 	if (drop_order != 0) {
8372 		if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8373 		    client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8374 		    ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8375 			// Allow listeners, inbound connections without remote addresses, and
8376 			// application service connections to bypass the unentitled drop order,
8377 			// to allow them to connect to application services (not directly over
8378 			// physical networking interfaces)
8379 			drop_order = 0;
8380 		}
8381 	}
8382 
8383 	if (proc_pid(effective_proc) != pid) {
8384 		proc_t found_proc = proc_find(pid);
8385 		if (found_proc != PROC_NULL) {
8386 			effective_proc = found_proc;
8387 			pid_version = proc_pidversion(effective_proc);
8388 			release_eproc = true;
8389 		}
8390 	}
8391 #if defined(XNU_TARGET_OS_OSX)
8392 	if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8393 		proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8394 		responsible_proc = proc_find(effective_proc->p_responsible_pid);
8395 	}
8396 #endif /* defined(XNU_TARGET_OS_OSX) */
8397 
8398 	// Lock
8399 	lck_rw_lock_shared(&necp_kernel_policy_lock);
8400 
8401 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8402 	size_t route_rule_id_array_count = 0;
8403 	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);
8404 
8405 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8406 	NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8407 
8408 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8409 	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8410 	    &info,
8411 	    &filter_control_unit,
8412 	    route_rule_id_array,
8413 	    &route_rule_id_array_count,
8414 	    MAX_AGGREGATE_ROUTE_RULES,
8415 	    netagent_ids,
8416 	    NECP_MAX_NETAGENTS,
8417 	    netagent_use_flags,
8418 	    NECP_MAX_NETAGENTS,
8419 	    required_agent_types,
8420 	    num_required_agent_types,
8421 	    info.used_responsible_pid ? responsible_proc : effective_proc,
8422 	    0,
8423 	    &skip_policy_id,
8424 	    NULL,
8425 	    &drop_dest_policy_result,
8426 	    &drop_all_bypass,
8427 	    &flow_divert_aggregate_unit,
8428 	    NULL,
8429 	    debug);
8430 
8431 	// Check for loopback exception again after the policy match
8432 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8433 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8434 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8435 		if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8436 			returned_result->filter_control_unit = 0;
8437 		} else {
8438 			returned_result->filter_control_unit = filter_control_unit;
8439 		}
8440 
8441 		if (flow_divert_aggregate_unit > 0) {
8442 			returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8443 		}
8444 
8445 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8446 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8447 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8448 		returned_result->routed_interface_index = lo_ifp->if_index;
8449 		*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8450 		error = 0;
8451 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8452 		goto done;
8453 	}
8454 
8455 	if (matched_policy) {
8456 		returned_result->policy_id = matched_policy->id;
8457 		returned_result->skip_policy_id = skip_policy_id;
8458 		returned_result->routing_result = matched_policy->result;
8459 		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8460 		if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8461 			uuid_copy(*returned_override_euuid, responsible_application_uuid);
8462 		}
8463 	} else {
8464 		bool drop_all = false;
8465 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8466 			// Mark socket as a drop if drop_all is set
8467 			drop_all = true;
8468 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8469 				drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8470 			}
8471 		}
8472 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8473 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8474 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8475 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8476 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8477 		} else {
8478 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8479 			returned_result->skip_policy_id = skip_policy_id;
8480 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8481 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8482 		}
8483 	}
8484 	if (necp_check_missing_client_drop(proc, &info) ||
8485 	    necp_check_restricted_multicast_drop(proc, &info, false)) {
8486 		// Mark as drop
8487 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8488 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8489 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8490 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8491 	}
8492 	if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8493 		returned_result->filter_control_unit = 0;
8494 	} else {
8495 		returned_result->filter_control_unit = filter_control_unit;
8496 	}
8497 
8498 	if (flow_divert_aggregate_unit > 0) {
8499 		returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8500 	}
8501 
8502 	// Handle netagents
8503 	size_t netagent_i = 0;
8504 	size_t removed_netagent_type_i = 0;
8505 	for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8506 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
8507 		if (netagent_id == 0) {
8508 			continue;
8509 		}
8510 
8511 		if (necp_agent_id_is_uuid(netagent_id)) {
8512 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
8513 			if (mapping != NULL) {
8514 				uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8515 				returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8516 				netagent_i++;
8517 			}
8518 		} else {
8519 			struct necp_agent_type_id_mapping *mapping = necp_lookup_agent_type_with_id_locked(netagent_id);
8520 			if (mapping != NULL && removed_netagent_type_i < NECP_MAX_REMOVE_NETAGENT_TYPES &&
8521 			    netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8522 				memcpy(&returned_result->remove_netagent_types[removed_netagent_type_i], &mapping->agent_type, sizeof(mapping->agent_type));
8523 				removed_netagent_type_i++;
8524 			}
8525 		}
8526 
8527 		// If the flags say to remove, clear the local copy
8528 		if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8529 			netagent_ids[netagent_cursor] = 0;
8530 		}
8531 	}
8532 
8533 	// Do routing evaluation
8534 	u_int output_bound_interface = bound_interface_index;
8535 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8536 		output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8537 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8538 		output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8539 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8540 		output_bound_interface = necp_get_primary_direct_interface_index();
8541 		if (output_bound_interface == IFSCOPE_NONE) {
8542 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8543 		} else {
8544 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8545 			returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8546 		}
8547 	}
8548 
8549 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8550 	    returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8551 		if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8552 			// Trigger the event that we dropped due to a local network policy
8553 #if defined(XNU_TARGET_OS_OSX)
8554 			bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8555 			necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8556 			    should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8557 			    NETPOLICY_NETWORKTYPE_LOCAL);
8558 #else
8559 			necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8560 #endif
8561 		}
8562 		if (reason != NULL) {
8563 			*reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8564 		}
8565 	}
8566 
8567 	if (local_addr.sa.sa_len == 0 ||
8568 	    (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8569 	    (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8570 		no_local_addr = TRUE;
8571 	}
8572 
8573 	if (remote_addr.sa.sa_len == 0 ||
8574 	    (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8575 	    (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8576 		no_remote_addr = TRUE;
8577 		remote_family = remote_addr.sa.sa_family;
8578 	}
8579 
8580 	returned_result->routed_interface_index = 0;
8581 	struct rtentry *rt = NULL;
8582 	if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8583 		// Treat the output bound interface as the routed interface for local address
8584 		// validation later.
8585 		returned_result->routed_interface_index = output_bound_interface;
8586 	} else {
8587 		if (no_remote_addr) {
8588 			memset(&remote_addr, 0, sizeof(remote_addr));
8589 			if (remote_family == AF_INET6) {
8590 				// Reset address to ::
8591 				remote_addr.sa.sa_family = AF_INET6;
8592 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8593 			} else {
8594 				// Reset address to 0.0.0.0
8595 				remote_addr.sa.sa_family = AF_INET;
8596 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8597 			}
8598 		}
8599 
8600 		rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8601 		    output_bound_interface);
8602 
8603 		if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8604 		    IS_INTF_CLAT46(rt->rt_ifp)) {
8605 			rtfree(rt);
8606 			rt = NULL;
8607 			returned_result->routed_interface_index = 0;
8608 		}
8609 
8610 		if (no_remote_addr && remote_family == AF_UNSPEC &&
8611 		    (rt == NULL || rt->rt_ifp == NULL)) {
8612 			// Route lookup for default IPv4 failed, try IPv6
8613 
8614 			// Cleanup old route if necessary
8615 			if (rt != NULL) {
8616 				rtfree(rt);
8617 				rt = NULL;
8618 			}
8619 
8620 			// Reset address to ::
8621 			memset(&remote_addr, 0, sizeof(remote_addr));
8622 			remote_addr.sa.sa_family = AF_INET6;
8623 			remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8624 
8625 			// Get route
8626 			rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8627 			    output_bound_interface);
8628 		}
8629 
8630 		if (rt != NULL &&
8631 		    rt->rt_ifp != NULL) {
8632 			returned_result->routed_interface_index = rt->rt_ifp->if_index;
8633 			/*
8634 			 * For local addresses, we allow the interface scope to be
8635 			 * either the loopback interface or the interface hosting the
8636 			 * local address.
8637 			 */
8638 			if (bound_interface_index != IFSCOPE_NONE &&
8639 			    rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8640 			    (output_bound_interface == lo_ifp->if_index ||
8641 			    rt->rt_ifp->if_index == lo_ifp->if_index ||
8642 			    rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8643 				struct sockaddr_storage dst;
8644 				unsigned int ifscope = bound_interface_index;
8645 
8646 				/*
8647 				 * Transform dst into the internal routing table form
8648 				 */
8649 				(void) sa_copy(SA(&remote_addr),
8650 				    &dst, &ifscope);
8651 
8652 				if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8653 				    rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8654 					returned_result->routed_interface_index =
8655 					    bound_interface_index;
8656 				}
8657 			}
8658 		}
8659 	}
8660 
8661 	if (returned_result->routed_interface_index != 0 &&
8662 	    returned_result->routed_interface_index != lo_ifp->if_index &&     // Loopback can accept any local address
8663 	    !no_local_addr) {
8664 		// Transform local_addr into the ifaddr form
8665 		// IPv6 Scope IDs are always embedded in the ifaddr list
8666 		struct sockaddr_storage local_address_sanitized;
8667 		u_int ifscope = IFSCOPE_NONE;
8668 		(void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8669 		SIN(&local_address_sanitized)->sin_port = 0;
8670 		if (local_address_sanitized.ss_family == AF_INET6) {
8671 			if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8672 				SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8673 			}
8674 		}
8675 
8676 		// Validate local address on routed interface
8677 		struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8678 		if (ifa == NULL) {
8679 			// Interface address not found, reject route
8680 			returned_result->routed_interface_index = 0;
8681 			if (rt != NULL) {
8682 				rtfree(rt);
8683 				rt = NULL;
8684 			}
8685 		} else {
8686 			ifaddr_release(ifa);
8687 			ifa = NULL;
8688 		}
8689 	}
8690 
8691 	if (flags != NULL) {
8692 #if SKYWALK
8693 		if (kernel_is_macos_or_server()) {
8694 			enum net_filter_event_subsystems filters = net_filter_event_get_state();
8695 
8696 			if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8697 				*flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8698 			}
8699 			if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8700 				*flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8701 			}
8702 			if (filters & NET_FILTER_EVENT_ALF) {
8703 				*flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8704 			}
8705 			if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8706 				*flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8707 			}
8708 		}
8709 #endif /* SKYWALK */
8710 		if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8711 			// Check for local/direct
8712 			bool is_local = FALSE;
8713 			if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8714 				is_local = TRUE;
8715 			} else if (returned_result->routed_interface_index != 0 &&
8716 			    !no_remote_addr) {
8717 				// Clean up the address before comparison with interface addresses
8718 
8719 				// Transform remote_addr into the ifaddr form
8720 				// IPv6 Scope IDs are always embedded in the ifaddr list
8721 				struct sockaddr_storage remote_address_sanitized;
8722 				u_int ifscope = IFSCOPE_NONE;
8723 				(void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8724 				SIN(&remote_address_sanitized)->sin_port = 0;
8725 				if (remote_address_sanitized.ss_family == AF_INET6) {
8726 					if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8727 						SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8728 					}
8729 				}
8730 
8731 				// Check if remote address is an interface address
8732 				struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8733 				if (ifa != NULL && ifa->ifa_ifp != NULL) {
8734 					u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8735 					if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8736 					    if_index_for_remote_addr == lo_ifp->if_index) {
8737 						is_local = TRUE;
8738 					}
8739 				}
8740 				if (ifa != NULL) {
8741 					ifaddr_release(ifa);
8742 					ifa = NULL;
8743 				}
8744 			}
8745 
8746 			if (is_local) {
8747 				*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8748 			} else if (rt != NULL) {
8749 				if (rt->rt_flags & RTF_GLOBAL) {
8750 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8751 				} else if (!(rt->rt_flags & RTF_GATEWAY) &&
8752 				    (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8753 					// Route is directly accessible
8754 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8755 				}
8756 			}
8757 
8758 			if (rt != NULL &&
8759 			    rt->rt_ifp != NULL) {
8760 				// Check probe status
8761 				if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8762 					*flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8763 				}
8764 
8765 				if (if_link_heuristics_enabled(rt->rt_ifp)) {
8766 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_HEURISTICS;
8767 				}
8768 
8769 				if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8770 					struct if_cellular_status_v1 *ifsr;
8771 
8772 					ifnet_lock_shared(rt->rt_ifp);
8773 					lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8774 
8775 					if (rt->rt_ifp->if_link_status != NULL) {
8776 						ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8777 
8778 						if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8779 							if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8780 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8781 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8782 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8783 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8784 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8785 							}
8786 						}
8787 					}
8788 					lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8789 					ifnet_lock_done(rt->rt_ifp);
8790 				}
8791 
8792 				// Check link quality
8793 				if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8794 				    (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8795 				    rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8796 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8797 				}
8798 
8799 				// Check QoS marking (fastlane)
8800 				for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8801 					if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8802 						*flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8803 						// If the route can use QoS markings, stop iterating route rules
8804 						break;
8805 					}
8806 				}
8807 
8808 				if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8809 					*flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8810 				}
8811 
8812 				if (traffic_class == SO_TC_BK_SYS) {
8813 					// Block BK_SYS traffic if interface is throttled
8814 					u_int32_t throttle_level = 0;
8815 					if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8816 						if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8817 							returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8818 							memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8819 						}
8820 					}
8821 				}
8822 			}
8823 		}
8824 
8825 		u_int interface_to_check = returned_result->routed_interface_index;
8826 		if (interface_to_check == 0) {
8827 			interface_to_check = output_bound_interface;
8828 		}
8829 		union necp_sockaddr_union default_address;
8830 		struct rtentry *v4Route = NULL;
8831 		struct rtentry *v6Route = NULL;
8832 
8833 		memset(&default_address, 0, sizeof(default_address));
8834 
8835 		// Reset address to 0.0.0.0
8836 		default_address.sa.sa_family = AF_INET;
8837 		default_address.sa.sa_len = sizeof(struct sockaddr_in);
8838 		v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8839 		    returned_result->routed_interface_index);
8840 
8841 		// Reset address to ::
8842 		default_address.sa.sa_family = AF_INET6;
8843 		default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8844 		v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8845 		    returned_result->routed_interface_index);
8846 
8847 		if (v4Route != NULL) {
8848 			if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8849 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8850 			}
8851 			if (returned_v4_gateway != NULL &&
8852 			    v4Route->rt_gateway != NULL &&
8853 			    v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8854 				memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8855 				memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8856 			}
8857 			rtfree(v4Route);
8858 			v4Route = NULL;
8859 		}
8860 
8861 		if (v6Route != NULL) {
8862 			if (v6Route->rt_ifp != NULL) {
8863 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8864 
8865 				if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8866 					*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8867 				}
8868 			}
8869 			if (returned_v6_gateway != NULL &&
8870 			    v6Route->rt_gateway != NULL &&
8871 			    v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8872 				SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8873 			}
8874 			rtfree(v6Route);
8875 			v6Route = NULL;
8876 		}
8877 	}
8878 
8879 	// Take two passes through the rule list: first for rules that don't match based on agents,
8880 	// second for rules that match based on agents. Since rules can modify the agent list itself,
8881 	// this makes the logic more deterministic. This allows a non-agent matching rule to remove
8882 	// an agent before it is used for matching later.
8883 	size_t route_rule_index = 0;
8884 	bool second_pass = false;
8885 	while (route_rule_index < route_rule_id_array_count) {
8886 		bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8887 		if (rule_matches_agents != second_pass) {
8888 			// Process rules that match based on agents only in the second pass
8889 			route_rule_index++;
8890 			if (route_rule_index == route_rule_id_array_count && !second_pass) {
8891 				route_rule_index = 0;
8892 				second_pass = true;
8893 			}
8894 			continue;
8895 		}
8896 
8897 		u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8898 		bool ultra_constrained_denied = false;
8899 		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);
8900 		if (!route_is_allowed) {
8901 			// If the route is blocked, treat the lookup as a drop
8902 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8903 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8904 
8905 			if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8906 				if (reason != NULL) {
8907 					if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8908 						*reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8909 					} else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8910 						*reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8911 					}
8912 				}
8913 				necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8914 			} else if (ultra_constrained_denied) {
8915 				if (reason != NULL) {
8916 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8917 				}
8918 				necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
8919 			}
8920 
8921 			// If the route gets denied, stop matching rules
8922 			break;
8923 		}
8924 
8925 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8926 		if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8927 			u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8928 			    route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8929 			if (flow_divert_control_unit != 0) {
8930 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8931 				returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8932 			}
8933 			if (flow_divert_aggregate_unit != 0) {
8934 				returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8935 			}
8936 		}
8937 
8938 		// Check if there is a route rule that adds or removes an agent
8939 		bool remove = false;
8940 		u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8941 		if (netagent_id != 0) {
8942 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
8943 			if (mapping != NULL) {
8944 				bool agent_already_present = false;
8945 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8946 					if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8947 						// Found the agent already present
8948 						agent_already_present = true;
8949 						if (remove) {
8950 							// Mark as remove if necessary
8951 							returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8952 						}
8953 					} else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8954 						// Found open slot
8955 						if (!agent_already_present) {
8956 							uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8957 							if (remove) {
8958 								returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8959 							} else {
8960 								returned_result->netagent_use_flags[netagent_cursor] = 0;
8961 							}
8962 						}
8963 						break;
8964 					}
8965 				}
8966 			}
8967 
8968 			// Update the local netagent_ids array for future evaluations
8969 			if (remove) {
8970 				// Check if the agent ID is in the array, and remove it
8971 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8972 					if (netagent_id == netagent_ids[netagent_cursor]) {
8973 						netagent_ids[netagent_cursor] = 0;
8974 					}
8975 				}
8976 			} else {
8977 				// Check if the agent ID is not yet in the array, and add it
8978 				bool found = false;
8979 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8980 					if (netagent_id == netagent_ids[netagent_cursor]) {
8981 						found = true;
8982 						break;
8983 					}
8984 				}
8985 				if (!found) {
8986 					for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8987 						if (netagent_ids[netagent_cursor] == 0) {
8988 							// Empty slot, add the agent
8989 							netagent_ids[netagent_cursor] = netagent_id;
8990 							break;
8991 						}
8992 					}
8993 				}
8994 			}
8995 		}
8996 
8997 		route_rule_index++;
8998 		if (route_rule_index == route_rule_id_array_count && !second_pass) {
8999 			route_rule_index = 0;
9000 			second_pass = true;
9001 		}
9002 	}
9003 
9004 	if (rt != NULL && rt->rt_ifp != NULL) {
9005 		const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
9006 		const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
9007 		const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
9008 		    IFNET_IS_EXPENSIVE(rt->rt_ifp));
9009 		const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
9010 		    IFNET_IS_CONSTRAINED(rt->rt_ifp));
9011 		const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
9012 		    IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
9013 		    (!if_ultra_constrained_default_allowed && !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT))));
9014 
9015 		const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
9016 		if (!is_listener && !is_browser) {
9017 			if (reason != NULL) {
9018 				if (expensive_prohibited) {
9019 					*reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
9020 				} else if (constrained_prohibited) {
9021 					*reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
9022 				} else if (ultra_constrained_not_allowed) {
9023 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
9024 					necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_ULTRA_CONSTRAINED);
9025 				}
9026 			}
9027 			if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
9028 				// If a property of the interface was not allowed, treat it as a drop
9029 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
9030 				memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
9031 			}
9032 		}
9033 
9034 		if ((extended_client_flags & NECP_CLIENT_PARAMETER_EXTENDED_FLAG_AOP2_OFFLOAD) &&
9035 		    ((rt->rt_ifp->if_xflags & IFXF_RX_FLOW_STEERING) == 0)) {
9036 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
9037 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
9038 		}
9039 	}
9040 
9041 	if (rt != NULL) {
9042 		if (returned_route != NULL) {
9043 			*returned_route = rt;
9044 		} else {
9045 			rtfree(rt);
9046 		}
9047 		rt = NULL;
9048 	}
9049 
9050 done:
9051 	// Unlock
9052 	lck_rw_done(&necp_kernel_policy_lock);
9053 
9054 	if (release_eproc && effective_proc != PROC_NULL) {
9055 		proc_rele(effective_proc);
9056 	}
9057 #if defined(XNU_TARGET_OS_OSX)
9058 	if (responsible_proc != PROC_NULL) {
9059 		proc_rele(responsible_proc);
9060 	}
9061 #endif
9062 
9063 	if (cred != NULL) {
9064 		kauth_cred_unref(&cred);
9065 	}
9066 
9067 	return error;
9068 }
9069 
9070 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)9071 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
9072 {
9073 	struct rtentry *rt = NULL;
9074 	bool is_local = FALSE;
9075 
9076 	if (remote_addr == NULL) {
9077 		return NULL;
9078 	}
9079 
9080 	if (remote_addr->sa.sa_len == 0 ||
9081 	    (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
9082 	    (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
9083 		return FALSE;
9084 	}
9085 
9086 	// Lookup route regardless of the scoped interface to check if
9087 	// remote address is in a local network.
9088 	rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
9089 
9090 	if (rt == NULL) {
9091 		goto done;
9092 	}
9093 	if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
9094 		goto free_rt;
9095 	}
9096 	is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
9097 
9098 free_rt:
9099 	rtfree(rt);
9100 
9101 done:
9102 	return is_local;
9103 }
9104 
9105 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)9106 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9107     necp_app_id app_id,
9108     necp_app_id real_app_id,
9109     uint8_t is_entitled,
9110     u_int32_t account_id,
9111     struct substring domain,
9112     u_int8_t domain_dot_count,
9113     const char *url __null_terminated,
9114     pid_t pid,
9115     int32_t pid_version,
9116     uid_t uid,
9117     uid_t real_uid,
9118     u_int32_t bound_interface_index,
9119     u_int32_t traffic_class,
9120     u_int16_t protocol,
9121     union necp_sockaddr_union *local,
9122     union necp_sockaddr_union *remote,
9123     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9124     u_int32_t num_required_agent_types,
9125     bool has_client,
9126     uint32_t client_flags,
9127     int is_platform_binary,
9128     bool has_signed_result,
9129     proc_t proc,
9130     u_int16_t pf_tag,
9131     u_int16_t scheme_port,
9132     struct rtentry *rt,
9133     bool is_loopback,
9134     int debug,
9135     bool real_is_platform_binary,
9136     u_int32_t bound_interface_flags,
9137     u_int32_t bound_interface_eflags,
9138     u_int32_t bound_interface_xflags,
9139     struct necp_socket_info *info,
9140     bool is_delegated,
9141     struct socket *socket)
9142 {
9143 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9144 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9145 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9146 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9147 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9148 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9149 				if (bound_interface_index == cond_bound_interface_index) {
9150 					// No match, matches forbidden interface
9151 					return FALSE;
9152 				}
9153 			} else {
9154 				if (bound_interface_index != cond_bound_interface_index) {
9155 					// No match, does not match required interface
9156 					return FALSE;
9157 				}
9158 			}
9159 		}
9160 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9161 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9162 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9163 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9164 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9165 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9166 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9167 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9168 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9169 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9170 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9171 					// No match, matches some forbidden interface flags
9172 					return FALSE;
9173 				}
9174 			} else {
9175 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9176 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9177 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9178 					// No match, does not match some required interface xflags
9179 					return FALSE;
9180 				}
9181 			}
9182 		}
9183 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9184 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9185 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9186 			if (bound_interface_index != 0) {
9187 				// No match, requires a non-bound packet
9188 				return FALSE;
9189 			}
9190 		}
9191 	}
9192 
9193 	if (kernel_policy->condition_mask == 0) {
9194 		return TRUE;
9195 	}
9196 
9197 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9198 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9199 		    "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9200 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9201 			if (app_id == kernel_policy->cond_app_id) {
9202 				// No match, matches forbidden application
9203 				return FALSE;
9204 			}
9205 		} else {
9206 			if (app_id != kernel_policy->cond_app_id) {
9207 				// No match, does not match required application
9208 				return FALSE;
9209 			}
9210 		}
9211 
9212 		// Check signing identifier only after APP ID matched
9213 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9214 		    kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9215 			u_int8_t matched = necp_boolean_state_false;
9216 			const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9217 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9218 			    "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9219 			    kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9220 			    signing_id ? signing_id : "<n/a>");
9221 			if (signing_id != NULL) {
9222 				if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9223 					matched = necp_boolean_state_true;
9224 				}
9225 			}
9226 
9227 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9228 				if (matched == necp_boolean_state_true) {
9229 					return FALSE;
9230 				}
9231 			} else {
9232 				if (matched != necp_boolean_state_true) {
9233 					return FALSE;
9234 				}
9235 			}
9236 		}
9237 	}
9238 
9239 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9240 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9241 		    "NECP_KERNEL_CONDITION_REAL_APP_ID",
9242 		    kernel_policy->cond_real_app_id, real_app_id);
9243 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9244 			if (real_app_id == kernel_policy->cond_real_app_id) {
9245 				// No match, matches forbidden application
9246 				return FALSE;
9247 			}
9248 		} else {
9249 			if (real_app_id != kernel_policy->cond_real_app_id) {
9250 				// No match, does not match required application
9251 				return FALSE;
9252 			}
9253 		}
9254 	}
9255 
9256 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9257 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9258 		if (!has_client) {
9259 			return FALSE;
9260 		}
9261 	}
9262 
9263 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9264 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9265 		if (!is_entitled) {
9266 			// Process is missing entitlement
9267 			return FALSE;
9268 		}
9269 	}
9270 
9271 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9272 		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);
9273 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9274 			if (is_platform_binary) {
9275 				// Process is platform binary
9276 				return FALSE;
9277 			}
9278 		} else {
9279 			if (!is_platform_binary) {
9280 				// Process is not platform binary
9281 				return FALSE;
9282 			}
9283 		}
9284 	}
9285 
9286 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9287 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9288 		if (has_signed_result == 0) {
9289 			// Client did not have a system-signed result
9290 			return FALSE;
9291 		}
9292 	}
9293 
9294 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9295 		if (proc != NULL) {
9296 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9297 			    kernel_policy->cond_sdk_version.platform,
9298 			    kernel_policy->cond_sdk_version.min_version,
9299 			    kernel_policy->cond_sdk_version.version,
9300 			    proc_platform(proc),
9301 			    proc_min_sdk(proc),
9302 			    proc_sdk(proc));
9303 			if (kernel_policy->cond_sdk_version.platform != 0) {
9304 				if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9305 					// Process does not match platform
9306 					return FALSE;
9307 				}
9308 			}
9309 
9310 			if (kernel_policy->cond_sdk_version.min_version != 0) {
9311 				if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9312 					// Process min version is older than required min version
9313 					return FALSE;
9314 				}
9315 			}
9316 
9317 			if (kernel_policy->cond_sdk_version.version != 0) {
9318 				if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9319 					// Process SDK version is older than required version
9320 					return FALSE;
9321 				}
9322 			}
9323 		}
9324 	}
9325 
9326 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9327 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9328 		    "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9329 		// Exact match requires the number of dots to match (no suffix matching allowed)
9330 		bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9331 		    necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9332 		if (domain_matches && socket != NULL) {
9333 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9334 		}
9335 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9336 			if (domain_matches) {
9337 				// No match, matches forbidden domain
9338 				return FALSE;
9339 			}
9340 		} else {
9341 			if (!domain_matches) {
9342 				// No match, does not match required domain
9343 				return FALSE;
9344 			}
9345 		}
9346 	} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9347 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9348 		    "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9349 		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9350 		if (domain_matches && socket != NULL) {
9351 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9352 		}
9353 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9354 			if (domain_matches) {
9355 				// No match, matches forbidden domain
9356 				return FALSE;
9357 			}
9358 		} else {
9359 			if (!domain_matches) {
9360 				// No match, does not match required domain
9361 				return FALSE;
9362 			}
9363 		}
9364 	}
9365 
9366 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9367 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9368 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9369 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9370 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9371 		bool domain_matches = false;
9372 		if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9373 			struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9374 			if (filter != NULL && filter->filter != NULL) {
9375 				domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9376 			}
9377 		} else {
9378 			domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9379 			if (debug) {
9380 				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);
9381 			}
9382 		}
9383 		if (domain_matches && socket != NULL) {
9384 			socket->so_flags1 |= SOF1_DOMAIN_MATCHED_POLICY;
9385 		}
9386 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9387 			if (domain_matches) {
9388 				// No match, matches forbidden domain
9389 				return FALSE;
9390 			}
9391 		} else {
9392 			if (!domain_matches) {
9393 				// No match, does not match required domain
9394 				return FALSE;
9395 			}
9396 		}
9397 	}
9398 
9399 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9400 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9401 		    "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9402 		bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9403 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9404 			if (url_matches) {
9405 				// No match, matches forbidden url
9406 				return FALSE;
9407 			}
9408 		} else {
9409 			if (!url_matches) {
9410 				// No match, does not match required url
9411 				return FALSE;
9412 			}
9413 		}
9414 	}
9415 
9416 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9417 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9418 		    "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9419 		    kernel_policy->cond_account_id, account_id);
9420 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9421 			if (account_id == kernel_policy->cond_account_id) {
9422 				// No match, matches forbidden account
9423 				return FALSE;
9424 			}
9425 		} else {
9426 			if (account_id != kernel_policy->cond_account_id) {
9427 				// No match, does not match required account
9428 				return FALSE;
9429 			}
9430 		}
9431 	}
9432 
9433 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9434 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9435 		    "NECP_KERNEL_CONDITION_PID",
9436 		    kernel_policy->cond_pid, pid);
9437 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9438 			if (pid == kernel_policy->cond_pid) {
9439 				// No match, matches forbidden pid
9440 				return FALSE;
9441 			}
9442 			if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9443 				return FALSE;
9444 			}
9445 		} else {
9446 			if (pid != kernel_policy->cond_pid) {
9447 				// No match, does not match required pid
9448 				return FALSE;
9449 			}
9450 			if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9451 				return FALSE;
9452 			}
9453 		}
9454 	}
9455 
9456 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9457 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9458 		    "NECP_KERNEL_CONDITION_UID",
9459 		    kernel_policy->cond_uid, uid);
9460 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9461 			if (uid == kernel_policy->cond_uid) {
9462 				// No match, matches forbidden uid
9463 				return FALSE;
9464 			}
9465 		} else {
9466 			if (uid != kernel_policy->cond_uid) {
9467 				// No match, does not match required uid
9468 				return FALSE;
9469 			}
9470 		}
9471 	}
9472 
9473 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9474 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9475 		    "NECP_KERNEL_CONDITION_REAL_UID",
9476 		    kernel_policy->cond_real_uid, real_uid);
9477 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9478 			if (real_uid == kernel_policy->cond_real_uid) {
9479 				// No match, matches forbidden uid
9480 				return FALSE;
9481 			}
9482 		} else {
9483 			if (real_uid != kernel_policy->cond_real_uid) {
9484 				// No match, does not match required uid
9485 				return FALSE;
9486 			}
9487 		}
9488 	}
9489 
9490 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9491 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9492 		    kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9493 		    traffic_class, 0, 0);
9494 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9495 			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9496 			    traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9497 				// No match, matches forbidden traffic class
9498 				return FALSE;
9499 			}
9500 		} else {
9501 			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9502 			    traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9503 				// No match, does not match required traffic class
9504 				return FALSE;
9505 			}
9506 		}
9507 	}
9508 
9509 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9510 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9511 		    "NECP_KERNEL_CONDITION_PROTOCOL",
9512 		    kernel_policy->cond_protocol, protocol);
9513 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9514 			if (protocol == kernel_policy->cond_protocol) {
9515 				// No match, matches forbidden protocol
9516 				return FALSE;
9517 			}
9518 		} else {
9519 			if (protocol != kernel_policy->cond_protocol) {
9520 				// No match, does not match required protocol
9521 				return FALSE;
9522 			}
9523 		}
9524 	}
9525 
9526 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9527 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9528 		    kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9529 		    "n/a", "n/a", "n/a");
9530 		bool matches_agent_type = FALSE;
9531 		for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9532 			struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9533 			if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9534 			    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) &&
9535 			    (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9536 			    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)) {
9537 				// Found a required agent that matches
9538 				matches_agent_type = TRUE;
9539 				break;
9540 			}
9541 		}
9542 		if (!matches_agent_type) {
9543 			return FALSE;
9544 		}
9545 	}
9546 
9547 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9548 		bool is_local = FALSE;
9549 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9550 
9551 		if (rt != NULL) {
9552 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9553 		} else {
9554 			is_local = necp_is_route_local(remote, include_local_addresses);
9555 		}
9556 		if (info != NULL) {
9557 			info->is_local = is_local;
9558 		}
9559 
9560 		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);
9561 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9562 			if (is_local) {
9563 				// Match local-networks, fail
9564 				return FALSE;
9565 			}
9566 		} else {
9567 			if (!is_local) {
9568 				// Either no route to validate or no match for local networks
9569 				return FALSE;
9570 			}
9571 		}
9572 	}
9573 
9574 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9575 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9576 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9577 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9578 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9579 				if (inRange) {
9580 					return FALSE;
9581 				}
9582 			} else {
9583 				if (!inRange) {
9584 					return FALSE;
9585 				}
9586 			}
9587 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9588 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9589 			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);
9590 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9591 				if (inSubnet) {
9592 					return FALSE;
9593 				}
9594 			} else {
9595 				if (!inSubnet) {
9596 					return FALSE;
9597 				}
9598 			}
9599 		}
9600 	}
9601 
9602 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9603 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9604 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9605 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9606 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9607 				if (inRange) {
9608 					return FALSE;
9609 				}
9610 			} else {
9611 				if (!inRange) {
9612 					return FALSE;
9613 				}
9614 			}
9615 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9616 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9617 			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);
9618 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9619 				if (inSubnet) {
9620 					return FALSE;
9621 				}
9622 			} else {
9623 				if (!inSubnet) {
9624 					return FALSE;
9625 				}
9626 			}
9627 		}
9628 	}
9629 
9630 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9631 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9632 		    "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9633 		    kernel_policy->cond_client_flags, client_flags);
9634 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9635 			if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9636 				// Flags do match, and condition is negative, fail.
9637 				return FALSE;
9638 			}
9639 		} else {
9640 			if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9641 				// Flags do not match, fail.
9642 				return FALSE;
9643 			}
9644 		}
9645 	}
9646 
9647 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9648 		bool isEmpty = necp_addr_is_empty(SA(local));
9649 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9650 		    "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9651 		    0, isEmpty);
9652 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9653 			if (isEmpty) {
9654 				return FALSE;
9655 			}
9656 		} else {
9657 			if (!isEmpty) {
9658 				return FALSE;
9659 			}
9660 		}
9661 	}
9662 
9663 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9664 		bool isEmpty = necp_addr_is_empty(SA(remote));
9665 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9666 		    "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9667 		    0, isEmpty);
9668 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9669 			if (isEmpty) {
9670 				return FALSE;
9671 			}
9672 		} else {
9673 			if (!isEmpty) {
9674 				return FALSE;
9675 			}
9676 		}
9677 	}
9678 
9679 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9680 		u_int16_t remote_port = 0;
9681 		if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9682 			remote_port = SIN(remote)->sin_port;
9683 		}
9684 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9685 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
9686 		    scheme_port, remote_port);
9687 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9688 			if (kernel_policy->cond_scheme_port == scheme_port ||
9689 			    kernel_policy->cond_scheme_port == remote_port) {
9690 				return FALSE;
9691 			}
9692 		} else {
9693 			if (kernel_policy->cond_scheme_port != scheme_port &&
9694 			    kernel_policy->cond_scheme_port != remote_port) {
9695 				return FALSE;
9696 			}
9697 		}
9698 	}
9699 
9700 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9701 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9702 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9703 		    kernel_policy->cond_packet_filter_tags,
9704 		    pf_tag);
9705 		bool tags_matched = false;
9706 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9707 			if (pf_tag == PF_TAG_ID_STACK_DROP) {
9708 				tags_matched = true;
9709 			}
9710 		}
9711 
9712 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9713 			if (tags_matched) {
9714 				return FALSE;
9715 			}
9716 		} else {
9717 			if (!tags_matched) {
9718 				return FALSE;
9719 			}
9720 		}
9721 	}
9722 
9723 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9724 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9725 		    "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9726 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9727 			if (is_loopback) {
9728 				return FALSE;
9729 			}
9730 		} else {
9731 			if (!is_loopback) {
9732 				return FALSE;
9733 			}
9734 		}
9735 	}
9736 
9737 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9738 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9739 		    "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9740 		if (is_delegated) {
9741 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9742 				if (real_is_platform_binary) {
9743 					return FALSE;
9744 				}
9745 			} else {
9746 				if (!real_is_platform_binary) {
9747 					return FALSE;
9748 				}
9749 			}
9750 		} else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9751 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9752 			// If the connection is not delegated, and the policy did not specify a particular effective process UUID
9753 			// or PID, check the process directly
9754 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9755 				if (is_platform_binary) {
9756 					return FALSE;
9757 				}
9758 			} else {
9759 				if (!is_platform_binary) {
9760 					return FALSE;
9761 				}
9762 			}
9763 		}
9764 	}
9765 
9766 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9767 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9768 		if (kernel_policy->cond_custom_entitlement != NULL) {
9769 			if (proc == NULL) {
9770 				// No process found, cannot check entitlement
9771 				return FALSE;
9772 			}
9773 			task_t __single task = proc_task(proc);
9774 			if (task == NULL ||
9775 			    !IOTaskHasEntitlementAsBooleanOrObject(task, kernel_policy->cond_custom_entitlement)) {
9776 				// Process is missing custom entitlement
9777 				return FALSE;
9778 			}
9779 		}
9780 	}
9781 
9782 	return TRUE;
9783 }
9784 
9785 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9786 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9787 {
9788 	return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9789 }
9790 
9791 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)9792 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)
9793 {
9794 	struct socket *so = NULL;
9795 	proc_t sock_proc = NULL;
9796 	proc_t curr_proc = current_proc();
9797 
9798 	memset(info, 0, sizeof(struct necp_socket_info));
9799 
9800 	so = inp->inp_socket;
9801 
9802 	info->drop_order = drop_order;
9803 	info->is_loopback = is_loopback;
9804 	info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9805 
9806 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9807 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9808 		info->uid = kauth_cred_getuid(so->so_cred);
9809 		info->real_uid = info->uid;
9810 	}
9811 
9812 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9813 		info->traffic_class = so->so_traffic_class;
9814 	}
9815 
9816 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9817 		info->has_client = !uuid_is_null(inp->necp_client_uuid);
9818 	}
9819 
9820 	if (inp->inp_ip_p) {
9821 		info->protocol = inp->inp_ip_p;
9822 	} else {
9823 		info->protocol = SOCK_PROTO(so);
9824 	}
9825 
9826 	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9827 		u_int32_t responsible_application_id = 0;
9828 
9829 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9830 		if (existing_mapping) {
9831 			info->application_id = existing_mapping->id;
9832 		}
9833 
9834 #if defined(XNU_TARGET_OS_OSX)
9835 		if (so->so_rpid > 0) {
9836 			existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9837 			if (existing_mapping != NULL) {
9838 				responsible_application_id = existing_mapping->id;
9839 			}
9840 		}
9841 #endif
9842 
9843 		if (responsible_application_id > 0) {
9844 			info->real_application_id = info->application_id;
9845 			info->application_id = responsible_application_id;
9846 			info->used_responsible_pid = true;
9847 		} else if (!(so->so_flags & SOF_DELEGATED)) {
9848 			info->real_application_id = info->application_id;
9849 		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9850 			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9851 			if (real_existing_mapping) {
9852 				info->real_application_id = real_existing_mapping->id;
9853 			}
9854 		}
9855 	}
9856 
9857 	pid_t socket_pid =
9858 #if defined(XNU_TARGET_OS_OSX)
9859 	    info->used_responsible_pid ? so->so_rpid :
9860 #endif
9861 	    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9862 	if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9863 		sock_proc = proc_find(socket_pid);
9864 		if (socket_proc) {
9865 			*socket_proc = sock_proc;
9866 		}
9867 	}
9868 
9869 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9870 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9871 		info->is_entitled = necp_task_has_match_entitlement(task);
9872 		if (!info->is_entitled) {
9873 			// Task does not have entitlement, check the parent task
9874 			necp_get_parent_is_entitled(task, info);
9875 		}
9876 	}
9877 
9878 	info->pid = socket_pid;
9879 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9880 		info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9881 	}
9882 
9883 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9884 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9885 		if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9886 			info->is_platform_binary = true;
9887 		} else if (so->so_rpid != 0) {
9888 			proc_t responsible_proc = proc_find(so->so_rpid);
9889 			if (responsible_proc != NULL) {
9890 				if (necp_is_platform_binary(responsible_proc)) {
9891 					info->is_platform_binary = true;
9892 					info->used_responsible_pid = true;
9893 				}
9894 				proc_rele(responsible_proc);
9895 			}
9896 		}
9897 	}
9898 
9899 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9900 		proc_t real_proc = curr_proc;
9901 		bool release_real_proc = false;
9902 		if (so->last_pid != proc_pid(real_proc)) {
9903 			if (so->last_pid == socket_pid && sock_proc != NULL) {
9904 				real_proc = sock_proc;
9905 			} else {
9906 				proc_t last_proc = proc_find(so->last_pid);
9907 				if (last_proc != NULL) {
9908 					real_proc = last_proc;
9909 					release_real_proc = true;
9910 				}
9911 			}
9912 		}
9913 		if (real_proc != NULL) {
9914 			if (real_proc == kernproc) {
9915 				info->real_is_platform_binary = true;
9916 			} else {
9917 				info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9918 			}
9919 			if (release_real_proc) {
9920 				proc_rele(real_proc);
9921 			}
9922 		}
9923 	}
9924 
9925 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9926 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9927 		if (existing_mapping) {
9928 			info->account_id = existing_mapping->id;
9929 		}
9930 	}
9931 
9932 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9933 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9934 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9935 		info->domain = inp->inp_necp_attributes.inp_domain;
9936 	}
9937 
9938 	if (override_bound_interface) {
9939 		info->bound_interface_index = override_bound_interface;
9940 	} else {
9941 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9942 			info->bound_interface_index = inp->inp_boundifp->if_index;
9943 		}
9944 	}
9945 
9946 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9947 	    info->bound_interface_index != IFSCOPE_NONE) {
9948 		ifnet_head_lock_shared();
9949 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9950 		if (interface != NULL) {
9951 			info->bound_interface_flags = interface->if_flags;
9952 			info->bound_interface_eflags = interface->if_eflags;
9953 			info->bound_interface_xflags = interface->if_xflags;
9954 		}
9955 		ifnet_head_done();
9956 	}
9957 
9958 	bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9959 	    uuid_is_null(inp->necp_client_uuid) &&
9960 	    necp_socket_has_resolver_signature(inp));
9961 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
9962 	    necp_restrict_multicast ||
9963 	    needs_address_for_signature ||
9964 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9965 	    NEED_DGRAM_FLOW_TRACKING(so)) {
9966 		if (override_local_addr != NULL) {
9967 			if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9968 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9969 				if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9970 					struct sockaddr_in sin;
9971 					in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9972 					memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9973 					memcpy(&info->local_addr, &sin, sin.sin_len);
9974 				}
9975 			} else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9976 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9977 			}
9978 		} else {
9979 			if (inp->inp_vflag & INP_IPV6) {
9980 				SIN6(&info->local_addr)->sin6_family = AF_INET6;
9981 				SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9982 				SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9983 				memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9984 			} else if (inp->inp_vflag & INP_IPV4) {
9985 				SIN(&info->local_addr)->sin_family = AF_INET;
9986 				SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9987 				SIN(&info->local_addr)->sin_port = inp->inp_lport;
9988 				memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9989 			}
9990 		}
9991 
9992 		if (override_remote_addr != NULL) {
9993 			if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9994 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9995 				if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9996 					struct sockaddr_in sin;
9997 					in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9998 					memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9999 					memcpy(&info->remote_addr, &sin, sin.sin_len);
10000 				}
10001 			} else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
10002 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
10003 			}
10004 		} else {
10005 			if (inp->inp_vflag & INP_IPV6) {
10006 				SIN6(&info->remote_addr)->sin6_family = AF_INET6;
10007 				SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
10008 				SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
10009 				memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
10010 			} else if (inp->inp_vflag & INP_IPV4) {
10011 				SIN(&info->remote_addr)->sin_family = AF_INET;
10012 				SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
10013 				SIN(&info->remote_addr)->sin_port = inp->inp_fport;
10014 				memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
10015 			}
10016 		}
10017 		// Clear the embedded scope id from v6 addresses
10018 		if (info->local_addr.sa.sa_family == AF_INET6) {
10019 			struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
10020 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
10021 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
10022 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
10023 					sin6->sin6_addr.s6_addr16[1] = 0;
10024 				}
10025 			}
10026 		}
10027 		if (info->remote_addr.sa.sa_family == AF_INET6) {
10028 			struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
10029 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
10030 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
10031 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
10032 					sin6->sin6_addr.s6_addr16[1] = 0;
10033 				}
10034 			}
10035 		}
10036 	}
10037 
10038 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
10039 		// For checking sockets, only validate that there is an NECP client present. It will have
10040 		// already checked for the signature.
10041 		if (!uuid_is_null(inp->necp_client_uuid)) {
10042 			info->has_system_signed_result = true;
10043 		} else {
10044 			info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
10045 		}
10046 	}
10047 
10048 	if (NEED_DGRAM_FLOW_TRACKING(so)) {
10049 		info->soflow_entry = soflow_get_flow(so, NULL, &(info->remote_addr.sa), NULL, 0, override_direction, input_ifindex);
10050 	} else {
10051 		info->soflow_entry = NULL;
10052 	}
10053 
10054 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
10055 		info->client_flags = 0;
10056 		if (INP_NO_CONSTRAINED(inp)) {
10057 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
10058 		}
10059 		if (INP_NO_EXPENSIVE(inp)) {
10060 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
10061 		}
10062 		if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
10063 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
10064 		}
10065 		if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
10066 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
10067 		}
10068 		if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
10069 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
10070 		}
10071 		if (NEED_DGRAM_FLOW_TRACKING(so)) {
10072 			// If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
10073 			// and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
10074 			if (info->soflow_entry != NULL) {
10075 				if (!info->soflow_entry->soflow_outgoing) {
10076 					info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10077 				}
10078 			} else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
10079 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10080 			}
10081 		} else {
10082 			// If the socket is explicitly marked as inbound then set the inbound flag.
10083 			if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
10084 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
10085 			}
10086 		}
10087 		if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
10088 		    inp->inp_flags2 & INP2_EXTERNAL_PORT) {
10089 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
10090 		}
10091 		if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
10092 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
10093 		}
10094 		if (inp->inp_socket->so_options & SO_REUSEPORT) {
10095 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
10096 		}
10097 	}
10098 }
10099 
10100 #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)
10101 
10102 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)10103 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
10104     struct necp_socket_info *info,
10105     necp_kernel_policy_filter *return_filter,
10106     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
10107     size_t *return_route_rule_id_array_count,
10108     size_t route_rule_id_array_count,
10109     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10110     size_t netagent_array_count,
10111     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10112     size_t netagent_use_flags_array_count,
10113     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10114     u_int32_t num_required_agent_types,
10115     proc_t proc,
10116     u_int16_t pf_tag,
10117     necp_kernel_policy_id *skip_policy_id,
10118     struct rtentry *rt,
10119     necp_kernel_policy_result *return_drop_dest_policy_result,
10120     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10121     u_int32_t *return_flow_divert_aggregate_unit,
10122     struct socket *so,
10123     int debug)
10124 {
10125 	struct necp_kernel_socket_policy *matched_policy = NULL;
10126 	u_int32_t skip_order = 0;
10127 	u_int32_t skip_session_order = 0;
10128 	bool skipped_ip_result = false;
10129 	size_t route_rule_id_count = 0;
10130 	int i;
10131 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10132 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10133 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10134 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10135 	size_t netagent_cursor = 0;
10136 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10137 	size_t netagent_array_count_adjusted = netagent_array_count;
10138 	if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10139 		netagent_array_count_adjusted = netagent_use_flags_array_count;
10140 	}
10141 
10142 	if (return_drop_all_bypass != NULL) {
10143 		*return_drop_all_bypass = drop_all_bypass;
10144 	}
10145 
10146 	if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10147 		netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10148 	}
10149 
10150 	// Pre-process domain for quick matching
10151 	struct substring domain_substring = {};
10152 	u_int8_t domain_dot_count = 0;
10153 	if (info->domain != NULL) {
10154 		domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10155 		domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10156 	}
10157 
10158 	if (return_filter != NULL) {
10159 		*return_filter = 0;
10160 	}
10161 
10162 	if (return_route_rule_id_array_count != NULL) {
10163 		*return_route_rule_id_array_count = 0;
10164 	}
10165 
10166 	// Do not subject layer-2 filter to NECP policies, return a PASS policy
10167 	if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10168 		return &pass_policy;
10169 	}
10170 
10171 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10172 
10173 	if (policy_search_array != NULL) {
10174 		for (i = 0; policy_search_array[i] != NULL; i++) {
10175 			NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10176 
10177 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10178 				// We've hit a drop all rule
10179 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10180 					drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10181 					if (return_drop_all_bypass != NULL) {
10182 						*return_drop_all_bypass = drop_all_bypass;
10183 					}
10184 				}
10185 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10186 					NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10187 					break;
10188 				}
10189 			}
10190 			if (necp_drop_dest_policy.entry_count != 0 &&
10191 			    necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10192 				// We've hit a drop by destination address rule
10193 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10194 				break;
10195 			}
10196 			if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10197 				// We've hit a drop order for this socket
10198 				break;
10199 			}
10200 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10201 				// Done skipping
10202 				skip_order = 0;
10203 				skip_session_order = 0;
10204 				// If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10205 				if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10206 					*skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10207 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10208 				}
10209 			}
10210 			if (skip_order) {
10211 				if (policy_search_array[i]->order < skip_order) {
10212 					// Skip this policy
10213 					// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10214 					// didn't, clear out the return value for skip ID when we are done with each session.'
10215 					if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10216 						skipped_ip_result = true;
10217 						NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10218 					}
10219 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10220 					continue;
10221 				} else {
10222 					// Done skipping
10223 					skip_order = 0;
10224 					skip_session_order = 0;
10225 				}
10226 			} else if (skip_session_order) {
10227 				// Skip this policy
10228 				// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10229 				// didn't, clear out the return value for skip ID when we are done with each session.'
10230 				if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10231 					skipped_ip_result = true;
10232 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10233 				}
10234 				NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10235 				continue;
10236 			}
10237 
10238 			if (necp_socket_check_policy(policy_search_array[i],
10239 			    info->application_id,
10240 			    info->real_application_id,
10241 			    info->is_entitled,
10242 			    info->account_id,
10243 			    domain_substring,
10244 			    domain_dot_count,
10245 			    info->url,
10246 			    info->pid,
10247 			    info->pid_version,
10248 			    info->uid,
10249 			    info->real_uid,
10250 			    info->bound_interface_index,
10251 			    info->traffic_class,
10252 			    info->protocol,
10253 			    &info->local_addr,
10254 			    &info->remote_addr,
10255 			    required_agent_types,
10256 			    num_required_agent_types,
10257 			    info->has_client,
10258 			    info->client_flags,
10259 			    info->is_platform_binary,
10260 			    info->has_system_signed_result,
10261 			    proc,
10262 			    pf_tag,
10263 			    info->scheme_port,
10264 			    rt,
10265 			    info->is_loopback,
10266 			    debug,
10267 			    info->real_is_platform_binary,
10268 			    info->bound_interface_flags,
10269 			    info->bound_interface_eflags,
10270 			    info->bound_interface_xflags,
10271 			    info,
10272 			    info->is_delegated,
10273 			    so)) {
10274 				if (!debug && necp_data_tracing_session_order) {
10275 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10276 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10277 						NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10278 					}
10279 				}
10280 
10281 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10282 					if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10283 						necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10284 						if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10285 							*return_filter = control_unit;
10286 						} else {
10287 							// Preserve pre-existing connections only if all filters preserve.
10288 							bool preserve_bit_off = false;
10289 							if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10290 							    (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10291 								preserve_bit_off = true;
10292 							}
10293 							*return_filter |= control_unit;
10294 							if (preserve_bit_off == true) {
10295 								*return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10296 							}
10297 						}
10298 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10299 							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);
10300 						}
10301 					}
10302 					continue;
10303 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10304 					if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10305 						return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10306 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10307 							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);
10308 						}
10309 					}
10310 					continue;
10311 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10312 				    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10313 					if (netagent_cursor < netagent_array_count_adjusted) {
10314 						bool agent_already_present = false;
10315 						for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10316 							if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10317 								// Already present. Mark the "SCOPED" flag if flags are necessary.
10318 								agent_already_present = true;
10319 								if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10320 								    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10321 									netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10322 								}
10323 							}
10324 						}
10325 
10326 						if (!agent_already_present) {
10327 							netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10328 							if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10329 								netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10330 							}
10331 							netagent_cursor++;
10332 						}
10333 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10334 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10335 							    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10336 							    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10337 							    policy_search_array[i]->result_parameter.netagent_id);
10338 						}
10339 					}
10340 					continue;
10341 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10342 					bool agent_already_present = false;
10343 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10344 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10345 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10346 							agent_already_present = true;
10347 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10348 						}
10349 					}
10350 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10351 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
10352 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10353 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10354 						netagent_cursor++;
10355 					}
10356 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10357 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10358 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10359 						    policy_search_array[i]->result_parameter.netagent_id);
10360 					}
10361 					continue;
10362 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT_TYPE) {
10363 					bool agent_already_present = false;
10364 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10365 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10366 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10367 							agent_already_present = true;
10368 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10369 						}
10370 					}
10371 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10372 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
10373 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10374 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10375 						netagent_cursor++;
10376 					}
10377 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10378 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove NetagentType %d",
10379 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10380 						    policy_search_array[i]->result_parameter.netagent_id);
10381 					}
10382 					continue;
10383 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10384 					u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10385 					if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10386 						/* For transparent proxies, accumulate the control unit and continue to the next policy */
10387 						if (return_flow_divert_aggregate_unit != NULL) {
10388 							*return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10389 							if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10390 								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);
10391 							}
10392 						}
10393 						continue;
10394 					}
10395 				}
10396 
10397 				// Matched policy is a skip. Do skip and continue.
10398 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10399 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10400 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10401 					skip_session_order = policy_search_array[i]->session_order + 1;
10402 					if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10403 						*skip_policy_id = policy_search_array[i]->id;
10404 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10405 							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);
10406 						}
10407 					}
10408 					continue;
10409 				}
10410 
10411 				// Matched an allow unentitled, which clears any drop order
10412 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10413 					info->drop_order = 0;
10414 					continue;
10415 				}
10416 
10417 				// Passed all tests, found a match
10418 				matched_policy = policy_search_array[i];
10419 				NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10420 				break;
10421 			}
10422 		}
10423 	}
10424 
10425 	if (return_netagent_array != NULL) {
10426 		if (return_netagent_use_flags_array != NULL) {
10427 			memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10428 			memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10429 		} else {
10430 			for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10431 				if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10432 					return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10433 				} else {
10434 					return_netagent_array[netagent_i] = 0;
10435 				}
10436 			}
10437 		}
10438 	}
10439 
10440 	if (return_route_rule_id_array_count != NULL) {
10441 		*return_route_rule_id_array_count = route_rule_id_count;
10442 	}
10443 	return matched_policy;
10444 }
10445 
10446 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10447 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10448 {
10449 	bool found_match = FALSE;
10450 	ifaddr_t ifa;
10451 	union necp_sockaddr_union address_storage;
10452 	int family = AF_INET;
10453 
10454 	ifnet_head_lock_shared();
10455 	ifnet_t interface = ifindex2ifnet[interface_index];
10456 	ifnet_head_done();
10457 
10458 	if (inp == NULL || interface == NULL) {
10459 		return FALSE;
10460 	}
10461 
10462 	if (inp->inp_vflag & INP_IPV4) {
10463 		family = AF_INET;
10464 	} else if (inp->inp_vflag & INP_IPV6) {
10465 		family = AF_INET6;
10466 	} else {
10467 		return FALSE;
10468 	}
10469 
10470 	// Match socket address against interface addresses
10471 	ifnet_lock_shared(interface);
10472 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10473 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10474 			if (address_storage.sa.sa_family != family) {
10475 				continue;
10476 			}
10477 
10478 			if (family == AF_INET) {
10479 				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10480 					found_match = TRUE;
10481 					break;
10482 				}
10483 			} else if (family == AF_INET6) {
10484 				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10485 					found_match = TRUE;
10486 					break;
10487 				}
10488 			}
10489 		}
10490 	}
10491 	ifnet_lock_done(interface);
10492 
10493 	return found_match;
10494 }
10495 
10496 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10497 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10498 {
10499 	if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10500 		proc_t curr_proc = current_proc();
10501 		proc_t sock_proc = NULL;
10502 		struct socket *so = inp ? inp->inp_socket : NULL;
10503 		pid_t socket_pid = (so == NULL) ? 0 :
10504 #if defined(XNU_TARGET_OS_OSX)
10505 		    so->so_rpid ? so->so_rpid :
10506 #endif
10507 		    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10508 		if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10509 			sock_proc = proc_find(socket_pid);
10510 		}
10511 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10512 		if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10513 			if (sock_proc) {
10514 				proc_rele(sock_proc);
10515 			}
10516 			return NECP_BYPASS_TYPE_DROP;
10517 		}
10518 		if (sock_proc) {
10519 			proc_rele(sock_proc);
10520 		}
10521 
10522 		if (necp_pass_loopback > 0) {
10523 			return NECP_BYPASS_TYPE_LOOPBACK;
10524 		}
10525 	} else if (necp_is_intcoproc(inp, NULL)) {
10526 		return NECP_BYPASS_TYPE_INTCOPROC;
10527 	}
10528 
10529 	return NECP_BYPASS_TYPE_NONE;
10530 }
10531 
10532 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10533 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10534 {
10535 	u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10536 	ifnet_t tunnel_interface = NULL;
10537 
10538 	ifnet_head_lock_shared();
10539 	tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10540 	ifnet_head_done();
10541 
10542 	if (tunnel_interface != NULL) {
10543 		tcp_set_tso(intotcpcb(inp), tunnel_interface);
10544 	}
10545 }
10546 
10547 static inline void
necp_unscope(struct inpcb * inp)10548 necp_unscope(struct inpcb *inp)
10549 {
10550 	// If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10551 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10552 		inp->inp_flags &= ~INP_BOUND_IF;
10553 		inp->inp_boundifp = NULL;
10554 	}
10555 }
10556 
10557 static inline void
necp_clear_tunnel(struct inpcb * inp)10558 necp_clear_tunnel(struct inpcb *inp)
10559 {
10560 	if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10561 		inp->inp_flags &= ~INP_BOUND_IF;
10562 		inp->inp_boundifp = NULL;
10563 	}
10564 }
10565 
10566 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10567 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10568 {
10569 	// Verify netagents
10570 	for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10571 		struct necp_uuid_id_mapping *mapping = NULL;
10572 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
10573 		if (netagent_id == 0) {
10574 			continue;
10575 		}
10576 		mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
10577 		if (mapping != NULL) {
10578 			u_int32_t agent_flags = 0;
10579 			agent_flags = netagent_get_flags(mapping->uuid);
10580 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10581 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10582 					continue;
10583 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10584 					if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10585 						int trigger_error = 0;
10586 						trigger_error = netagent_kernel_trigger(mapping->uuid);
10587 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10588 							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);
10589 						}
10590 					}
10591 					return false;
10592 				}
10593 			}
10594 		}
10595 	}
10596 	return true;
10597 }
10598 
10599 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)10600 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10601 {
10602 	struct socket *so = NULL;
10603 	necp_kernel_policy_filter filter_control_unit = 0;
10604 	struct necp_kernel_socket_policy *matched_policy = NULL;
10605 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10606 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10607 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10608 	proc_t __single socket_proc = NULL;
10609 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10610 
10611 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10612 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10613 
10614 	struct necp_socket_info info = {};
10615 
10616 	u_int32_t flow_divert_aggregate_unit = 0;
10617 
10618 	if (inp == NULL) {
10619 		return NECP_KERNEL_POLICY_ID_NONE;
10620 	}
10621 
10622 	// Ignore invalid addresses
10623 	if (override_local_addr != NULL &&
10624 	    !necp_address_is_valid(override_local_addr)) {
10625 		override_local_addr = NULL;
10626 	}
10627 	if (override_remote_addr != NULL &&
10628 	    !necp_address_is_valid(override_remote_addr)) {
10629 		override_remote_addr = NULL;
10630 	}
10631 
10632 	so = inp->inp_socket;
10633 
10634 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10635 
10636 	// Don't lock. Possible race condition, but we don't want the performance hit.
10637 	if (necp_drop_management_order == 0 &&
10638 	    (necp_kernel_socket_policies_count == 0 ||
10639 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10640 		if (necp_drop_all_order > 0 || drop_order > 0) {
10641 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10642 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10643 			inp->inp_policyresult.policy_gencount = 0;
10644 			inp->inp_policyresult.app_id = 0;
10645 			inp->inp_policyresult.flowhash = 0;
10646 			inp->inp_policyresult.results.filter_control_unit = 0;
10647 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10648 			inp->inp_policyresult.results.route_rule_id = 0;
10649 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10650 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10651 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10652 			} else {
10653 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10654 			}
10655 		}
10656 		return NECP_KERNEL_POLICY_ID_NONE;
10657 	}
10658 
10659 	// Check for loopback exception
10660 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10661 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10662 		// Mark socket as a drop
10663 		necp_unscope(inp);
10664 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10665 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10666 		inp->inp_policyresult.policy_gencount = 0;
10667 		inp->inp_policyresult.app_id = 0;
10668 		inp->inp_policyresult.flowhash = 0;
10669 		inp->inp_policyresult.results.filter_control_unit = 0;
10670 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10671 		inp->inp_policyresult.results.route_rule_id = 0;
10672 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10673 		return NECP_KERNEL_POLICY_ID_NONE;
10674 	}
10675 
10676 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10677 		// Mark socket as a pass
10678 		necp_unscope(inp);
10679 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10680 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10681 		inp->inp_policyresult.policy_gencount = 0;
10682 		inp->inp_policyresult.app_id = 0;
10683 		inp->inp_policyresult.flowhash = 0;
10684 		inp->inp_policyresult.results.filter_control_unit = 0;
10685 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10686 		inp->inp_policyresult.results.route_rule_id = 0;
10687 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10688 		return NECP_KERNEL_POLICY_ID_NONE;
10689 	}
10690 
10691 	// Lock
10692 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10693 	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);
10694 
10695 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10696 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10697 
10698 	// Check info
10699 	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10700 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10701 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10702 	    inp->inp_policyresult.flowhash == flowhash) {
10703 		// If already matched this socket on this generation of table, skip
10704 
10705 		if (info.soflow_entry != NULL) {
10706 			soflow_free_flow(info.soflow_entry);
10707 		}
10708 
10709 		// Unlock
10710 		lck_rw_done(&necp_kernel_policy_lock);
10711 
10712 		if (socket_proc) {
10713 			proc_rele(socket_proc);
10714 		}
10715 
10716 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10717 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10718 			    inp->inp_socket, info.bound_interface_index, info.protocol,
10719 			    inp->inp_policyresult.policy_id,
10720 			    inp->inp_policyresult.results.result,
10721 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10722 		}
10723 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10724 		return inp->inp_policyresult.policy_id;
10725 	}
10726 
10727 	inp->inp_policyresult.app_id = info.application_id;
10728 
10729 	// Match socket to policy
10730 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10731 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10732 	size_t route_rule_id_array_count = 0;
10733 
10734 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10735 	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)],
10736 	    &info,
10737 	    &filter_control_unit,
10738 	    route_rule_id_array,
10739 	    &route_rule_id_array_count,
10740 	    MAX_AGGREGATE_ROUTE_RULES,
10741 	    netagent_ids,
10742 	    NECP_MAX_NETAGENTS,
10743 	    NULL,
10744 	    0,
10745 	    NULL,
10746 	    0,
10747 	    effective_proc,
10748 	    0,
10749 	    &skip_policy_id,
10750 	    inp->inp_route.ro_rt,
10751 	    &drop_dest_policy_result,
10752 	    &drop_all_bypass,
10753 	    &flow_divert_aggregate_unit,
10754 	    so,
10755 	    debug);
10756 
10757 	// Check for loopback exception again after the policy match
10758 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10759 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10760 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10761 		// Mark socket as a pass
10762 		necp_unscope(inp);
10763 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10764 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10765 		inp->inp_policyresult.policy_gencount = 0;
10766 		inp->inp_policyresult.app_id = 0;
10767 		inp->inp_policyresult.flowhash = 0;
10768 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10769 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10770 		inp->inp_policyresult.results.route_rule_id = 0;
10771 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10772 		if (info.soflow_entry != NULL) {
10773 			info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10774 			info.soflow_entry->soflow_policies_gencount = 0;
10775 			soflow_free_flow(info.soflow_entry);
10776 		}
10777 
10778 		// Unlock
10779 		lck_rw_done(&necp_kernel_policy_lock);
10780 
10781 		if (socket_proc) {
10782 			proc_rele(socket_proc);
10783 		}
10784 
10785 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10786 		return NECP_KERNEL_POLICY_ID_NONE;
10787 	}
10788 
10789 	// Verify netagents
10790 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10791 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10792 			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);
10793 		}
10794 
10795 		// Mark socket as a drop if required agent is not active
10796 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10797 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10798 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10799 		inp->inp_policyresult.flowhash = flowhash;
10800 		inp->inp_policyresult.results.filter_control_unit = 0;
10801 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10802 		inp->inp_policyresult.results.route_rule_id = 0;
10803 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10804 		if (info.soflow_entry != NULL) {
10805 			info.soflow_entry->soflow_filter_control_unit = 0;
10806 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10807 			soflow_free_flow(info.soflow_entry);
10808 		}
10809 
10810 		// Unlock
10811 		lck_rw_done(&necp_kernel_policy_lock);
10812 
10813 		if (socket_proc) {
10814 			proc_rele(socket_proc);
10815 		}
10816 
10817 		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);
10818 		return NECP_KERNEL_POLICY_ID_NONE;
10819 	}
10820 
10821 	u_int32_t route_rule_id = 0;
10822 	if (route_rule_id_array_count == 1) {
10823 		route_rule_id = route_rule_id_array[0];
10824 	} else if (route_rule_id_array_count > 1) {
10825 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10826 	}
10827 
10828 	bool reset_tcp_tunnel_interface = false;
10829 	bool send_local_network_denied_event = false;
10830 	if (matched_policy) {
10831 		// For PASS policy result, clear previous rescope / tunnel inteface
10832 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10833 		    (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10834 			necp_unscope(inp);
10835 			necp_clear_tunnel(inp);
10836 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10837 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10838 			}
10839 		}
10840 		matched_policy_id = matched_policy->id;
10841 		inp->inp_policyresult.policy_id = matched_policy->id;
10842 		inp->inp_policyresult.skip_policy_id = skip_policy_id;
10843 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10844 		inp->inp_policyresult.flowhash = flowhash;
10845 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10846 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10847 		inp->inp_policyresult.results.route_rule_id = route_rule_id;
10848 		inp->inp_policyresult.results.result = matched_policy->result;
10849 		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10850 		if (info.soflow_entry != NULL) {
10851 			info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10852 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10853 		}
10854 
10855 		if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10856 			inp->inp_policyresult.app_id = info.real_application_id;
10857 		}
10858 
10859 		if (necp_socket_is_connected(inp) &&
10860 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10861 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10862 			NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10863 			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10864 		} else if (necp_socket_is_connected(inp) &&
10865 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10866 		    info.protocol == IPPROTO_TCP) {
10867 			// Reset TCP socket interface based parameters if tunnel policy changes
10868 			reset_tcp_tunnel_interface = true;
10869 		}
10870 
10871 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10872 			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);
10873 		}
10874 
10875 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10876 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10877 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10878 			// Trigger the event that we dropped due to a local network policy
10879 			send_local_network_denied_event = true;
10880 		}
10881 	} else {
10882 		bool drop_all = false;
10883 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10884 			// Mark socket as a drop if set
10885 			drop_all = true;
10886 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10887 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10888 			}
10889 		}
10890 
10891 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10892 		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);
10893 		if (flow_divert_control_unit != 0) {
10894 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10895 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10896 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10897 			inp->inp_policyresult.flowhash = flowhash;
10898 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10899 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10900 			inp->inp_policyresult.results.route_rule_id = route_rule_id;
10901 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10902 			inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10903 			if (info.soflow_entry != NULL) {
10904 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10905 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10906 			}
10907 			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);
10908 		} else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10909 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10910 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10911 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10912 			inp->inp_policyresult.flowhash = flowhash;
10913 			inp->inp_policyresult.results.filter_control_unit = 0;
10914 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10915 			inp->inp_policyresult.results.route_rule_id = 0;
10916 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10917 			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);
10918 			if (info.soflow_entry != NULL) {
10919 				info.soflow_entry->soflow_filter_control_unit = 0;
10920 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10921 			}
10922 		} else {
10923 			// Mark non-matching socket so we don't re-check it
10924 			necp_unscope(inp);
10925 			if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10926 				necp_clear_tunnel(inp);
10927 			}
10928 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10929 				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);
10930 			}
10931 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10932 			inp->inp_policyresult.skip_policy_id = skip_policy_id;
10933 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10934 			inp->inp_policyresult.flowhash = flowhash;
10935 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10936 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10937 			inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10938 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10939 			if (info.soflow_entry != NULL) {
10940 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
10941 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10942 			}
10943 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10944 		}
10945 	}
10946 
10947 	if (necp_check_missing_client_drop(effective_proc, &info) ||
10948 	    necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10949 		// Mark as drop
10950 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10951 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10952 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10953 		inp->inp_policyresult.flowhash = flowhash;
10954 		inp->inp_policyresult.results.filter_control_unit = 0;
10955 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10956 		inp->inp_policyresult.results.route_rule_id = 0;
10957 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10958 		if (info.soflow_entry != NULL) {
10959 			info.soflow_entry->soflow_filter_control_unit = 0;
10960 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
10961 		}
10962 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10963 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10964 		}
10965 	}
10966 
10967 	if (info.soflow_entry != NULL) {
10968 		soflow_free_flow(info.soflow_entry);
10969 	}
10970 
10971 	// Unlock
10972 	lck_rw_done(&necp_kernel_policy_lock);
10973 
10974 	if (reset_tcp_tunnel_interface) {
10975 		// Update MSS when not holding the policy lock to avoid recursive locking
10976 		tcp_mtudisc(inp, 0);
10977 
10978 		// Update TSO flag based on the tunnel interface
10979 		necp_socket_ip_tunnel_tso(inp);
10980 	}
10981 
10982 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10983 		inp->inp_policyresult.network_denied_notifies++;
10984 #if defined(XNU_TARGET_OS_OSX)
10985 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10986 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10987 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10988 		    NETPOLICY_NETWORKTYPE_LOCAL);
10989 #else
10990 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10991 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10992 		    NETPOLICY_NETWORKTYPE_LOCAL);
10993 #endif
10994 	}
10995 
10996 	if (socket_proc) {
10997 		proc_rele(socket_proc);
10998 	}
10999 
11000 	return matched_policy_id;
11001 }
11002 
11003 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)11004 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)
11005 {
11006 	u_int32_t bound_interface_flags = 0;
11007 	u_int32_t bound_interface_eflags = 0;
11008 	u_int32_t bound_interface_xflags = 0;
11009 
11010 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
11011 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
11012 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
11013 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
11014 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
11015 			    cond_bound_interface_index, bound_interface_index);
11016 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
11017 				if (bound_interface_index == cond_bound_interface_index) {
11018 					// No match, matches forbidden interface
11019 					return FALSE;
11020 				}
11021 			} else {
11022 				if (bound_interface_index != cond_bound_interface_index) {
11023 					// No match, does not match required interface
11024 					return FALSE;
11025 				}
11026 			}
11027 		}
11028 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
11029 			if (bound_interface_index != IFSCOPE_NONE) {
11030 				ifnet_head_lock_shared();
11031 				ifnet_t interface = ifindex2ifnet[bound_interface_index];
11032 				if (interface != NULL) {
11033 					bound_interface_flags = interface->if_flags;
11034 					bound_interface_eflags = interface->if_eflags;
11035 					bound_interface_xflags = interface->if_xflags;
11036 				}
11037 				ifnet_head_done();
11038 			}
11039 
11040 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11041 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
11042 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11043 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
11044 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
11045 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
11046 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
11047 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
11048 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
11049 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
11050 					// No match, matches some forbidden interface flags
11051 					return FALSE;
11052 				}
11053 			} else {
11054 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
11055 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
11056 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
11057 					// No match, does not match some required interface xflags
11058 					return FALSE;
11059 				}
11060 			}
11061 		}
11062 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
11063 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
11064 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
11065 			if (bound_interface_index != 0) {
11066 				// No match, requires a non-bound packet
11067 				return FALSE;
11068 			}
11069 		}
11070 	}
11071 
11072 	if (kernel_policy->condition_mask == 0) {
11073 		return TRUE;
11074 	}
11075 
11076 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
11077 		necp_kernel_policy_id matched_policy_id =
11078 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
11079 		NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
11080 		    "NECP_KERNEL_CONDITION_POLICY_ID",
11081 		    kernel_policy->cond_policy_id, 0, 0,
11082 		    matched_policy_id, socket_policy_id, socket_skip_policy_id);
11083 		if (matched_policy_id != kernel_policy->cond_policy_id) {
11084 			// No match, does not match required id
11085 			return FALSE;
11086 		}
11087 	}
11088 
11089 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
11090 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
11091 		    "NECP_KERNEL_CONDITION_LAST_INTERFACE",
11092 		    kernel_policy->cond_last_interface_index, last_interface_index);
11093 		if (last_interface_index != kernel_policy->cond_last_interface_index) {
11094 			return FALSE;
11095 		}
11096 	}
11097 
11098 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11099 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
11100 		    "NECP_KERNEL_CONDITION_PROTOCOL",
11101 		    kernel_policy->cond_protocol, protocol);
11102 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
11103 			if (protocol == kernel_policy->cond_protocol) {
11104 				// No match, matches forbidden protocol
11105 				return FALSE;
11106 			}
11107 		} else {
11108 			if (protocol != kernel_policy->cond_protocol) {
11109 				// No match, does not match required protocol
11110 				return FALSE;
11111 			}
11112 		}
11113 	}
11114 
11115 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11116 		bool is_local = FALSE;
11117 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
11118 
11119 		if (rt != NULL) {
11120 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
11121 		} else {
11122 			is_local = necp_is_route_local(remote, include_local_addresses);
11123 		}
11124 		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);
11125 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
11126 			if (is_local) {
11127 				// Match local-networks, fail
11128 				return FALSE;
11129 			}
11130 		} else {
11131 			if (!is_local) {
11132 				// Either no route to validate or no match for local networks
11133 				return FALSE;
11134 			}
11135 		}
11136 	}
11137 
11138 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
11139 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11140 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
11141 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
11142 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
11143 				if (inRange) {
11144 					return FALSE;
11145 				}
11146 			} else {
11147 				if (!inRange) {
11148 					return FALSE;
11149 				}
11150 			}
11151 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11152 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11153 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11154 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11155 				if (inSubnet) {
11156 					return FALSE;
11157 				}
11158 			} else {
11159 				if (!inSubnet) {
11160 					return FALSE;
11161 				}
11162 			}
11163 		}
11164 	}
11165 
11166 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11167 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11168 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11169 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11170 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11171 				if (inRange) {
11172 					return FALSE;
11173 				}
11174 			} else {
11175 				if (!inRange) {
11176 					return FALSE;
11177 				}
11178 			}
11179 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11180 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11181 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11182 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11183 				if (inSubnet) {
11184 					return FALSE;
11185 				}
11186 			} else {
11187 				if (!inSubnet) {
11188 					return FALSE;
11189 				}
11190 			}
11191 		}
11192 	}
11193 
11194 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11195 		u_int16_t remote_port = 0;
11196 		if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11197 			remote_port = SIN(remote)->sin_port;
11198 		}
11199 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11200 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
11201 		    0, remote_port);
11202 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11203 			if (kernel_policy->cond_scheme_port == remote_port) {
11204 				return FALSE;
11205 			}
11206 		} else {
11207 			if (kernel_policy->cond_scheme_port != remote_port) {
11208 				return FALSE;
11209 			}
11210 		}
11211 	}
11212 
11213 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11214 		bool tags_matched = false;
11215 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11216 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11217 		    kernel_policy->cond_packet_filter_tags, pf_tag);
11218 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11219 			if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11220 				tags_matched = true;
11221 			}
11222 
11223 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11224 				if (tags_matched) {
11225 					return FALSE;
11226 				}
11227 			} else {
11228 				if (!tags_matched) {
11229 					return FALSE;
11230 				}
11231 			}
11232 		}
11233 	}
11234 
11235 	return TRUE;
11236 }
11237 
11238 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)11239 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)
11240 {
11241 	u_int32_t skip_order = 0;
11242 	u_int32_t skip_session_order = 0;
11243 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11244 	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)];
11245 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11246 	size_t route_rule_id_count = 0;
11247 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11248 	if (return_drop_all_bypass != NULL) {
11249 		*return_drop_all_bypass = drop_all_bypass;
11250 	}
11251 
11252 	if (return_route_rule_id != NULL) {
11253 		*return_route_rule_id = 0;
11254 	}
11255 
11256 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11257 
11258 	if (policy_search_array != NULL) {
11259 		for (int i = 0; policy_search_array[i] != NULL; i++) {
11260 			NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11261 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11262 				// We've hit a drop all rule
11263 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11264 					drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11265 					if (return_drop_all_bypass != NULL) {
11266 						*return_drop_all_bypass = drop_all_bypass;
11267 					}
11268 				}
11269 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11270 					NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11271 					break;
11272 				}
11273 			}
11274 			if (necp_drop_dest_policy.entry_count > 0 &&
11275 			    necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11276 				// We've hit a drop by destination address rule
11277 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11278 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11279 				break;
11280 			}
11281 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11282 				// Done skipping
11283 				skip_order = 0;
11284 				skip_session_order = 0;
11285 			}
11286 			if (skip_order) {
11287 				if (policy_search_array[i]->order < skip_order) {
11288 					// Skip this policy
11289 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11290 					continue;
11291 				} else {
11292 					// Done skipping
11293 					skip_order = 0;
11294 					skip_session_order = 0;
11295 				}
11296 			} else if (skip_session_order) {
11297 				// Skip this policy
11298 				NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11299 				continue;
11300 			}
11301 
11302 			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)) {
11303 				if (!debug && necp_data_tracing_session_order) {
11304 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11305 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11306 						NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11307 					}
11308 				}
11309 
11310 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11311 					if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11312 						route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11313 					}
11314 					continue;
11315 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11316 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11317 					skip_session_order = policy_search_array[i]->session_order + 1;
11318 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11319 					continue;
11320 				}
11321 
11322 				// Passed all tests, found a match
11323 				matched_policy = policy_search_array[i];
11324 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11325 				break;
11326 			}
11327 		}
11328 	}
11329 
11330 	if (route_rule_id_count == 1) {
11331 		*return_route_rule_id = route_rule_id_array[0];
11332 	} else if (route_rule_id_count > 1) {
11333 		*return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11334 	}
11335 
11336 	return matched_policy;
11337 }
11338 
11339 static inline bool
necp_output_bypass(struct mbuf * packet)11340 necp_output_bypass(struct mbuf *packet)
11341 {
11342 	if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11343 		return true;
11344 	}
11345 	if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11346 		return true;
11347 	}
11348 	if (necp_is_intcoproc(NULL, packet)) {
11349 		return true;
11350 	}
11351 	return false;
11352 }
11353 
11354 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)11355 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11356     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11357 {
11358 	struct ip *ip = NULL;
11359 	int hlen = sizeof(struct ip);
11360 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11361 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11362 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11363 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11364 	u_int16_t protocol = 0;
11365 	u_int32_t bound_interface_index = 0;
11366 	u_int32_t last_interface_index = 0;
11367 	union necp_sockaddr_union local_addr = { };
11368 	union necp_sockaddr_union remote_addr = { };
11369 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11370 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11371 	u_int16_t pf_tag = 0;
11372 
11373 	if (result) {
11374 		*result = 0;
11375 	}
11376 
11377 	if (result_parameter) {
11378 		memset(result_parameter, 0, sizeof(*result_parameter));
11379 	}
11380 
11381 	if (packet == NULL) {
11382 		return NECP_KERNEL_POLICY_ID_NONE;
11383 	}
11384 
11385 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11386 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11387 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11388 
11389 	// Exit early for an empty list
11390 	// Don't lock. Possible race condition, but we don't want the performance hit.
11391 	if (necp_kernel_ip_output_policies_count == 0 ||
11392 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11393 		if (necp_drop_all_order > 0) {
11394 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11395 			if (result) {
11396 				if (necp_output_bypass(packet)) {
11397 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11398 				} else {
11399 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11400 				}
11401 			}
11402 		}
11403 
11404 		return matched_policy_id;
11405 	}
11406 
11407 	// Check for loopback exception
11408 	if (necp_output_bypass(packet)) {
11409 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11410 		if (result) {
11411 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11412 		}
11413 		return matched_policy_id;
11414 	}
11415 
11416 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11417 
11418 	// Process packet to get relevant fields
11419 	ip = mtod(packet, struct ip *);
11420 #ifdef _IP_VHL
11421 	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11422 #else
11423 	hlen = ip->ip_hl << 2;
11424 #endif
11425 
11426 	protocol = ip->ip_p;
11427 
11428 	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11429 	    (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11430 	    ipoa->ipoa_boundif != IFSCOPE_NONE) {
11431 		bound_interface_index = ipoa->ipoa_boundif;
11432 	}
11433 
11434 	local_addr.sin.sin_family = AF_INET;
11435 	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11436 	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11437 
11438 	remote_addr.sin.sin_family = AF_INET;
11439 	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11440 	memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11441 
11442 	switch (protocol) {
11443 	case IPPROTO_TCP: {
11444 		struct tcphdr th;
11445 		if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11446 			m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11447 			SIN(&local_addr)->sin_port = th.th_sport;
11448 			SIN(&remote_addr)->sin_port = th.th_dport;
11449 		}
11450 		break;
11451 	}
11452 	case IPPROTO_UDP: {
11453 		struct udphdr uh;
11454 		if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11455 			m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11456 			SIN(&local_addr)->sin_port = uh.uh_sport;
11457 			SIN(&remote_addr)->sin_port = uh.uh_dport;
11458 		}
11459 		break;
11460 	}
11461 	default: {
11462 		SIN(&local_addr)->sin_port = 0;
11463 		SIN(&remote_addr)->sin_port = 0;
11464 		break;
11465 	}
11466 	}
11467 
11468 	// Match packet to policy
11469 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11470 	u_int32_t route_rule_id = 0;
11471 
11472 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11473 	NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11474 
11475 	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);
11476 	if (matched_policy) {
11477 		matched_policy_id = matched_policy->id;
11478 		if (result) {
11479 			*result = matched_policy->result;
11480 		}
11481 
11482 		if (result_parameter) {
11483 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11484 		}
11485 
11486 		if (route_rule_id != 0 &&
11487 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11488 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11489 		}
11490 
11491 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11492 			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);
11493 		}
11494 	} else {
11495 		bool drop_all = false;
11496 		/*
11497 		 * Apply drop-all only to packets which have never matched a primary policy (check
11498 		 * if the packet saved policy id is none or falls within the socket policy id range).
11499 		 */
11500 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11501 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11502 			drop_all = true;
11503 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11504 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11505 			}
11506 		}
11507 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11508 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11509 			if (result) {
11510 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11511 				NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11512 			}
11513 		} else if (route_rule_id != 0 &&
11514 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11515 			// If we matched a route rule, mark it
11516 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11517 		}
11518 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11519 			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);
11520 		}
11521 	}
11522 
11523 	lck_rw_done(&necp_kernel_policy_lock);
11524 
11525 	return matched_policy_id;
11526 }
11527 
11528 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)11529 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11530     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11531 {
11532 	struct ip6_hdr *ip6 = NULL;
11533 	int next = -1;
11534 	int offset = 0;
11535 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11536 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11537 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11538 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11539 	u_int16_t protocol = 0;
11540 	u_int32_t bound_interface_index = 0;
11541 	u_int32_t last_interface_index = 0;
11542 	union necp_sockaddr_union local_addr = { };
11543 	union necp_sockaddr_union remote_addr = { };
11544 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11545 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11546 	u_int16_t pf_tag = 0;
11547 
11548 	if (result) {
11549 		*result = 0;
11550 	}
11551 
11552 	if (result_parameter) {
11553 		memset(result_parameter, 0, sizeof(*result_parameter));
11554 	}
11555 
11556 	if (packet == NULL) {
11557 		return NECP_KERNEL_POLICY_ID_NONE;
11558 	}
11559 
11560 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11561 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11562 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11563 
11564 	// Exit early for an empty list
11565 	// Don't lock. Possible race condition, but we don't want the performance hit.
11566 	if (necp_drop_management_order == 0 &&
11567 	    (necp_kernel_ip_output_policies_count == 0 ||
11568 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11569 		if (necp_drop_all_order > 0) {
11570 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11571 			if (result) {
11572 				if (necp_output_bypass(packet)) {
11573 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11574 				} else {
11575 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11576 				}
11577 			}
11578 		}
11579 
11580 		return matched_policy_id;
11581 	}
11582 
11583 	// Check for loopback exception
11584 	if (necp_output_bypass(packet)) {
11585 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11586 		if (result) {
11587 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11588 		}
11589 		return matched_policy_id;
11590 	}
11591 
11592 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11593 
11594 	// Process packet to get relevant fields
11595 	ip6 = mtod(packet, struct ip6_hdr *);
11596 
11597 	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11598 	    (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11599 	    ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11600 		bound_interface_index = ip6oa->ip6oa_boundif;
11601 	}
11602 
11603 	SIN6(&local_addr)->sin6_family = AF_INET6;
11604 	SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11605 	memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11606 
11607 	SIN6(&remote_addr)->sin6_family = AF_INET6;
11608 	SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11609 	memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11610 
11611 	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11612 	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11613 		protocol = next;
11614 		switch (protocol) {
11615 		case IPPROTO_TCP: {
11616 			struct tcphdr th;
11617 			if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11618 				m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11619 				SIN6(&local_addr)->sin6_port = th.th_sport;
11620 				SIN6(&remote_addr)->sin6_port = th.th_dport;
11621 			}
11622 			break;
11623 		}
11624 		case IPPROTO_UDP: {
11625 			struct udphdr uh;
11626 			if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11627 				m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11628 				SIN6(&local_addr)->sin6_port = uh.uh_sport;
11629 				SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11630 			}
11631 			break;
11632 		}
11633 		default: {
11634 			SIN6(&local_addr)->sin6_port = 0;
11635 			SIN6(&remote_addr)->sin6_port = 0;
11636 			break;
11637 		}
11638 		}
11639 	}
11640 
11641 	// Match packet to policy
11642 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11643 	u_int32_t route_rule_id = 0;
11644 
11645 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11646 	NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11647 
11648 	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);
11649 	if (matched_policy) {
11650 		matched_policy_id = matched_policy->id;
11651 		if (result) {
11652 			*result = matched_policy->result;
11653 		}
11654 
11655 		if (result_parameter) {
11656 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11657 		}
11658 
11659 		if (route_rule_id != 0 &&
11660 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11661 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11662 		}
11663 
11664 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11665 			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);
11666 		}
11667 	} else {
11668 		bool drop_all = false;
11669 		/*
11670 		 * Apply drop-all only to packets which have never matched a primary policy (check
11671 		 * if the packet saved policy id is none or falls within the socket policy id range).
11672 		 */
11673 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11674 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11675 			drop_all = true;
11676 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11677 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11678 			}
11679 		}
11680 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11681 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11682 			if (result) {
11683 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11684 				NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11685 			}
11686 		} else if (route_rule_id != 0 &&
11687 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11688 			// If we matched a route rule, mark it
11689 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11690 		}
11691 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11692 			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);
11693 		}
11694 	}
11695 
11696 	lck_rw_done(&necp_kernel_policy_lock);
11697 
11698 	return matched_policy_id;
11699 }
11700 
11701 // Utilities
11702 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11703 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11704 {
11705 	int cmp = 0;
11706 
11707 	if (addr == NULL || range_start == NULL || range_end == NULL) {
11708 		return FALSE;
11709 	}
11710 
11711 	/* Must be greater than or equal to start */
11712 	cmp = necp_addr_compare(addr, range_start, 1);
11713 	if (cmp != 0 && cmp != 1) {
11714 		return FALSE;
11715 	}
11716 
11717 	/* Must be less than or equal to end */
11718 	cmp = necp_addr_compare(addr, range_end, 1);
11719 	if (cmp != 0 && cmp != -1) {
11720 		return FALSE;
11721 	}
11722 
11723 	return TRUE;
11724 }
11725 
11726 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)11727 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11728 {
11729 	int cmp = 0;
11730 
11731 	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11732 		return FALSE;
11733 	}
11734 
11735 	/* Must be greater than or equal to start */
11736 	cmp = necp_addr_compare(inner_range_start, range_start, 1);
11737 	if (cmp != 0 && cmp != 1) {
11738 		return FALSE;
11739 	}
11740 
11741 	/* Must be less than or equal to end */
11742 	cmp = necp_addr_compare(inner_range_end, range_end, 1);
11743 	if (cmp != 0 && cmp != -1) {
11744 		return FALSE;
11745 	}
11746 
11747 	return TRUE;
11748 }
11749 
11750 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11751 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11752 {
11753 	if (addr == NULL || subnet_addr == NULL) {
11754 		return FALSE;
11755 	}
11756 
11757 	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11758 		return FALSE;
11759 	}
11760 
11761 	switch (addr->sa_family) {
11762 	case AF_INET: {
11763 		if (satosin(subnet_addr)->sin_port != 0 &&
11764 		    satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11765 			return FALSE;
11766 		}
11767 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11768 	}
11769 	case AF_INET6: {
11770 		if (satosin6(subnet_addr)->sin6_port != 0 &&
11771 		    satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11772 			return FALSE;
11773 		}
11774 		if (satosin6(addr)->sin6_scope_id &&
11775 		    satosin6(subnet_addr)->sin6_scope_id &&
11776 		    satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11777 			return FALSE;
11778 		}
11779 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11780 	}
11781 	default: {
11782 		return FALSE;
11783 	}
11784 	}
11785 
11786 	return FALSE;
11787 }
11788 
11789 /*
11790  * Return values:
11791  * -1: sa1 < sa2
11792  * 0: sa1 == sa2
11793  * 1: sa1 > sa2
11794  * 2: Not comparable or error
11795  */
11796 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11797 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11798 {
11799 	int result = 0;
11800 	int port_result = 0;
11801 
11802 	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11803 		return 2;
11804 	}
11805 
11806 	if (sa1->sa_len == 0) {
11807 		return 0;
11808 	}
11809 
11810 	switch (sa1->sa_family) {
11811 	case AF_INET: {
11812 		if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11813 			return 2;
11814 		}
11815 
11816 		result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11817 
11818 		if (check_port) {
11819 			if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11820 				port_result = -1;
11821 			} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11822 				port_result = 1;
11823 			}
11824 
11825 			if (result == 0) {
11826 				result = port_result;
11827 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11828 				return 2;
11829 			}
11830 		}
11831 
11832 		break;
11833 	}
11834 	case AF_INET6: {
11835 		if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11836 			return 2;
11837 		}
11838 
11839 		if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11840 			return 2;
11841 		}
11842 
11843 		result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11844 
11845 		if (check_port) {
11846 			if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11847 				port_result = -1;
11848 			} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11849 				port_result = 1;
11850 			}
11851 
11852 			if (result == 0) {
11853 				result = port_result;
11854 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11855 				return 2;
11856 			}
11857 		}
11858 
11859 		break;
11860 	}
11861 	default: {
11862 		result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11863 		break;
11864 	}
11865 	}
11866 
11867 	if (result < 0) {
11868 		result = (-1);
11869 	} else if (result > 0) {
11870 		result = (1);
11871 	}
11872 
11873 	return result;
11874 }
11875 
11876 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11877 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11878 {
11879 	u_int8_t mask;
11880 
11881 	/* Handle null pointers */
11882 	if (p1 == NULL || p2 == NULL) {
11883 		return p1 == p2;
11884 	}
11885 
11886 	while (bits >= 8) {
11887 		if (*p1++ != *p2++) {
11888 			return FALSE;
11889 		}
11890 		bits -= 8;
11891 	}
11892 
11893 	if (bits > 0) {
11894 		mask = ~((1 << (8 - bits)) - 1);
11895 		if ((*p1 & mask) != (*p2 & mask)) {
11896 			return FALSE;
11897 		}
11898 	}
11899 	return TRUE;
11900 }
11901 
11902 static bool
necp_addr_is_empty(struct sockaddr * addr)11903 necp_addr_is_empty(struct sockaddr *addr)
11904 {
11905 	if (addr == NULL) {
11906 		return TRUE;
11907 	}
11908 
11909 	if (addr->sa_len == 0) {
11910 		return TRUE;
11911 	}
11912 
11913 	switch (addr->sa_family) {
11914 	case AF_INET: {
11915 		static struct sockaddr_in ipv4_empty_address = {
11916 			.sin_len = sizeof(struct sockaddr_in),
11917 			.sin_family = AF_INET,
11918 			.sin_port = 0,
11919 			.sin_addr = { .s_addr = 0 }, // 0.0.0.0
11920 			.sin_zero = {0},
11921 		};
11922 		if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11923 			return TRUE;
11924 		} else {
11925 			return FALSE;
11926 		}
11927 	}
11928 	case AF_INET6: {
11929 		static struct sockaddr_in6 ipv6_empty_address = {
11930 			.sin6_len = sizeof(struct sockaddr_in6),
11931 			.sin6_family = AF_INET6,
11932 			.sin6_port = 0,
11933 			.sin6_flowinfo = 0,
11934 			.sin6_addr = IN6ADDR_ANY_INIT, // ::
11935 			.sin6_scope_id = 0,
11936 		};
11937 		if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11938 			return TRUE;
11939 		} else {
11940 			return FALSE;
11941 		}
11942 	}
11943 	default:
11944 		return FALSE;
11945 	}
11946 
11947 	return FALSE;
11948 }
11949 
11950 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)11951 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)
11952 {
11953 	bool qos_marking = FALSE;
11954 	int exception_index = 0;
11955 	struct necp_route_rule *route_rule = NULL;
11956 
11957 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11958 	if (route_rule == NULL) {
11959 		qos_marking = FALSE;
11960 		goto done;
11961 	}
11962 
11963 	if (route_rule->match_netagent_id != 0) {
11964 		if (netagent_array == NULL || netagent_array_count == 0) {
11965 			// No agents, ignore rule
11966 			goto done;
11967 		}
11968 		bool found_match = FALSE;
11969 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11970 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11971 				found_match = TRUE;
11972 				break;
11973 			}
11974 		}
11975 		if (!found_match) {
11976 			// Agents don't match, ignore rule
11977 			goto done;
11978 		}
11979 	}
11980 
11981 	qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11982 
11983 	if (ifp == NULL) {
11984 		goto done;
11985 	}
11986 
11987 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11988 		if (route_rule->exception_if_indices[exception_index] == 0) {
11989 			break;
11990 		}
11991 		if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11992 			continue;
11993 		}
11994 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11995 			qos_marking = TRUE;
11996 			if (necp_debug > 2) {
11997 				NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11998 				    route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11999 			}
12000 			goto done;
12001 		}
12002 	}
12003 
12004 	if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
12005 	    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
12006 	    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
12007 	    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
12008 	    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
12009 	    (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_ULTRA_CONSTRAINED(ifp)) ||
12010 	    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
12011 	    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
12012 		qos_marking = TRUE;
12013 		if (necp_debug > 2) {
12014 			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",
12015 			    route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
12016 			    route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action,
12017 			    route_rule->ultra_constrained_action, route_rule_id, qos_marking);
12018 		}
12019 		goto done;
12020 	}
12021 done:
12022 	if (necp_debug > 1) {
12023 		NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
12024 		    route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
12025 	}
12026 	return qos_marking;
12027 }
12028 
12029 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)12030 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)
12031 {
12032 	bool new_qos_marking = old_qos_marking;
12033 	struct ifnet *ifp = interface;
12034 
12035 	if (net_qos_policy_restricted == 0) {
12036 		return new_qos_marking;
12037 	}
12038 
12039 	/*
12040 	 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
12041 	 */
12042 	if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
12043 		return new_qos_marking;
12044 	}
12045 
12046 	lck_rw_lock_shared(&necp_kernel_policy_lock);
12047 
12048 	if (ifp == NULL && route != NULL) {
12049 		ifp = route->rt_ifp;
12050 	}
12051 	/*
12052 	 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
12053 	 */
12054 	if (ifp == NULL || route_rule_id == 0) {
12055 		new_qos_marking = FALSE;
12056 		goto done;
12057 	}
12058 
12059 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12060 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12061 		if (aggregate_route_rule != NULL) {
12062 			int index = 0;
12063 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12064 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12065 				if (sub_route_rule_id == 0) {
12066 					break;
12067 				}
12068 				new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
12069 				if (new_qos_marking == TRUE) {
12070 					break;
12071 				}
12072 			}
12073 		}
12074 	} else {
12075 		new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
12076 	}
12077 	/*
12078 	 * Now that we have an interface we remember the gencount
12079 	 */
12080 	*qos_marking_gencount = necp_kernel_socket_policies_gencount;
12081 
12082 done:
12083 	lck_rw_done(&necp_kernel_policy_lock);
12084 	return new_qos_marking;
12085 }
12086 
12087 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)12088 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
12089 {
12090 	bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
12091 
12092 	if (net_qos_policy_restricted == 0) {
12093 		return;
12094 	}
12095 	if (inp->inp_socket == NULL) {
12096 		return;
12097 	}
12098 	if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
12099 		return;
12100 	}
12101 
12102 	qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
12103 
12104 	if (qos_marking == TRUE) {
12105 		inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
12106 	} else {
12107 		inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
12108 	}
12109 }
12110 
12111 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)12112 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
12113 {
12114 	if (ifp != NULL &&
12115 	    (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12116 	    ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12117 		return true;
12118 	}
12119 	if (delegated_ifp != NULL &&
12120 	    (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
12121 	    delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
12122 		return true;
12123 	}
12124 	return false;
12125 }
12126 
12127 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)12128 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,
12129     u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied)
12130 {
12131 	bool default_is_allowed = TRUE;
12132 	u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
12133 	int exception_index = 0;
12134 	struct ifnet *delegated_ifp = NULL;
12135 	struct necp_route_rule *route_rule = NULL;
12136 
12137 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12138 	if (route_rule == NULL) {
12139 		return TRUE;
12140 	}
12141 
12142 	if (route_rule->match_netagent_id != 0) {
12143 		if (netagent_array == NULL || netagent_array_count == 0) {
12144 			// No agents, ignore rule
12145 			return TRUE;
12146 		}
12147 		bool found_match = FALSE;
12148 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12149 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12150 				found_match = TRUE;
12151 				break;
12152 			}
12153 		}
12154 		if (!found_match) {
12155 			// Agents don't match, ignore rule
12156 			return TRUE;
12157 		}
12158 	}
12159 
12160 	default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12161 	if (ifp == NULL && route != NULL) {
12162 		ifp = route->rt_ifp;
12163 	}
12164 	if (ifp == NULL) {
12165 		if (necp_debug > 1 && !default_is_allowed) {
12166 			NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12167 		}
12168 		return default_is_allowed;
12169 	}
12170 
12171 	delegated_ifp = ifp->if_delegated.ifp;
12172 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12173 		if (route_rule->exception_if_indices[exception_index] == 0) {
12174 			break;
12175 		}
12176 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12177 		    (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12178 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12179 				const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12180 				if (necp_debug > 1 && lqm_abort) {
12181 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12182 					    route_rule->exception_if_indices[exception_index], route_rule_id);
12183 				}
12184 				return false;
12185 			} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12186 				if (necp_debug > 1) {
12187 					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));
12188 				}
12189 				if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12190 					*interface_type_denied = route_rule->effective_type;
12191 				}
12192 				return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12193 			}
12194 		}
12195 	}
12196 
12197 	if (IFNET_IS_CELLULAR(ifp)) {
12198 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12199 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12200 				if (interface_type_denied != NULL) {
12201 					*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12202 					if (route_rule->effective_type != 0) {
12203 						*interface_type_denied = route_rule->effective_type;
12204 					}
12205 				}
12206 				// Mark aggregate action as deny
12207 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12208 			}
12209 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12210 			if (interface_type_denied != NULL) {
12211 				*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12212 				if (route_rule->effective_type != 0) {
12213 					*interface_type_denied = route_rule->effective_type;
12214 				}
12215 			}
12216 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12217 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12218 			    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12219 				// Deny wins if there is a conflict
12220 				type_aggregate_action = route_rule->cellular_action;
12221 			}
12222 		}
12223 	}
12224 
12225 	if (IFNET_IS_WIFI(ifp)) {
12226 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12227 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12228 				if (interface_type_denied != NULL) {
12229 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12230 					if (route_rule->effective_type != 0) {
12231 						*interface_type_denied = route_rule->effective_type;
12232 					}
12233 				}
12234 				// Mark aggregate action as deny
12235 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12236 			}
12237 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12238 			if (interface_type_denied != NULL) {
12239 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12240 				if (route_rule->effective_type != 0) {
12241 					*interface_type_denied = route_rule->effective_type;
12242 				}
12243 			}
12244 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12245 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12246 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12247 				// Deny wins if there is a conflict
12248 				type_aggregate_action = route_rule->wifi_action;
12249 			}
12250 		}
12251 	}
12252 
12253 	if (IFNET_IS_COMPANION_LINK(ifp) ||
12254 	    (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12255 		if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12256 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12257 				if (interface_type_denied != NULL) {
12258 					*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12259 					if (route_rule->effective_type != 0) {
12260 						*interface_type_denied = route_rule->effective_type;
12261 					}
12262 				}
12263 				// Mark aggregate action as deny
12264 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12265 			}
12266 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12267 			if (interface_type_denied != NULL) {
12268 				*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12269 				if (route_rule->effective_type != 0) {
12270 					*interface_type_denied = route_rule->effective_type;
12271 				}
12272 			}
12273 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12274 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12275 			    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12276 				// Deny wins if there is a conflict
12277 				type_aggregate_action = route_rule->companion_action;
12278 			}
12279 		}
12280 	}
12281 
12282 	if (IFNET_IS_WIRED(ifp)) {
12283 		if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12284 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12285 				if (interface_type_denied != NULL) {
12286 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12287 					if (route_rule->effective_type != 0) {
12288 						*interface_type_denied = route_rule->effective_type;
12289 					}
12290 				}
12291 				// Mark aggregate action as deny
12292 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12293 			}
12294 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12295 			if (interface_type_denied != NULL) {
12296 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12297 				if (route_rule->effective_type != 0) {
12298 					*interface_type_denied = route_rule->effective_type;
12299 				}
12300 			}
12301 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12302 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12303 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12304 				// Deny wins if there is a conflict
12305 				type_aggregate_action = route_rule->wired_action;
12306 			}
12307 		}
12308 	}
12309 
12310 	if (IFNET_IS_EXPENSIVE(ifp)) {
12311 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12312 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12313 				// Mark aggregate action as deny
12314 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12315 			}
12316 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12317 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12318 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12319 			    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12320 				// Deny wins if there is a conflict
12321 				type_aggregate_action = route_rule->expensive_action;
12322 			}
12323 		}
12324 	}
12325 
12326 	if (IFNET_IS_CONSTRAINED(ifp)) {
12327 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12328 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12329 				// Mark aggregate action as deny
12330 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12331 			}
12332 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12333 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12334 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12335 			    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12336 				// Deny wins if there is a conflict
12337 				type_aggregate_action = route_rule->constrained_action;
12338 			}
12339 		}
12340 	}
12341 
12342 	if (IFNET_IS_VPN(ifp)) {
12343 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12344 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12345 				// Mark aggregate action as deny
12346 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12347 			}
12348 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12349 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12350 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12351 			    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12352 				// Deny wins if there is a conflict
12353 				type_aggregate_action = route_rule->vpn_action;
12354 			}
12355 		}
12356 	}
12357 
12358 	if (IFNET_IS_ULTRA_CONSTRAINED(ifp)) {
12359 		if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12360 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12361 				// Mark aggregate action as deny
12362 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12363 			}
12364 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->ultra_constrained_action)) {
12365 			if (ultra_constrained_denied != NULL && IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action)) {
12366 				*ultra_constrained_denied = true;
12367 			}
12368 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12369 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12370 			    IS_NECP_ROUTE_RULE_DENY(route_rule->ultra_constrained_action))) {
12371 				// Deny wins if there is a conflict
12372 				type_aggregate_action = route_rule->ultra_constrained_action;
12373 			}
12374 		}
12375 	}
12376 
12377 	if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12378 		if (necp_debug > 1) {
12379 			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));
12380 		}
12381 		return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12382 	}
12383 
12384 	if (necp_debug > 1 && !default_is_allowed) {
12385 		NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12386 	}
12387 	return default_is_allowed;
12388 }
12389 
12390 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12391 necp_proc_is_allowed_on_management_interface(proc_t proc)
12392 {
12393 	bool allowed = false;
12394 	const task_t __single task = proc_task(proc);
12395 
12396 	if (task != NULL) {
12397 		if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12398 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12399 #if DEBUG || DEVELOPMENT
12400 		    || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12401 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12402 #endif /* DEBUG || DEVELOPMENT */
12403 		    ) {
12404 			allowed = true;
12405 		}
12406 	}
12407 	return allowed;
12408 }
12409 
12410 __attribute__((noinline))
12411 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12412 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12413 {
12414 	char buf[128];
12415 
12416 	if (inp != NULL) {
12417 		inp_snprintf_tuple(inp, buf, sizeof(buf));
12418 	} else {
12419 		*buf = 0;
12420 	}
12421 	os_log(OS_LOG_DEFAULT,
12422 	    "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12423 	    proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12424 	    proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12425 	    inp != NULL ? buf : "",
12426 	    ifp->if_xname);
12427 }
12428 
12429 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12430 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12431 {
12432 	if (if_management_interface_check_needed == false) {
12433 		return true;
12434 	}
12435 	if (necp_drop_management_order == 0) {
12436 		return true;
12437 	}
12438 	if (ifp == NULL && route != NULL) {
12439 		ifp = route->rt_ifp;
12440 	}
12441 	if (ifp == NULL) {
12442 		return true;
12443 	}
12444 
12445 	if (IFNET_IS_MANAGEMENT(ifp)) {
12446 		bool allowed = true;
12447 
12448 		if (inp != NULL) {
12449 			/*
12450 			 * The entitlement check is already performed for socket flows
12451 			 */
12452 			allowed = INP_MANAGEMENT_ALLOWED(inp);
12453 		} else if (proc != NULL) {
12454 			allowed = necp_proc_is_allowed_on_management_interface(proc);
12455 		}
12456 		if (__improbable(if_management_verbose > 1 && allowed == false)) {
12457 			necp_log_interface_not_allowed(ifp, proc, inp);
12458 		}
12459 		return allowed;
12460 	}
12461 	return true;
12462 }
12463 
12464 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)12465 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,
12466     u_int32_t route_rule_id, u_int32_t *interface_type_denied, bool *ultra_constrained_denied)
12467 {
12468 	if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12469 		if (necp_debug > 1) {
12470 			NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12471 		}
12472 		return TRUE;
12473 	}
12474 
12475 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12476 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12477 		if (aggregate_route_rule != NULL) {
12478 			int index = 0;
12479 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12480 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12481 				if (sub_route_rule_id == 0) {
12482 					break;
12483 				}
12484 				if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied, ultra_constrained_denied)) {
12485 					return FALSE;
12486 				}
12487 			}
12488 		}
12489 	} else {
12490 		return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied, ultra_constrained_denied);
12491 	}
12492 
12493 	return TRUE;
12494 }
12495 
12496 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12497 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12498 {
12499 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12500 	if (route_rule == NULL) {
12501 		return false;
12502 	}
12503 
12504 	return route_rule->match_netagent_id != 0;
12505 }
12506 
12507 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)12508 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)
12509 {
12510 	if (remove == NULL) {
12511 		return 0;
12512 	}
12513 
12514 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12515 	if (route_rule == NULL) {
12516 		return 0;
12517 	}
12518 
12519 	// No netagent, skip
12520 	if (route_rule->netagent_id == 0) {
12521 		return 0;
12522 	}
12523 
12524 	if (route_rule->match_netagent_id != 0) {
12525 		if (netagent_array == NULL || netagent_array_count == 0) {
12526 			// No agents, ignore rule
12527 			return 0;
12528 		}
12529 		bool found_match = FALSE;
12530 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12531 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12532 				found_match = TRUE;
12533 				break;
12534 			}
12535 		}
12536 		if (!found_match) {
12537 			// Agents don't match, ignore rule
12538 			return 0;
12539 		}
12540 	}
12541 
12542 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12543 	if (ifp == NULL) {
12544 		// No interface, apply the default action
12545 		if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12546 		    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12547 			*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12548 			return route_rule->netagent_id;
12549 		}
12550 		return 0;
12551 	}
12552 
12553 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12554 		if (route_rule->exception_if_indices[exception_index] == 0) {
12555 			break;
12556 		}
12557 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12558 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12559 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12560 			    route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12561 				*remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12562 				return route_rule->netagent_id;
12563 			}
12564 			return 0;
12565 		}
12566 	}
12567 
12568 	if (ifp->if_type == IFT_CELLULAR &&
12569 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12570 		if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12571 		    route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12572 			*remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12573 			return route_rule->netagent_id;
12574 		}
12575 		return 0;
12576 	}
12577 
12578 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12579 	    route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12580 		if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12581 		    route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12582 			*remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12583 			return route_rule->netagent_id;
12584 		}
12585 		return 0;
12586 	}
12587 
12588 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12589 	    route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12590 		if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12591 		    route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12592 			*remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12593 			return route_rule->netagent_id;
12594 		}
12595 		return 0;
12596 	}
12597 
12598 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12599 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12600 		if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12601 		    route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12602 			*remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12603 			return route_rule->netagent_id;
12604 		}
12605 		return 0;
12606 	}
12607 
12608 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12609 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12610 		if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12611 		    route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12612 			*remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12613 			return route_rule->netagent_id;
12614 		}
12615 		return 0;
12616 	}
12617 
12618 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12619 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12620 		if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12621 		    route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12622 			*remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12623 			return route_rule->netagent_id;
12624 		}
12625 		return 0;
12626 	}
12627 
12628 	if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12629 	    route_rule->ultra_constrained_action != NECP_ROUTE_RULE_NONE) {
12630 		if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12631 		    route_rule->ultra_constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12632 			*remove = (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12633 			return route_rule->netagent_id;
12634 		}
12635 		return 0;
12636 	}
12637 
12638 	if (ifp->if_xflags & IFXF_IS_VPN &&
12639 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12640 		if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12641 		    route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12642 			*remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12643 			return route_rule->netagent_id;
12644 		}
12645 		return 0;
12646 	}
12647 
12648 	// No more specific case matched, apply the default action
12649 	if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12650 	    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12651 		*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12652 		return route_rule->netagent_id;
12653 	}
12654 
12655 	return 0;
12656 }
12657 
12658 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)12659 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)
12660 {
12661 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12662 	if (route_rule == NULL) {
12663 		return 0;
12664 	}
12665 
12666 	// No control unit, skip
12667 	if (route_rule->control_unit == 0) {
12668 		return 0;
12669 	}
12670 
12671 	if (route_rule->match_netagent_id != 0) {
12672 		if (netagent_array == NULL || netagent_array_count == 0) {
12673 			// No agents, ignore rule
12674 			return 0;
12675 		}
12676 		bool found_match = FALSE;
12677 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12678 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12679 				found_match = TRUE;
12680 				break;
12681 			}
12682 		}
12683 		if (!found_match) {
12684 			// Agents don't match, ignore rule
12685 			return 0;
12686 		}
12687 	}
12688 
12689 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12690 	if (ifp == NULL) {
12691 		// No interface, apply the default action
12692 		if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12693 			return route_rule->control_unit;
12694 		}
12695 		return 0;
12696 	}
12697 
12698 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12699 		if (route_rule->exception_if_indices[exception_index] == 0) {
12700 			break;
12701 		}
12702 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12703 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12704 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12705 				return route_rule->control_unit;
12706 			}
12707 			return 0;
12708 		}
12709 	}
12710 
12711 	if (ifp->if_type == IFT_CELLULAR &&
12712 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12713 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12714 			return route_rule->control_unit;
12715 		}
12716 		return 0;
12717 	}
12718 
12719 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12720 	    route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12721 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12722 			return route_rule->control_unit;
12723 		}
12724 		return 0;
12725 	}
12726 
12727 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12728 	    route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12729 		if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12730 			return route_rule->control_unit;
12731 		}
12732 		return 0;
12733 	}
12734 
12735 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12736 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12737 		if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12738 			return route_rule->control_unit;
12739 		}
12740 		return 0;
12741 	}
12742 
12743 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12744 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12745 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12746 			return route_rule->control_unit;
12747 		}
12748 		return 0;
12749 	}
12750 
12751 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12752 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12753 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12754 			return route_rule->control_unit;
12755 		}
12756 		return 0;
12757 	}
12758 
12759 	if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12760 	    route_rule->ultra_constrained_action != NECP_ROUTE_RULE_NONE) {
12761 		if (route_rule->ultra_constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12762 			return route_rule->control_unit;
12763 		}
12764 		return 0;
12765 	}
12766 
12767 	if (ifp->if_xflags & IFXF_IS_VPN &&
12768 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12769 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12770 			return route_rule->control_unit;
12771 		}
12772 		return 0;
12773 	}
12774 
12775 	// No more specific case matched, apply the default action
12776 	if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12777 		return route_rule->control_unit;
12778 	}
12779 	return 0;
12780 }
12781 
12782 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)12783 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,
12784     u_int32_t *flow_divert_aggregate_unit)
12785 {
12786 	if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12787 		return 0;
12788 	}
12789 
12790 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12791 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12792 		if (aggregate_route_rule != NULL) {
12793 			int index = 0;
12794 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12795 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12796 				if (sub_route_rule_id == 0) {
12797 					break;
12798 				}
12799 				uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12800 				if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12801 					// For transparent proxies, accumulate the control unit and continue to the next route rule
12802 					*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12803 					continue;
12804 				}
12805 
12806 				if (control_unit != 0) {
12807 					return control_unit;
12808 				}
12809 			}
12810 		}
12811 	} else {
12812 		uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12813 		if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12814 			// For transparent proxies, accumulate the control unit and let the caller continue
12815 			*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12816 			return 0;
12817 		}
12818 		return control_unit;
12819 	}
12820 
12821 	return 0;
12822 }
12823 
12824 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12825 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12826 {
12827 	bool is_allowed = true;
12828 	u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12829 	if (route_rule_id != 0 &&
12830 	    interface != NULL) {
12831 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12832 		is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL, NULL);
12833 		lck_rw_done(&necp_kernel_policy_lock);
12834 	}
12835 	return is_allowed;
12836 }
12837 
12838 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12839 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12840 {
12841 	size_t netagent_cursor;
12842 	for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12843 		struct necp_uuid_id_mapping *mapping = NULL;
12844 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
12845 		if (netagent_id == 0) {
12846 			continue;
12847 		}
12848 		mapping = necp_uuid_lookup_uuid_with_agent_id_locked(netagent_id);
12849 		if (mapping != NULL) {
12850 			u_int32_t agent_flags = 0;
12851 			agent_flags = netagent_get_flags(mapping->uuid);
12852 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12853 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12854 					continue;
12855 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12856 					return FALSE;
12857 				}
12858 			}
12859 		}
12860 	}
12861 	return TRUE;
12862 }
12863 
12864 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12865 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12866 {
12867 	bool allowed_to_receive = TRUE;
12868 
12869 	if (pf_tag == PF_TAG_ID_STACK_DROP &&
12870 	    (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12871 		allowed_to_receive = FALSE;
12872 	}
12873 
12874 	return allowed_to_receive;
12875 }
12876 
12877 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)12878 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)
12879 {
12880 	u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12881 	bool allowed_to_receive = TRUE;
12882 	struct necp_socket_info info = {};
12883 	u_int32_t flowhash = 0;
12884 	u_int32_t route_rule_id = 0;
12885 	struct rtentry *route = NULL;
12886 	u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12887 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12888 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12889 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12890 	proc_t __single socket_proc = NULL;
12891 	necp_kernel_policy_filter filter_control_unit = 0;
12892 	u_int32_t pass_flags = 0;
12893 	u_int32_t flow_divert_aggregate_unit = 0;
12894 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12895 	int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12896 
12897 	memset(&netagent_ids, 0, sizeof(netagent_ids));
12898 
12899 	if (return_policy_id) {
12900 		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12901 	}
12902 	if (return_skip_policy_id) {
12903 		*return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12904 	}
12905 	if (return_route_rule_id) {
12906 		*return_route_rule_id = 0;
12907 	}
12908 	if (return_pass_flags) {
12909 		*return_pass_flags = 0;
12910 	}
12911 
12912 	if (inp == NULL) {
12913 		goto done;
12914 	}
12915 
12916 	route = inp->inp_route.ro_rt;
12917 
12918 	struct socket *so = inp->inp_socket;
12919 
12920 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12921 
12922 	// Don't lock. Possible race condition, but we don't want the performance hit.
12923 	if (necp_drop_management_order == 0 &&
12924 	    (necp_kernel_socket_policies_count == 0 ||
12925 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12926 		if (necp_drop_all_order > 0 || drop_order > 0) {
12927 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12928 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12929 				allowed_to_receive = TRUE;
12930 			} else {
12931 				allowed_to_receive = FALSE;
12932 			}
12933 		}
12934 		goto done;
12935 	}
12936 
12937 	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
12938 	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12939 		bool policies_have_changed = FALSE;
12940 		bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12941 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12942 			policies_have_changed = TRUE;
12943 		} else {
12944 			if (inp->inp_policyresult.results.route_rule_id != 0) {
12945 				lck_rw_lock_shared(&necp_kernel_policy_lock);
12946 				if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied, NULL)) {
12947 					route_allowed = FALSE;
12948 				}
12949 				lck_rw_done(&necp_kernel_policy_lock);
12950 			}
12951 		}
12952 
12953 		if (!policies_have_changed) {
12954 			if (debug) {
12955 				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);
12956 				debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12957 			}
12958 
12959 			if (!route_allowed ||
12960 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12961 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12962 			    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12963 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12964 				allowed_to_receive = FALSE;
12965 				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);
12966 			} else {
12967 				if (return_policy_id) {
12968 					*return_policy_id = inp->inp_policyresult.policy_id;
12969 				}
12970 				if (return_skip_policy_id) {
12971 					*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12972 				}
12973 				if (return_route_rule_id) {
12974 					*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12975 				}
12976 				if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12977 					pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12978 				}
12979 				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);
12980 			}
12981 			goto done;
12982 		}
12983 	}
12984 
12985 	// Check for loopback exception
12986 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12987 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12988 		allowed_to_receive = FALSE;
12989 		goto done;
12990 	}
12991 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12992 		allowed_to_receive = TRUE;
12993 		goto done;
12994 	}
12995 
12996 	// Actually calculate policy result
12997 	lck_rw_lock_shared(&necp_kernel_policy_lock);
12998 	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);
12999 
13000 	debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
13001 	NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
13002 
13003 	flowhash = necp_socket_calc_flowhash_locked(&info);
13004 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13005 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
13006 	    inp->inp_policyresult.flowhash == flowhash) {
13007 		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
13008 		    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13009 		    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13010 		    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
13011 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13012 		    (inp->inp_policyresult.results.route_rule_id != 0 &&
13013 		    !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied, NULL))) {
13014 			allowed_to_receive = FALSE;
13015 			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);
13016 		} else {
13017 			if (return_policy_id) {
13018 				*return_policy_id = inp->inp_policyresult.policy_id;
13019 			}
13020 			if (return_route_rule_id) {
13021 				*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13022 			}
13023 			if (return_skip_policy_id) {
13024 				*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13025 			}
13026 			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
13027 				pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
13028 			}
13029 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
13030 				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",
13031 				    inp->inp_socket, info.bound_interface_index, info.protocol,
13032 				    inp->inp_policyresult.policy_id,
13033 				    inp->inp_policyresult.skip_policy_id,
13034 				    inp->inp_policyresult.results.result,
13035 				    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
13036 			}
13037 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
13038 			    return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
13039 		}
13040 		lck_rw_done(&necp_kernel_policy_lock);
13041 		goto done;
13042 	}
13043 
13044 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
13045 	size_t route_rule_id_array_count = 0;
13046 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
13047 	struct necp_kernel_socket_policy *matched_policy =
13048 	    necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
13049 	    &info,
13050 	    &filter_control_unit,
13051 	    route_rule_id_array,
13052 	    &route_rule_id_array_count,
13053 	    MAX_AGGREGATE_ROUTE_RULES,
13054 	    netagent_ids,
13055 	    NECP_MAX_NETAGENTS,
13056 	    NULL,
13057 	    0,
13058 	    NULL,
13059 	    0,
13060 	    effective_proc,
13061 	    pf_tag,
13062 	    return_skip_policy_id,
13063 	    inp->inp_route.ro_rt,
13064 	    &drop_dest_policy_result,
13065 	    &drop_all_bypass,
13066 	    &flow_divert_aggregate_unit,
13067 	    so,
13068 	    debug);
13069 
13070 	// Check for loopback exception again after the policy match
13071 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
13072 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
13073 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
13074 		// If policies haven't changed since last evaluation, do not update filter result in order to
13075 		// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13076 		// allow content filter to detect and drop pre-existing flows.
13077 		uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13078 		int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13079 		if (info.soflow_entry != NULL) {
13080 			current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13081 			current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13082 		}
13083 		if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13084 		    current_filter_control_unit != filter_control_unit) {
13085 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13086 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13087 			if (info.soflow_entry != NULL) {
13088 				info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13089 				info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13090 			}
13091 		}
13092 		if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13093 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13094 		}
13095 		allowed_to_receive = TRUE;
13096 		lck_rw_done(&necp_kernel_policy_lock);
13097 
13098 		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);
13099 		goto done;
13100 	}
13101 
13102 	if (info.protocol != IPPROTO_UDP) {
13103 		goto skip_agent_check;
13104 	}
13105 
13106 	// Verify netagents
13107 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
13108 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
13109 			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);
13110 		}
13111 
13112 		// Mark socket as a drop if required agent is not active
13113 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13114 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13115 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13116 		inp->inp_policyresult.flowhash = flowhash;
13117 		inp->inp_policyresult.results.filter_control_unit = 0;
13118 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
13119 		inp->inp_policyresult.results.route_rule_id = 0;
13120 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
13121 		if (info.soflow_entry != NULL) {
13122 			info.soflow_entry->soflow_filter_control_unit = 0;
13123 			info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13124 		}
13125 
13126 		// Unlock
13127 		allowed_to_receive = FALSE;
13128 		lck_rw_done(&necp_kernel_policy_lock);
13129 
13130 		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);
13131 
13132 		goto done;
13133 	}
13134 
13135 skip_agent_check:
13136 
13137 	if (route_rule_id_array_count == 1) {
13138 		route_rule_id = route_rule_id_array[0];
13139 	} else if (route_rule_id_array_count > 1) {
13140 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
13141 	}
13142 
13143 	bool send_local_network_denied_event = false;
13144 	if (matched_policy != NULL) {
13145 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
13146 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
13147 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
13148 			// Trigger the event that we dropped due to a local network policy
13149 			send_local_network_denied_event = true;
13150 		}
13151 
13152 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
13153 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13154 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
13155 		    matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
13156 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
13157 		    (route_rule_id != 0 &&
13158 		    !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied, NULL)) ||
13159 		    !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
13160 			allowed_to_receive = FALSE;
13161 		} else {
13162 			if (return_policy_id) {
13163 				*return_policy_id = matched_policy->id;
13164 			}
13165 			if (return_route_rule_id) {
13166 				*return_route_rule_id = route_rule_id;
13167 			}
13168 			if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
13169 				pass_flags = matched_policy->result_parameter.pass_flags;
13170 			}
13171 			// If policies haven't changed since last evaluation, do not update filter result in order to
13172 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13173 			// allow content filter to detect and drop pre-existing flows.
13174 			uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13175 			int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13176 			if (info.soflow_entry != NULL) {
13177 				current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13178 				current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13179 			}
13180 			if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13181 			    current_filter_control_unit != filter_control_unit) {
13182 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13183 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13184 				if (info.soflow_entry != NULL) {
13185 					info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13186 					info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13187 				}
13188 			}
13189 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13190 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13191 			}
13192 		}
13193 
13194 		if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
13195 			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>",
13196 			    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);
13197 		}
13198 	} else {
13199 		bool drop_all = false;
13200 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
13201 			drop_all = true;
13202 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
13203 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
13204 			}
13205 		}
13206 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
13207 			allowed_to_receive = FALSE;
13208 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
13209 		} else {
13210 			if (return_policy_id) {
13211 				*return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13212 			}
13213 			if (return_route_rule_id) {
13214 				*return_route_rule_id = route_rule_id;
13215 			}
13216 
13217 			// If policies haven't changed since last evaluation, do not update filter result in order to
13218 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13219 			// allow content filter to detect and drop pre-existing flows.
13220 			uint32_t current_filter_control_unit = inp->inp_policyresult.results.filter_control_unit;
13221 			int32_t current_policies_gencount = inp->inp_policyresult.policy_gencount;
13222 			if (info.soflow_entry != NULL) {
13223 				current_filter_control_unit = info.soflow_entry->soflow_filter_control_unit;
13224 				current_policies_gencount = info.soflow_entry->soflow_policies_gencount;
13225 			}
13226 			if (current_policies_gencount != necp_kernel_socket_policies_gencount &&
13227 			    current_filter_control_unit != filter_control_unit) {
13228 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13229 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13230 				if (info.soflow_entry != NULL) {
13231 					info.soflow_entry->soflow_filter_control_unit = filter_control_unit;
13232 					info.soflow_entry->soflow_policies_gencount = necp_kernel_socket_policies_gencount;
13233 				}
13234 			}
13235 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13236 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13237 			}
13238 			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);
13239 		}
13240 	}
13241 
13242 	if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13243 		allowed_to_receive = FALSE;
13244 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13245 	}
13246 
13247 	lck_rw_done(&necp_kernel_policy_lock);
13248 
13249 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13250 		inp->inp_policyresult.network_denied_notifies++;
13251 #if defined(XNU_TARGET_OS_OSX)
13252 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13253 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13254 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13255 		    NETPOLICY_NETWORKTYPE_LOCAL);
13256 #else
13257 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13258 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13259 		    NETPOLICY_NETWORKTYPE_LOCAL);
13260 #endif
13261 	}
13262 
13263 done:
13264 	if (return_pass_flags != NULL) {
13265 		*return_pass_flags = pass_flags;
13266 	}
13267 
13268 	if (pf_tag != 0 && allowed_to_receive) {
13269 		allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13270 	}
13271 
13272 	if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13273 		soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13274 	}
13275 
13276 	if (socket_proc) {
13277 		proc_rele(socket_proc);
13278 	}
13279 
13280 	if (info.soflow_entry != NULL) {
13281 		soflow_free_flow(info.soflow_entry);
13282 	}
13283 
13284 	return allowed_to_receive;
13285 }
13286 
13287 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)13288 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)
13289 {
13290 	struct sockaddr_in local = {};
13291 	struct sockaddr_in remote = {};
13292 	local.sin_family = remote.sin_family = AF_INET;
13293 	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13294 	local.sin_port = local_port;
13295 	remote.sin_port = remote_port;
13296 	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13297 	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13298 
13299 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13300 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13301 }
13302 
13303 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)13304 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)
13305 {
13306 	struct sockaddr_in6 local = {};
13307 	struct sockaddr_in6 remote = {};
13308 	local.sin6_family = remote.sin6_family = AF_INET6;
13309 	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13310 	local.sin6_port = local_port;
13311 	remote.sin6_port = remote_port;
13312 	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13313 	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13314 
13315 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13316 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13317 }
13318 
13319 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)13320 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,
13321     u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13322 {
13323 	return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13324 	           return_policy_id, return_route_rule_id,
13325 	           return_skip_policy_id, return_pass_flags);
13326 }
13327 
13328 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)13329 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13330     necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13331 {
13332 	if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13333 		return EINVAL;
13334 	}
13335 
13336 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13337 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13338 		    policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13339 	}
13340 
13341 	// Mark ID for Pass and IP Tunnel
13342 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13343 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13344 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13345 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13346 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13347 	} else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13348 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13349 		// This case is same as a PASS
13350 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13351 	} else {
13352 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13353 	}
13354 	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13355 	if (route_rule_id != 0) {
13356 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13357 	} else {
13358 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13359 	}
13360 	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);
13361 
13362 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13363 	    skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13364 		// Only mark the skip policy if it is a valid policy ID
13365 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13366 	} else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13367 	    inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13368 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13369 	} else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13370 		// Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13371 		// to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13372 		// See necp_get_skip_policy_id_from_packet() and
13373 		// necp_packet_should_skip_filters().
13374 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13375 	} else {
13376 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13377 	}
13378 
13379 	if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13380 	    ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13381 		m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13382 	}
13383 
13384 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13385 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13386 		    packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13387 	}
13388 
13389 	return 0;
13390 }
13391 
13392 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13393 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13394 {
13395 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13396 		return EINVAL;
13397 	}
13398 
13399 	// Mark ID for Pass and IP Tunnel
13400 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13401 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13402 	} else {
13403 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13404 	}
13405 
13406 	return 0;
13407 }
13408 
13409 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13410 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13411 {
13412 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13413 		return EINVAL;
13414 	}
13415 
13416 	// Mark ID for Pass and IP Tunnel
13417 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13418 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13419 	} else {
13420 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13421 	}
13422 
13423 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13424 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13425 	} else {
13426 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13427 	}
13428 	return 0;
13429 }
13430 
13431 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13432 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13433 {
13434 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13435 		return EINVAL;
13436 	}
13437 
13438 	// Mark ID for Pass and IP Tunnel
13439 	if (interface != NULL) {
13440 		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13441 	}
13442 
13443 	return 0;
13444 }
13445 
13446 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13447 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13448 {
13449 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13450 		return EINVAL;
13451 	}
13452 
13453 	if (is_keepalive) {
13454 		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13455 	} else {
13456 		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13457 	}
13458 
13459 	return 0;
13460 }
13461 
13462 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13463 necp_get_policy_id_from_packet(struct mbuf *packet)
13464 {
13465 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13466 		return NECP_KERNEL_POLICY_ID_NONE;
13467 	}
13468 
13469 	return packet->m_pkthdr.necp_mtag.necp_policy_id;
13470 }
13471 
13472 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13473 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13474 {
13475 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13476 		return NECP_KERNEL_POLICY_ID_NONE;
13477 	}
13478 
13479 	// Check for overloaded value. See necp_mark_packet_from_socket().
13480 	if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13481 		return NECP_KERNEL_POLICY_ID_NONE;
13482 	}
13483 
13484 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13485 }
13486 
13487 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13488 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13489 {
13490 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13491 		return 0;
13492 	}
13493 
13494 	return m_pftag(packet)->pftag_tag;
13495 }
13496 
13497 bool
necp_packet_should_skip_filters(struct mbuf * packet)13498 necp_packet_should_skip_filters(struct mbuf *packet)
13499 {
13500 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13501 		return false;
13502 	}
13503 
13504 	// Check for overloaded value. See necp_mark_packet_from_socket().
13505 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13506 }
13507 
13508 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13509 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13510 {
13511 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13512 		return 0;
13513 	}
13514 
13515 	return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13516 }
13517 
13518 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13519 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13520 {
13521 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13522 		return 0;
13523 	}
13524 
13525 	return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13526 }
13527 
13528 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13529 necp_get_app_uuid_from_packet(struct mbuf *packet,
13530     uuid_t app_uuid)
13531 {
13532 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13533 		return EINVAL;
13534 	}
13535 
13536 	bool found_mapping = FALSE;
13537 	if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13538 		lck_rw_lock_shared(&necp_kernel_policy_lock);
13539 		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);
13540 		struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13541 		if (entry != NULL) {
13542 			uuid_copy(app_uuid, entry->uuid);
13543 			found_mapping = true;
13544 		}
13545 		lck_rw_done(&necp_kernel_policy_lock);
13546 	}
13547 	if (!found_mapping) {
13548 		uuid_clear(app_uuid);
13549 	}
13550 	return 0;
13551 }
13552 
13553 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13554 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13555 {
13556 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13557 		return FALSE;
13558 	}
13559 
13560 	return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13561 }
13562 
13563 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13564 necp_socket_get_content_filter_control_unit(struct socket *so)
13565 {
13566 	struct inpcb *inp = sotoinpcb(so);
13567 
13568 	if (inp == NULL) {
13569 		return 0;
13570 	}
13571 	return inp->inp_policyresult.results.filter_control_unit;
13572 }
13573 
13574 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13575 necp_socket_get_policy_gencount(struct socket *so)
13576 {
13577 	struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13578 
13579 	if (inp == NULL) {
13580 		return 0;
13581 	}
13582 	return inp->inp_policyresult.policy_gencount;
13583 }
13584 
13585 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13586 necp_socket_should_use_flow_divert(struct inpcb *inp)
13587 {
13588 	if (inp == NULL) {
13589 		return FALSE;
13590 	}
13591 
13592 	return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13593 	       (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13594 	       (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13595 }
13596 
13597 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13598 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13599 {
13600 	if (inp == NULL) {
13601 		return 0;
13602 	}
13603 
13604 	if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13605 		return 0;
13606 	}
13607 
13608 	if (aggregate_unit != NULL &&
13609 	    inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13610 		*aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13611 	}
13612 
13613 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13614 		return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13615 	}
13616 
13617 	return 0;
13618 }
13619 
13620 bool
necp_socket_should_rescope(struct inpcb * inp)13621 necp_socket_should_rescope(struct inpcb *inp)
13622 {
13623 	if (inp == NULL) {
13624 		return FALSE;
13625 	}
13626 
13627 	return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13628 	       inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13629 }
13630 
13631 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13632 necp_socket_get_rescope_if_index(struct inpcb *inp)
13633 {
13634 	if (inp == NULL) {
13635 		return 0;
13636 	}
13637 
13638 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13639 		return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13640 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13641 		return necp_get_primary_direct_interface_index();
13642 	}
13643 
13644 	return 0;
13645 }
13646 
13647 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13648 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13649 {
13650 	if (inp == NULL) {
13651 		return current_mtu;
13652 	}
13653 
13654 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13655 	    (inp->inp_flags & INP_BOUND_IF) &&
13656 	    inp->inp_boundifp) {
13657 		u_int bound_interface_index = inp->inp_boundifp->if_index;
13658 		u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13659 
13660 		// The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13661 		if (bound_interface_index != tunnel_interface_index) {
13662 			ifnet_t tunnel_interface = NULL;
13663 
13664 			ifnet_head_lock_shared();
13665 			tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13666 			ifnet_head_done();
13667 
13668 			if (tunnel_interface != NULL) {
13669 				u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13670 				u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13671 				const char ipsec_prefix[] = "ipsec";
13672 				if (delegate_tunnel_mtu != 0 &&
13673 				    strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13674 					// For ipsec interfaces, calculate the overhead from the delegate interface
13675 					u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13676 					if (delegate_tunnel_mtu > tunnel_overhead) {
13677 						delegate_tunnel_mtu -= tunnel_overhead;
13678 					}
13679 
13680 					if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13681 						// If the (delegate - overhead) < direct, return (delegate - overhead)
13682 						return delegate_tunnel_mtu;
13683 					} else {
13684 						// Otherwise return direct
13685 						return direct_tunnel_mtu;
13686 					}
13687 				} else {
13688 					// For non-ipsec interfaces, just return the tunnel MTU
13689 					return direct_tunnel_mtu;
13690 				}
13691 			}
13692 		}
13693 	}
13694 
13695 	// By default, just return the MTU passed in
13696 	return current_mtu;
13697 }
13698 
13699 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13700 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13701 {
13702 	if (result_parameter == NULL) {
13703 		return NULL;
13704 	}
13705 
13706 	return ifindex2ifnet[result_parameter->tunnel_interface_index];
13707 }
13708 
13709 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13710 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13711 {
13712 	bool found_match = FALSE;
13713 	bool can_rebind = FALSE;
13714 	ifaddr_t ifa;
13715 	union necp_sockaddr_union address_storage;
13716 
13717 	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13718 		return FALSE;
13719 	}
13720 
13721 	// Match source address against interface addresses
13722 	ifnet_lock_shared(interface);
13723 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13724 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13725 			if (address_storage.sa.sa_family != family) {
13726 				continue;
13727 			}
13728 
13729 			if (family == AF_INET) {
13730 				struct ip *ip = mtod(packet, struct ip *);
13731 				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13732 					found_match = TRUE;
13733 					break;
13734 				}
13735 			} else if (family == AF_INET6) {
13736 				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13737 				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13738 					found_match = TRUE;
13739 					break;
13740 				}
13741 			}
13742 		}
13743 	}
13744 	const uint32_t if_idx = interface->if_index;
13745 	ifnet_lock_done(interface);
13746 
13747 	// If source address matched, attempt to construct a route to the destination address
13748 	if (found_match) {
13749 		ROUTE_RELEASE(new_route);
13750 
13751 		if (family == AF_INET) {
13752 			struct ip *ip = mtod(packet, struct ip *);
13753 			struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13754 			dst4->sin_family = AF_INET;
13755 			dst4->sin_len = sizeof(struct sockaddr_in);
13756 			dst4->sin_addr = ip->ip_dst;
13757 			rtalloc_scoped(new_route, if_idx);
13758 			if (!ROUTE_UNUSABLE(new_route)) {
13759 				can_rebind = TRUE;
13760 			}
13761 		} else if (family == AF_INET6) {
13762 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13763 			struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13764 			dst6->sin6_family = AF_INET6;
13765 			dst6->sin6_len = sizeof(struct sockaddr_in6);
13766 			dst6->sin6_addr = ip6->ip6_dst;
13767 			rtalloc_scoped(new_route, if_idx);
13768 			if (!ROUTE_UNUSABLE(new_route)) {
13769 				can_rebind = TRUE;
13770 			}
13771 		}
13772 	}
13773 
13774 	return can_rebind;
13775 }
13776 
13777 static bool
necp_addr_is_loopback(struct sockaddr * address)13778 necp_addr_is_loopback(struct sockaddr *address)
13779 {
13780 	if (address == NULL) {
13781 		return FALSE;
13782 	}
13783 
13784 	if (address->sa_family == AF_INET) {
13785 		return IN_LOOPBACK(ntohl(SIN(address)->sin_addr.s_addr));
13786 	} else if (address->sa_family == AF_INET6) {
13787 		if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13788 			return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13789 		} else {
13790 			// Match ::ffff:127.0.0.1 loopback address
13791 			in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13792 			return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13793 		}
13794 	}
13795 
13796 	return FALSE;
13797 }
13798 
13799 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)13800 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13801 {
13802 	// Note: This function only checks for the loopback addresses.
13803 	// In the future, we may want to expand to also allow any traffic
13804 	// going through the loopback interface, but until then, this
13805 	// check is cheaper.
13806 
13807 	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13808 		return TRUE;
13809 	}
13810 
13811 	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13812 		return TRUE;
13813 	}
13814 
13815 	if (inp != NULL) {
13816 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13817 			return TRUE;
13818 		}
13819 		if (inp->inp_vflag & INP_IPV4) {
13820 			if (IN_LOOPBACK(ntohl(inp->inp_laddr.s_addr)) ||
13821 			    IN_LOOPBACK(ntohl(inp->inp_faddr.s_addr))) {
13822 				return TRUE;
13823 			}
13824 		} else if (inp->inp_vflag & INP_IPV6) {
13825 			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13826 			    IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13827 				return TRUE;
13828 			}
13829 		}
13830 	} else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13831 		return TRUE;
13832 	}
13833 
13834 	if (packet != NULL) {
13835 		struct ip *ip = mtod(packet, struct ip *);
13836 		if (ip->ip_v == 4) {
13837 			if (IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) {
13838 				return TRUE;
13839 			}
13840 			if (IN_LOOPBACK(ntohl(ip->ip_dst.s_addr))) {
13841 				return TRUE;
13842 			}
13843 		} else if (ip->ip_v == 6) {
13844 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13845 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13846 				return TRUE;
13847 			}
13848 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13849 				return TRUE;
13850 			}
13851 		}
13852 	}
13853 
13854 	return FALSE;
13855 }
13856 
13857 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13858 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13859 {
13860 	if (inp != NULL) {
13861 		if (!(inp->inp_vflag & INP_IPV6)) {
13862 			return false;
13863 		}
13864 		if (INP_INTCOPROC_ALLOWED(inp)) {
13865 			return true;
13866 		}
13867 		if ((inp->inp_flags & INP_BOUND_IF) &&
13868 		    IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13869 			return true;
13870 		}
13871 		return false;
13872 	}
13873 	if (packet != NULL) {
13874 		struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13875 		struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13876 		if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13877 		    NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13878 			return true;
13879 		}
13880 	}
13881 
13882 	return false;
13883 }
13884 
13885 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13886 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13887 {
13888 	char dest_str[MAX_IPv6_STR_LEN];
13889 
13890 	if (necp_drop_dest_debug > 0) {
13891 		if (sau->sa.sa_family == AF_INET) {
13892 			(void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13893 		} else if (sau->sa.sa_family == AF_INET6) {
13894 			(void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13895 		} else {
13896 			dest_str[0] = 0;
13897 		}
13898 	}
13899 	for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13900 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13901 		struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13902 
13903 		if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13904 			if (necp_drop_dest_debug > 0) {
13905 				char subnet_str[MAX_IPv6_STR_LEN];
13906 				struct proc *p = current_proc();
13907 				pid_t pid = proc_pid(p);
13908 
13909 				if (sau->sa.sa_family == AF_INET) {
13910 					(void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13911 					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);
13912 				} else if (sau->sa.sa_family == AF_INET6) {
13913 					(void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13914 					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);
13915 				}
13916 			}
13917 			return true;
13918 		}
13919 	}
13920 	if (necp_drop_dest_debug > 1) {
13921 		struct proc *p = current_proc();
13922 		pid_t pid = proc_pid(p);
13923 
13924 		os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13925 	}
13926 	return false;
13927 }
13928 
13929 static int
13930 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13931 {
13932 #pragma unused(arg1, arg2, oidp)
13933 	int changed = 0;
13934 	int error = 0;
13935 	struct necp_drop_dest_policy tmp_drop_dest_policy;
13936 	struct proc *p = current_proc();
13937 	pid_t pid = proc_pid(p);
13938 
13939 	if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13940 	    priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13941 		NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13942 		return EPERM;
13943 	}
13944 	if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13945 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13946 		return EINVAL;
13947 	}
13948 
13949 	memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13950 	error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13951 	if (error != 0) {
13952 		NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13953 		return error;
13954 	}
13955 	if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13956 		return error;
13957 	}
13958 
13959 	//
13960 	// Validate the passed parameters
13961 	//
13962 	if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13963 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13964 		return EINVAL;
13965 	}
13966 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13967 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13968 		struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13969 
13970 		switch (tmp_drop_dest_entry->level) {
13971 		case NECP_SESSION_PRIORITY_UNKNOWN:
13972 			if (tmp_drop_dest_policy.entry_count != 0) {
13973 				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);
13974 				return EINVAL;
13975 			}
13976 			break;
13977 		case NECP_SESSION_PRIORITY_CONTROL:
13978 		case NECP_SESSION_PRIORITY_CONTROL_1:
13979 		case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13980 		case NECP_SESSION_PRIORITY_HIGH:
13981 		case NECP_SESSION_PRIORITY_HIGH_1:
13982 		case NECP_SESSION_PRIORITY_HIGH_2:
13983 		case NECP_SESSION_PRIORITY_HIGH_3:
13984 		case NECP_SESSION_PRIORITY_HIGH_4:
13985 		case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13986 		case NECP_SESSION_PRIORITY_DEFAULT:
13987 		case NECP_SESSION_PRIORITY_LOW:
13988 			if (tmp_drop_dest_policy.entry_count == 0) {
13989 				NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13990 				return EINVAL;
13991 			}
13992 			break;
13993 		default: {
13994 			NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13995 			return EINVAL;
13996 		}
13997 		}
13998 
13999 		switch (npca->address.sa.sa_family) {
14000 		case AF_INET: {
14001 			if (npca->prefix > 32) {
14002 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
14003 				return EINVAL;
14004 			}
14005 			if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
14006 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
14007 				return EINVAL;
14008 			}
14009 			if (npca->address.sin.sin_port != 0) {
14010 				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);
14011 				return EINVAL;
14012 			}
14013 			break;
14014 		}
14015 		case AF_INET6: {
14016 			if (npca->prefix > 128) {
14017 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
14018 				return EINVAL;
14019 			}
14020 			if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
14021 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
14022 				return EINVAL;
14023 			}
14024 			if (npca->address.sin6.sin6_port != 0) {
14025 				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);
14026 				return EINVAL;
14027 			}
14028 			if (npca->address.sin6.sin6_flowinfo != 0) {
14029 				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);
14030 				return EINVAL;
14031 			}
14032 			if (npca->address.sin6.sin6_scope_id != 0) {
14033 				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);
14034 				return EINVAL;
14035 			}
14036 			break;
14037 		}
14038 		default: {
14039 			return EINVAL;
14040 		}
14041 		}
14042 	}
14043 
14044 	//
14045 	// Commit the changed policy
14046 	//
14047 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
14048 	memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
14049 
14050 	necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
14051 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
14052 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
14053 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
14054 
14055 		memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
14056 
14057 		necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
14058 	}
14059 	lck_rw_done(&necp_kernel_policy_lock);
14060 
14061 	return 0;
14062 }
14063 
14064 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])14065 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
14066 {
14067 	uint16_t fam = address->sa.sa_family;
14068 	memset(addr_str, 0, MAX_IPv6_STR_LEN);
14069 	if (fam == AF_INET) {
14070 		(void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
14071 	} else if (fam == AF_INET6) {
14072 		(void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
14073 	}
14074 	return __unsafe_null_terminated_from_indexable(addr_str);
14075 }
14076