xref: /xnu-11215.61.5/bsd/net/necp.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1 /*
2  * Copyright (c) 2013-2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <string.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/malloc.h>
34 #include <sys/kernel.h>
35 #include <sys/kern_control.h>
36 #include <sys/mbuf.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/proc_uuid_policy.h>
39 #include <net/if.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/coalition.h>
45 #include <sys/ubc.h>
46 #include <sys/codesign.h>
47 #include <kern/cs_blobs.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip6.h>
50 #include <netinet/tcp.h>
51 #include <netinet/tcp_var.h>
52 #include <netinet/tcp_cache.h>
53 #include <netinet/udp.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/in_tclass.h>
56 #include <netinet6/esp.h>
57 #include <net/flowhash.h>
58 #include <net/bloom_filter.h>
59 #include <net/if_var.h>
60 #include <net/pfvar.h>
61 #if SKYWALK
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) */
64 #include <sys/kauth.h>
65 #include <sys/sysctl.h>
66 #include <sys/sysproto.h>
67 #include <sys/priv.h>
68 #include <sys/kern_event.h>
69 #include <sys/file_internal.h>
70 #include <IOKit/IOBSD.h>
71 #include <libkern/crypto/rand.h>
72 #include <corecrypto/cchmac.h>
73 #include <corecrypto/ccsha2.h>
74 #include <os/refcnt.h>
75 #include <mach-o/loader.h>
76 #include <net/network_agent.h>
77 #include <net/necp.h>
78 #include <netinet/flow_divert_proto.h>
79 #include <kern/socket_flows.h>
80 
81 #include <net/sockaddr_utils.h>
82 #include <net/trie_utility.h>
83 
84 /*
85  * NECP - Network Extension Control Policy database
86  * ------------------------------------------------
87  * The goal of this module is to allow clients connecting via a
88  * policy file descriptor to create high-level policy sessions, which
89  * are ingested into low-level kernel policies that control and tag
90  * traffic at the application, socket, and IP layers.
91  *
92  * ------------------------------------------------
93  * Sessions
94  * ------------------------------------------------
95  * Each session owns a list of session policies, each of which can
96  * specify any combination of conditions and a single result. Each
97  * session also has a priority level (such as High, Default, or Low)
98  * which is requested by the client. Based on the requested level,
99  * a session order value is assigned to the session, which will be used
100  * to sort kernel policies generated by the session. The session client
101  * can specify the sub-order for each policy it creates which will be
102  * used to further sort the kernel policies.
103  *
104  *  Policy fd --> 1 necp_session --> list of necp_session_policy structs
105  *
106  * ------------------------------------------------
107  * Kernel Policies
108  * ------------------------------------------------
109  * Whenever a session send the Apply command, its policies are ingested
110  * and generate kernel policies. There are two phases of kernel policy
111  * ingestion.
112  *
113  * 1. The session policy is parsed to create kernel policies at the socket
114  *	  and IP layers, when applicable. For example, a policy that requires
115  *    all traffic from App1 to Pass will generate a socket kernel policy to
116  *    match App1 and mark packets with ID1, and also an IP policy to match
117  *    ID1 and let the packet pass. This is handled in necp_apply_policy. The
118  *    resulting kernel policies are added to the global socket and IP layer
119  *    policy lists.
120  *  necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
121  *                                      ||                             ||
122  *                                      \/                             \/
123  *                          necp_kernel_socket_policies   necp_kernel_ip_output_policies
124  *
125  * 2. Once the global lists of kernel policies have been filled out, each
126  *    list is traversed to create optimized sub-lists ("Maps") which are used during
127  *    data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
128  *    which hashes incoming packets based on marked socket-layer policies, and removes
129  *    duplicate or overlapping policies. Socket policies are sent into two maps,
130  *    necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
131  *    The app layer map is used for policy checks coming in from user space, and is one
132  *    list with duplicate and overlapping policies removed. The socket map hashes based
133  *    on app UUID, and removes duplicate and overlapping policies.
134  *  necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
135  *                            |-> necp_kernel_socket_policies_map
136  *
137  *  necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
138  *
139  * ------------------------------------------------
140  * Drop All Level
141  * ------------------------------------------------
142  * The Drop All Level is a sysctl that controls the level at which policies are allowed
143  * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
144  * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
145  * by a session with a priority level better than (numerically less than) the
146  * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
147  * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
148  * session orders to be dropped.
149  */
150 
151 u_int32_t necp_drop_all_order = 0;
152 u_int32_t necp_drop_all_level = 0;
153 
154 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
155 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
156 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
157 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
158 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
159 
160 u_int32_t necp_drop_unentitled_order = 0;
161 #ifdef XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
163 #else // XNU_TARGET_OS_WATCH
164 u_int32_t necp_drop_unentitled_level = 0;
165 #endif // XNU_TARGET_OS_WATCH
166 
167 u_int32_t necp_drop_management_order = 0;
168 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
169 
170 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
171 
172 os_log_t necp_log_handle = NULL;
173 os_log_t necp_data_trace_log_handle = NULL;
174 
175 u_int32_t necp_session_count = 0;
176 u_int32_t necp_trie_count = 0;
177 
178 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
179     struct necp_session_policy, NET_KT_DEFAULT);
180 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
181     struct necp_kernel_socket_policy, NET_KT_DEFAULT);
182 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
183     struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
184 
185 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do {          \
186 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) {  \
187 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
188 	} else {                                                                                                                                                \
189 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
190 	                if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) {      \
191 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
192 	                        break;                                                                                                                          \
193 	                }                                                                                                                                               \
194 	        }                                                                                                                                                       \
195 	}                                                                                                                                                               \
196 } while (0)
197 
198 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do {      \
199 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) {                                                                                                               \
200 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
201 	} else {                                                                                                                                                \
202 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
203 	                if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) {         \
204 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
205 	                        break;                                                                                                                          \
206 	                }                                                                                                                                               \
207 	        }                                                                                                                                                       \
208 	}                                                                                                                                                               \
209 } while (0)
210 
211 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
212 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) {                                                                                                                      \
213 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
214 	} else {                                                                                                                                                \
215 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
216 	                if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield)))	{ \
217 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
218 	                        break;                                                                                                                          \
219 	                }                                                                                                                                               \
220 	        }                                                                                                                                                       \
221 	}                                                                                                                                                               \
222 } while (0)
223 
224 #define IS_NECP_ROUTE_RULE_DENY(x)     ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
225 
226 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x)     (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
227 
228 #define NECP_KERNEL_CONDITION_ALL_INTERFACES            0x000001
229 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE           0x000002
230 #define NECP_KERNEL_CONDITION_PROTOCOL                          0x000004
231 #define NECP_KERNEL_CONDITION_LOCAL_START                       0x000008
232 #define NECP_KERNEL_CONDITION_LOCAL_END                         0x000010
233 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX                      0x000020
234 #define NECP_KERNEL_CONDITION_REMOTE_START                      0x000040
235 #define NECP_KERNEL_CONDITION_REMOTE_END                        0x000080
236 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX                     0x000100
237 #define NECP_KERNEL_CONDITION_APP_ID                            0x000200
238 #define NECP_KERNEL_CONDITION_REAL_APP_ID                       0x000400
239 #define NECP_KERNEL_CONDITION_DOMAIN                            0x000800
240 #define NECP_KERNEL_CONDITION_ACCOUNT_ID                        0x001000
241 #define NECP_KERNEL_CONDITION_POLICY_ID                         0x002000
242 #define NECP_KERNEL_CONDITION_PID                                       0x004000
243 #define NECP_KERNEL_CONDITION_UID                                       0x008000
244 #define NECP_KERNEL_CONDITION_LAST_INTERFACE            0x010000                        // Only set from packets looping between interfaces
245 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS                     0x020000
246 #define NECP_KERNEL_CONDITION_ENTITLEMENT                       0x040000
247 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT        0x080000
248 #define NECP_KERNEL_CONDITION_AGENT_TYPE                        0x100000
249 #define NECP_KERNEL_CONDITION_HAS_CLIENT                        0x200000
250 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS                    0x400000
251 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS                      0x800000
252 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY                       0x1000000
253 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY                      0x2000000
254 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY                   0x4000000
255 #define NECP_KERNEL_CONDITION_SDK_VERSION                       0x8000000
256 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER                0x10000000
257 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS                0x20000000
258 #define NECP_KERNEL_CONDITION_IS_LOOPBACK                       0x40000000
259 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY       0x80000000
260 #define NECP_KERNEL_CONDITION_SCHEME_PORT                       0x100000000
261 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER                     0x200000000
262 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT              0x400000000
263 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN                      0x800000000
264 #define NECP_KERNEL_CONDITION_REAL_UID                          0x1000000000
265 #define NECP_KERNEL_CONDITION_URL                               0x2000000000
266 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS             0x4000000000
267 
268 #define NECP_MAX_POLICY_RESULT_SIZE                                     512
269 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE                         1024
270 #define NECP_MAX_CONDITIONS_ARRAY_SIZE                          4096
271 #define NECP_MAX_POLICY_LIST_COUNT                                      1024
272 
273 #define NECP_MAX_DOMAIN_FILTER_SIZE                             65536 // Allows room for 100K domains
274 #define NECP_MAX_DOMAIN_TRIE_SIZE                               (1024 * 512) // Allows 5000+ domains
275 
276 typedef enum {
277 	NECP_BYPASS_TYPE_NONE = 0,
278 	NECP_BYPASS_TYPE_INTCOPROC = 1,
279 	NECP_BYPASS_TYPE_LOOPBACK = 2,
280 	NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
281 } necp_socket_bypass_type_t;
282 
283 // Cap the policy size at the max result + conditions size, with room for extra TLVs
284 #define NECP_MAX_POLICY_SIZE                                            (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
285 
286 struct necp_service_registration {
287 	LIST_ENTRY(necp_service_registration)   session_chain;
288 	LIST_ENTRY(necp_service_registration)   kernel_chain;
289 	u_int32_t                                                               service_id;
290 };
291 
292 struct necp_domain_filter {
293 	LIST_ENTRY(necp_domain_filter) owner_chain;
294 	LIST_ENTRY(necp_domain_filter) chain;
295 	u_int32_t       id;
296 	struct net_bloom_filter *filter;
297 	os_refcnt_t     refcount;
298 };
299 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
300 
301 /*
302  * Filter id space is split between domain bloom filter id and domain trie filter id.
303  * id <= 10000 - bloom filter ids
304  * id > 10000 - trie filter ids
305  */
306 #define NECP_DOMAIN_FILTER_ID_MAX           10000
307 #define NECP_DOMAIN_TRIE_ID_START           NECP_DOMAIN_FILTER_ID_MAX
308 #define NECP_IS_DOMAIN_FILTER_ID(id)        (id <= NECP_DOMAIN_FILTER_ID_MAX)
309 
310 struct necp_domain_trie {
311 	LIST_ENTRY(necp_domain_trie) owner_chain;
312 	LIST_ENTRY(necp_domain_trie) chain;
313 	u_int32_t       id;
314 	struct necp_domain_trie_request *trie_request;
315 	size_t trie_request_size;
316 	struct net_trie trie;
317 	os_refcnt_t     refcount;
318 };
319 static LIST_HEAD(necp_domain_trie_list, necp_domain_trie) necp_global_domain_trie_list;
320 
321 struct necp_session {
322 	u_int8_t                                        necp_fd_type;
323 	u_int32_t                                       control_unit;
324 	u_int32_t                                       session_priority; // Descriptive priority rating
325 	u_int32_t                                       session_order;
326 
327 	necp_policy_id                          last_policy_id;
328 
329 	decl_lck_mtx_data(, lock);
330 
331 	bool                                            proc_locked; // Messages must come from proc_uuid
332 	uuid_t                                          proc_uuid;
333 	int                                                     proc_pid;
334 
335 	bool                                            dirty;
336 	LIST_HEAD(_policies, necp_session_policy) policies;
337 
338 	LIST_HEAD(_services, necp_service_registration) services;
339 	struct necp_domain_filter_list domain_filters;
340 	struct necp_domain_trie_list domain_tries;
341 
342 	TAILQ_ENTRY(necp_session) chain;
343 };
344 
345 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
346 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
347 
348 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
349 
350 struct necp_socket_info {
351 	pid_t pid;
352 	int32_t pid_version;
353 	uid_t uid;
354 	uid_t real_uid;
355 	union necp_sockaddr_union local_addr;
356 	union necp_sockaddr_union remote_addr;
357 	u_int32_t bound_interface_index;
358 	u_int32_t bound_interface_flags;
359 	u_int32_t bound_interface_eflags;
360 	u_int32_t bound_interface_xflags;
361 	u_int32_t traffic_class;
362 	u_int16_t protocol;
363 	u_int16_t scheme_port;
364 	u_int32_t application_id;
365 	u_int32_t real_application_id;
366 	u_int32_t account_id;
367 	u_int32_t drop_order;
368 	u_int32_t client_flags;
369 	char *domain __null_terminated;
370 	char *url __null_terminated;
371 	unsigned is_entitled : 1;
372 	unsigned has_client : 1;
373 	unsigned has_system_signed_result : 1;
374 	unsigned is_platform_binary : 1;
375 	unsigned used_responsible_pid : 1;
376 	unsigned is_loopback : 1;
377 	unsigned real_is_platform_binary : 1;
378 	unsigned is_delegated : 1;
379 	unsigned is_local : 1;
380 	unsigned __pad_bits : 7;
381 };
382 
383 static  LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
384 static  LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
385 static  LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
386     &necp_kernel_policy_mtx_attr);
387 
388 static  LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
389 static  LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
390 
391 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
392 
393 /*
394  * On modification, invalidate cached lookups by bumping the generation count.
395  * Other calls will need to take the slowpath of taking
396  * the subsystem lock.
397  */
398 static volatile int32_t necp_kernel_socket_policies_gencount;
399 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do {                                                     \
400 	if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) {      \
401 	        necp_kernel_socket_policies_gencount = 1;                                                                               \
402 	}                                                                                                                                                               \
403 } while (0)
404 
405 /*
406  * Drop-all Bypass:
407  * Allow priviledged processes to bypass the default drop-all
408  * via entitlement check.  For OSX, since entitlement check is
409  * not supported for configd, configd signing identity is checked
410  * instead.
411  */
412 #define SIGNING_ID_CONFIGD "com.apple.configd"
413 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
414 
415 typedef enum {
416 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
417 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
418 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
419 } necp_drop_all_bypass_check_result_t;
420 
421 static u_int64_t necp_kernel_application_policies_condition_mask;
422 static size_t necp_kernel_application_policies_count;
423 static u_int64_t necp_kernel_socket_policies_condition_mask;
424 static size_t necp_kernel_socket_policies_count;
425 static size_t necp_kernel_socket_policies_non_app_count;
426 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
427 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
428 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
429 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
430 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
431 static size_t necp_kernel_socket_policies_app_layer_map_count;
432 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
433 /*
434  * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
435  * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
436  * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
437  *
438  * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
439  */
440 
441 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
442 static size_t necp_kernel_ip_output_policies_count;
443 static size_t necp_kernel_ip_output_policies_non_id_count;
444 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
445 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
446 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
447 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
448 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
449 static struct necp_kernel_socket_policy pass_policy =
450 {
451 	.id = NECP_KERNEL_POLICY_ID_NO_MATCH,
452 	.result = NECP_KERNEL_POLICY_RESULT_PASS,
453 };
454 
455 static struct necp_session *necp_create_session(void);
456 static void necp_delete_session(struct necp_session *session);
457 
458 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
459     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
460 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
461 
462 #define MAX_RESULT_STRING_LEN 64
463 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);
464 
465 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);
466 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
467 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
468 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
469 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
470 static void necp_policy_apply_all(struct necp_session *session);
471 
472 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);
473 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
474 static bool necp_kernel_socket_policies_reprocess(void);
475 static bool necp_kernel_socket_policies_update_uuid_table(void);
476 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
477     struct necp_socket_info *info,
478     necp_kernel_policy_filter *return_filter,
479     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
480     size_t *return_route_rule_id_array_count,
481     size_t route_rule_id_array_count,
482     necp_kernel_policy_result *return_service_action,
483     necp_kernel_policy_service *return_service,
484     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
485     size_t netagent_array_count,
486     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
487     size_t netagent_use_flags_array_count,
488     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
489     u_int32_t num_required_agent_types,
490     proc_t proc,
491     u_int16_t pf_tag,
492     necp_kernel_policy_id *skip_policy_id,
493     struct rtentry *rt,
494     necp_kernel_policy_result *return_drop_dest_policy_result,
495     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
496     u_int32_t *return_flow_divert_aggregate_unit,
497     struct socket *so,
498     int debug);
499 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);
500 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
501 static bool necp_kernel_ip_output_policies_reprocess(void);
502 
503 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
504 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);
505 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
506 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
507 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
508 static bool necp_addr_is_empty(struct sockaddr *addr);
509 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);
510 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
511 
512 struct necp_uuid_id_mapping {
513 	LIST_ENTRY(necp_uuid_id_mapping) chain;
514 	uuid_t          uuid;
515 	u_int32_t       id;
516 	os_refcnt_t     refcount;
517 	u_int32_t       table_usecount; // Add to UUID policy table count
518 };
519 static size_t necp_num_uuid_app_id_mappings;
520 static bool necp_uuid_app_id_mappings_dirty;
521 #define NECP_UUID_APP_ID_HASH_SIZE 64
522 static u_long necp_uuid_app_id_hash_mask;
523 static u_long necp_uuid_app_id_hash_num_buckets;
524 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * __counted_by(necp_uuid_app_id_hash_num_buckets) necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
525 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
526 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
527 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
528 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
529 
530 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
531 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
532 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
533 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
534 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
535 
536 struct necp_string_id_mapping {
537 	LIST_ENTRY(necp_string_id_mapping) chain;
538 	char            *string __null_terminated;
539 	necp_app_id     id;
540 	os_refcnt_t     refcount;
541 };
542 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
543 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
544 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
545 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
546 
547 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);
548 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
549 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
550 
551 static u_int32_t necp_create_domain_trie(struct necp_domain_trie_list *list, struct necp_domain_trie_list *owner_list,
552     struct necp_domain_trie_request *necp_trie_request, size_t necp_trie_request_size);
553 static bool necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id);
554 static void necp_free_domain_trie(struct necp_domain_trie *trie);
555 static struct necp_domain_trie *necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id);
556 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);
557 
558 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
559 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
560 
561 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
562 
563 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
564 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
565 
566 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
567 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);
568 
569 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
570 
571 #define MAX_ROUTE_RULE_INTERFACES 10
572 struct necp_route_rule {
573 	LIST_ENTRY(necp_route_rule) chain;
574 	u_int32_t       id;
575 	u_int32_t       netagent_id;
576 	u_int32_t       control_unit;
577 	u_int32_t       match_netagent_id;
578 	u_int32_t       effective_type;
579 	u_int8_t        default_action;
580 	u_int8_t        cellular_action;
581 	u_int8_t        wifi_action;
582 	u_int8_t        wired_action;
583 	u_int8_t        expensive_action;
584 	u_int8_t        constrained_action;
585 	u_int8_t        companion_action;
586 	u_int8_t        vpn_action;
587 	u_int           exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
588 	u_int8_t        exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
589 	os_refcnt_t     refcount;
590 };
591 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
592 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);
593 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
594 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
595 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,
596     u_int32_t route_rule_id, u_int32_t *interface_type_denied);
597 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);
598 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
599 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);
600 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
601 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
602 
603 #define MAX_AGGREGATE_ROUTE_RULES 16
604 struct necp_aggregate_route_rule {
605 	LIST_ENTRY(necp_aggregate_route_rule) chain;
606 	u_int32_t       id;
607 	u_int32_t       rule_ids[MAX_AGGREGATE_ROUTE_RULES];
608 };
609 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
610 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
611 
612 // Sysctl definitions
613 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
614 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
615 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
616 
617 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
618 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
619 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
620 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
621 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
622 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
623 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
624 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", "");
625 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", "");
626 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", "");
627 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
628 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, "");
629 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
630 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
631 SYSCTL_INT(_net_necp, NECPCTL_TRIE_COUNT, trie_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_trie_count, 0, "");
632 
633 static struct necp_drop_dest_policy necp_drop_dest_policy;
634 static int necp_drop_dest_debug = 0;    // 0: off, 1: match, >1: every evaluation
635 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
636 
637 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
638 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
639     0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
640 
641 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
642 
643 /*
644  * data tracing control -
645  *
646  * necp_data_tracing_level    : 1 for brief trace, 2 for policy details, 3 for condition details
647  * necp_data_tracing_port     : match traffic with specified port
648  * necp_data_tracing_proto    : match traffic with specified protocol
649  * necp_data_tracing_pid      : match traffic with specified pid (only applied at socket level)
650  * necp_data_tracing_ifindex  : match traffic on specified ifindex
651  * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched.  Default is 0 to trace traffic if any specified attributes matched.
652  * data_tracing_session_order     : match policies in the specified session - log traffic that hit these policies
653  * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
654  */
655 static int necp_data_tracing_level = 0;
656 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
657 
658 static int necp_data_tracing_port = 0;
659 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
660 
661 static int necp_data_tracing_proto = 0;
662 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
663 
664 static int necp_data_tracing_pid = 0;
665 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
666 
667 static int necp_data_tracing_ifindex = 0;
668 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
669 
670 static int necp_data_tracing_match_all = 0;
671 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
672 
673 static int necp_data_tracing_session_order = 0;
674 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
675 
676 static int necp_data_tracing_policy_order = 0;
677 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
678 
679 #define NECP_DATA_TRACE_LEVEL_BRIEF     1
680 #define NECP_DATA_TRACE_LEVEL_POLICY    2
681 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
682 #define NECP_DATA_TRACE_LEVEL_DP        4
683 
684 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
685     (pid == necp_data_tracing_pid)
686 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
687     (protocol == necp_data_tracing_proto)
688 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
689     (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
690 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
691     (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
692 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
693 	(ifindex == necp_data_tracing_ifindex)
694 
695 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
696     ((necp_data_tracing_level && \
697 	((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
698 	(necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
699 	(necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
700 	(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)
701 
702 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
703     ((necp_data_tracing_level && \
704 	((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
705 	(!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
706 	(!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
707 	(!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)
708 
709 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
710     (necp_data_tracing_match_all ? \
711 	NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
712 	NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
713 
714 #define NECP_DATA_TRACE_ON(debug) (debug)
715 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
716 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
717 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
718 
719 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
720 
721 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
722     if (NECP_DATA_TRACE_ON(debug)) { \
723     char laddr_str[MAX_IPv6_STR_LEN]; \
724     char raddr_str[MAX_IPv6_STR_LEN]; \
725     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>", \
726 	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); \
727     }
728 
729 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
730     if (NECP_DATA_TRACE_ON(debug)) { \
731     char laddr_str[MAX_IPv6_STR_LEN]; \
732     char raddr_str[MAX_IPv6_STR_LEN]; \
733     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>", \
734 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); \
735     }
736 
737 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
738     if (NECP_DATA_TRACE_ON(debug)) { \
739     char laddr_str[MAX_IPv6_STR_LEN]; \
740     char raddr_str[MAX_IPv6_STR_LEN]; \
741     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>", \
742 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); \
743     }
744 
745 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
746     if (NECP_DATA_TRACE_ON(debug)) { \
747     char laddr_str[MAX_IPv6_STR_LEN]; \
748     char raddr_str[MAX_IPv6_STR_LEN]; \
749     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)", \
750 	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]); \
751     }
752 
753 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
754     if (NECP_DATA_TRACE_ON(debug)) { \
755     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
756 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
757     }
758 
759 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
760     if (NECP_DATA_TRACE_ON(debug)) { \
761     char laddr_str[MAX_IPv6_STR_LEN]; \
762     char raddr_str[MAX_IPv6_STR_LEN]; \
763     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>", \
764 	        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)); \
765     }
766 
767 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
768     if (NECP_DATA_TRACE_ON(debug)) { \
769     char laddr_str[MAX_IPv6_STR_LEN]; \
770     char raddr_str[MAX_IPv6_STR_LEN]; \
771     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>", \
772 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); \
773     }
774 
775 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
776     if (NECP_DATA_TRACE_ON(debug)) { \
777     char laddr_str[MAX_IPv6_STR_LEN]; \
778     char raddr_str[MAX_IPv6_STR_LEN]; \
779     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)", \
780 	    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]); \
781     }
782 
783 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
784     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
785     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)", \
786 	    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); \
787     }
788 
789 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
790     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
791     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)", \
792 	        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); \
793     }
794 
795 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
796     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
797     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)>", \
798 	        caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
799     }
800 
801 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
802     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
803     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
804 	    caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
805 	    input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
806     }
807 
808 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
809     NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
810 
811 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
812     NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
813 
814 
815 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
816     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
817     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)>", \
818 	    caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
819     }
820 
821 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
822     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
823     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
824 	caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
825 	input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
826     }
827 
828 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
829     NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
830 
831 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
832     NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
833 
834 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
835     (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
836      addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
837 
838 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
839 	"INVALID",
840 	"PASS",
841 	"SKIP",
842 	"DROP",
843 	"SOCKET_DIVERT",
844 	"SOCKET_FILTER",
845 	"IP_TUNNEL",
846 	"IP_FILTER",
847 	"TRIGGER",
848 	"TRIGGER_IF_NEEDED",
849 	"TRIGGER_SCOPED",
850 	"NO_TRIGGER_SCOPED",
851 	"SOCKET_SCOPED",
852 	"ROUTE_RULES",
853 	"USE_NETAGENT",
854 	"NETAGENT_SCOPED",
855 	"SCOPED_DIRECT",
856 	"ALLOW_UNENTITLED",
857 	"REMOVE_NETAGENT"
858 };
859 
860 
861 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
862 
863 static int necp_drop_loopback_count = 0;
864 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
865 
866 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)867 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
868 {
869 	bool is_interface_address = false;
870 	if (addr == NULL) {
871 		return false;
872 	}
873 
874 	// Clean up the address before comparison with interface addresses
875 	// Transform remote_addr into the ifaddr form
876 	// IPv6 Scope IDs are always embedded in the ifaddr list
877 	struct sockaddr_storage remote_address_sanitized;
878 	u_int ifscope = IFSCOPE_NONE;
879 	(void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
880 	SIN(&remote_address_sanitized)->sin_port = 0;
881 	if (remote_address_sanitized.ss_family == AF_INET6) {
882 		if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
883 			SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
884 		}
885 	}
886 
887 	// Check if remote address is an interface address
888 	struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
889 	if (ifa != NULL && ifa->ifa_ifp != NULL) {
890 		is_interface_address = true;
891 	}
892 	if (ifa != NULL) {
893 		ifaddr_release(ifa);
894 		ifa = NULL;
895 	}
896 
897 	return is_interface_address;
898 }
899 
900 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
901     ((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)))
902 
903 // Session order allocation
904 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)905 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
906 {
907 	u_int32_t new_order = 0;
908 
909 	// For now, just allocate 1000 orders for each priority
910 	if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
911 		priority = NECP_SESSION_PRIORITY_DEFAULT;
912 	}
913 
914 	// Use the control unit to decide the offset into the priority list
915 	new_order = (control_unit) + ((priority - 1) * 1000);
916 
917 	return new_order;
918 }
919 
920 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)921 necp_get_first_order_for_priority(u_int32_t priority)
922 {
923 	if (priority == 0) {
924 		return 0;
925 	}
926 	return ((priority - 1) * 1000) + 1;
927 }
928 
929 // Sysctl handler
930 static int
931 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
932 {
933 #pragma unused(arg1, arg2)
934 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
935 	necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
936 	return error;
937 }
938 
939 static int
940 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
941 {
942 #pragma unused(arg1, arg2)
943 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
944 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
945 	return error;
946 }
947 
948 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
949 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)950 _necp_process_drop_order_inner(kauth_cred_t cred)
951 {
952 	if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
953 	    priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
954 		return necp_drop_unentitled_order;
955 	} else {
956 		return 0;
957 	}
958 }
959 
960 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
961 #pragma GCC poison _necp_process_drop_order_inner
962 
963 static int
964 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
965 {
966 #pragma unused(arg1, arg2)
967 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
968 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
969 	return error;
970 }
971 
972 static inline bool
necp_socket_is_connected(struct inpcb * inp)973 necp_socket_is_connected(struct inpcb *inp)
974 {
975 	return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
976 }
977 
978 
979 // Session fd
980 
981 static int necp_session_op_close(struct fileglob *, vfs_context_t);
982 
983 static const struct fileops necp_session_fd_ops = {
984 	.fo_type     = DTYPE_NETPOLICY,
985 	.fo_read     = fo_no_read,
986 	.fo_write    = fo_no_write,
987 	.fo_ioctl    = fo_no_ioctl,
988 	.fo_select   = fo_no_select,
989 	.fo_close    = necp_session_op_close,
990 	.fo_drain    = fo_no_drain,
991 	.fo_kqfilter = fo_no_kqfilter,
992 };
993 
994 static inline int
necp_is_platform_binary(proc_t proc)995 necp_is_platform_binary(proc_t proc)
996 {
997 	return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
998 }
999 
1000 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)1001 necp_check_drop_all_bypass_result(proc_t proc)
1002 {
1003 	if (proc == NULL) {
1004 		proc = current_proc();
1005 		if (proc == NULL) {
1006 			return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1007 		}
1008 	}
1009 
1010 #if defined(XNU_TARGET_OS_OSX)
1011 	const char *signing_id __null_terminated = NULL;
1012 	const bool isConfigd = (necp_is_platform_binary(proc) &&
1013 	    (signing_id = cs_identity_get(proc)) &&
1014 	    (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
1015 	    (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
1016 	if (isConfigd) {
1017 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1018 	}
1019 #endif
1020 
1021 	const task_t __single task = proc_task(proc);
1022 	if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
1023 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
1024 	} else {
1025 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
1026 	}
1027 }
1028 
1029 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)1030 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
1031 {
1032 #pragma unused(uap)
1033 	int error = 0;
1034 	struct necp_session *session = NULL;
1035 	struct fileproc * __single fp = NULL;
1036 	int fd = -1;
1037 	uid_t uid = kauth_cred_getuid(kauth_cred_get());
1038 
1039 	if (!necp_is_platform_binary(p)) {
1040 		NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1041 		error = EACCES;
1042 		goto done;
1043 	}
1044 
1045 	if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1046 		NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1047 		error = EACCES;
1048 		goto done;
1049 	}
1050 
1051 	error = falloc(p, &fp, &fd);
1052 	if (error != 0) {
1053 		goto done;
1054 	}
1055 
1056 	session = necp_create_session();
1057 	if (session == NULL) {
1058 		error = ENOMEM;
1059 		goto done;
1060 	}
1061 
1062 	fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1063 	fp->fp_glob->fg_flag = 0;
1064 	fp->fp_glob->fg_ops = &necp_session_fd_ops;
1065 	fp_set_data(fp, session);
1066 
1067 	proc_fdlock(p);
1068 	procfdtbl_releasefd(p, fd, NULL);
1069 	fp_drop(p, fd, fp, 1);
1070 	proc_fdunlock(p);
1071 
1072 	*retval = fd;
1073 done:
1074 	if (error != 0) {
1075 		if (fp != NULL) {
1076 			fp_free(p, fd, fp);
1077 			fp = NULL;
1078 		}
1079 	}
1080 
1081 	return error;
1082 }
1083 
1084 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1085 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1086 {
1087 #pragma unused(ctx)
1088 	struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1089 	fg_set_data(fg, NULL);
1090 
1091 	if (session != NULL) {
1092 		necp_policy_mark_all_for_deletion(session);
1093 		necp_policy_apply_all(session);
1094 		necp_delete_session(session);
1095 		return 0;
1096 	} else {
1097 		return ENOENT;
1098 	}
1099 }
1100 
1101 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1102 necp_session_find_from_fd(struct proc *p, int fd,
1103     struct fileproc **fpp, struct necp_session **session)
1104 {
1105 	struct fileproc * __single fp = NULL;
1106 	int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1107 
1108 	if (error == 0) {
1109 		*fpp = fp;
1110 		*session = (struct necp_session *)fp_get_data(fp);
1111 		if ((*session)->necp_fd_type != necp_fd_type_session) {
1112 			// Not a client fd, ignore
1113 			fp_drop(p, fd, fp, 0);
1114 			error = EINVAL;
1115 		}
1116 	}
1117 
1118 	return error;
1119 }
1120 
1121 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1122 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1123 {
1124 	int error = 0;
1125 	u_int8_t * __indexable tlv_buffer = NULL;
1126 
1127 	if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1128 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1129 		error = EINVAL;
1130 		goto done;
1131 	}
1132 
1133 	if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1134 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1135 		error = EINVAL;
1136 		goto done;
1137 	}
1138 
1139 	if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1140 		error = ENOMEM;
1141 		goto done;
1142 	}
1143 
1144 	error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1145 	if (error != 0) {
1146 		NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1147 		goto done;
1148 	}
1149 
1150 	necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1151 	if (error != 0) {
1152 		NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1153 		goto done;
1154 	}
1155 
1156 	error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1157 	if (error != 0) {
1158 		NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1159 		goto done;
1160 	}
1161 
1162 done:
1163 	if (tlv_buffer != NULL) {
1164 		kfree_data(tlv_buffer, uap->in_buffer_length);
1165 		tlv_buffer = NULL;
1166 	}
1167 	*retval = error;
1168 
1169 	return error;
1170 }
1171 
1172 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1173 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1174 {
1175 	int error = 0;
1176 	u_int8_t * __indexable response = NULL;
1177 
1178 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1179 		NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1180 		error = EINVAL;
1181 		goto done;
1182 	}
1183 
1184 	necp_policy_id policy_id = 0;
1185 	error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1186 	if (error != 0) {
1187 		NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1188 		goto done;
1189 	}
1190 
1191 	struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1192 	if (policy == NULL || policy->pending_deletion) {
1193 		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1194 		error = ENOENT;
1195 		goto done;
1196 	}
1197 
1198 	u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1199 	u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1200 	u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1201 
1202 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1203 		NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1204 		error = EINVAL;
1205 		goto done;
1206 	}
1207 
1208 	if (response_size > NECP_MAX_POLICY_SIZE) {
1209 		NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1210 		error = EINVAL;
1211 		goto done;
1212 	}
1213 
1214 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1215 	if (response == NULL) {
1216 		error = ENOMEM;
1217 		goto done;
1218 	}
1219 
1220 	u_int8_t *cursor = response;
1221 	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1222 	if (result_tlv_size) {
1223 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1224 	}
1225 	if (policy->conditions_size) {
1226 		memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1227 	}
1228 
1229 	error = copyout(response, uap->out_buffer, response_size);
1230 	if (error != 0) {
1231 		NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1232 		goto done;
1233 	}
1234 
1235 done:
1236 	if (response != NULL) {
1237 		kfree_data(response, response_size);
1238 		response = NULL;
1239 	}
1240 	*retval = error;
1241 
1242 	return error;
1243 }
1244 
1245 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1246 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1247 {
1248 	int error = 0;
1249 
1250 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1251 		NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1252 		error = EINVAL;
1253 		goto done;
1254 	}
1255 
1256 	necp_policy_id delete_policy_id = 0;
1257 	error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1258 	if (error != 0) {
1259 		NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1260 		goto done;
1261 	}
1262 
1263 	struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1264 	if (policy == NULL || policy->pending_deletion) {
1265 		NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1266 		error = ENOENT;
1267 		goto done;
1268 	}
1269 
1270 	necp_policy_mark_for_deletion(session, policy);
1271 done:
1272 	*retval = error;
1273 	return error;
1274 }
1275 
1276 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1277 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1278 {
1279 #pragma unused(uap)
1280 	necp_policy_apply_all(session);
1281 	*retval = 0;
1282 	return 0;
1283 }
1284 
1285 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1286 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1287 {
1288 	u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1289 	u_int32_t response_size = 0;
1290 	u_int8_t * __indexable response = NULL;
1291 	int num_policies = 0;
1292 	int cur_policy_index = 0;
1293 	int error = 0;
1294 	struct necp_session_policy *policy;
1295 
1296 	LIST_FOREACH(policy, &session->policies, chain) {
1297 		if (!policy->pending_deletion) {
1298 			num_policies++;
1299 		}
1300 	}
1301 
1302 	if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1303 		NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1304 		error = EINVAL;
1305 		goto done;
1306 	}
1307 
1308 	response_size = num_policies * tlv_size;
1309 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1310 		NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1311 		error = EINVAL;
1312 		goto done;
1313 	}
1314 
1315 	// Create a response with one Policy ID TLV for each policy
1316 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1317 	if (response == NULL) {
1318 		error = ENOMEM;
1319 		goto done;
1320 	}
1321 
1322 	u_int8_t *cursor = response;
1323 	LIST_FOREACH(policy, &session->policies, chain) {
1324 		if (!policy->pending_deletion && cur_policy_index < num_policies) {
1325 			cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1326 			cur_policy_index++;
1327 		}
1328 	}
1329 
1330 	error = copyout(response, uap->out_buffer, response_size);
1331 	if (error != 0) {
1332 		NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1333 		goto done;
1334 	}
1335 
1336 done:
1337 	if (response != NULL) {
1338 		kfree_data(response, response_size);
1339 		response = NULL;
1340 	}
1341 	*retval = error;
1342 
1343 	return error;
1344 }
1345 
1346 
1347 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1348 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1349 {
1350 #pragma unused(uap)
1351 	necp_policy_mark_all_for_deletion(session);
1352 	*retval = 0;
1353 	return 0;
1354 }
1355 
1356 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1357 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1358 {
1359 	int error = 0;
1360 	struct necp_session_policy *policy = NULL;
1361 	struct necp_session_policy *temp_policy = NULL;
1362 
1363 	if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1364 		NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1365 		error = EINVAL;
1366 		goto done;
1367 	}
1368 
1369 	necp_session_priority requested_session_priority = 0;
1370 	error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1371 	if (error != 0) {
1372 		NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1373 		goto done;
1374 	}
1375 
1376 	// Enforce special session priorities with entitlements
1377 	if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1378 	    requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1379 	    requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1380 	    requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1381 		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1382 		if (cred_result != 0) {
1383 			NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1384 			error = EPERM;
1385 			goto done;
1386 		}
1387 	}
1388 
1389 	if (session->session_priority != requested_session_priority) {
1390 		session->session_priority = requested_session_priority;
1391 		session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1392 		session->dirty = TRUE;
1393 
1394 		// Mark all policies as needing updates
1395 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1396 			policy->pending_update = TRUE;
1397 		}
1398 	}
1399 
1400 done:
1401 	*retval = error;
1402 	return error;
1403 }
1404 
1405 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1406 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1407 {
1408 #pragma unused(uap)
1409 	session->proc_locked = TRUE;
1410 	*retval = 0;
1411 	return 0;
1412 }
1413 
1414 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1415 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1416 {
1417 	int error = 0;
1418 	struct necp_service_registration *new_service = NULL;
1419 
1420 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1421 		NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1422 		error = EINVAL;
1423 		goto done;
1424 	}
1425 
1426 	uuid_t service_uuid;
1427 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1428 	if (error != 0) {
1429 		NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1430 		goto done;
1431 	}
1432 
1433 	new_service = kalloc_type(struct necp_service_registration,
1434 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
1435 
1436 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1437 	new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1438 	LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1439 	LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1440 	lck_rw_done(&necp_kernel_policy_lock);
1441 
1442 done:
1443 	*retval = error;
1444 	return error;
1445 }
1446 
1447 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1448 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1449 {
1450 	int error = 0;
1451 	struct necp_service_registration * __single service = NULL;
1452 	struct necp_service_registration *temp_service = NULL;
1453 	struct necp_uuid_id_mapping *mapping = NULL;
1454 
1455 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1456 		NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1457 		error = EINVAL;
1458 		goto done;
1459 	}
1460 
1461 	uuid_t service_uuid;
1462 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1463 	if (error != 0) {
1464 		NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1465 		goto done;
1466 	}
1467 
1468 	// Remove all matching services for this session
1469 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1470 	mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1471 	if (mapping != NULL) {
1472 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1473 			if (service->service_id == mapping->id) {
1474 				LIST_REMOVE(service, session_chain);
1475 				LIST_REMOVE(service, kernel_chain);
1476 				kfree_type(struct necp_service_registration, service);
1477 			}
1478 		}
1479 		necp_remove_uuid_service_id_mapping(service_uuid);
1480 	}
1481 	lck_rw_done(&necp_kernel_policy_lock);
1482 
1483 done:
1484 	*retval = error;
1485 	return error;
1486 }
1487 
1488 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1489 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1490 {
1491 #pragma unused(session)
1492 	int error = 0;
1493 
1494 	if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1495 		NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1496 		error = EINVAL;
1497 		goto done;
1498 	}
1499 
1500 	error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1501 done:
1502 	*retval = error;
1503 	return error;
1504 }
1505 
1506 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1507 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1508 {
1509 	int error = 0;
1510 	struct net_bloom_filter *bloom_filter = NULL;
1511 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1512 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1513 
1514 	if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1515 	    in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1516 	    uap->in_buffer == 0) {
1517 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1518 		error = EINVAL;
1519 		goto done;
1520 	}
1521 
1522 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1523 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1524 		error = EINVAL;
1525 		goto done;
1526 	}
1527 
1528 	bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1529 	if (bloom_filter == NULL) {
1530 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1531 		error = ENOMEM;
1532 		goto done;
1533 	}
1534 
1535 	error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1536 	if (error != 0) {
1537 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1538 		goto done;
1539 	}
1540 
1541 	size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1542 	if (expected_filter_size != in_buffer_length) {
1543 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1544 		error = EINVAL;
1545 		goto done;
1546 	}
1547 
1548 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1549 	u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1550 	lck_rw_done(&necp_kernel_policy_lock);
1551 
1552 	if (filter_id == 0) {
1553 		error = ENOMEM;
1554 	} else {
1555 		// Bloom filter is taken over by the new filter entry, clear the local pointer
1556 		bloom_filter = NULL;
1557 
1558 		error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1559 		if (error != 0) {
1560 			NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1561 			goto done;
1562 		}
1563 	}
1564 
1565 done:
1566 	*retval = error;
1567 	if (error != 0 && bloom_filter != NULL) {
1568 		uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1569 		kfree_data(filter_buffer, in_buffer_length);
1570 		bloom_filter = NULL;
1571 	}
1572 	return error;
1573 }
1574 
1575 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1576 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1577 {
1578 	int error = 0;
1579 
1580 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1581 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1582 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1583 		error = EINVAL;
1584 		goto done;
1585 	}
1586 
1587 	u_int32_t filter_id;
1588 	error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1589 	if (error != 0) {
1590 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1591 		goto done;
1592 	}
1593 
1594 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1595 	bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1596 	if (!removed) {
1597 		error = ENOENT;
1598 	}
1599 	lck_rw_done(&necp_kernel_policy_lock);
1600 
1601 done:
1602 	*retval = error;
1603 	return error;
1604 }
1605 
1606 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1607 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1608 {
1609 #pragma unused(uap)
1610 
1611 	struct necp_domain_filter * __single filter = NULL;
1612 	struct necp_domain_filter *temp_filter = NULL;
1613 	LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1614 		if (os_ref_release_locked(&filter->refcount) == 0) {
1615 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1616 			LIST_REMOVE(filter, chain);
1617 			lck_rw_done(&necp_kernel_policy_lock);
1618 			LIST_REMOVE(filter, owner_chain);
1619 			net_bloom_filter_destroy(filter->filter);
1620 			kfree_type(struct necp_domain_filter, filter);
1621 		}
1622 	}
1623 
1624 	*retval = 0;
1625 	return 0;
1626 }
1627 
1628 static int
necp_session_add_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1629 necp_session_add_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1630 {
1631 	int error = 0;
1632 
1633 	struct necp_domain_trie_request *domain_trie_request = NULL;
1634 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1635 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1636 
1637 	if (in_buffer_length < sizeof(struct necp_domain_trie_request) ||
1638 	    in_buffer_length > NECP_MAX_DOMAIN_TRIE_SIZE ||
1639 	    uap->in_buffer == 0) {
1640 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1641 		error = EINVAL;
1642 		goto done;
1643 	}
1644 
1645 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1646 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie buffer not large enough (%zu)", (size_t)out_buffer_length);
1647 		error = EINVAL;
1648 		goto done;
1649 	}
1650 
1651 	domain_trie_request = (struct necp_domain_trie_request *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1652 	if (domain_trie_request == NULL) {
1653 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie allocate trie request error (%zu)", in_buffer_length);
1654 		error = ENOMEM;
1655 		goto done;
1656 	}
1657 
1658 	error = copyin(uap->in_buffer, domain_trie_request, in_buffer_length);
1659 	if (error != 0) {
1660 		NECPLOG(LOG_ERR, "necp_session_add_domain_trie filter copyin error (%d)", error);
1661 		goto done;
1662 	}
1663 
1664 	NECPLOG(LOG_INFO, "necp_session_add_domain_trie received %zu bytes <trie mem size %d>", in_buffer_length, domain_trie_request->total_mem_size);
1665 
1666 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1667 	u_int32_t id = necp_create_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, domain_trie_request, in_buffer_length);
1668 	lck_rw_done(&necp_kernel_policy_lock);
1669 
1670 	if (id == 0) {
1671 		error = ENOMEM;
1672 	} else {
1673 		error = copyout(&id, uap->out_buffer, sizeof(id));
1674 		if (error != 0) {
1675 			NECPLOG(LOG_ERR, "necp_session_add_domain_trie ID copyout error (%d)", error);
1676 			goto done;
1677 		}
1678 	}
1679 
1680 done:
1681 	*retval = error;
1682 	if (error != 0 && domain_trie_request != NULL) {
1683 		uint8_t * __single domain_buffer = (uint8_t *)domain_trie_request;
1684 		kfree_data(domain_buffer, in_buffer_length);
1685 		domain_trie_request = NULL;
1686 	}
1687 	return error;
1688 }
1689 
1690 static int
necp_session_remove_domain_trie(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1691 necp_session_remove_domain_trie(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1692 {
1693 	int error = 0;
1694 
1695 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1696 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1697 		NECPLOG(LOG_ERR, "necp_session_remove_domain_trie invalid input (%zu)", (size_t)in_buffer_length);
1698 		error = EINVAL;
1699 		goto done;
1700 	}
1701 
1702 	u_int32_t id;
1703 	error = copyin(uap->in_buffer, &id, sizeof(id));
1704 	if (error != 0) {
1705 		NECPLOG(LOG_ERR, "necp_session_remove_domain_trie uuid copyin error (%d)", error);
1706 		goto done;
1707 	}
1708 
1709 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1710 	bool removed = necp_remove_domain_trie(&necp_global_domain_trie_list, &session->domain_tries, id);
1711 	if (!removed) {
1712 		error = ENOENT;
1713 	}
1714 	lck_rw_done(&necp_kernel_policy_lock);
1715 
1716 done:
1717 	*retval = error;
1718 	return error;
1719 }
1720 
1721 static int
necp_session_remove_all_domain_tries(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1722 necp_session_remove_all_domain_tries(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1723 {
1724 #pragma unused(uap)
1725 	struct necp_domain_trie* __single trie = NULL;
1726 	struct necp_domain_trie* __single temp_trie = NULL;
1727 	LIST_FOREACH_SAFE(trie, &session->domain_tries, owner_chain, temp_trie) {
1728 		if (os_ref_release_locked(&trie->refcount) == 0) {
1729 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1730 			LIST_REMOVE(trie, chain);
1731 			lck_rw_done(&necp_kernel_policy_lock);
1732 			LIST_REMOVE(trie, owner_chain);
1733 			necp_free_domain_trie(trie);
1734 		}
1735 	}
1736 	*retval = 0;
1737 	return 0;
1738 }
1739 
1740 static int
necp_session_trie_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1741 necp_session_trie_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1742 {
1743 #pragma unused(session)
1744 
1745 	int error = 0;
1746 
1747 	uint8_t request_buffer[2000] = { 0 };
1748 	uint8_t *ptr = NULL;
1749 	uint32_t count = 0;
1750 	int output_length = 0;
1751 
1752 	lck_rw_lock_shared(&necp_kernel_policy_lock);
1753 	count = necp_trie_count;
1754 	lck_rw_done(&necp_kernel_policy_lock);
1755 
1756 	if (count == 0) {
1757 		error = ENOENT;
1758 		goto done;
1759 	}
1760 
1761 	output_length = sizeof(count) + (count * sizeof(struct necp_domain_trie_request)); // first byte contains count
1762 	if (output_length > uap->out_buffer_length) {
1763 		NECPLOG(LOG_ERR, "necp_session_trie_dump_all out_buffer not large enough for %zu", (size_t)output_length);
1764 		error = EINVAL;
1765 		goto done;
1766 	}
1767 	if (output_length > sizeof(request_buffer)) {
1768 		NECPLOG(LOG_ERR, "necp_session_trie_dump_all temporary buffer not large enough for %zu", (size_t)output_length);
1769 		error = EINVAL;
1770 		goto done;
1771 	}
1772 
1773 	memcpy(request_buffer, (u_int8_t *)&count, sizeof(count));
1774 	ptr = request_buffer + sizeof(count);
1775 
1776 	lck_rw_lock_shared(&necp_kernel_policy_lock);
1777 	struct necp_domain_trie* __single trie = NULL;
1778 	LIST_FOREACH(trie, &necp_global_domain_trie_list, chain) {
1779 		if (trie->trie_request != NULL) {
1780 			memcpy((u_int8_t *)ptr, (u_int8_t *)trie->trie_request, sizeof(struct necp_domain_trie_request));
1781 			ptr += sizeof(struct necp_domain_trie_request);
1782 		}
1783 	}
1784 	lck_rw_done(&necp_kernel_policy_lock);
1785 
1786 	error = copyout(request_buffer, uap->out_buffer, output_length);
1787 
1788 done:
1789 	*retval = error;
1790 	return error;
1791 }
1792 
1793 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1794 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1795 {
1796 	struct fileproc * __single fp;
1797 	int error = 0;
1798 	int return_value = 0;
1799 	struct necp_session * __single session = NULL;
1800 
1801 	error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1802 	if (error != 0) {
1803 		NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1804 		return error;
1805 	}
1806 
1807 	NECP_SESSION_LOCK(session);
1808 
1809 	if (session->proc_locked) {
1810 		// Verify that the calling process is allowed to do actions
1811 		uuid_t proc_uuid;
1812 		proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1813 		if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1814 			error = EPERM;
1815 			goto done;
1816 		}
1817 	} else {
1818 		// If not locked, update the proc_uuid and proc_pid of the session
1819 		proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1820 		session->proc_pid = proc_pid(current_proc());
1821 	}
1822 
1823 	u_int32_t action = uap->action;
1824 	switch (action) {
1825 	case NECP_SESSION_ACTION_POLICY_ADD: {
1826 		return_value = necp_session_add_policy(session, uap, retval);
1827 		break;
1828 	}
1829 	case NECP_SESSION_ACTION_POLICY_GET: {
1830 		return_value = necp_session_get_policy(session, uap, retval);
1831 		break;
1832 	}
1833 	case NECP_SESSION_ACTION_POLICY_DELETE:  {
1834 		return_value = necp_session_delete_policy(session, uap, retval);
1835 		break;
1836 	}
1837 	case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1838 		return_value = necp_session_apply_all(session, uap, retval);
1839 		break;
1840 	}
1841 	case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1842 		return_value = necp_session_list_all(session, uap, retval);
1843 		break;
1844 	}
1845 	case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1846 		return_value = necp_session_delete_all(session, uap, retval);
1847 		break;
1848 	}
1849 	case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1850 		return_value = necp_session_set_session_priority(session, uap, retval);
1851 		break;
1852 	}
1853 	case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1854 		return_value = necp_session_lock_to_process(session, uap, retval);
1855 		break;
1856 	}
1857 	case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1858 		return_value = necp_session_register_service(session, uap, retval);
1859 		break;
1860 	}
1861 	case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1862 		return_value = necp_session_unregister_service(session, uap, retval);
1863 		break;
1864 	}
1865 	case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1866 		return_value = necp_session_dump_all(session, uap, retval);
1867 		break;
1868 	}
1869 	case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1870 		return_value = necp_session_add_domain_filter(session, uap, retval);
1871 		break;
1872 	}
1873 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1874 		return_value = necp_session_remove_domain_filter(session, uap, retval);
1875 		break;
1876 	}
1877 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1878 		return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1879 		break;
1880 	}
1881 	case NECP_SESSION_ACTION_ADD_DOMAIN_TRIE: {
1882 		return_value = necp_session_add_domain_trie(session, uap, retval);
1883 		break;
1884 	}
1885 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_TRIE: {
1886 		return_value = necp_session_remove_domain_trie(session, uap, retval);
1887 		break;
1888 	}
1889 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_TRIES: {
1890 		return_value = necp_session_remove_all_domain_tries(session, uap, retval);
1891 		break;
1892 	}
1893 	case NECP_SESSION_ACTION_TRIE_DUMP_ALL: {
1894 		return_value = necp_session_trie_dump_all(session, uap, retval);
1895 		break;
1896 	}
1897 	default: {
1898 		NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1899 		return_value = EINVAL;
1900 		break;
1901 	}
1902 	}
1903 
1904 done:
1905 	NECP_SESSION_UNLOCK(session);
1906 	fp_drop(p, uap->necp_fd, fp, 0);
1907 	return return_value;
1908 }
1909 
1910 struct necp_resolver_key_state {
1911 	const struct ccdigest_info *digest_info;
1912 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1913 };
1914 static struct necp_resolver_key_state s_necp_resolver_key_state;
1915 
1916 static void
necp_generate_resolver_key(void)1917 necp_generate_resolver_key(void)
1918 {
1919 	s_necp_resolver_key_state.digest_info = ccsha256_di();
1920 	cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1921 }
1922 
1923 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)1924 necp_sign_update_context(const struct ccdigest_info *di,
1925     cchmac_ctx_t ctx,
1926     uuid_t client_id,
1927     u_int32_t sign_type,
1928     u_int8_t *data,
1929     size_t data_length)
1930 {
1931 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1932 	const char * __null_terminated context_string = "NECP Resolver Binder";
1933 	uint8_t separator = 0;
1934 	cchmac_update(di, ctx, sizeof(context), context);
1935 	cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1936 	cchmac_update(di, ctx, sizeof(separator), &separator);
1937 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1938 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1939 	cchmac_update(di, ctx, data_length, data);
1940 }
1941 
1942 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)1943 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1944     u_int8_t *data, size_t data_length,
1945     u_int8_t *tag, size_t *out_tag_length)
1946 {
1947 	if (s_necp_resolver_key_state.digest_info == NULL) {
1948 		return EINVAL;
1949 	}
1950 
1951 	if (data == NULL ||
1952 	    data_length == 0 ||
1953 	    tag == NULL ||
1954 	    out_tag_length == NULL) {
1955 		return EINVAL;
1956 	}
1957 
1958 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1959 	if (*out_tag_length < required_tag_length) {
1960 		return ERANGE;
1961 	}
1962 
1963 	*out_tag_length = required_tag_length;
1964 
1965 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1966 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1967 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1968 	    sizeof(s_necp_resolver_key_state.key),
1969 	    s_necp_resolver_key_state.key);
1970 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1971 	    ctx, client_id, sign_type, data, data_length);
1972 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1973 
1974 	return 0;
1975 }
1976 
1977 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)1978 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1979     u_int8_t * __sized_by(data_length)data, size_t data_length,
1980     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1981 {
1982 	if (s_necp_resolver_key_state.digest_info == NULL) {
1983 		return false;
1984 	}
1985 
1986 	if (data == NULL ||
1987 	    data_length == 0 ||
1988 	    tag == NULL ||
1989 	    tag_length == 0) {
1990 		return false;
1991 	}
1992 
1993 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1994 	if (tag_length != required_tag_length) {
1995 		return false;
1996 	}
1997 
1998 	uint8_t actual_tag[required_tag_length];
1999 
2000 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
2001 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
2002 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
2003 	    sizeof(s_necp_resolver_key_state.key),
2004 	    s_necp_resolver_key_state.key);
2005 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
2006 	    ctx, client_id, sign_type, data, data_length);
2007 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
2008 
2009 	return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
2010 }
2011 
2012 struct necp_application_id_key_state {
2013 	const struct ccdigest_info *digest_info;
2014 	uint8_t key[CCSHA256_OUTPUT_SIZE];
2015 };
2016 static struct necp_application_id_key_state s_necp_application_id_key_state;
2017 
2018 static void
necp_generate_application_id_key(void)2019 necp_generate_application_id_key(void)
2020 {
2021 	s_necp_application_id_key_state.digest_info = ccsha256_di();
2022 	cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
2023 }
2024 
2025 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)2026 necp_sign_application_id_update_context(const struct ccdigest_info *di,
2027     cchmac_ctx_t ctx,
2028     uuid_t client_id,
2029     u_int32_t sign_type)
2030 {
2031 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
2032 	const char context_string[] = "NECP Application ID";
2033 	uint8_t separator = 0;
2034 	cchmac_update(di, ctx, sizeof(context), context);
2035 	cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
2036 	cchmac_update(di, ctx, sizeof(separator), &separator);
2037 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
2038 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
2039 }
2040 
2041 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)2042 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
2043     u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
2044 {
2045 	if (s_necp_application_id_key_state.digest_info == NULL) {
2046 		return EINVAL;
2047 	}
2048 
2049 	if (tag == NULL ||
2050 	    out_tag_length == NULL) {
2051 		return EINVAL;
2052 	}
2053 
2054 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2055 	if (*out_tag_length < required_tag_length) {
2056 		return ERANGE;
2057 	}
2058 
2059 	*out_tag_length = required_tag_length;
2060 
2061 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2062 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
2063 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2064 	    sizeof(s_necp_application_id_key_state.key),
2065 	    s_necp_application_id_key_state.key);
2066 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2067 	    ctx, client_id, sign_type);
2068 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
2069 
2070 	return 0;
2071 }
2072 
2073 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)2074 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
2075     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
2076 {
2077 	if (s_necp_application_id_key_state.digest_info == NULL) {
2078 		return false;
2079 	}
2080 
2081 	if (tag == NULL ||
2082 	    tag_length == 0) {
2083 		return false;
2084 	}
2085 
2086 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
2087 	if (tag_length != required_tag_length) {
2088 		return false;
2089 	}
2090 
2091 	uint8_t actual_tag[required_tag_length];
2092 
2093 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
2094 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
2095 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
2096 	    sizeof(s_necp_application_id_key_state.key),
2097 	    s_necp_application_id_key_state.key);
2098 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
2099 	    ctx, client_id, sign_type);
2100 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
2101 
2102 	return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
2103 }
2104 
2105 void
necp_init(void)2106 necp_init(void)
2107 {
2108 	necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
2109 	necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
2110 
2111 	necp_client_init();
2112 
2113 	TAILQ_INIT(&necp_session_list);
2114 
2115 	LIST_INIT(&necp_kernel_socket_policies);
2116 	LIST_INIT(&necp_kernel_ip_output_policies);
2117 
2118 	LIST_INIT(&necp_account_id_list);
2119 
2120 	LIST_INIT(&necp_uuid_service_id_list);
2121 
2122 	LIST_INIT(&necp_registered_service_list);
2123 
2124 	LIST_INIT(&necp_route_rules);
2125 	LIST_INIT(&necp_aggregate_route_rules);
2126 
2127 	LIST_INIT(&necp_global_domain_filter_list);
2128 	LIST_INIT(&necp_global_domain_trie_list);
2129 
2130 	necp_generate_resolver_key();
2131 	necp_generate_application_id_key();
2132 
2133 	necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
2134 	    hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
2135 	    NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
2136 	necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
2137 	necp_num_uuid_app_id_mappings = 0;
2138 	necp_uuid_app_id_mappings_dirty = FALSE;
2139 
2140 	necp_kernel_application_policies_condition_mask = 0;
2141 	necp_kernel_socket_policies_condition_mask = 0;
2142 	necp_kernel_ip_output_policies_condition_mask = 0;
2143 
2144 	necp_kernel_application_policies_count = 0;
2145 	necp_kernel_socket_policies_count = 0;
2146 	necp_kernel_socket_policies_non_app_count = 0;
2147 	necp_kernel_ip_output_policies_count = 0;
2148 	necp_kernel_ip_output_policies_non_id_count = 0;
2149 
2150 	necp_kernel_socket_policies_gencount = 1;
2151 
2152 	memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
2153 	memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
2154 	necp_kernel_socket_policies_app_layer_map = NULL;
2155 
2156 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
2157 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
2158 }
2159 
2160 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)2161 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
2162 {
2163 	struct kev_msg ev_msg;
2164 	memset(&ev_msg, 0, sizeof(ev_msg));
2165 
2166 	ev_msg.vendor_code      = KEV_VENDOR_APPLE;
2167 	ev_msg.kev_class        = KEV_NETWORK_CLASS;
2168 	ev_msg.kev_subclass     = KEV_NECP_SUBCLASS;
2169 	ev_msg.event_code       = KEV_NECP_POLICIES_CHANGED;
2170 
2171 	ev_msg.dv[0].data_ptr    = necp_event_data;
2172 	ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
2173 	ev_msg.dv[1].data_length = 0;
2174 
2175 	kev_post_msg(&ev_msg);
2176 }
2177 
2178 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)2179 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
2180     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2181 {
2182 	if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
2183 		NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
2184 		return false;
2185 	}
2186 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2187 	if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
2188 	    (uintptr_t)(next_tlv - buffer) > buffer_length) {     // make sure the next TLV has enough room in buffer
2189 		NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
2190 		    length, buffer_length);
2191 		return false;
2192 	}
2193 	return true;
2194 }
2195 
2196 u_int8_t * __counted_by(0)
2197 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2198     u_int32_t length, const void * __sized_by(length)value, bool *updated,
2199     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2200 {
2201 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2202 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2203 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2204 		// If we can't fit this TLV, return the current cursor
2205 		return cursor;
2206 	}
2207 	u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2208 	if (*updated || *(u_int8_t *)(cursor) != type) {
2209 		*(u_int8_t *)(cursor) = type;
2210 		*updated = TRUE;
2211 	}
2212 	if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
2213 		*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2214 		*updated = TRUE;
2215 	}
2216 	if (length > 0) {
2217 		if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
2218 			memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2219 			*updated = TRUE;
2220 		}
2221 	}
2222 	return next_tlv;
2223 }
2224 
2225 u_int8_t * __counted_by(0)
2226 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2227     u_int32_t length, const void * __sized_by(length)value,
2228     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2229 {
2230 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2231 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2232 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2233 		return NULL;
2234 	}
2235 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2236 	*(u_int8_t *)(cursor) = type;
2237 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2238 	if (length > 0) {
2239 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2240 	}
2241 
2242 	return next_tlv;
2243 }
2244 
2245 static u_int8_t * __counted_by(0)
2246 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2247     u_int32_t length, const void * __sized_by(length)value,
2248     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2249 {
2250 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2251 	// Add one extra byte to 'length' to account for the flags byte for validation.
2252 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2253 	if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2254 		return NULL;
2255 	}
2256 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2257 
2258 	// TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2259 	*(u_int8_t *)(cursor) = type;
2260 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2261 	*(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2262 	if (length > 0) {
2263 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2264 	}
2265 
2266 	return next_tlv;
2267 }
2268 
2269 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)2270 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2271 {
2272 	u_int8_t * __indexable type = NULL;
2273 	uint64_t end_offset = 0;
2274 
2275 	if (buffer == NULL ||
2276 	    os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2277 		return 0;
2278 	}
2279 
2280 	type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2281 	return type ? *type : 0;
2282 }
2283 
2284 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)2285 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2286 {
2287 	u_int32_t * __indexable length = NULL;
2288 	uint64_t end_offset = 0;
2289 
2290 	if (buffer == NULL ||
2291 	    os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2292 		return 0;
2293 	}
2294 
2295 	length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2296 	return length ? *length : 0;
2297 }
2298 
2299 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)2300 __necp_buffer_get_tlv_value(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset, u_int32_t * value_size)
2301 {
2302 	u_int8_t * __indexable value = NULL;
2303 	uint64_t end_offset = 0;
2304 
2305 	if (buffer == NULL) {
2306 		return NULL;
2307 	}
2308 
2309 	u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2310 	if (length == 0) {
2311 		return NULL;
2312 	}
2313 
2314 	if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2315 		return NULL;
2316 	}
2317 
2318 	if (value_size) {
2319 		*value_size = length;
2320 	}
2321 
2322 	value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2323 	return value;
2324 }
2325 
2326 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)2327 necp_buffer_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2328 {
2329 	if (err != NULL) {
2330 		*err = ENOENT;
2331 	}
2332 	if (offset < 0) {
2333 		if (err != NULL) {
2334 			*err = EINVAL;
2335 		}
2336 		return -1;
2337 	}
2338 	int cursor = offset;
2339 	int next_cursor;
2340 	u_int32_t curr_length;
2341 	u_int8_t curr_type;
2342 
2343 	while (TRUE) {
2344 		if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2345 			return -1;
2346 		}
2347 		if (!next) {
2348 			curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2349 		} else {
2350 			next = 0;
2351 			curr_type = NECP_TLV_NIL;
2352 		}
2353 		curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2354 		if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2355 			return -1;
2356 		}
2357 
2358 		next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2359 		if (curr_type == type) {
2360 			// check if entire TLV fits inside buffer
2361 			if (((u_int32_t)next_cursor) <= buffer_length) {
2362 				if (err != NULL) {
2363 					*err = 0;
2364 				}
2365 				return cursor;
2366 			} else {
2367 				return -1;
2368 			}
2369 		}
2370 		cursor = next_cursor;
2371 	}
2372 }
2373 
2374 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)2375 necp_find_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2376 {
2377 	int cursor = -1;
2378 	if (buffer != NULL) {
2379 		cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2380 	}
2381 	return cursor;
2382 }
2383 
2384 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)2385 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2386     int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2387 {
2388 	if (buffer == NULL) {
2389 		NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2390 		return EINVAL;
2391 	}
2392 
2393 	// Handle buffer parsing
2394 
2395 	// Validate that buffer has enough room for any TLV
2396 	if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2397 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2398 		    buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2399 		return EINVAL;
2400 	}
2401 
2402 	// Validate that buffer has enough room for this TLV
2403 	u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2404 	if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2405 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2406 		    tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2407 		return EINVAL;
2408 	}
2409 
2410 	if (out_buffer != NULL && out_buffer_length > 0) {
2411 		// Validate that out buffer is large enough for  value
2412 		if (out_buffer_length < tlv_length) {
2413 			NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2414 			    out_buffer_length, tlv_length);
2415 			return EINVAL;
2416 		}
2417 
2418 		// Get value pointer
2419 		u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2420 		if (tlv_value == NULL) {
2421 			NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2422 			return ENOENT;
2423 		}
2424 
2425 		// Copy value
2426 		memcpy(out_buffer, tlv_value, tlv_length);
2427 	}
2428 
2429 	// Copy out length
2430 	if (value_size != NULL) {
2431 		*value_size = tlv_length;
2432 	}
2433 
2434 	return 0;
2435 }
2436 
2437 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)2438 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2439     int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2440 {
2441 	int error = 0;
2442 
2443 	int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2444 	if (tlv_offset < 0) {
2445 		return error;
2446 	}
2447 
2448 	return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2449 }
2450 
2451 // Session Management
2452 
2453 static struct necp_session *
necp_create_session(void)2454 necp_create_session(void)
2455 {
2456 	struct necp_session *new_session = NULL;
2457 
2458 	new_session = kalloc_type(struct necp_session,
2459 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2460 
2461 	new_session->necp_fd_type = necp_fd_type_session;
2462 	new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2463 	new_session->dirty = FALSE;
2464 	LIST_INIT(&new_session->policies);
2465 	LIST_INIT(&new_session->services);
2466 	LIST_INIT(&new_session->domain_filters);
2467 	LIST_INIT(&new_session->domain_tries);
2468 	lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2469 
2470 	// Take the lock
2471 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2472 
2473 	// Find the next available control unit
2474 	u_int32_t control_unit = 1;
2475 	struct necp_session *next_session = NULL;
2476 	TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2477 		if (next_session->control_unit > control_unit) {
2478 			// Found a gap, grab this control unit
2479 			break;
2480 		}
2481 
2482 		// Try the next control unit, loop around
2483 		control_unit = next_session->control_unit + 1;
2484 	}
2485 
2486 	new_session->control_unit = control_unit;
2487 	new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2488 
2489 	if (next_session != NULL) {
2490 		TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2491 	} else {
2492 		TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2493 	}
2494 
2495 	necp_session_count++;
2496 	lck_rw_done(&necp_kernel_policy_lock);
2497 
2498 	if (necp_debug) {
2499 		NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2500 	}
2501 
2502 	return new_session;
2503 }
2504 
2505 static void
necp_delete_session(struct necp_session * session)2506 necp_delete_session(struct necp_session *session)
2507 {
2508 	if (session != NULL) {
2509 		struct necp_service_registration * __single service = NULL;
2510 		struct necp_service_registration *temp_service = NULL;
2511 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2512 			LIST_REMOVE(service, session_chain);
2513 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2514 			LIST_REMOVE(service, kernel_chain);
2515 			lck_rw_done(&necp_kernel_policy_lock);
2516 			kfree_type(struct necp_service_registration, service);
2517 		}
2518 		struct necp_domain_filter * __single filter = NULL;
2519 		struct necp_domain_filter *temp_filter = NULL;
2520 		LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2521 			if (os_ref_release_locked(&filter->refcount) == 0) {
2522 				lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2523 				LIST_REMOVE(filter, chain);
2524 				lck_rw_done(&necp_kernel_policy_lock);
2525 				LIST_REMOVE(filter, owner_chain);
2526 				net_bloom_filter_destroy(filter->filter);
2527 				kfree_type(struct necp_domain_filter, filter);
2528 			}
2529 		}
2530 		if (necp_debug) {
2531 			NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2532 		}
2533 
2534 		lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2535 		TAILQ_REMOVE(&necp_session_list, session, chain);
2536 		necp_session_count--;
2537 		lck_rw_done(&necp_kernel_policy_lock);
2538 
2539 		lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2540 		kfree_type(struct necp_session, session);
2541 	}
2542 }
2543 
2544 // Session Policy Management
2545 
2546 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2547 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2548 {
2549 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2550 }
2551 
2552 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2553 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2554 {
2555 	return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2556 }
2557 
2558 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2559 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2560 {
2561 	return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2562 }
2563 
2564 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2565 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2566 {
2567 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2568 	if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2569 		return TRUE;
2570 	}
2571 	return FALSE;
2572 }
2573 
2574 static inline bool
_necp_address_is_valid(struct sockaddr * address)2575 _necp_address_is_valid(struct sockaddr *address)
2576 {
2577 	if (address->sa_family == AF_INET) {
2578 		return address->sa_len == sizeof(struct sockaddr_in);
2579 	} else if (address->sa_family == AF_INET6) {
2580 		return address->sa_len == sizeof(struct sockaddr_in6);
2581 	} else {
2582 		return FALSE;
2583 	}
2584 }
2585 
2586 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2587 
2588 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2589 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2590 {
2591 	bool validated = FALSE;
2592 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2593 	u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2594 	*is_pass_skip = FALSE;
2595 	switch (type) {
2596 	case NECP_POLICY_RESULT_PASS: {
2597 		*is_pass_skip = TRUE;
2598 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2599 			validated = TRUE;
2600 		}
2601 		break;
2602 	}
2603 	case NECP_POLICY_RESULT_DROP: {
2604 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2605 			validated = TRUE;
2606 		}
2607 		break;
2608 	}
2609 	case NECP_POLICY_RESULT_ROUTE_RULES:
2610 	case NECP_POLICY_RESULT_SCOPED_DIRECT:
2611 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2612 		validated = TRUE;
2613 		break;
2614 	}
2615 	case NECP_POLICY_RESULT_SKIP:
2616 		*is_pass_skip = TRUE;
2617 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
2618 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
2619 		if (parameter_length >= sizeof(u_int32_t)) {
2620 			validated = TRUE;
2621 		}
2622 		break;
2623 	}
2624 	case NECP_POLICY_RESULT_IP_TUNNEL: {
2625 		if (parameter_length > sizeof(u_int32_t)) {
2626 			validated = TRUE;
2627 		}
2628 		break;
2629 	}
2630 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2631 		if (parameter_length > 0) {
2632 			validated = TRUE;
2633 		}
2634 		break;
2635 	}
2636 	case NECP_POLICY_RESULT_USE_NETAGENT:
2637 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2638 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2639 		if (parameter_length >= sizeof(uuid_t)) {
2640 			validated = TRUE;
2641 		}
2642 		break;
2643 	}
2644 	default: {
2645 		validated = FALSE;
2646 		break;
2647 	}
2648 	}
2649 
2650 	if (necp_debug) {
2651 		NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2652 	}
2653 
2654 	return validated;
2655 }
2656 
2657 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2658 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2659 {
2660 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2661 }
2662 
2663 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2664 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2665 {
2666 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2667 }
2668 
2669 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2670 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2671 {
2672 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2673 }
2674 
2675 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2676 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2677 {
2678 	return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2679 }
2680 
2681 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2682 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2683 {
2684 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2685 }
2686 
2687 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2688 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2689 {
2690 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2691 }
2692 
2693 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2694 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2695 {
2696 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2697 }
2698 
2699 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2700 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2701 {
2702 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2703 	return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2704 }
2705 
2706 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2707 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2708 {
2709 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2710 	u_int32_t condition_length = 0;
2711 	pid_t *condition_value = NULL;
2712 
2713 	if (type == NECP_POLICY_CONDITION_PID) {
2714 		condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2715 		if (condition_length >= sizeof(pid_t)) {
2716 			condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2717 			return *condition_value == 0;
2718 		}
2719 	}
2720 	return false;
2721 }
2722 
2723 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2724 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2725 {
2726 	bool validated = FALSE;
2727 	bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2728 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2729 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2730 	    policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2731 	    policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2732 	    policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2733 	    policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2734 	    policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2735 	    policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2736 	u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2737 	u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2738 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2739 	u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2740 	switch (type) {
2741 	case NECP_POLICY_CONDITION_APPLICATION:
2742 	case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2743 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2744 		    condition_length >= sizeof(uuid_t) &&
2745 		    condition_value != NULL &&
2746 		    !uuid_is_null(condition_value)) {
2747 			validated = TRUE;
2748 		}
2749 		break;
2750 	}
2751 	case NECP_POLICY_CONDITION_DOMAIN:
2752 	case NECP_POLICY_CONDITION_ACCOUNT:
2753 	case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2754 	case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2755 	case NECP_POLICY_CONDITION_URL: {
2756 		if (condition_length > 0) {
2757 			validated = TRUE;
2758 		}
2759 		break;
2760 	}
2761 	case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2762 		if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2763 			validated = TRUE;
2764 		}
2765 		break;
2766 	}
2767 	case NECP_POLICY_CONDITION_DEFAULT:
2768 	case NECP_POLICY_CONDITION_ALL_INTERFACES:
2769 	case NECP_POLICY_CONDITION_ENTITLEMENT:
2770 	case NECP_POLICY_CONDITION_HAS_CLIENT:
2771 	case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2772 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2773 			validated = TRUE;
2774 		}
2775 		break;
2776 	}
2777 	case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2778 		if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2779 			validated = TRUE;
2780 		}
2781 		break;
2782 	}
2783 	case NECP_POLICY_CONDITION_SDK_VERSION: {
2784 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2785 		    condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2786 			validated = TRUE;
2787 		}
2788 		break;
2789 	}
2790 	case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2791 		if (condition_length >= sizeof(u_int16_t)) {
2792 			validated = TRUE;
2793 		}
2794 		break;
2795 	}
2796 	case NECP_POLICY_CONDITION_PID: {
2797 		if (condition_length >= sizeof(pid_t) &&
2798 		    condition_value != NULL) {
2799 			validated = TRUE;
2800 		}
2801 		break;
2802 	}
2803 	case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2804 		if (condition_length >= sizeof(u_int32_t)) {
2805 			validated = TRUE;
2806 		}
2807 		break;
2808 	}
2809 	case NECP_POLICY_CONDITION_UID:
2810 	case NECP_POLICY_CONDITION_REAL_UID: {
2811 		if (condition_length >= sizeof(uid_t)) {
2812 			validated = TRUE;
2813 		}
2814 		break;
2815 	}
2816 	case NECP_POLICY_CONDITION_LOCAL_ADDR:
2817 	case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2818 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2819 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2820 			validated = TRUE;
2821 		}
2822 		break;
2823 	}
2824 	case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2825 	case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2826 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2827 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2828 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2829 			validated = TRUE;
2830 		}
2831 		break;
2832 	}
2833 	case NECP_POLICY_CONDITION_AGENT_TYPE: {
2834 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2835 		    condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2836 			validated = TRUE;
2837 		}
2838 		break;
2839 	}
2840 	case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2841 		if (condition_length >= sizeof(u_int16_t)) {
2842 			validated = TRUE;
2843 		}
2844 		break;
2845 	}
2846 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2847 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2848 		if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2849 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2850 			validated = TRUE;
2851 		}
2852 		break;
2853 	}
2854 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2855 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2856 		if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2857 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2858 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2859 			validated = TRUE;
2860 		}
2861 		break;
2862 	}
2863 	case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2864 		if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2865 			validated = TRUE;
2866 		}
2867 		break;
2868 	}
2869 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2870 		validated = TRUE;
2871 		break;
2872 	}
2873 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2874 		validated = TRUE;
2875 		break;
2876 	}
2877 	case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2878 		if (condition_length >= sizeof(u_int16_t)) {
2879 			u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2880 			if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2881 				validated = TRUE;
2882 			}
2883 		}
2884 		break;
2885 	}
2886 	case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2887 		validated = TRUE;
2888 		break;
2889 	}
2890 	case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2891 		validated = TRUE;
2892 		break;
2893 	}
2894 	case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2895 		validated = TRUE;
2896 		break;
2897 	}
2898 	case NECP_POLICY_CONDITION_SCHEME_PORT: {
2899 		if (condition_length >= sizeof(u_int16_t)) {
2900 			validated = TRUE;
2901 		}
2902 		break;
2903 	}
2904 	case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2905 		if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2906 			validated = TRUE;
2907 		}
2908 		break;
2909 	}
2910 	default: {
2911 		validated = FALSE;
2912 		break;
2913 	}
2914 	}
2915 
2916 	if (necp_debug) {
2917 		NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2918 	}
2919 
2920 	return validated;
2921 }
2922 
2923 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2924 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2925 {
2926 	return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2927 	       necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2928 }
2929 
2930 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2931 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2932 {
2933 	bool validated = FALSE;
2934 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2935 	switch (type) {
2936 	case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2937 		validated = TRUE;
2938 		break;
2939 	}
2940 	case NECP_ROUTE_RULE_DENY_INTERFACE: {
2941 		validated = TRUE;
2942 		break;
2943 	}
2944 	case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2945 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2946 		validated = (rule_length >= sizeof(u_int32_t));
2947 		break;
2948 	}
2949 	case NECP_ROUTE_RULE_QOS_MARKING: {
2950 		validated = TRUE;
2951 		break;
2952 	}
2953 	case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2954 		validated = TRUE;
2955 		break;
2956 	}
2957 	case NECP_ROUTE_RULE_USE_NETAGENT:
2958 	case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2959 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2960 		validated = (rule_length >= sizeof(uuid_t));
2961 		break;
2962 	}
2963 	case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2964 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2965 		validated = (rule_length >= sizeof(uint32_t));
2966 		break;
2967 	}
2968 	default: {
2969 		validated = FALSE;
2970 		break;
2971 	}
2972 	}
2973 
2974 	if (necp_debug) {
2975 		NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2976 	}
2977 
2978 	return validated;
2979 }
2980 
2981 static int
necp_get_posix_error_for_necp_error(int response_error)2982 necp_get_posix_error_for_necp_error(int response_error)
2983 {
2984 	switch (response_error) {
2985 	case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2986 	case NECP_ERROR_INVALID_TLV:
2987 	case NECP_ERROR_POLICY_RESULT_INVALID:
2988 	case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2989 	case NECP_ERROR_ROUTE_RULES_INVALID: {
2990 		return EINVAL;
2991 	}
2992 	case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2993 		return ENOENT;
2994 	}
2995 	case NECP_ERROR_INVALID_PROCESS: {
2996 		return EPERM;
2997 	}
2998 	case NECP_ERROR_INTERNAL:
2999 	default: {
3000 		return ENOMEM;
3001 	}
3002 	}
3003 }
3004 
3005 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)3006 necp_handle_policy_add(struct necp_session *session,
3007     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
3008 {
3009 	bool has_default_condition = FALSE;
3010 	bool has_non_default_condition = FALSE;
3011 	bool has_application_condition = FALSE;
3012 	bool has_real_application_condition = FALSE;
3013 	bool requires_application_condition = FALSE;
3014 	bool has_kernel_pid = FALSE;
3015 	bool is_pass_skip = FALSE;
3016 	u_int32_t conditions_array_size = 0;
3017 	u_int8_t *conditions_array = NULL;
3018 	int conditions_array_cursor;
3019 
3020 	bool has_default_route_rule = FALSE;
3021 	u_int32_t route_rules_array_size = 0;
3022 	u_int8_t *route_rules_array = NULL;
3023 	int route_rules_array_cursor;
3024 
3025 	int cursor;
3026 	int error = 0;
3027 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3028 
3029 	necp_policy_order order = 0;
3030 	struct necp_session_policy *policy = NULL;
3031 	u_int32_t policy_result_size = 0;
3032 	u_int8_t *policy_result = NULL;
3033 
3034 	// Read policy order
3035 	error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
3036 	if (error) {
3037 		NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
3038 		response_error = NECP_ERROR_INVALID_TLV;
3039 		goto fail;
3040 	}
3041 
3042 	// Read policy result
3043 	cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
3044 	if (error || cursor < 0) {
3045 		NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
3046 		response_error = NECP_ERROR_INVALID_TLV;
3047 		goto fail;
3048 	}
3049 
3050 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
3051 	if (error || policy_result_size == 0) {
3052 		NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
3053 		response_error = NECP_ERROR_INVALID_TLV;
3054 		goto fail;
3055 	}
3056 	if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
3057 		NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
3058 		response_error = NECP_ERROR_INVALID_TLV;
3059 		goto fail;
3060 	}
3061 	policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
3062 	if (policy_result == NULL) {
3063 		NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
3064 		response_error = NECP_ERROR_INTERNAL;
3065 		goto fail;
3066 	}
3067 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
3068 	if (error) {
3069 		NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
3070 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3071 		goto fail;
3072 	}
3073 	if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
3074 		NECPLOG0(LOG_ERR, "Failed to validate policy result");
3075 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
3076 		goto fail;
3077 	}
3078 
3079 	if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
3080 		// Read route rules conditions
3081 
3082 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3083 		    cursor >= 0;
3084 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3085 			u_int32_t route_rule_size = 0;
3086 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3087 			if (os_add_overflow(route_rules_array_size,
3088 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
3089 			    &route_rules_array_size)) {
3090 				NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
3091 				response_error = NECP_ERROR_INVALID_TLV;
3092 				goto fail;
3093 			}
3094 		}
3095 
3096 		if (route_rules_array_size == 0) {
3097 			NECPLOG0(LOG_ERR, "Failed to get policy route rules");
3098 			response_error = NECP_ERROR_INVALID_TLV;
3099 			goto fail;
3100 		}
3101 		if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
3102 			NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
3103 			response_error = NECP_ERROR_INVALID_TLV;
3104 			goto fail;
3105 		}
3106 		route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
3107 		if (route_rules_array == NULL) {
3108 			NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
3109 			response_error = NECP_ERROR_INTERNAL;
3110 			goto fail;
3111 		}
3112 
3113 		route_rules_array_cursor = 0;
3114 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
3115 		    cursor >= 0;
3116 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
3117 			u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
3118 			u_int32_t route_rule_size = 0;
3119 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
3120 			if (route_rule_size > 0 &&
3121 			    (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
3122 				// Add type
3123 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
3124 				route_rules_array_cursor += sizeof(route_rule_type);
3125 
3126 				// Add length
3127 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
3128 				route_rules_array_cursor += sizeof(route_rule_size);
3129 
3130 				// Add value
3131 				necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
3132 
3133 				if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3134 					NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
3135 					response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3136 					goto fail;
3137 				}
3138 
3139 				if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
3140 					if (has_default_route_rule) {
3141 						NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
3142 						response_error = NECP_ERROR_ROUTE_RULES_INVALID;
3143 						goto fail;
3144 					}
3145 					has_default_route_rule = TRUE;
3146 				}
3147 
3148 				route_rules_array_cursor += route_rule_size;
3149 			}
3150 		}
3151 	}
3152 
3153 	// Read policy conditions
3154 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3155 	    cursor >= 0;
3156 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3157 		u_int32_t condition_size = 0;
3158 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3159 
3160 		if (condition_size > 0) {
3161 			if (os_add_overflow(conditions_array_size,
3162 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
3163 			    &conditions_array_size)) {
3164 				NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
3165 				response_error = NECP_ERROR_INVALID_TLV;
3166 				goto fail;
3167 			}
3168 		}
3169 	}
3170 
3171 	if (conditions_array_size == 0) {
3172 		NECPLOG0(LOG_ERR, "Failed to get policy conditions");
3173 		response_error = NECP_ERROR_INVALID_TLV;
3174 		goto fail;
3175 	}
3176 	if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
3177 		NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
3178 		response_error = NECP_ERROR_INVALID_TLV;
3179 		goto fail;
3180 	}
3181 	conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
3182 	if (conditions_array == NULL) {
3183 		NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
3184 		response_error = NECP_ERROR_INTERNAL;
3185 		goto fail;
3186 	}
3187 
3188 	conditions_array_cursor = 0;
3189 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
3190 	    cursor >= 0;
3191 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
3192 		u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
3193 		u_int32_t condition_size = 0;
3194 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
3195 		if (condition_size > 0 &&
3196 		    (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
3197 			// Add type
3198 			memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
3199 			conditions_array_cursor += sizeof(condition_type);
3200 
3201 			// Add length
3202 			memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
3203 			conditions_array_cursor += sizeof(condition_size);
3204 
3205 			// Add value
3206 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
3207 			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))) {
3208 				NECPLOG0(LOG_ERR, "Failed to validate policy condition");
3209 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3210 				goto fail;
3211 			}
3212 
3213 			if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
3214 				has_default_condition = TRUE;
3215 			} else {
3216 				has_non_default_condition = TRUE;
3217 			}
3218 			if (has_default_condition && has_non_default_condition) {
3219 				NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
3220 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3221 				goto fail;
3222 			}
3223 
3224 			if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3225 				has_application_condition = TRUE;
3226 			}
3227 
3228 			if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3229 				has_real_application_condition = TRUE;
3230 			}
3231 
3232 			if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3233 				requires_application_condition = TRUE;
3234 			}
3235 
3236 			if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3237 				has_kernel_pid = TRUE;
3238 			}
3239 
3240 			conditions_array_cursor += condition_size;
3241 		}
3242 	}
3243 
3244 	if (requires_application_condition && !has_application_condition) {
3245 		NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3246 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3247 		goto fail;
3248 	}
3249 
3250 	if (has_kernel_pid && !is_pass_skip) {
3251 		NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3252 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3253 		goto fail;
3254 	}
3255 
3256 	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) {
3257 		response_error = NECP_ERROR_INTERNAL;
3258 		goto fail;
3259 	}
3260 
3261 	return policy->local_id;
3262 
3263 fail:
3264 	if (policy_result != NULL) {
3265 		kfree_data_sized_by(policy_result, policy_result_size);
3266 	}
3267 	if (conditions_array != NULL) {
3268 		kfree_data_sized_by(conditions_array, conditions_array_size);
3269 	}
3270 	if (route_rules_array != NULL) {
3271 		kfree_data_sized_by(route_rules_array, route_rules_array_size);
3272 	}
3273 
3274 	if (return_error != NULL) {
3275 		*return_error = necp_get_posix_error_for_necp_error(response_error);
3276 	}
3277 	return 0;
3278 }
3279 
3280 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3281 necp_policy_get_new_id(struct necp_session *session)
3282 {
3283 	session->last_policy_id++;
3284 	if (session->last_policy_id < 1) {
3285 		session->last_policy_id = 1;
3286 	}
3287 
3288 	necp_policy_id newid = session->last_policy_id;
3289 
3290 	if (newid == 0) {
3291 		NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3292 		return 0;
3293 	}
3294 
3295 	return newid;
3296 }
3297 
3298 /*
3299  *	For the policy dump response this is the structure:
3300  *
3301  *	<NECP_PACKET_HEADER>
3302  *	{
3303  *		type	:	NECP_TLV_POLICY_DUMP
3304  *		length	:	...
3305  *		value	:
3306  *		{
3307  *			{
3308  *				type	:	NECP_TLV_POLICY_ID
3309  *				len		:	...
3310  *				value	:	...
3311  *			}
3312  *			{
3313  *				type	:	NECP_TLV_POLICY_ORDER
3314  *				len		:	...
3315  *				value	:	...
3316  *			}
3317  *			{
3318  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3319  *				len		:	...
3320  *				value	:	...
3321  *			}
3322  *			{
3323  *				type	:	NECP_TLV_POLICY_OWNER
3324  *				len		:	...
3325  *				value	:	...
3326  *			}
3327  *			{
3328  *				type	:	NECP_TLV_POLICY_CONDITION
3329  *				len		:	...
3330  *				value	:
3331  *				{
3332  *					{
3333  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3334  *						len		:	...
3335  *						value	:	...
3336  *					}
3337  *					{
3338  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3339  *						len		:	...
3340  *						value	:	...
3341  *					}
3342  *					...
3343  *				}
3344  *			}
3345  *		}
3346  *	}
3347  *	{
3348  *		type	:	NECP_TLV_POLICY_DUMP
3349  *		length	:	...
3350  *		value	:
3351  *		{
3352  *			{
3353  *				type	:	NECP_TLV_POLICY_ID
3354  *				len		:	...
3355  *				value	:	...
3356  *			}
3357  *			{
3358  *				type	:	NECP_TLV_POLICY_ORDER
3359  *				len		:	...
3360  *				value	:	...
3361  *			}
3362  *			{
3363  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3364  *				len		:	...
3365  *				value	:	...
3366  *			}
3367  *			{
3368  *				type	:	NECP_TLV_POLICY_OWNER
3369  *				len		:	...
3370  *				value	:	...
3371  *			}
3372  *			{
3373  *				type	:	NECP_TLV_POLICY_CONDITION
3374  *				len		:	...
3375  *				value	:
3376  *				{
3377  *					{
3378  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3379  *						len		:	...
3380  *						value	:	...
3381  *					}
3382  *					{
3383  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3384  *						len		:	...
3385  *						value	:	...
3386  *					}
3387  *					...
3388  *				}
3389  *			}
3390  *		}
3391  *	}
3392  *	...
3393  */
3394 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3395 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3396 {
3397 	struct necp_kernel_socket_policy * __single policy = NULL;
3398 	int policy_i;
3399 	int policy_count = 0;
3400 	u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3401 	u_int32_t * __indexable tlv_buffer_lengths = NULL;
3402 	u_int32_t total_tlv_len = 0;
3403 	u_int8_t * __indexable result_buf = NULL;
3404 	u_int8_t *result_buf_cursor = result_buf;
3405 	char result_string[MAX_RESULT_STRING_LEN];
3406 	char proc_name_string[MAXCOMLEN + 1];
3407 
3408 	int error_code = 0;
3409 	bool error_occured = false;
3410 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3411 
3412 #define REPORT_ERROR(error) error_occured = true;               \
3413 	                                                response_error = error;         \
3414 	                                                goto done
3415 
3416 #define UNLOCK_AND_REPORT_ERROR(lock, error)    lck_rw_done(lock);      \
3417 	                                                                                        REPORT_ERROR(error)
3418 
3419 	errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3420 	if (cred_result != 0) {
3421 		NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3422 		REPORT_ERROR(NECP_ERROR_INTERNAL);
3423 	}
3424 
3425 	// LOCK
3426 	lck_rw_lock_shared(&necp_kernel_policy_lock);
3427 
3428 	if (necp_debug) {
3429 		NECPLOG0(LOG_DEBUG, "Gathering policies");
3430 	}
3431 
3432 	policy_count = necp_kernel_application_policies_count;
3433 
3434 	tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3435 	if (tlv_buffer_pointers == NULL) {
3436 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3437 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3438 	}
3439 
3440 	tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3441 	if (tlv_buffer_lengths == NULL) {
3442 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3443 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3444 	}
3445 
3446 	for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3447 		policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3448 
3449 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
3450 		memset(proc_name_string, 0, MAXCOMLEN + 1);
3451 
3452 		necp_get_result_description(result_string, policy->result, policy->result_parameter);
3453 		proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3454 
3455 		u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3456 		u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3457 
3458 		if (necp_debug) {
3459 			NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3460 		}
3461 
3462 		u_int32_t total_allocated_bytes =       sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) +                                     // NECP_TLV_POLICY_ID
3463 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) +                                                                                              // NECP_TLV_POLICY_ORDER
3464 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) +                                                                              // NECP_TLV_POLICY_SESSION_ORDER
3465 		    sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len +                                                                                                          // NECP_TLV_POLICY_RESULT_STRING
3466 		    sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len +                                                                                                              // NECP_TLV_POLICY_OWNER
3467 		    sizeof(u_int8_t) + sizeof(u_int32_t);                                                                                                                                               // NECP_TLV_POLICY_CONDITION
3468 
3469 		// We now traverse the condition_mask to see how much space we need to allocate
3470 		u_int64_t condition_mask = policy->condition_mask;
3471 		u_int64_t condition_negated_mask = policy->condition_negated_mask;
3472 		u_int8_t num_conditions = 0;
3473 		struct necp_string_id_mapping *account_id_entry = NULL;
3474 		char if_name[IFXNAMSIZ];
3475 		u_int32_t condition_tlv_length = 0;
3476 		memset(if_name, 0, sizeof(if_name));
3477 
3478 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3479 			num_conditions++;
3480 		} else {
3481 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3482 				num_conditions++;
3483 			}
3484 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3485 				num_conditions++;
3486 			}
3487 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3488 				snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3489 				condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3490 				num_conditions++;
3491 			}
3492 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3493 				condition_tlv_length += sizeof(policy->cond_protocol);
3494 				num_conditions++;
3495 			}
3496 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3497 				condition_tlv_length += sizeof(uuid_t);
3498 				num_conditions++;
3499 			}
3500 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3501 				condition_tlv_length += sizeof(uuid_t);
3502 				num_conditions++;
3503 			}
3504 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3505 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3506 				u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3507 				condition_tlv_length += domain_len;
3508 				num_conditions++;
3509 			}
3510 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3511 				condition_tlv_length += sizeof(u_int32_t);
3512 				num_conditions++;
3513 			}
3514 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3515 				u_int32_t url_len = strlen(policy->cond_url) + 1;
3516 				condition_tlv_length += url_len;
3517 				num_conditions++;
3518 			}
3519 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3520 				account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3521 				u_int32_t account_id_len = 0;
3522 				if (account_id_entry) {
3523 					account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3524 				}
3525 				condition_tlv_length += account_id_len;
3526 				num_conditions++;
3527 			}
3528 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3529 				condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3530 				num_conditions++;
3531 			}
3532 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3533 				condition_tlv_length += sizeof(uid_t);
3534 				num_conditions++;
3535 			}
3536 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3537 				condition_tlv_length += sizeof(uid_t);
3538 				num_conditions++;
3539 			}
3540 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3541 				condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3542 				num_conditions++;
3543 			}
3544 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3545 				num_conditions++;
3546 			}
3547 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3548 				u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3549 				condition_tlv_length += entitlement_len;
3550 				num_conditions++;
3551 			}
3552 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3553 				num_conditions++;
3554 			}
3555 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3556 				num_conditions++;
3557 			}
3558 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3559 				condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3560 				num_conditions++;
3561 			}
3562 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3563 				condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3564 				num_conditions++;
3565 			}
3566 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3567 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3568 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3569 				} else {
3570 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3571 				}
3572 				num_conditions++;
3573 			}
3574 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3575 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3576 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3577 				} else {
3578 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3579 				}
3580 				num_conditions++;
3581 			}
3582 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3583 				condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3584 				num_conditions++;
3585 			}
3586 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3587 				condition_tlv_length += sizeof(u_int32_t);
3588 				num_conditions++;
3589 			}
3590 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3591 				num_conditions++;
3592 			}
3593 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3594 				num_conditions++;
3595 			}
3596 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3597 				u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3598 				condition_tlv_length += identifier_len;
3599 				num_conditions++;
3600 			}
3601 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3602 				condition_tlv_length += sizeof(u_int16_t);
3603 				num_conditions++;
3604 			}
3605 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3606 				num_conditions++;
3607 			}
3608 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3609 				num_conditions++;
3610 			}
3611 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3612 				condition_tlv_length += sizeof(u_int16_t);
3613 				num_conditions++;
3614 			}
3615 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3616 				condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3617 				num_conditions++;
3618 			}
3619 		}
3620 
3621 		// These are for the condition TLVs (id, length, flags).  The space for "value" is already accounted for above.
3622 		condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3623 		total_allocated_bytes += condition_tlv_length;
3624 
3625 		u_int8_t * __indexable tlv_buffer;
3626 		tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3627 		if (tlv_buffer == NULL) {
3628 			NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3629 			continue;
3630 		}
3631 
3632 		u_int8_t *cursor = tlv_buffer;
3633 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3634 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3635 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3636 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3637 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3638 
3639 #define N_QUICK 256
3640 		u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3641 
3642 		u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3643 		if (condition_tlv_length <= N_QUICK) {
3644 			cond_buf = q_cond_buf;
3645 		} else {
3646 			cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3647 			if (cond_buf == NULL) {
3648 				NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3649 				kfree_data(tlv_buffer, total_allocated_bytes);
3650 				continue;
3651 			}
3652 		}
3653 
3654 		memset(cond_buf, 0, condition_tlv_length);
3655 		u_int8_t *cond_buf_cursor = cond_buf;
3656 		u_int8_t cond_flags = 0;
3657 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3658 			cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3659 		} else {
3660 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3661 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3662 				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);
3663 			}
3664 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3665 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3666 				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);
3667 			}
3668 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3669 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3670 				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);
3671 			}
3672 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3673 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3674 				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,
3675 				    if_name, cond_buf, condition_tlv_length);
3676 			}
3677 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3678 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3679 				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,
3680 				    cond_buf, condition_tlv_length);
3681 			}
3682 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3683 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3684 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3685 				if (entry != NULL) {
3686 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3687 					    cond_buf, condition_tlv_length);
3688 				}
3689 			}
3690 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3691 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3692 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3693 				if (entry != NULL) {
3694 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3695 					    cond_buf, condition_tlv_length);
3696 				}
3697 			}
3698 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3699 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3700 				cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3701 				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);
3702 			}
3703 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3704 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3705 				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,
3706 				    cond_buf, condition_tlv_length);
3707 			}
3708 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3709 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3710 				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);
3711 			}
3712 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3713 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3714 				if (account_id_entry != NULL) {
3715 					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);
3716 				}
3717 			}
3718 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3719 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3720 				uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3721 				memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3722 				memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3723 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3724 				    cond_buf, condition_tlv_length);
3725 			}
3726 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3727 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3728 				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,
3729 				    cond_buf, condition_tlv_length);
3730 			}
3731 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3732 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3733 				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,
3734 				    cond_buf, condition_tlv_length);
3735 			}
3736 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3737 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3738 				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,
3739 				    cond_buf, condition_tlv_length);
3740 			}
3741 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3742 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3743 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3744 				    cond_buf, condition_tlv_length);
3745 			}
3746 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3747 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3748 				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);
3749 			}
3750 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3751 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3752 				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);
3753 			}
3754 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3755 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3756 				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);
3757 			}
3758 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3759 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3760 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3761 				    sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3762 				    cond_buf, condition_tlv_length);
3763 			}
3764 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3765 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3766 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3767 					struct necp_policy_condition_addr_range range;
3768 					memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3769 					memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3770 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3771 					    cond_buf, condition_tlv_length);
3772 				} else {
3773 					struct necp_policy_condition_addr addr;
3774 					addr.prefix = policy->cond_local_prefix;
3775 					memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3776 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3777 					    cond_buf, condition_tlv_length);
3778 				}
3779 			}
3780 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3781 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3782 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3783 					struct necp_policy_condition_addr_range range;
3784 					memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3785 					memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3786 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3787 					    cond_buf, condition_tlv_length);
3788 				} else {
3789 					struct necp_policy_condition_addr addr;
3790 					addr.prefix = policy->cond_remote_prefix;
3791 					memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3792 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3793 					    cond_buf, condition_tlv_length);
3794 				}
3795 			}
3796 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3797 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3798 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3799 				    sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3800 				    cond_buf, condition_tlv_length);
3801 			}
3802 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3803 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3804 				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);
3805 			}
3806 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3807 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3808 				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);
3809 			}
3810 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3811 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3812 				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);
3813 			}
3814 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3815 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3816 				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);
3817 			}
3818 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3819 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3820 				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);
3821 			}
3822 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3823 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3824 				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);
3825 			}
3826 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3827 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3828 				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);
3829 			}
3830 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3831 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3832 				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);
3833 			}
3834 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3835 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3836 				uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3837 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3838 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3839 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3840 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3841 				    cond_buf, condition_tlv_length);
3842 			}
3843 		}
3844 
3845 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3846 		if (cond_buf != q_cond_buf) {
3847 			kfree_data(cond_buf, condition_tlv_length);
3848 		}
3849 
3850 		tlv_buffer_pointers[policy_i] = tlv_buffer;
3851 		tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3852 
3853 		// This is the length of the TLV for NECP_TLV_POLICY_DUMP
3854 		total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3855 	}
3856 
3857 	// UNLOCK
3858 	lck_rw_done(&necp_kernel_policy_lock);
3859 
3860 	// Copy out
3861 	if (out_buffer != 0) {
3862 		if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3863 			NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3864 			REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3865 		}
3866 
3867 		// Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3868 		result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3869 		if (result_buf == NULL) {
3870 			NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3871 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3872 		}
3873 
3874 		// Add four bytes for total length at the start
3875 		memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3876 
3877 		// Copy the TLVs
3878 		result_buf_cursor = result_buf + sizeof(u_int32_t);
3879 		for (int i = 0; i < policy_count; i++) {
3880 			if (tlv_buffer_pointers[i] != NULL) {
3881 				result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3882 				    result_buf, total_tlv_len + sizeof(u_int32_t));
3883 			}
3884 		}
3885 
3886 		int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3887 		if (copy_error) {
3888 			NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3889 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3890 		}
3891 	}
3892 
3893 done:
3894 
3895 	if (error_occured) {
3896 		error_code = necp_get_posix_error_for_necp_error(response_error);
3897 	}
3898 
3899 	if (result_buf != NULL) {
3900 		kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3901 	}
3902 
3903 	if (tlv_buffer_pointers != NULL) {
3904 		for (int i = 0; i < policy_count; i++) {
3905 			if (tlv_buffer_pointers[i] != NULL) {
3906 				kfree_data_addr(tlv_buffer_pointers[i]);
3907 				tlv_buffer_pointers[i] = NULL;
3908 			}
3909 		}
3910 		kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3911 	}
3912 
3913 	if (tlv_buffer_lengths != NULL) {
3914 		kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3915 	}
3916 #undef N_QUICK
3917 #undef RESET_COND_BUF
3918 #undef REPORT_ERROR
3919 #undef UNLOCK_AND_REPORT_ERROR
3920 
3921 	return error_code;
3922 }
3923 
3924 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)3925 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t * __sized_by(conditions_array_size)conditions_array, u_int32_t conditions_array_size, u_int8_t * __sized_by(route_rules_array_size)route_rules_array, u_int32_t route_rules_array_size, u_int8_t *__sized_by(result_size)result, u_int32_t result_size)
3926 {
3927 	struct necp_session_policy *new_policy = NULL;
3928 	struct necp_session_policy *tmp_policy = NULL;
3929 
3930 	if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3931 		goto done;
3932 	}
3933 
3934 	new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3935 	new_policy->applied = FALSE;
3936 	new_policy->pending_deletion = FALSE;
3937 	new_policy->pending_update = FALSE;
3938 	new_policy->order = order;
3939 	new_policy->conditions = conditions_array;
3940 	new_policy->conditions_size = conditions_array_size;
3941 	new_policy->route_rules = route_rules_array;
3942 	new_policy->route_rules_size = route_rules_array_size;
3943 	new_policy->result = result;
3944 	new_policy->result_size = result_size;
3945 	new_policy->local_id = necp_policy_get_new_id(session);
3946 
3947 	LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3948 
3949 	session->dirty = TRUE;
3950 
3951 	if (necp_debug) {
3952 		NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3953 	}
3954 done:
3955 	return new_policy;
3956 }
3957 
3958 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3959 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3960 {
3961 	struct necp_session_policy *policy = NULL;
3962 	if (policy_id == 0) {
3963 		return NULL;
3964 	}
3965 
3966 	LIST_FOREACH(policy, &session->policies, chain) {
3967 		if (policy->local_id == policy_id) {
3968 			return policy;
3969 		}
3970 	}
3971 
3972 	return NULL;
3973 }
3974 
3975 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3976 necp_policy_get_result_type(struct necp_session_policy *policy)
3977 {
3978 	return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3979 }
3980 
3981 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3982 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3983 {
3984 	return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3985 }
3986 
3987 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)3988 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t * __sized_by(parameter_buffer_length)parameter_buffer, u_int32_t parameter_buffer_length)
3989 {
3990 	if (policy) {
3991 		u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3992 		if (parameter_buffer_length >= parameter_length) {
3993 			u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3994 			if (parameter && parameter_buffer) {
3995 				memcpy(parameter_buffer, parameter, parameter_length);
3996 				return TRUE;
3997 			}
3998 		}
3999 	}
4000 
4001 	return FALSE;
4002 }
4003 
4004 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)4005 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
4006 {
4007 	if (session == NULL || policy == NULL) {
4008 		return FALSE;
4009 	}
4010 
4011 	policy->pending_deletion = TRUE;
4012 	session->dirty = TRUE;
4013 
4014 	if (necp_debug) {
4015 		NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
4016 	}
4017 	return TRUE;
4018 }
4019 
4020 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)4021 necp_policy_mark_all_for_deletion(struct necp_session *session)
4022 {
4023 	struct necp_session_policy *policy = NULL;
4024 	struct necp_session_policy *temp_policy = NULL;
4025 
4026 	LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4027 		necp_policy_mark_for_deletion(session, policy);
4028 	}
4029 
4030 	return TRUE;
4031 }
4032 
4033 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)4034 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
4035 {
4036 	if (session == NULL || policy == NULL) {
4037 		return FALSE;
4038 	}
4039 
4040 	LIST_REMOVE(policy, chain);
4041 
4042 	if (policy->result) {
4043 		kfree_data_sized_by(policy->result, policy->result_size);
4044 		policy->result = NULL;
4045 		policy->result_size = 0;
4046 	}
4047 
4048 	if (policy->conditions) {
4049 		kfree_data_sized_by(policy->conditions, policy->conditions_size);
4050 		policy->conditions = NULL;
4051 		policy->conditions_size = 0;
4052 	}
4053 
4054 	if (policy->route_rules) {
4055 		kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
4056 		policy->route_rules = NULL;
4057 		policy->route_rules_size = 0;
4058 	}
4059 
4060 	zfree(necp_session_policy_zone, policy);
4061 
4062 	if (necp_debug) {
4063 		NECPLOG0(LOG_DEBUG, "Removed NECP policy");
4064 	}
4065 	return TRUE;
4066 }
4067 
4068 static bool
necp_policy_unapply(struct necp_session_policy * policy)4069 necp_policy_unapply(struct necp_session_policy *policy)
4070 {
4071 	int i = 0;
4072 	if (policy == NULL) {
4073 		return FALSE;
4074 	}
4075 
4076 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4077 
4078 	// Release local uuid mappings
4079 	if (!uuid_is_null(policy->applied_app_uuid)) {
4080 		bool removed_mapping = FALSE;
4081 		if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
4082 			necp_uuid_app_id_mappings_dirty = TRUE;
4083 			necp_num_uuid_app_id_mappings--;
4084 		}
4085 		uuid_clear(policy->applied_app_uuid);
4086 	}
4087 	if (!uuid_is_null(policy->applied_real_app_uuid)) {
4088 		necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
4089 		uuid_clear(policy->applied_real_app_uuid);
4090 	}
4091 	if (!uuid_is_null(policy->applied_result_uuid)) {
4092 		necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
4093 		uuid_clear(policy->applied_result_uuid);
4094 	}
4095 
4096 	// Release string mappings
4097 	if (policy->applied_account != NULL) {
4098 		necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
4099 		kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
4100 		policy->applied_account = NULL;
4101 		policy->applied_account_size = 0;
4102 	}
4103 
4104 	// Release route rule
4105 	if (policy->applied_route_rules_id != 0) {
4106 		necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
4107 		policy->applied_route_rules_id = 0;
4108 	}
4109 
4110 	// Remove socket policies
4111 	for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
4112 		if (policy->kernel_socket_policies[i] != 0) {
4113 			necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
4114 			policy->kernel_socket_policies[i] = 0;
4115 		}
4116 	}
4117 
4118 	// Remove IP output policies
4119 	for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
4120 		if (policy->kernel_ip_output_policies[i] != 0) {
4121 			necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
4122 			policy->kernel_ip_output_policies[i] = 0;
4123 		}
4124 	}
4125 
4126 	policy->applied = FALSE;
4127 
4128 	return TRUE;
4129 }
4130 
4131 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION                 0
4132 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION             1
4133 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION                                2
4134 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS                   3
4135 struct necp_policy_result_ip_tunnel {
4136 	u_int32_t secondary_result;
4137 	char interface_name[IFXNAMSIZ];
4138 } __attribute__((__packed__));
4139 
4140 struct necp_policy_result_service {
4141 	uuid_t identifier;
4142 	u_int32_t data;
4143 } __attribute__((__packed__));
4144 
4145 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)4146 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
4147 {
4148 	bool socket_only_conditions = FALSE;
4149 	bool socket_ip_conditions = FALSE;
4150 
4151 	bool socket_layer_non_id_conditions = FALSE;
4152 	bool ip_output_layer_non_id_conditions = FALSE;
4153 	bool ip_output_layer_non_id_only = FALSE;
4154 	bool ip_output_layer_id_condition = FALSE;
4155 	bool ip_output_layer_tunnel_condition_from_id = FALSE;
4156 	bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
4157 	necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
4158 
4159 	u_int64_t master_condition_mask = 0;
4160 	u_int64_t master_condition_negated_mask = 0;
4161 	ifnet_t __single cond_bound_interface = NULL;
4162 	u_int32_t cond_account_id = 0;
4163 	char *cond_domain __null_terminated = NULL;
4164 	u_int32_t cond_domain_filter = 0;
4165 	char *cond_url __null_terminated = NULL;
4166 	char *cond_custom_entitlement __null_terminated = NULL;
4167 	char *cond_signing_identifier __null_terminated = NULL;
4168 	pid_t cond_pid = 0;
4169 	int32_t cond_pid_version = 0;
4170 	uid_t cond_uid = 0;
4171 	uid_t cond_real_uid = 0;
4172 	necp_app_id cond_app_id = 0;
4173 	necp_app_id cond_real_app_id = 0;
4174 	struct necp_policy_condition_tc_range cond_traffic_class;
4175 	cond_traffic_class.start_tc = 0;
4176 	cond_traffic_class.end_tc = 0;
4177 	u_int16_t cond_protocol = 0;
4178 	union necp_sockaddr_union cond_local_start;
4179 	union necp_sockaddr_union cond_local_end;
4180 	u_int8_t cond_local_prefix = 0;
4181 	union necp_sockaddr_union cond_remote_start;
4182 	union necp_sockaddr_union cond_remote_end;
4183 	u_int8_t cond_remote_prefix = 0;
4184 	u_int32_t cond_client_flags = 0;
4185 	u_int8_t cond_local_networks_flags = 0;
4186 	u_int32_t offset = 0;
4187 	u_int8_t ultimate_result = 0;
4188 	u_int32_t secondary_result = 0;
4189 	struct necp_policy_condition_agent_type cond_agent_type = {};
4190 	struct necp_policy_condition_sdk_version cond_sdk_version = {};
4191 	u_int16_t cond_packet_filter_tags = 0;
4192 	u_int16_t cond_scheme_port = 0;
4193 	u_int32_t cond_bound_interface_flags = 0;
4194 	u_int32_t cond_bound_interface_eflags = 0;
4195 	u_int32_t cond_bound_interface_xflags = 0;
4196 	necp_kernel_policy_result_parameter secondary_result_parameter;
4197 	memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
4198 	u_int32_t cond_last_interface_index = 0;
4199 	necp_kernel_policy_result_parameter ultimate_result_parameter;
4200 	memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
4201 
4202 	if (policy == NULL) {
4203 		return FALSE;
4204 	}
4205 
4206 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4207 
4208 	// Process conditions
4209 	while (offset < policy->conditions_size) {
4210 		u_int32_t length = 0;
4211 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
4212 
4213 		u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
4214 		u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
4215 		bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
4216 		u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
4217 		u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
4218 		switch (condition_type) {
4219 		case NECP_POLICY_CONDITION_DEFAULT: {
4220 			socket_ip_conditions = TRUE;
4221 			break;
4222 		}
4223 		case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4224 			master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4225 			socket_ip_conditions = TRUE;
4226 			break;
4227 		}
4228 		case NECP_POLICY_CONDITION_HAS_CLIENT: {
4229 			master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4230 			socket_only_conditions = TRUE;
4231 			break;
4232 		}
4233 		case NECP_POLICY_CONDITION_ENTITLEMENT: {
4234 			if (condition_length > 0) {
4235 				if (cond_custom_entitlement == NULL) {
4236 					cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4237 					if (cond_custom_entitlement != NULL) {
4238 						master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4239 						socket_only_conditions = TRUE;
4240 					}
4241 				}
4242 			} else {
4243 				master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4244 				socket_only_conditions = TRUE;
4245 			}
4246 			break;
4247 		}
4248 		case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4249 			master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4250 			if (condition_is_negative) {
4251 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4252 			}
4253 			socket_only_conditions = TRUE;
4254 			break;
4255 		}
4256 		case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4257 			master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4258 			socket_only_conditions = TRUE;
4259 			break;
4260 		}
4261 		case NECP_POLICY_CONDITION_SDK_VERSION: {
4262 			if (condition_length >= sizeof(cond_sdk_version)) {
4263 				master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4264 				memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4265 				socket_only_conditions = TRUE;
4266 			}
4267 			break;
4268 		}
4269 		case NECP_POLICY_CONDITION_DOMAIN: {
4270 			// Make sure there is only one such rule
4271 			if (condition_length > 0 && cond_domain == NULL) {
4272 				const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4273 
4274 				u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4275 				cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4276 				if (cond_domain != NULL) {
4277 					master_condition_mask |= mask_value;
4278 					if (condition_is_negative) {
4279 						master_condition_negated_mask |= mask_value;
4280 					}
4281 					socket_only_conditions = TRUE;
4282 				}
4283 			}
4284 			break;
4285 		}
4286 		case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4287 			// Make sure there is only one such rule
4288 			if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4289 				memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4290 				if (cond_domain_filter != 0) {
4291 					master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4292 					if (condition_is_negative) {
4293 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4294 					}
4295 					socket_only_conditions = TRUE;
4296 				}
4297 			}
4298 			break;
4299 		}
4300 		case NECP_POLICY_CONDITION_URL: {
4301 			// Make sure there is only one such rule
4302 			if (condition_length > 0 && cond_url == NULL) {
4303 				u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4304 				cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4305 				if (cond_url != NULL) {
4306 					master_condition_mask |= mask_value;
4307 					if (condition_is_negative) {
4308 						master_condition_negated_mask |= mask_value;
4309 					}
4310 					socket_only_conditions = TRUE;
4311 				}
4312 			}
4313 			break;
4314 		}
4315 		case NECP_POLICY_CONDITION_ACCOUNT: {
4316 			// Make sure there is only one such rule
4317 			if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4318 				size_t string_buffer_size = 0;
4319 				char * __sized_by(string_buffer_size) string = NULL;
4320 				string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4321 				string_buffer_size = condition_length + 1;
4322 				if (string != NULL) {
4323 					memcpy(string, condition_value, condition_length);
4324 					string[condition_length] = 0;
4325 					cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4326 					if (cond_account_id != 0) {
4327 						policy->applied_account = string;         // Save the string in parent policy
4328 						policy->applied_account_size = string_buffer_size;
4329 						master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4330 						if (condition_is_negative) {
4331 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4332 						}
4333 						socket_only_conditions = TRUE;
4334 					} else {
4335 						kfree_data_sized_by(string, string_buffer_size);
4336 					}
4337 				}
4338 			}
4339 			break;
4340 		}
4341 		case NECP_POLICY_CONDITION_APPLICATION: {
4342 			// Make sure there is only one such rule, because we save the uuid in the policy
4343 			if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4344 				bool allocated_mapping = FALSE;
4345 				uuid_t application_uuid;
4346 				memcpy(application_uuid, condition_value, sizeof(uuid_t));
4347 				cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4348 				if (cond_app_id != 0) {
4349 					if (allocated_mapping) {
4350 						necp_uuid_app_id_mappings_dirty = TRUE;
4351 						necp_num_uuid_app_id_mappings++;
4352 					}
4353 					uuid_copy(policy->applied_app_uuid, application_uuid);
4354 					master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4355 					if (condition_is_negative) {
4356 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4357 					}
4358 					socket_only_conditions = TRUE;
4359 				}
4360 			}
4361 			break;
4362 		}
4363 		case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4364 			// Make sure there is only one such rule, because we save the uuid in the policy
4365 			if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4366 				uuid_t real_application_uuid;
4367 				memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4368 				cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4369 				if (cond_real_app_id != 0) {
4370 					uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4371 					master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4372 					if (condition_is_negative) {
4373 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4374 					}
4375 					socket_only_conditions = TRUE;
4376 				}
4377 			}
4378 			break;
4379 		}
4380 		case NECP_POLICY_CONDITION_PID: {
4381 			if (condition_length >= sizeof(pid_t)) {
4382 				master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4383 				if (condition_is_negative) {
4384 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4385 				}
4386 				memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4387 				if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4388 					memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4389 				}
4390 				socket_only_conditions = TRUE;
4391 			}
4392 			break;
4393 		}
4394 		case NECP_POLICY_CONDITION_UID: {
4395 			if (condition_length >= sizeof(uid_t)) {
4396 				master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4397 				if (condition_is_negative) {
4398 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4399 				}
4400 				memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4401 				socket_only_conditions = TRUE;
4402 			}
4403 			break;
4404 		}
4405 		case NECP_POLICY_CONDITION_REAL_UID: {
4406 			if (condition_length >= sizeof(uid_t)) {
4407 				master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4408 				if (condition_is_negative) {
4409 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4410 				}
4411 				memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4412 				socket_only_conditions = TRUE;
4413 			}
4414 			break;
4415 		}
4416 		case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4417 			if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4418 				master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4419 				if (condition_is_negative) {
4420 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4421 				}
4422 				memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4423 				socket_only_conditions = TRUE;
4424 			}
4425 			break;
4426 		}
4427 		case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4428 			if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4429 				char interface_name[IFXNAMSIZ];
4430 				memcpy(interface_name, condition_value, condition_length);
4431 				interface_name[condition_length - 1] = 0;         // Make sure the string is NULL terminated
4432 				if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4433 					master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4434 					if (condition_is_negative) {
4435 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4436 					}
4437 				}
4438 				socket_ip_conditions = TRUE;
4439 			}
4440 			break;
4441 		}
4442 		case NECP_POLICY_CONDITION_IP_PROTOCOL:
4443 		case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4444 			if (condition_length >= sizeof(u_int16_t)) {
4445 				master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4446 				if (condition_is_negative) {
4447 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4448 				}
4449 				memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4450 				if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4451 					socket_only_conditions = TRUE;
4452 				} else {
4453 					socket_ip_conditions = TRUE;
4454 				}
4455 			}
4456 			break;
4457 		}
4458 		case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4459 			if (condition_is_negative) {
4460 				master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4461 			}
4462 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4463 			socket_ip_conditions = TRUE;
4464 			if (condition_length >= sizeof(u_int8_t)) {
4465 				memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4466 			}
4467 			break;
4468 		}
4469 		case NECP_POLICY_CONDITION_LOCAL_ADDR:
4470 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4471 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4472 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4473 				break;
4474 			}
4475 
4476 			cond_local_prefix = address_struct->prefix;
4477 			memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4478 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4479 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4480 			if (condition_is_negative) {
4481 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4482 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4483 			}
4484 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4485 				socket_only_conditions = TRUE;
4486 			} else {
4487 				socket_ip_conditions = TRUE;
4488 			}
4489 			break;
4490 		}
4491 		case NECP_POLICY_CONDITION_REMOTE_ADDR:
4492 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4493 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4494 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4495 				break;
4496 			}
4497 
4498 			cond_remote_prefix = address_struct->prefix;
4499 			memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4500 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4501 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4502 			if (condition_is_negative) {
4503 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4504 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4505 			}
4506 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4507 				socket_only_conditions = TRUE;
4508 			} else {
4509 				socket_ip_conditions = TRUE;
4510 			}
4511 			break;
4512 		}
4513 		case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4514 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4515 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4516 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4517 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4518 				break;
4519 			}
4520 
4521 			memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4522 			memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4523 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4524 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4525 			if (condition_is_negative) {
4526 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4527 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4528 			}
4529 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4530 				socket_only_conditions = TRUE;
4531 			} else {
4532 				socket_ip_conditions = TRUE;
4533 			}
4534 			break;
4535 		}
4536 		case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4537 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4538 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4539 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4540 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4541 				break;
4542 			}
4543 
4544 			memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4545 			memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4546 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4547 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4548 			if (condition_is_negative) {
4549 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4550 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4551 			}
4552 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4553 				socket_only_conditions = TRUE;
4554 			} else {
4555 				socket_ip_conditions = TRUE;
4556 			}
4557 			break;
4558 		}
4559 		case NECP_POLICY_CONDITION_AGENT_TYPE: {
4560 			if (condition_length >= sizeof(cond_agent_type)) {
4561 				master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4562 				memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4563 				socket_only_conditions = TRUE;
4564 			}
4565 			break;
4566 		}
4567 		case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4568 			if (condition_is_negative) {
4569 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4570 			}
4571 			master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4572 			socket_only_conditions = TRUE;
4573 			if (condition_length >= sizeof(u_int32_t)) {
4574 				memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4575 			} else {
4576 				// Empty means match on fallback traffic
4577 				cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4578 			}
4579 			break;
4580 		}
4581 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4582 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4583 			if (condition_is_negative) {
4584 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4585 			}
4586 			socket_only_conditions = TRUE;
4587 			break;
4588 		}
4589 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4590 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4591 			if (condition_is_negative) {
4592 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4593 			}
4594 			socket_only_conditions = TRUE;
4595 			break;
4596 		}
4597 		case NECP_POLICY_CONDITION_SCHEME_PORT: {
4598 			master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4599 			if (condition_is_negative) {
4600 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4601 			}
4602 			memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4603 			socket_ip_conditions = TRUE;
4604 			break;
4605 		}
4606 		case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4607 			if (condition_length > 0) {
4608 				if (cond_signing_identifier == NULL) {
4609 					cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4610 					if (cond_signing_identifier != NULL) {
4611 						master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4612 						socket_only_conditions = TRUE;
4613 						if (condition_is_negative) {
4614 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4615 						}
4616 					}
4617 				}
4618 			}
4619 			break;
4620 		}
4621 		case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4622 			if (condition_length >= sizeof(u_int16_t)) {
4623 				master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4624 				if (condition_is_negative) {
4625 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4626 				}
4627 				memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4628 				socket_ip_conditions = TRUE;
4629 			}
4630 			break;
4631 		}
4632 		case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4633 			master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4634 			if (condition_is_negative) {
4635 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4636 			}
4637 			socket_only_conditions = TRUE;
4638 			break;
4639 		}
4640 		case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4641 			master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4642 			if (condition_is_negative) {
4643 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4644 			}
4645 			socket_only_conditions = TRUE;
4646 			break;
4647 		}
4648 		case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4649 			if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4650 				u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4651 				memcpy(&flags, condition_value, sizeof(flags));
4652 				cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4653 				cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4654 				cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4655 				master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4656 				if (condition_is_negative) {
4657 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4658 				}
4659 				socket_ip_conditions = TRUE;
4660 			}
4661 			break;
4662 		}
4663 		default: {
4664 			break;
4665 		}
4666 		}
4667 
4668 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4669 	}
4670 
4671 	// Process result
4672 	ultimate_result = necp_policy_get_result_type(policy);
4673 	switch (ultimate_result) {
4674 	case NECP_POLICY_RESULT_PASS: {
4675 		u_int32_t pass_flags = 0;
4676 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4677 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4678 				ultimate_result_parameter.pass_flags = pass_flags;
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 		} else if (socket_ip_conditions) {
4685 			socket_layer_non_id_conditions = TRUE;
4686 			ip_output_layer_id_condition = TRUE;
4687 			ip_output_layer_non_id_conditions = TRUE;
4688 		}
4689 		break;
4690 	}
4691 	case NECP_POLICY_RESULT_DROP: {
4692 		u_int32_t drop_flags = 0;
4693 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4694 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4695 				ultimate_result_parameter.drop_flags = drop_flags;
4696 			}
4697 		}
4698 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4699 			socket_layer_non_id_conditions = TRUE;
4700 		} else if (socket_ip_conditions) {
4701 			socket_layer_non_id_conditions = TRUE;
4702 			ip_output_layer_non_id_conditions = TRUE;
4703 			ip_output_layer_non_id_only = TRUE;         // Only apply drop to packets that didn't go through socket layer
4704 		}
4705 		break;
4706 	}
4707 	case NECP_POLICY_RESULT_SKIP: {
4708 		u_int32_t skip_policy_order = 0;
4709 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4710 			ultimate_result_parameter.skip_policy_order = skip_policy_order;
4711 		}
4712 
4713 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4714 			socket_layer_non_id_conditions = TRUE;
4715 			ip_output_layer_id_condition = TRUE;
4716 		} else if (socket_ip_conditions) {
4717 			socket_layer_non_id_conditions = TRUE;
4718 			ip_output_layer_non_id_conditions = TRUE;
4719 		}
4720 		break;
4721 	}
4722 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
4723 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
4724 		u_int32_t control_unit = 0;
4725 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4726 			ultimate_result_parameter.flow_divert_control_unit = control_unit;
4727 		}
4728 		socket_layer_non_id_conditions = TRUE;
4729 		break;
4730 	}
4731 	case NECP_POLICY_RESULT_IP_TUNNEL: {
4732 		struct necp_policy_result_ip_tunnel tunnel_parameters;
4733 		u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4734 		if (tunnel_parameters_length > sizeof(u_int32_t) &&
4735 		    tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4736 		    necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4737 			ifnet_t __single tunnel_interface = NULL;
4738 			tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0;         // Make sure the string is NULL terminated
4739 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4740 				ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4741 				ifnet_release(tunnel_interface);
4742 			}
4743 
4744 			secondary_result = tunnel_parameters.secondary_result;
4745 			if (secondary_result) {
4746 				cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4747 			}
4748 		}
4749 
4750 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4751 			socket_layer_non_id_conditions = TRUE;
4752 			ip_output_layer_id_condition = TRUE;
4753 			if (secondary_result) {
4754 				ip_output_layer_tunnel_condition_from_id = TRUE;
4755 			}
4756 		} else if (socket_ip_conditions) {
4757 			socket_layer_non_id_conditions = TRUE;
4758 			ip_output_layer_id_condition = TRUE;
4759 			ip_output_layer_non_id_conditions = TRUE;
4760 			if (secondary_result) {
4761 				ip_output_layer_tunnel_condition_from_id = TRUE;
4762 				ip_output_layer_tunnel_condition_from_non_id = TRUE;
4763 			}
4764 		}
4765 		break;
4766 	}
4767 	case NECP_POLICY_RESULT_USE_NETAGENT:
4768 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4769 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4770 		uuid_t netagent_uuid;
4771 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4772 			ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4773 			if (ultimate_result_parameter.netagent_id != 0) {
4774 				uuid_copy(policy->applied_result_uuid, netagent_uuid);
4775 				socket_layer_non_id_conditions = TRUE;
4776 			}
4777 		}
4778 		break;
4779 	}
4780 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4781 		u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4782 		if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4783 			char interface_name[IFXNAMSIZ];
4784 			ifnet_t __single scope_interface = NULL;
4785 			necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4786 			interface_name[interface_name_length - 1] = 0;         // Make sure the string is NULL terminated
4787 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4788 				ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4789 				socket_layer_non_id_conditions = TRUE;
4790 				ifnet_release(scope_interface);
4791 			}
4792 		}
4793 		break;
4794 	}
4795 	case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4796 		socket_layer_non_id_conditions = TRUE;
4797 		break;
4798 	}
4799 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4800 		socket_layer_non_id_conditions = TRUE;
4801 		break;
4802 	}
4803 	case NECP_POLICY_RESULT_ROUTE_RULES: {
4804 		if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4805 			bool has_socket_only_actions = FALSE;
4806 			u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4807 			if (route_rule_id > 0) {
4808 				policy->applied_route_rules_id = route_rule_id;
4809 				ultimate_result_parameter.route_rule_id = route_rule_id;
4810 				if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4811 					socket_layer_non_id_conditions = TRUE;
4812 				} else if (socket_ip_conditions) {
4813 					socket_layer_non_id_conditions = TRUE;
4814 					ip_output_layer_non_id_conditions = TRUE;
4815 					ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4816 				}
4817 			}
4818 		}
4819 		break;
4820 	}
4821 	default: {
4822 		break;
4823 	}
4824 	}
4825 
4826 	if (socket_layer_non_id_conditions) {
4827 		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);
4828 
4829 		if (policy_id == 0) {
4830 			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4831 			goto fail;
4832 		}
4833 
4834 		cond_ip_output_layer_id = policy_id;
4835 		policy->kernel_socket_policies[0] = policy_id;
4836 	}
4837 
4838 	if (ip_output_layer_non_id_conditions) {
4839 		u_int64_t condition_mask = master_condition_mask;
4840 		if (ip_output_layer_non_id_only) {
4841 			condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4842 		}
4843 
4844 		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);
4845 
4846 		if (policy_id == 0) {
4847 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4848 			goto fail;
4849 		}
4850 
4851 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4852 	}
4853 
4854 	if (ip_output_layer_id_condition) {
4855 		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);
4856 
4857 		if (policy_id == 0) {
4858 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4859 			goto fail;
4860 		}
4861 
4862 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4863 	}
4864 
4865 	// Extra policies for IP Output tunnels for when packets loop back
4866 	if (ip_output_layer_tunnel_condition_from_id) {
4867 		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);
4868 
4869 		if (policy_id == 0) {
4870 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4871 			goto fail;
4872 		}
4873 
4874 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4875 	}
4876 
4877 	if (ip_output_layer_tunnel_condition_from_id) {
4878 		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);
4879 
4880 		if (policy_id == 0) {
4881 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4882 			goto fail;
4883 		}
4884 
4885 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4886 	}
4887 
4888 	policy->applied = TRUE;
4889 	policy->pending_update = FALSE;
4890 	return TRUE;
4891 
4892 fail:
4893 	return FALSE;
4894 }
4895 
4896 static void
necp_policy_apply_all(struct necp_session * session)4897 necp_policy_apply_all(struct necp_session *session)
4898 {
4899 	struct necp_session_policy *policy = NULL;
4900 	struct necp_session_policy *temp_policy = NULL;
4901 	struct kev_necp_policies_changed_data kev_data;
4902 	kev_data.changed_count = 0;
4903 
4904 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4905 
4906 	// Remove exisiting applied policies
4907 	if (session->dirty) {
4908 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4909 			if (policy->pending_deletion) {
4910 				if (policy->applied) {
4911 					necp_policy_unapply(policy);
4912 				}
4913 				// Delete the policy
4914 				necp_policy_delete(session, policy);
4915 			} else if (!policy->applied) {
4916 				necp_policy_apply(session, policy);
4917 			} else if (policy->pending_update) {
4918 				// Must have been applied, but needs an update. Remove and re-add.
4919 				necp_policy_unapply(policy);
4920 				necp_policy_apply(session, policy);
4921 			}
4922 		}
4923 
4924 		necp_kernel_socket_policies_update_uuid_table();
4925 		necp_kernel_socket_policies_reprocess();
4926 		necp_kernel_ip_output_policies_reprocess();
4927 
4928 		// Clear dirty bit flags
4929 		session->dirty = FALSE;
4930 	}
4931 
4932 	lck_rw_done(&necp_kernel_policy_lock);
4933 
4934 	necp_update_all_clients();
4935 	necp_post_change_event(&kev_data);
4936 
4937 	if (necp_debug) {
4938 		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4939 	}
4940 }
4941 
4942 // Kernel Policy Management
4943 // ---------------------
4944 // Kernel policies are derived from session policies
4945 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4946 necp_kernel_policy_get_new_id(bool socket_level)
4947 {
4948 	static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4949 	static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4950 
4951 	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4952 
4953 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4954 
4955 	if (socket_level) {
4956 		bool wrapped = FALSE;
4957 		do {
4958 			necp_last_kernel_socket_policy_id++;
4959 			if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4960 			    necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4961 				if (wrapped) {
4962 					// Already wrapped, give up
4963 					NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4964 					return NECP_KERNEL_POLICY_ID_NONE;
4965 				}
4966 				necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4967 				wrapped = TRUE;
4968 			}
4969 			newid = necp_last_kernel_socket_policy_id;
4970 		} while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4971 	} else {
4972 		bool wrapped = FALSE;
4973 		do {
4974 			necp_last_kernel_ip_policy_id++;
4975 			if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4976 				if (wrapped) {
4977 					// Already wrapped, give up
4978 					NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4979 					return NECP_KERNEL_POLICY_ID_NONE;
4980 				}
4981 				necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4982 				wrapped = TRUE;
4983 			}
4984 			newid = necp_last_kernel_ip_policy_id;
4985 		} while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4986 	}
4987 
4988 	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4989 		NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4990 		return NECP_KERNEL_POLICY_ID_NONE;
4991 	}
4992 
4993 	return newid;
4994 }
4995 
4996 #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)
4997 
4998 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)4999 necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement __null_terminated, u_int32_t cond_account_id, char *cond_domain __null_terminated, u_int32_t cond_domain_filter, char *cond_url __null_terminated, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union * __single cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier __null_terminated, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
5000 {
5001 	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
5002 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5003 
5004 	new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
5005 
5006 	new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
5007 	new_kernel_policy->order = order;
5008 	new_kernel_policy->session_order = session_order;
5009 	new_kernel_policy->session_pid = session_pid;
5010 
5011 	// Sanitize condition mask
5012 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
5013 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
5014 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
5015 	}
5016 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
5017 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
5018 	}
5019 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
5020 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
5021 	}
5022 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
5023 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
5024 	}
5025 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
5026 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
5027 	}
5028 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
5029 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
5030 	}
5031 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
5032 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
5033 	}
5034 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
5035 
5036 	// Set condition values
5037 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
5038 		new_kernel_policy->cond_app_id = cond_app_id;
5039 	}
5040 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
5041 		new_kernel_policy->cond_real_app_id = cond_real_app_id;
5042 	}
5043 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
5044 		new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
5045 	}
5046 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
5047 		new_kernel_policy->cond_account_id = cond_account_id;
5048 	}
5049 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
5050 	    (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
5051 		new_kernel_policy->cond_domain = cond_domain;
5052 		new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
5053 	}
5054 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
5055 		new_kernel_policy->cond_domain_filter = cond_domain_filter;
5056 	}
5057 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
5058 		new_kernel_policy->cond_url = cond_url;
5059 	}
5060 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
5061 		new_kernel_policy->cond_pid = cond_pid;
5062 		new_kernel_policy->cond_pid_version = cond_pid_version;
5063 	}
5064 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
5065 		new_kernel_policy->cond_uid = cond_uid;
5066 	}
5067 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
5068 		new_kernel_policy->cond_real_uid = cond_real_uid;
5069 	}
5070 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
5071 		if (cond_bound_interface) {
5072 			ifnet_reference(cond_bound_interface);
5073 		}
5074 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
5075 	}
5076 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
5077 		new_kernel_policy->cond_traffic_class = cond_traffic_class;
5078 	}
5079 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
5080 		new_kernel_policy->cond_protocol = cond_protocol;
5081 	}
5082 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5083 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
5084 	}
5085 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5086 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
5087 	}
5088 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5089 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
5090 	}
5091 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5092 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
5093 	}
5094 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5095 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
5096 	}
5097 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5098 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
5099 	}
5100 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
5101 		memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
5102 	}
5103 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
5104 		memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
5105 	}
5106 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
5107 		new_kernel_policy->cond_client_flags = cond_client_flags;
5108 	}
5109 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
5110 		new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
5111 	}
5112 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
5113 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
5114 	}
5115 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
5116 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
5117 	}
5118 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
5119 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
5120 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
5121 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
5122 	}
5123 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
5124 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
5125 	}
5126 
5127 	new_kernel_policy->result = result;
5128 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
5129 
5130 	if (necp_debug) {
5131 		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
5132 	}
5133 	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
5134 
5135 	return new_kernel_policy ? new_kernel_policy->id : 0;
5136 }
5137 
5138 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)5139 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
5140 {
5141 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5142 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
5143 
5144 	if (policy_id == 0) {
5145 		return NULL;
5146 	}
5147 
5148 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
5149 		if (kernel_policy->id == policy_id) {
5150 			return kernel_policy;
5151 		}
5152 	}
5153 
5154 	return NULL;
5155 }
5156 
5157 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)5158 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
5159 {
5160 	struct necp_kernel_socket_policy * __single policy = NULL;
5161 	char * __indexable buffer = NULL;
5162 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5163 
5164 	policy = necp_kernel_socket_policy_find(policy_id);
5165 	if (policy) {
5166 		LIST_REMOVE(policy, chain);
5167 
5168 		if (policy->cond_bound_interface) {
5169 			ifnet_release(policy->cond_bound_interface);
5170 			policy->cond_bound_interface = NULL;
5171 		}
5172 
5173 		if (policy->cond_domain) {
5174 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
5175 			kfree_data_addr(buffer);
5176 			policy->cond_domain = NULL;
5177 		}
5178 
5179 		if (policy->cond_url) {
5180 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
5181 			kfree_data_addr(buffer);
5182 			policy->cond_url = NULL;
5183 		}
5184 
5185 		if (policy->cond_custom_entitlement) {
5186 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
5187 			kfree_data_addr(buffer);
5188 			policy->cond_custom_entitlement = NULL;
5189 		}
5190 
5191 		if (policy->cond_signing_identifier) {
5192 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
5193 			kfree_data_addr(buffer);
5194 			policy->cond_signing_identifier = NULL;
5195 		}
5196 
5197 		zfree(necp_socket_policy_zone, policy);
5198 		return TRUE;
5199 	}
5200 
5201 	return FALSE;
5202 }
5203 
5204 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)5205 __sized_by(MAX_RESULT_STRING_LEN)
5206 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)
5207 {
5208 	uuid_string_t uuid_string;
5209 	switch (result) {
5210 	case NECP_KERNEL_POLICY_RESULT_NONE: {
5211 		snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
5212 		break;
5213 	}
5214 	case NECP_KERNEL_POLICY_RESULT_PASS: {
5215 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
5216 		break;
5217 	}
5218 	case NECP_KERNEL_POLICY_RESULT_SKIP: {
5219 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
5220 		break;
5221 	}
5222 	case NECP_KERNEL_POLICY_RESULT_DROP: {
5223 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5224 		break;
5225 	}
5226 	case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5227 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5228 		break;
5229 	}
5230 	case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5231 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5232 		break;
5233 	}
5234 	case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5235 		ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5236 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5237 		break;
5238 	}
5239 	case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5240 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5241 		break;
5242 	}
5243 	case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5244 		ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5245 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5246 		break;
5247 	}
5248 	case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5249 		snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5250 		break;
5251 	}
5252 	case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5253 		snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5254 		break;
5255 	}
5256 	case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5257 		int index = 0;
5258 		char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5259 		struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5260 		if (route_rule != NULL) {
5261 			for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5262 				if (route_rule->exception_if_indices[index] != 0) {
5263 					ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5264 					snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5265 				} else {
5266 					memset(interface_names[index], 0, IFXNAMSIZ);
5267 				}
5268 			}
5269 			switch (route_rule->default_action) {
5270 			case NECP_ROUTE_RULE_DENY_INTERFACE:
5271 			case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5272 				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)",
5273 				    (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5274 				    (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5275 				    (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5276 				    (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5277 				    (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5278 				    (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5279 				    (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5280 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5281 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5282 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5283 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5284 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5285 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5286 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5287 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5288 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5289 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5290 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5291 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5292 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5293 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5294 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5295 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5296 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5297 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5298 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5299 				break;
5300 			case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5301 				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)",
5302 				    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5303 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5304 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5305 				    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5306 				    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5307 				    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5308 				    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5309 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5310 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5311 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5312 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5313 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5314 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5315 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5316 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5317 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5318 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5319 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5320 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5321 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5322 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5323 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5324 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5325 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5326 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5327 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5328 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5329 				break;
5330 			case NECP_ROUTE_RULE_QOS_MARKING:
5331 				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)",
5332 				    (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5333 				    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5334 				    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5335 				    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5336 				    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5337 				    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5338 				    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5339 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5340 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5341 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5342 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5343 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5344 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5345 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5346 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5347 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5348 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5349 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5350 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5351 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5352 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5353 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5354 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5355 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5356 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5357 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5358 				break;
5359 			default:
5360 				snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5361 				break;
5362 			}
5363 		}
5364 		break;
5365 	}
5366 	case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5367 		bool found_mapping = FALSE;
5368 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5369 		if (mapping != NULL) {
5370 			uuid_unparse(mapping->uuid, uuid_string);
5371 			found_mapping = TRUE;
5372 		}
5373 		snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5374 		break;
5375 	}
5376 	case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5377 		bool found_mapping = FALSE;
5378 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5379 		if (mapping != NULL) {
5380 			uuid_unparse(mapping->uuid, uuid_string);
5381 			found_mapping = TRUE;
5382 		}
5383 		snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5384 		break;
5385 	}
5386 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5387 		bool found_mapping = FALSE;
5388 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5389 		if (mapping != NULL) {
5390 			uuid_unparse(mapping->uuid, uuid_string);
5391 			found_mapping = TRUE;
5392 		}
5393 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5394 		break;
5395 	}
5396 	default: {
5397 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5398 		break;
5399 	}
5400 	}
5401 	return result_string;
5402 }
5403 
5404 static void
necp_kernel_socket_policies_dump_all(void)5405 necp_kernel_socket_policies_dump_all(void)
5406 {
5407 	if (necp_debug) {
5408 		struct necp_kernel_socket_policy *policy = NULL;
5409 		int policy_i;
5410 		int app_i;
5411 		char result_string[MAX_RESULT_STRING_LEN];
5412 		char proc_name_string[MAXCOMLEN + 1];
5413 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
5414 		memset(proc_name_string, 0, MAXCOMLEN + 1);
5415 
5416 		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5417 		NECPLOG0(LOG_DEBUG, "-----------\n");
5418 		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5419 			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5420 			proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5421 			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));
5422 		}
5423 		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5424 			NECPLOG0(LOG_DEBUG, "-----------\n");
5425 		}
5426 
5427 		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5428 		NECPLOG0(LOG_DEBUG, "-----------\n");
5429 		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5430 			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5431 			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5432 				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5433 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5434 				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));
5435 			}
5436 			NECPLOG0(LOG_DEBUG, "-----------\n");
5437 		}
5438 	}
5439 }
5440 
5441 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5442 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5443 {
5444 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5445 		// Drop always cancels out lower policies
5446 		return TRUE;
5447 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5448 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5449 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5450 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5451 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5452 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5453 		// Filters and route rules never cancel out lower policies
5454 		return FALSE;
5455 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5456 		if (upper_policy->session_order != lower_policy->session_order) {
5457 			// A skip cannot override a policy of a different session
5458 			return FALSE;
5459 		} else {
5460 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
5461 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5462 				// This policy is beyond the skip
5463 				return FALSE;
5464 			} else {
5465 				// This policy is inside the skip
5466 				return TRUE;
5467 			}
5468 		}
5469 	}
5470 
5471 	// A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5472 	return TRUE;
5473 }
5474 
5475 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)5476 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5477 {
5478 	bool can_skip = FALSE;
5479 	u_int32_t highest_skip_session_order = 0;
5480 	u_int32_t highest_skip_order = 0;
5481 	int i;
5482 	for (i = 0; i < valid_indices; i++) {
5483 		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5484 
5485 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
5486 		if (can_skip) {
5487 			if (highest_skip_session_order != compared_policy->session_order ||
5488 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5489 				// If we've moved on to the next session, or passed the skip window
5490 				highest_skip_session_order = 0;
5491 				highest_skip_order = 0;
5492 				can_skip = FALSE;
5493 			} else {
5494 				// If this policy is also a skip, in can increase the skip window
5495 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5496 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5497 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5498 					}
5499 				}
5500 				continue;
5501 			}
5502 		}
5503 
5504 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5505 			// This policy is a skip. Set the skip window accordingly
5506 			can_skip = TRUE;
5507 			highest_skip_session_order = compared_policy->session_order;
5508 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5509 		}
5510 
5511 		// The result of the compared policy must be able to block out this policy result
5512 		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5513 			continue;
5514 		}
5515 
5516 		// If new policy matches All Interfaces, compared policy must also
5517 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5518 			continue;
5519 		}
5520 
5521 		// If new policy matches Local Networks, compared policy must also
5522 		if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5523 		    policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5524 			continue;
5525 		}
5526 
5527 		// Default makes lower policies unecessary always
5528 		if (compared_policy->condition_mask == 0) {
5529 			return TRUE;
5530 		}
5531 
5532 		// Compared must be more general than policy, and include only conditions within policy
5533 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5534 			continue;
5535 		}
5536 
5537 		// Negative conditions must match for the overlapping conditions
5538 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5539 			continue;
5540 		}
5541 
5542 		if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5543 		    compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5544 		    strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5545 			continue;
5546 		}
5547 
5548 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5549 		    compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5550 			continue;
5551 		}
5552 
5553 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5554 		    strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5555 			continue;
5556 		}
5557 
5558 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5559 		    strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5560 			continue;
5561 		}
5562 
5563 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5564 		    compared_policy->cond_account_id != policy->cond_account_id) {
5565 			continue;
5566 		}
5567 
5568 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5569 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
5570 			continue;
5571 		}
5572 
5573 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5574 		    compared_policy->cond_app_id != policy->cond_app_id) {
5575 			continue;
5576 		}
5577 
5578 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5579 		    compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5580 			continue;
5581 		}
5582 
5583 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5584 		    (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5585 			continue;
5586 		}
5587 
5588 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5589 		    compared_policy->cond_uid != policy->cond_uid) {
5590 			continue;
5591 		}
5592 
5593 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5594 		    compared_policy->cond_real_uid != policy->cond_real_uid) {
5595 			continue;
5596 		}
5597 
5598 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5599 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5600 			continue;
5601 		}
5602 
5603 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5604 		    compared_policy->cond_protocol != policy->cond_protocol) {
5605 			continue;
5606 		}
5607 
5608 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5609 		    compared_policy->cond_client_flags != policy->cond_client_flags) {
5610 			continue;
5611 		}
5612 
5613 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5614 		    !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5615 		    compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5616 			continue;
5617 		}
5618 
5619 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5620 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5621 				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))) {
5622 					continue;
5623 				}
5624 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5625 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5626 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5627 					continue;
5628 				}
5629 			}
5630 		}
5631 
5632 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5633 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5634 				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))) {
5635 					continue;
5636 				}
5637 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5638 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5639 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5640 					continue;
5641 				}
5642 			}
5643 		}
5644 
5645 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5646 		    memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5647 			continue;
5648 		}
5649 
5650 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5651 		    memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5652 			continue;
5653 		}
5654 
5655 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5656 		    memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5657 			continue;
5658 		}
5659 
5660 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5661 		    memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5662 			continue;
5663 		}
5664 
5665 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5666 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5667 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5668 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5669 			continue;
5670 		}
5671 
5672 		return TRUE;
5673 	}
5674 
5675 	return FALSE;
5676 }
5677 
5678 static bool
necp_kernel_socket_policies_reprocess(void)5679 necp_kernel_socket_policies_reprocess(void)
5680 {
5681 	int app_i;
5682 	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5683 	int app_layer_current_free_index = 0;
5684 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5685 
5686 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5687 
5688 	// Reset mask to 0
5689 	necp_kernel_application_policies_condition_mask = 0;
5690 	necp_kernel_socket_policies_condition_mask = 0;
5691 	necp_kernel_application_policies_count = 0;
5692 	necp_kernel_socket_policies_count = 0;
5693 	necp_kernel_socket_policies_non_app_count = 0;
5694 
5695 	// Reset all maps to NULL
5696 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5697 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5698 			kfree_type(struct necp_kernel_socket_policy *,
5699 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5700 			    necp_kernel_socket_policies_map[app_i]);
5701 			necp_kernel_socket_policies_map[app_i] = NULL;
5702 		}
5703 
5704 		// Init counts
5705 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5706 	}
5707 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5708 		kfree_type(struct necp_kernel_socket_policy *,
5709 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5710 		    necp_kernel_socket_policies_app_layer_map);
5711 	}
5712 	necp_kernel_socket_policies_app_layer_map = NULL;
5713 	necp_kernel_socket_policies_app_layer_map_count = 0;
5714 
5715 	// Create masks and counts
5716 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5717 		// App layer mask/count
5718 		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5719 		necp_kernel_application_policies_count++;
5720 		necp_kernel_socket_policies_app_layer_map_count++;
5721 
5722 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5723 			// Agent type conditions only apply to app layer
5724 			continue;
5725 		}
5726 
5727 		// Update socket layer bucket mask/counts
5728 		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5729 		necp_kernel_socket_policies_count++;
5730 
5731 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5732 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5733 			necp_kernel_socket_policies_non_app_count++;
5734 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5735 				necp_kernel_socket_policies_map_counts[app_i]++;
5736 			}
5737 		} else {
5738 			necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5739 		}
5740 	}
5741 
5742 	// Allocate maps
5743 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5744 		if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5745 			// Allocate a NULL-terminated array of policy pointers for each bucket
5746 			necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5747 			    necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5748 			if (necp_kernel_socket_policies_map[app_i] == NULL) {
5749 				goto fail;
5750 			}
5751 		}
5752 		bucket_current_free_index[app_i] = 0;
5753 	}
5754 	necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5755 	    necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5756 	if (necp_kernel_socket_policies_app_layer_map == NULL) {
5757 		goto fail;
5758 	}
5759 
5760 	// Fill out maps
5761 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5762 		// Add app layer policies
5763 		if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5764 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5765 			app_layer_current_free_index++;
5766 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5767 		}
5768 
5769 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5770 			// Agent type conditions only apply to app layer
5771 			continue;
5772 		}
5773 
5774 		// Add socket policies
5775 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5776 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5777 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5778 				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])) {
5779 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5780 					bucket_current_free_index[app_i]++;
5781 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5782 				}
5783 			}
5784 		} else {
5785 			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5786 			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])) {
5787 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5788 				bucket_current_free_index[app_i]++;
5789 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5790 			}
5791 		}
5792 	}
5793 	necp_kernel_socket_policies_dump_all();
5794 	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5795 	return TRUE;
5796 
5797 fail:
5798 	// Free memory, reset masks to 0
5799 	necp_kernel_application_policies_condition_mask = 0;
5800 	necp_kernel_socket_policies_condition_mask = 0;
5801 	necp_kernel_application_policies_count = 0;
5802 	necp_kernel_socket_policies_count = 0;
5803 	necp_kernel_socket_policies_non_app_count = 0;
5804 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5805 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5806 			kfree_type(struct necp_kernel_socket_policy *,
5807 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5808 			    necp_kernel_socket_policies_map[app_i]);
5809 			necp_kernel_socket_policies_map[app_i] = NULL;
5810 		}
5811 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5812 	}
5813 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5814 		kfree_type(struct necp_kernel_socket_policy *,
5815 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5816 		    necp_kernel_socket_policies_app_layer_map);
5817 		necp_kernel_socket_policies_app_layer_map = NULL;
5818 	}
5819 	necp_kernel_socket_policies_app_layer_map_count = 0;
5820 	return FALSE;
5821 }
5822 
5823 static u_int32_t
necp_get_new_string_id(void)5824 necp_get_new_string_id(void)
5825 {
5826 	static u_int32_t necp_last_string_id = 0;
5827 
5828 	u_int32_t newid = 0;
5829 
5830 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5831 
5832 	bool wrapped = FALSE;
5833 	do {
5834 		necp_last_string_id++;
5835 		if (necp_last_string_id < 1) {
5836 			if (wrapped) {
5837 				// Already wrapped, give up
5838 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5839 				return 0;
5840 			}
5841 			necp_last_string_id = 1;
5842 			wrapped = TRUE;
5843 		}
5844 		newid = necp_last_string_id;
5845 	} while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5846 
5847 	if (newid == 0) {
5848 		NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5849 		return 0;
5850 	}
5851 
5852 	return newid;
5853 }
5854 
5855 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5856 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5857 {
5858 	struct necp_string_id_mapping *searchentry = NULL;
5859 	struct necp_string_id_mapping *foundentry = NULL;
5860 
5861 	LIST_FOREACH(searchentry, list, chain) {
5862 		if (strcmp(searchentry->string, string) == 0) {
5863 			foundentry = searchentry;
5864 			break;
5865 		}
5866 	}
5867 
5868 	return foundentry;
5869 }
5870 
5871 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5872 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5873 {
5874 	struct necp_string_id_mapping *searchentry = NULL;
5875 	struct necp_string_id_mapping *foundentry = NULL;
5876 
5877 	LIST_FOREACH(searchentry, list, chain) {
5878 		if (searchentry->id == local_id) {
5879 			foundentry = searchentry;
5880 			break;
5881 		}
5882 	}
5883 
5884 	return foundentry;
5885 }
5886 
5887 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5888 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5889 {
5890 	u_int32_t string_id = 0;
5891 	struct necp_string_id_mapping *existing_mapping = NULL;
5892 
5893 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5894 
5895 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5896 	if (existing_mapping != NULL) {
5897 		string_id = existing_mapping->id;
5898 		os_ref_retain_locked(&existing_mapping->refcount);
5899 	} else {
5900 		struct necp_string_id_mapping * __single new_mapping = NULL;
5901 		new_mapping = kalloc_type(struct necp_string_id_mapping,
5902 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5903 
5904 		size_t length = strlen(string) + 1;
5905 		char *buffer = kalloc_data(length, Z_WAITOK);
5906 		if (buffer != NULL) {
5907 			strlcpy(buffer, string, length);
5908 			new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5909 			new_mapping->id = necp_get_new_string_id();
5910 			os_ref_init(&new_mapping->refcount, &necp_refgrp);
5911 			LIST_INSERT_HEAD(list, new_mapping, chain);
5912 			string_id = new_mapping->id;
5913 		} else {
5914 			kfree_type(struct necp_string_id_mapping, new_mapping);
5915 			new_mapping = NULL;
5916 		}
5917 	}
5918 	return string_id;
5919 }
5920 
5921 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5922 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5923 {
5924 	struct necp_string_id_mapping * __single existing_mapping = NULL;
5925 	char * __indexable buffer = NULL;
5926 
5927 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5928 
5929 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5930 	if (existing_mapping != NULL) {
5931 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5932 			LIST_REMOVE(existing_mapping, chain);
5933 			buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5934 			kfree_data_addr(buffer);
5935 			kfree_type(struct necp_string_id_mapping, existing_mapping);
5936 		}
5937 		return TRUE;
5938 	}
5939 
5940 	return FALSE;
5941 }
5942 
5943 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5944 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5945 {
5946 	struct necp_domain_filter *searchfilter = NULL;
5947 	struct necp_domain_filter *foundfilter = NULL;
5948 
5949 	LIST_FOREACH(searchfilter, list, chain) {
5950 		if (searchfilter->id == filter_id) {
5951 			foundfilter = searchfilter;
5952 			break;
5953 		}
5954 	}
5955 
5956 	return foundfilter;
5957 }
5958 
5959 static u_int32_t
necp_get_new_domain_filter_id(void)5960 necp_get_new_domain_filter_id(void)
5961 {
5962 	static u_int32_t necp_last_filter_id = 0;
5963 
5964 	u_int32_t newid = 0;
5965 
5966 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5967 
5968 	bool wrapped = FALSE;
5969 	do {
5970 		// Scope id within its space
5971 		if (++necp_last_filter_id > NECP_DOMAIN_FILTER_ID_MAX) {
5972 			necp_last_filter_id = 0;
5973 		}
5974 		if (necp_last_filter_id < 1) {
5975 			if (wrapped) {
5976 				// Already wrapped, give up
5977 				NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5978 				return 0;
5979 			}
5980 			necp_last_filter_id = 1;
5981 			wrapped = TRUE;
5982 		}
5983 		newid = necp_last_filter_id;
5984 	} while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5985 
5986 	if (newid == 0) {
5987 		NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5988 		return 0;
5989 	}
5990 
5991 	return newid;
5992 }
5993 
5994 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)5995 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5996 {
5997 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5998 
5999 	struct necp_domain_filter *new_filter = NULL;
6000 	new_filter = kalloc_type(struct necp_domain_filter,
6001 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6002 
6003 	new_filter->filter = filter;
6004 	new_filter->id = necp_get_new_domain_filter_id();
6005 	LIST_INSERT_HEAD(list, new_filter, chain);
6006 	LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
6007 	os_ref_init(&new_filter->refcount, &necp_refgrp);
6008 
6009 	return new_filter->id;
6010 }
6011 
6012 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)6013 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
6014 {
6015 	struct necp_domain_filter * __single existing_filter = NULL;
6016 
6017 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6018 
6019 	existing_filter = necp_lookup_domain_filter(list, filter_id);
6020 	if (existing_filter != NULL) {
6021 		if (os_ref_release_locked(&existing_filter->refcount) == 0) {
6022 			LIST_REMOVE(existing_filter, chain);
6023 			LIST_REMOVE(existing_filter, owner_chain);
6024 			net_bloom_filter_destroy(existing_filter->filter);
6025 			kfree_type(struct necp_domain_filter, existing_filter);
6026 		}
6027 		return true;
6028 	}
6029 
6030 	return false;
6031 }
6032 
6033 static struct necp_domain_trie *
necp_lookup_domain_trie(struct necp_domain_trie_list * list,u_int32_t id)6034 necp_lookup_domain_trie(struct necp_domain_trie_list *list, u_int32_t id)
6035 {
6036 	struct necp_domain_trie *searchTrie = NULL;
6037 	struct necp_domain_trie *foundTrie = NULL;
6038 
6039 	LIST_FOREACH(searchTrie, list, chain) {
6040 		if (searchTrie->id == id) {
6041 			foundTrie = searchTrie;
6042 			break;
6043 		}
6044 	}
6045 
6046 	return foundTrie;
6047 }
6048 
6049 static u_int32_t
necp_get_new_domain_trie_id(void)6050 necp_get_new_domain_trie_id(void)
6051 {
6052 	static u_int32_t necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START;
6053 	u_int32_t newid = necp_last_trie_id;
6054 
6055 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6056 
6057 	bool wrapped = FALSE;
6058 	do {
6059 		if (++necp_last_trie_id < NECP_DOMAIN_TRIE_ID_START + 1) {
6060 			if (wrapped) {
6061 				// Already wrapped, give up
6062 				NECPLOG0(LOG_ERR, "Failed to find a free trie ID.\n");
6063 				return 0;
6064 			}
6065 			necp_last_trie_id = NECP_DOMAIN_TRIE_ID_START + 1;
6066 			wrapped = TRUE;
6067 		}
6068 		newid = necp_last_trie_id;
6069 	} while (necp_lookup_domain_trie(&necp_global_domain_trie_list, newid) != NULL); // If already used, keep trying
6070 
6071 	if (newid == NECP_DOMAIN_TRIE_ID_START) {
6072 		NECPLOG0(LOG_ERR, "Allocate trie id failed.\n");
6073 		return 0;
6074 	}
6075 
6076 	return newid;
6077 }
6078 
6079 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)6080 necp_create_domain_trie(struct necp_domain_trie_list *list,
6081     struct necp_domain_trie_list *owner_list,
6082     struct necp_domain_trie_request *trie_request, size_t trie_request_size)
6083 {
6084 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6085 
6086 	struct necp_domain_trie *new_trie = NULL;
6087 	new_trie = kalloc_type(struct necp_domain_trie, Z_WAITOK | Z_ZERO | Z_NOFAIL);
6088 	if (new_trie == NULL) {
6089 		NECPLOG0(LOG_ERR, "Failed to allow domain trie\n");
6090 		return 0;
6091 	}
6092 
6093 	if (net_trie_init_with_mem(&new_trie->trie, trie_request->data, trie_request->total_mem_size,
6094 	    trie_request->nodes_mem_size, trie_request->maps_mem_size, trie_request->bytes_mem_size,
6095 	    trie_request->nodes_count, trie_request->maps_count, trie_request->bytes_count) == false) {
6096 		NECPLOG0(LOG_ERR, "Failed to initialize domain trie\n");
6097 		kfree_type(struct necp_domain_trie, new_trie);
6098 		return 0;
6099 	}
6100 	new_trie->trie_request = trie_request;
6101 	new_trie->trie_request_size = trie_request_size;
6102 	new_trie->id = necp_get_new_domain_trie_id();
6103 	new_trie->trie_request->id = new_trie->id;
6104 	LIST_INSERT_HEAD(list, new_trie, chain);
6105 	LIST_INSERT_HEAD(owner_list, new_trie, owner_chain);
6106 
6107 	os_ref_init(&new_trie->refcount, &necp_refgrp);
6108 	necp_trie_count++;
6109 	return new_trie->id;
6110 }
6111 
6112 static void
necp_free_domain_trie(struct necp_domain_trie * existing_trie)6113 necp_free_domain_trie(struct necp_domain_trie *existing_trie)
6114 {
6115 	if (existing_trie != NULL) {
6116 		uint8_t *necp_trie_request_buffer = (uint8_t *)existing_trie->trie_request;
6117 		kfree_data(necp_trie_request_buffer, existing_trie->trie_request_size);
6118 		kfree_type(struct necp_domain_trie, existing_trie);
6119 	}
6120 }
6121 
6122 static bool
necp_remove_domain_trie(struct necp_domain_trie_list * list,__unused struct necp_domain_trie_list * owner_list,u_int32_t id)6123 necp_remove_domain_trie(struct necp_domain_trie_list *list, __unused struct necp_domain_trie_list *owner_list, u_int32_t id)
6124 {
6125 	struct necp_domain_trie * __single existing_trie = NULL;
6126 
6127 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6128 
6129 	existing_trie = necp_lookup_domain_trie(list, id);
6130 	if (existing_trie != NULL) {
6131 		if (os_ref_release_locked(&existing_trie->refcount) == 0) {
6132 			LIST_REMOVE(existing_trie, chain);
6133 			LIST_REMOVE(existing_trie, owner_chain);
6134 			necp_free_domain_trie(existing_trie);
6135 			necp_trie_count--;
6136 		}
6137 		return true;
6138 	}
6139 
6140 	return false;
6141 }
6142 
6143 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)6144 necp_match_domain_with_trie(struct necp_domain_trie_list *list, u_int32_t id, char * __sized_by(length) domain, size_t length)
6145 {
6146 	size_t metadata_length = 0;
6147 	const uint8_t * __sized_by(metadata_length) metadata = NULL;
6148 
6149 	struct necp_domain_trie *necp_trie = necp_lookup_domain_trie(list, id);
6150 	if (necp_trie == NULL || necp_trie->trie_request == NULL) {
6151 		return false;
6152 	}
6153 	Boolean reverse = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_REVERSE_SEARCH);
6154 	Boolean allow_partial_match  = (necp_trie->trie_request->flags & NECP_DOMAIN_TRIE_FLAG_ALLOW_PARTIAL_MATCH);
6155 	return net_trie_search(&necp_trie->trie, (const uint8_t *)domain, length,
6156 	           &metadata, &metadata_length, reverse, allow_partial_match, necp_trie->trie_request->partial_match_terminator, NULL, NULL) != NULL_TRIE_IDX;
6157 }
6158 
6159 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
6160 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
6161 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)6162 necp_get_new_route_rule_id(bool aggregate)
6163 {
6164 	static u_int32_t necp_last_route_rule_id = 0;
6165 	static u_int32_t necp_last_aggregate_route_rule_id = 0;
6166 
6167 	u_int32_t newid = 0;
6168 
6169 	if (!aggregate) {
6170 		// Main necp_kernel_policy_lock protects non-aggregate rule IDs
6171 		LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6172 
6173 		bool wrapped = FALSE;
6174 		do {
6175 			necp_last_route_rule_id++;
6176 			if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
6177 			    necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6178 				if (wrapped) {
6179 					// Already wrapped, give up
6180 					NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
6181 					return 0;
6182 				}
6183 				necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
6184 				wrapped = TRUE;
6185 			}
6186 			newid = necp_last_route_rule_id;
6187 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6188 	} else {
6189 		// necp_route_rule_lock protects aggregate rule IDs
6190 		LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
6191 
6192 		bool wrapped = FALSE;
6193 		do {
6194 			necp_last_aggregate_route_rule_id++;
6195 			if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
6196 				if (wrapped) {
6197 					// Already wrapped, give up
6198 					NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
6199 					return 0;
6200 				}
6201 				necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
6202 				wrapped = TRUE;
6203 			}
6204 			newid = necp_last_aggregate_route_rule_id;
6205 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
6206 	}
6207 
6208 	if (newid == 0) {
6209 		NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
6210 		return 0;
6211 	}
6212 
6213 	return newid;
6214 }
6215 
6216 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)6217 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6218 {
6219 	struct necp_route_rule *searchentry = NULL;
6220 	struct necp_route_rule *foundentry = NULL;
6221 
6222 	LIST_FOREACH(searchentry, list, chain) {
6223 		if (searchentry->id == route_rule_id) {
6224 			foundentry = searchentry;
6225 			break;
6226 		}
6227 	}
6228 
6229 	return foundentry;
6230 }
6231 
6232 static struct necp_route_rule *
necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list * list,u_int8_t default_action,u_int8_t cellular_action,u_int8_t wifi_action,u_int8_t wired_action,u_int8_t expensive_action,u_int8_t constrained_action,u_int8_t companion_action,u_int8_t vpn_action,u_int32_t * __indexable if_indices,u_int8_t * __indexable if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit,u_int32_t effective_type)6233 necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int8_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int8_t companion_action, u_int8_t vpn_action, u_int32_t * __indexable if_indices, u_int8_t * __indexable if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
6234 {
6235 	struct necp_route_rule *searchentry = NULL;
6236 	struct necp_route_rule *foundentry = NULL;
6237 
6238 	LIST_FOREACH(searchentry, list, chain) {
6239 		if (searchentry->default_action == default_action &&
6240 		    searchentry->cellular_action == cellular_action &&
6241 		    searchentry->wifi_action == wifi_action &&
6242 		    searchentry->wired_action == wired_action &&
6243 		    searchentry->expensive_action == expensive_action &&
6244 		    searchentry->constrained_action == constrained_action &&
6245 		    searchentry->companion_action == companion_action &&
6246 		    searchentry->vpn_action == vpn_action &&
6247 		    searchentry->control_unit == control_unit &&
6248 		    searchentry->effective_type == effective_type) {
6249 			bool match_failed = FALSE;
6250 			size_t index_a = 0;
6251 			size_t index_b = 0;
6252 			size_t count_a = 0;
6253 			size_t count_b = 0;
6254 			for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
6255 				bool found_index = FALSE;
6256 				if (searchentry->exception_if_indices[index_a] == 0) {
6257 					break;
6258 				}
6259 				count_a++;
6260 				for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
6261 					if (if_indices[index_b] == 0) {
6262 						break;
6263 					}
6264 					if (index_b >= count_b) {
6265 						count_b = index_b + 1;
6266 					}
6267 					if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
6268 					    searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
6269 						found_index = TRUE;
6270 						break;
6271 					}
6272 				}
6273 				if (!found_index) {
6274 					match_failed = TRUE;
6275 					break;
6276 				}
6277 			}
6278 
6279 			if (match_failed || count_a != count_b) {
6280 				continue;
6281 			}
6282 
6283 			bool has_agent_a = !uuid_is_null(netagent_uuid);
6284 			bool has_agent_b = (searchentry->netagent_id != 0);
6285 			if (has_agent_a != has_agent_b) {
6286 				continue;
6287 			}
6288 
6289 			if (has_agent_a) {
6290 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
6291 				if (mapping == NULL) {
6292 					// Bad mapping, doesn't match
6293 					continue;
6294 				}
6295 				if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
6296 					// UUIDs don't match
6297 					continue;
6298 				}
6299 			}
6300 
6301 			bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
6302 			bool has_match_agent_b = (searchentry->match_netagent_id != 0);
6303 			if (has_match_agent_a != has_match_agent_b) {
6304 				continue;
6305 			}
6306 
6307 			if (has_match_agent_a) {
6308 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
6309 				if (mapping == NULL) {
6310 					// Bad mapping, doesn't match
6311 					continue;
6312 				}
6313 				if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
6314 					// UUIDs don't match
6315 					continue;
6316 				}
6317 			}
6318 
6319 			// Rules match!
6320 			foundentry = searchentry;
6321 			break;
6322 		}
6323 	}
6324 
6325 	return foundentry;
6326 }
6327 
6328 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)6329 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,
6330     bool *has_socket_only_actions)
6331 {
6332 	size_t offset = 0;
6333 	u_int32_t route_rule_id = 0;
6334 	struct necp_route_rule *existing_rule = NULL;
6335 	u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
6336 	u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
6337 	u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
6338 	u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
6339 	u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
6340 	u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
6341 	u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
6342 	u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
6343 	u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
6344 	size_t num_valid_indices = 0;
6345 	memset(&if_indices, 0, sizeof(if_indices));
6346 	u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
6347 	memset(&if_actions, 0, sizeof(if_actions));
6348 
6349 	uuid_t netagent_uuid = {};
6350 
6351 	uuid_t match_netagent_uuid = {};
6352 	uint32_t control_unit = 0;
6353 	uint32_t effective_type = 0;
6354 
6355 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6356 
6357 	if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6358 		return 0;
6359 	}
6360 
6361 	// Process rules
6362 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6363 		ifnet_t __single rule_interface = NULL;
6364 		char interface_name[IFXNAMSIZ];
6365 		u_int32_t length = 0;
6366 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6367 
6368 		if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6369 			// Invalid TLV goes beyond end of the rules array
6370 			break;
6371 		}
6372 
6373 		// Increment offset for the next time through the loop
6374 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6375 
6376 		u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6377 		u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6378 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6379 		u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6380 
6381 		if (rule_action == NECP_ROUTE_RULE_NONE) {
6382 			// Don't allow an explicit rule to be None action
6383 			continue;
6384 		}
6385 
6386 		if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6387 		    rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6388 			if (rule_length < sizeof(uuid_t)) {
6389 				// Too short, skip
6390 				continue;
6391 			}
6392 
6393 			if (!uuid_is_null(netagent_uuid)) {
6394 				if (uuid_compare(netagent_uuid, rule_value) != 0) {
6395 					// UUIDs don't match, skip
6396 					continue;
6397 				}
6398 			} else {
6399 				// Copy out agent UUID
6400 				memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6401 			}
6402 
6403 			// Adjust remaining length
6404 			rule_value += sizeof(netagent_uuid);
6405 			rule_length -= sizeof(netagent_uuid);
6406 			*has_socket_only_actions = true;
6407 		} else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6408 			if (rule_length < sizeof(control_unit)) {
6409 				// Too short, skip
6410 				continue;
6411 			}
6412 
6413 			memcpy(&control_unit, rule_value, sizeof(control_unit));
6414 
6415 			// Adjust remaining length
6416 			rule_value += sizeof(control_unit);
6417 			rule_length -= sizeof(control_unit);
6418 			*has_socket_only_actions = true;
6419 		} else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6420 			if (rule_length < sizeof(effective_type)) {
6421 				// Too short, skip
6422 				continue;
6423 			}
6424 
6425 			memcpy(&effective_type, rule_value, sizeof(effective_type));
6426 
6427 			// Adjust remaining length
6428 			rule_value += sizeof(effective_type);
6429 			rule_length -= sizeof(effective_type);
6430 		}
6431 
6432 		if (rule_length == 0) {
6433 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6434 				cellular_action = rule_action;
6435 			}
6436 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6437 				wifi_action = rule_action;
6438 			}
6439 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6440 				wired_action = rule_action;
6441 			}
6442 			if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6443 				expensive_action = rule_action;
6444 			}
6445 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6446 				constrained_action = rule_action;
6447 			}
6448 			if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6449 				companion_action = rule_action;
6450 			}
6451 			if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6452 				vpn_action = rule_action;
6453 			}
6454 			if (rule_flags == 0) {
6455 				default_action = rule_action;
6456 			}
6457 			continue;
6458 		} else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6459 			if (rule_length < sizeof(uuid_t)) {
6460 				// Too short, skip
6461 				continue;
6462 			}
6463 
6464 			// Store the netagent UUID to match
6465 			memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6466 			// If the data is exactly a UUID, this is the default action
6467 			if (rule_length == sizeof(uuid_t)) {
6468 				default_action = rule_action;
6469 				continue;
6470 			}
6471 
6472 			// If the data is longer than a UUID, this also includes an interface name
6473 			// Adjust remaining length to make sure the interface name is picked up below
6474 			rule_value += sizeof(uuid_t);
6475 			rule_length -= sizeof(uuid_t);
6476 		}
6477 
6478 		if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6479 			continue;
6480 		}
6481 
6482 		if (rule_length <= IFXNAMSIZ) {
6483 			memcpy(interface_name, rule_value, rule_length);
6484 			interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6485 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6486 				if_actions[num_valid_indices] = rule_action;
6487 				if_indices[num_valid_indices++] = rule_interface->if_index;
6488 				ifnet_release(rule_interface);
6489 			}
6490 		}
6491 	}
6492 
6493 	existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, vpn_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
6494 	if (existing_rule != NULL) {
6495 		route_rule_id = existing_rule->id;
6496 		os_ref_retain_locked(&existing_rule->refcount);
6497 	} else {
6498 		struct necp_route_rule *new_rule = NULL;
6499 		new_rule = kalloc_type(struct necp_route_rule,
6500 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6501 		route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6502 		if (!uuid_is_null(netagent_uuid)) {
6503 			new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6504 		}
6505 		if (!uuid_is_null(match_netagent_uuid)) {
6506 			new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6507 		}
6508 		new_rule->effective_type = effective_type;
6509 		new_rule->control_unit = control_unit;
6510 		new_rule->default_action = default_action;
6511 		new_rule->cellular_action = cellular_action;
6512 		new_rule->wifi_action = wifi_action;
6513 		new_rule->wired_action = wired_action;
6514 		new_rule->expensive_action = expensive_action;
6515 		new_rule->constrained_action =  constrained_action;
6516 		new_rule->companion_action =  companion_action;
6517 		new_rule->vpn_action =  vpn_action;
6518 		memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6519 		memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6520 		os_ref_init(&new_rule->refcount, &necp_refgrp);
6521 		LIST_INSERT_HEAD(list, new_rule, chain);
6522 	}
6523 	return route_rule_id;
6524 }
6525 
6526 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6527 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6528 {
6529 	if (rule_id) {
6530 		lck_rw_lock_exclusive(&necp_route_rule_lock);
6531 
6532 		struct necp_aggregate_route_rule * __single existing_rule = NULL;
6533 		struct necp_aggregate_route_rule *tmp_rule = NULL;
6534 
6535 		LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6536 			int index = 0;
6537 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6538 				u_int32_t route_rule_id = existing_rule->rule_ids[index];
6539 				if (route_rule_id == rule_id) {
6540 					LIST_REMOVE(existing_rule, chain);
6541 					kfree_type(struct necp_aggregate_route_rule, existing_rule);
6542 					break;
6543 				}
6544 			}
6545 		}
6546 
6547 		lck_rw_done(&necp_route_rule_lock);
6548 	}
6549 }
6550 
6551 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6552 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6553 {
6554 	struct necp_route_rule * __single existing_rule = NULL;
6555 
6556 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6557 
6558 	existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6559 	if (existing_rule != NULL) {
6560 		if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6561 			necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6562 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6563 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6564 			LIST_REMOVE(existing_rule, chain);
6565 			kfree_type(struct necp_route_rule, existing_rule);
6566 		}
6567 		return TRUE;
6568 	}
6569 
6570 	return FALSE;
6571 }
6572 
6573 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6574 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6575 {
6576 	struct necp_aggregate_route_rule *searchentry = NULL;
6577 	struct necp_aggregate_route_rule *foundentry = NULL;
6578 
6579 	lck_rw_lock_shared(&necp_route_rule_lock);
6580 
6581 	LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6582 		if (searchentry->id == route_rule_id) {
6583 			foundentry = searchentry;
6584 			break;
6585 		}
6586 	}
6587 
6588 	lck_rw_done(&necp_route_rule_lock);
6589 
6590 	return foundentry;
6591 }
6592 
6593 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6594 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6595 {
6596 	u_int32_t aggregate_route_rule_id = 0;
6597 	struct necp_aggregate_route_rule *new_rule = NULL;
6598 	struct necp_aggregate_route_rule *existing_rule = NULL;
6599 
6600 	lck_rw_lock_exclusive(&necp_route_rule_lock);
6601 
6602 	// Check if the rule already exists
6603 	LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6604 		if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6605 			lck_rw_done(&necp_route_rule_lock);
6606 			return existing_rule->id;
6607 		}
6608 	}
6609 
6610 	new_rule = kalloc_type(struct necp_aggregate_route_rule,
6611 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6612 	aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6613 	new_rule->id = aggregate_route_rule_id;
6614 	memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6615 	LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6616 	lck_rw_done(&necp_route_rule_lock);
6617 
6618 	return aggregate_route_rule_id;
6619 }
6620 
6621 #define NECP_NULL_SERVICE_ID 1
6622 #define NECP_FIRST_VALID_SERVICE_ID  2
6623 #define NECP_FIRST_VALID_APP_ID  UINT16_MAX
6624 static u_int32_t
necp_get_new_uuid_id(bool service)6625 necp_get_new_uuid_id(bool service)
6626 {
6627 	static u_int32_t necp_last_service_uuid_id = 0;
6628 	static u_int32_t necp_last_app_uuid_id = 0;
6629 
6630 	u_int32_t newid = 0;
6631 
6632 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6633 
6634 	if (service) {
6635 		bool wrapped = FALSE;
6636 		do {
6637 			necp_last_service_uuid_id++;
6638 			if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6639 			    necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6640 				if (wrapped) {
6641 					// Already wrapped, give up
6642 					NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6643 					return NECP_NULL_SERVICE_ID;
6644 				}
6645 				necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6646 				wrapped = TRUE;
6647 			}
6648 			newid = necp_last_service_uuid_id;
6649 		} while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6650 	} else {
6651 		bool wrapped = FALSE;
6652 		do {
6653 			necp_last_app_uuid_id++;
6654 			if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6655 				if (wrapped) {
6656 					// Already wrapped, give up
6657 					NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6658 					return NECP_NULL_SERVICE_ID;
6659 				}
6660 				necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6661 				wrapped = TRUE;
6662 			}
6663 			newid = necp_last_app_uuid_id;
6664 		} while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6665 	}
6666 
6667 	if (newid == NECP_NULL_SERVICE_ID) {
6668 		NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6669 		return NECP_NULL_SERVICE_ID;
6670 	}
6671 
6672 	return newid;
6673 }
6674 
6675 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6676 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6677 {
6678 	struct necp_uuid_id_mapping *searchentry = NULL;
6679 	struct necp_uuid_id_mapping *foundentry = NULL;
6680 
6681 	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6682 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6683 			foundentry = searchentry;
6684 			break;
6685 		}
6686 	}
6687 
6688 	return foundentry;
6689 }
6690 
6691 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6692 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6693 {
6694 	struct necp_uuid_id_mapping *searchentry = NULL;
6695 	struct necp_uuid_id_mapping *foundentry = NULL;
6696 
6697 	struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6698 	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--) {
6699 		LIST_FOREACH(searchentry, uuid_list_head, chain) {
6700 			if (searchentry->id == local_id) {
6701 				foundentry = searchentry;
6702 				break;
6703 			}
6704 		}
6705 	}
6706 
6707 	return foundentry;
6708 }
6709 
6710 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6711 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6712 {
6713 	u_int32_t local_id = 0;
6714 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6715 
6716 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6717 
6718 	if (allocated_mapping) {
6719 		*allocated_mapping = FALSE;
6720 	}
6721 
6722 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6723 	if (existing_mapping != NULL) {
6724 		local_id = existing_mapping->id;
6725 		os_ref_retain_locked(&existing_mapping->refcount);
6726 		if (uuid_policy_table) {
6727 			existing_mapping->table_usecount++;
6728 		}
6729 	} else {
6730 		struct necp_uuid_id_mapping *new_mapping = NULL;
6731 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6732 		    Z_WAITOK | Z_NOFAIL);
6733 		uuid_copy(new_mapping->uuid, uuid);
6734 		new_mapping->id = necp_get_new_uuid_id(false);
6735 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6736 		if (uuid_policy_table) {
6737 			new_mapping->table_usecount = 1;
6738 		} else {
6739 			new_mapping->table_usecount = 0;
6740 		}
6741 
6742 		LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6743 
6744 		if (allocated_mapping) {
6745 			*allocated_mapping = TRUE;
6746 		}
6747 
6748 		local_id = new_mapping->id;
6749 	}
6750 
6751 	return local_id;
6752 }
6753 
6754 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6755 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6756 {
6757 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6758 
6759 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6760 
6761 	if (removed_mapping) {
6762 		*removed_mapping = FALSE;
6763 	}
6764 
6765 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6766 	if (existing_mapping != NULL) {
6767 		if (uuid_policy_table) {
6768 			existing_mapping->table_usecount--;
6769 		}
6770 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6771 			LIST_REMOVE(existing_mapping, chain);
6772 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6773 			if (removed_mapping) {
6774 				*removed_mapping = TRUE;
6775 			}
6776 		}
6777 		return TRUE;
6778 	}
6779 
6780 	return FALSE;
6781 }
6782 
6783 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6784 necp_uuid_get_null_service_id_mapping(void)
6785 {
6786 	static struct necp_uuid_id_mapping null_mapping;
6787 	uuid_clear(null_mapping.uuid);
6788 	null_mapping.id = NECP_NULL_SERVICE_ID;
6789 
6790 	return &null_mapping;
6791 }
6792 
6793 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6794 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6795 {
6796 	struct necp_uuid_id_mapping *searchentry = NULL;
6797 	struct necp_uuid_id_mapping *foundentry = NULL;
6798 
6799 	if (uuid_is_null(uuid)) {
6800 		return necp_uuid_get_null_service_id_mapping();
6801 	}
6802 
6803 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6804 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6805 			foundentry = searchentry;
6806 			break;
6807 		}
6808 	}
6809 
6810 	return foundentry;
6811 }
6812 
6813 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6814 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6815 {
6816 	struct necp_uuid_id_mapping *searchentry = NULL;
6817 	struct necp_uuid_id_mapping *foundentry = NULL;
6818 
6819 	if (local_id == NECP_NULL_SERVICE_ID) {
6820 		return necp_uuid_get_null_service_id_mapping();
6821 	}
6822 
6823 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6824 		if (searchentry->id == local_id) {
6825 			foundentry = searchentry;
6826 			break;
6827 		}
6828 	}
6829 
6830 	return foundentry;
6831 }
6832 
6833 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6834 necp_create_uuid_service_id_mapping(uuid_t uuid)
6835 {
6836 	u_int32_t local_id = 0;
6837 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6838 
6839 	if (uuid_is_null(uuid)) {
6840 		return NECP_NULL_SERVICE_ID;
6841 	}
6842 
6843 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6844 
6845 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6846 	if (existing_mapping != NULL) {
6847 		local_id = existing_mapping->id;
6848 		os_ref_retain_locked(&existing_mapping->refcount);
6849 	} else {
6850 		struct necp_uuid_id_mapping *new_mapping = NULL;
6851 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6852 		    Z_WAITOK | Z_NOFAIL);
6853 		uuid_copy(new_mapping->uuid, uuid);
6854 		new_mapping->id = necp_get_new_uuid_id(true);
6855 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6856 
6857 		LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6858 
6859 		local_id = new_mapping->id;
6860 	}
6861 
6862 	return local_id;
6863 }
6864 
6865 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6866 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6867 {
6868 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6869 
6870 	if (uuid_is_null(uuid)) {
6871 		return TRUE;
6872 	}
6873 
6874 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6875 
6876 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6877 	if (existing_mapping != NULL) {
6878 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6879 			LIST_REMOVE(existing_mapping, chain);
6880 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6881 		}
6882 		return TRUE;
6883 	}
6884 
6885 	return FALSE;
6886 }
6887 
6888 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6889 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6890 {
6891 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6892 
6893 	if (service_id == 0) {
6894 		return TRUE;
6895 	}
6896 
6897 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6898 
6899 	existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6900 	if (existing_mapping != NULL) {
6901 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6902 			LIST_REMOVE(existing_mapping, chain);
6903 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6904 		}
6905 		return TRUE;
6906 	}
6907 
6908 	return FALSE;
6909 }
6910 
6911 static bool
necp_kernel_socket_policies_update_uuid_table(void)6912 necp_kernel_socket_policies_update_uuid_table(void)
6913 {
6914 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6915 
6916 	if (necp_uuid_app_id_mappings_dirty) {
6917 		uuid_t dummy_uuid = {};
6918 		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6919 			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6920 			return FALSE;
6921 		}
6922 
6923 		if (necp_num_uuid_app_id_mappings > 0) {
6924 			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6925 			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--) {
6926 				struct necp_uuid_id_mapping *mapping = NULL;
6927 				LIST_FOREACH(mapping, uuid_list_head, chain) {
6928 					if (mapping->table_usecount > 0 &&
6929 					    proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6930 						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6931 					}
6932 				}
6933 			}
6934 		}
6935 
6936 		necp_uuid_app_id_mappings_dirty = FALSE;
6937 	}
6938 
6939 	return TRUE;
6940 }
6941 
6942 #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)
6943 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)6944 necp_kernel_ip_output_policy_add(necp_policy_order order, necp_policy_order suborder, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_kernel_policy_id cond_policy_id, ifnet_t cond_bound_interface, u_int32_t cond_last_interface_index, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, u_int8_t cond_local_networks_flags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6945 {
6946 	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6947 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6948 
6949 	new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6950 	new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6951 	new_kernel_policy->suborder = suborder;
6952 	new_kernel_policy->order = order;
6953 	new_kernel_policy->session_order = session_order;
6954 	new_kernel_policy->session_pid = session_pid;
6955 
6956 	// Sanitize condition mask
6957 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6958 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6959 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6960 	}
6961 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6962 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6963 	}
6964 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6965 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6966 	}
6967 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6968 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6969 	}
6970 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6971 
6972 	// Set condition values
6973 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6974 		new_kernel_policy->cond_policy_id = cond_policy_id;
6975 	}
6976 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6977 		if (cond_bound_interface) {
6978 			ifnet_reference(cond_bound_interface);
6979 		}
6980 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
6981 	}
6982 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6983 		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6984 	}
6985 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6986 		new_kernel_policy->cond_protocol = cond_protocol;
6987 	}
6988 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6989 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6990 	}
6991 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6992 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6993 	}
6994 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6995 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
6996 	}
6997 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6998 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
6999 	}
7000 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7001 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
7002 	}
7003 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7004 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
7005 	}
7006 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
7007 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
7008 	}
7009 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7010 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
7011 	}
7012 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
7013 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
7014 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
7015 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
7016 	}
7017 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
7018 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
7019 	}
7020 
7021 	new_kernel_policy->result = result;
7022 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
7023 
7024 	if (necp_debug) {
7025 		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
7026 	}
7027 	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
7028 
7029 	return new_kernel_policy ? new_kernel_policy->id : 0;
7030 }
7031 
7032 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)7033 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
7034 {
7035 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7036 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
7037 
7038 	if (policy_id == 0) {
7039 		return NULL;
7040 	}
7041 
7042 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
7043 		if (kernel_policy->id == policy_id) {
7044 			return kernel_policy;
7045 		}
7046 	}
7047 
7048 	return NULL;
7049 }
7050 
7051 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)7052 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
7053 {
7054 	struct necp_kernel_ip_output_policy * __single policy = NULL;
7055 
7056 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7057 
7058 	policy = necp_kernel_ip_output_policy_find(policy_id);
7059 	if (policy) {
7060 		LIST_REMOVE(policy, chain);
7061 
7062 		if (policy->cond_bound_interface) {
7063 			ifnet_release(policy->cond_bound_interface);
7064 			policy->cond_bound_interface = NULL;
7065 		}
7066 
7067 		zfree(necp_ip_policy_zone, policy);
7068 		return TRUE;
7069 	}
7070 
7071 	return FALSE;
7072 }
7073 
7074 static void
necp_kernel_ip_output_policies_dump_all(void)7075 necp_kernel_ip_output_policies_dump_all(void)
7076 {
7077 	if (necp_debug) {
7078 		struct necp_kernel_ip_output_policy *policy = NULL;
7079 		int policy_i;
7080 		int id_i;
7081 		char result_string[MAX_RESULT_STRING_LEN];
7082 		char proc_name_string[MAXCOMLEN + 1];
7083 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
7084 		memset(proc_name_string, 0, MAXCOMLEN + 1);
7085 
7086 		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
7087 		NECPLOG0(LOG_DEBUG, "-----------\n");
7088 		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
7089 			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
7090 			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++) {
7091 				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
7092 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
7093 				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));
7094 			}
7095 			NECPLOG0(LOG_DEBUG, "-----------\n");
7096 		}
7097 	}
7098 }
7099 
7100 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)7101 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
7102 {
7103 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7104 		if (upper_policy->session_order != lower_policy->session_order) {
7105 			// A skip cannot override a policy of a different session
7106 			return FALSE;
7107 		} else {
7108 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
7109 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
7110 				// This policy is beyond the skip
7111 				return FALSE;
7112 			} else {
7113 				// This policy is inside the skip
7114 				return TRUE;
7115 			}
7116 		}
7117 	}
7118 
7119 	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
7120 	return TRUE;
7121 }
7122 
7123 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)7124 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy ** __indexable policy_array, int valid_indices)
7125 {
7126 	bool can_skip = FALSE;
7127 	u_int32_t highest_skip_session_order = 0;
7128 	u_int32_t highest_skip_order = 0;
7129 	int i;
7130 	for (i = 0; i < valid_indices; i++) {
7131 		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
7132 
7133 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
7134 		if (can_skip) {
7135 			if (highest_skip_session_order != compared_policy->session_order ||
7136 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
7137 				// If we've moved on to the next session, or passed the skip window
7138 				highest_skip_session_order = 0;
7139 				highest_skip_order = 0;
7140 				can_skip = FALSE;
7141 			} else {
7142 				// If this policy is also a skip, in can increase the skip window
7143 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7144 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
7145 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7146 					}
7147 				}
7148 				continue;
7149 			}
7150 		}
7151 
7152 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7153 			// This policy is a skip. Set the skip window accordingly
7154 			can_skip = TRUE;
7155 			highest_skip_session_order = compared_policy->session_order;
7156 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
7157 		}
7158 
7159 		// The result of the compared policy must be able to block out this policy result
7160 		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
7161 			continue;
7162 		}
7163 
7164 		// If new policy matches All Interfaces, compared policy must also
7165 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
7166 			continue;
7167 		}
7168 
7169 		// If new policy matches Local Networks, compared policy must also
7170 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
7171 			continue;
7172 		}
7173 
7174 		// Default makes lower policies unnecessary always
7175 		if (compared_policy->condition_mask == 0) {
7176 			return TRUE;
7177 		}
7178 
7179 		// Compared must be more general than policy, and include only conditions within policy
7180 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
7181 			continue;
7182 		}
7183 
7184 		// Negative conditions must match for the overlapping conditions
7185 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
7186 			continue;
7187 		}
7188 
7189 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
7190 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
7191 			continue;
7192 		}
7193 
7194 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
7195 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
7196 			continue;
7197 		}
7198 
7199 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
7200 		    compared_policy->cond_protocol != policy->cond_protocol) {
7201 			continue;
7202 		}
7203 
7204 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
7205 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
7206 				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))) {
7207 					continue;
7208 				}
7209 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
7210 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
7211 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
7212 					continue;
7213 				}
7214 			}
7215 		}
7216 
7217 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
7218 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
7219 				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))) {
7220 					continue;
7221 				}
7222 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
7223 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
7224 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
7225 					continue;
7226 				}
7227 			}
7228 		}
7229 
7230 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
7231 		    compared_policy->cond_scheme_port != policy->cond_scheme_port) {
7232 			continue;
7233 		}
7234 
7235 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
7236 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
7237 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
7238 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
7239 			continue;
7240 		}
7241 
7242 		return TRUE;
7243 	}
7244 
7245 	return FALSE;
7246 }
7247 
7248 static bool
necp_kernel_ip_output_policies_reprocess(void)7249 necp_kernel_ip_output_policies_reprocess(void)
7250 {
7251 	int i;
7252 	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
7253 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
7254 
7255 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
7256 
7257 	// Reset mask to 0
7258 	necp_kernel_ip_output_policies_condition_mask = 0;
7259 	necp_kernel_ip_output_policies_count = 0;
7260 	necp_kernel_ip_output_policies_non_id_count = 0;
7261 
7262 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7263 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7264 			kfree_type(struct necp_kernel_ip_output_policy *,
7265 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7266 			    necp_kernel_ip_output_policies_map[i]);
7267 			necp_kernel_ip_output_policies_map[i] = NULL;
7268 		}
7269 
7270 		// Init counts
7271 		necp_kernel_ip_output_policies_map_counts[i] = 0;
7272 	}
7273 
7274 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7275 		// Update mask
7276 		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
7277 		necp_kernel_ip_output_policies_count++;
7278 
7279 		/* Update bucket counts:
7280 		 * Non-id and SKIP policies will be added to all buckets
7281 		 * Add local networks policy to all buckets for incoming IP
7282 		 */
7283 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7284 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7285 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7286 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7287 				necp_kernel_ip_output_policies_map_counts[i]++;
7288 			}
7289 		}
7290 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
7291 			necp_kernel_ip_output_policies_non_id_count++;
7292 		} else {
7293 			necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
7294 		}
7295 	}
7296 
7297 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7298 		if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
7299 			// Allocate a NULL-terminated array of policy pointers for each bucket
7300 			necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
7301 			    necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
7302 			if (necp_kernel_ip_output_policies_map[i] == NULL) {
7303 				goto fail;
7304 			}
7305 		}
7306 		bucket_current_free_index[i] = 0;
7307 	}
7308 
7309 	u_int32_t current_session_order = 0;
7310 	u_int32_t current_session_last_non_skip_policy = 0;
7311 
7312 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
7313 		// For each new session, find the last non-skip policy. We can
7314 		// avoid adding any skip policies that don't actually skip over
7315 		// any non-skip policies.
7316 		if (current_session_order != kernel_policy->session_order) {
7317 			current_session_order = kernel_policy->session_order;
7318 			current_session_last_non_skip_policy = 0;
7319 
7320 			struct necp_kernel_ip_output_policy *inner_policy = NULL;
7321 			LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
7322 				if (inner_policy->session_order < current_session_order) {
7323 					continue;
7324 				}
7325 				if (inner_policy->session_order > current_session_order) {
7326 					break;
7327 				}
7328 				if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7329 					continue;
7330 				}
7331 
7332 				current_session_last_non_skip_policy = inner_policy->order;
7333 			}
7334 		}
7335 
7336 		if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7337 			if (current_session_last_non_skip_policy == 0) {
7338 				// No useful policies to skip over, don't add
7339 				continue;
7340 			}
7341 			if (kernel_policy->order >= current_session_last_non_skip_policy) {
7342 				// Skip policy is after the last useful policy, don't add
7343 				continue;
7344 			}
7345 		}
7346 
7347 		// Insert pointers into map
7348 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
7349 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
7350 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
7351 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7352 				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])) {
7353 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7354 					bucket_current_free_index[i]++;
7355 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7356 				}
7357 			}
7358 		} else {
7359 			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7360 			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])) {
7361 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7362 				bucket_current_free_index[i]++;
7363 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7364 			}
7365 		}
7366 	}
7367 
7368 	if (bucket_current_free_index[0] == 0) {
7369 		// No non-id policies were actually added
7370 		necp_kernel_ip_output_policies_non_id_count = 0;
7371 
7372 		// Also check if no policies at all were added
7373 		bool policies_added = FALSE;
7374 		for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7375 			if (bucket_current_free_index[i] != 0) {
7376 				policies_added = TRUE;
7377 				break;
7378 			}
7379 		}
7380 		if (!policies_added) {
7381 			necp_kernel_ip_output_policies_condition_mask = 0;
7382 			necp_kernel_ip_output_policies_count = 0;
7383 		}
7384 	}
7385 
7386 	necp_kernel_ip_output_policies_dump_all();
7387 	return TRUE;
7388 
7389 fail:
7390 	// Free memory, reset mask to 0
7391 	necp_kernel_ip_output_policies_condition_mask = 0;
7392 	necp_kernel_ip_output_policies_count = 0;
7393 	necp_kernel_ip_output_policies_non_id_count = 0;
7394 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7395 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7396 			kfree_type(struct necp_kernel_ip_output_policy *,
7397 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7398 			    necp_kernel_ip_output_policies_map[i]);
7399 			necp_kernel_ip_output_policies_map[i] = NULL;
7400 		}
7401 	}
7402 	return FALSE;
7403 }
7404 
7405 // Outbound Policy Matching
7406 // ---------------------
7407 struct substring {
7408 	size_t length;
7409 	char * __sized_by(length) string;
7410 };
7411 
7412 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7413 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7414 {
7415 	struct substring sub = {};
7416 	char * __indexable ptr = string;
7417 	size_t len = string ? length : 0;
7418 
7419 	while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7420 		ptr++;
7421 		len--;
7422 	}
7423 
7424 	while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7425 		len--;
7426 	}
7427 
7428 	sub.string = ptr;
7429 	sub.length = len;
7430 	return sub;
7431 }
7432 
7433 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7434 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7435 {
7436 	size_t trimmed_domain_length = 0;
7437 	char *trimmed_domain = NULL;
7438 	struct substring sub = necp_trim_dots_and_stars(string, length);
7439 
7440 	trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7441 	trimmed_domain_length = sub.length + 1;
7442 	if (trimmed_domain == NULL) {
7443 		return NULL;
7444 	}
7445 
7446 	strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7447 	trimmed_domain[sub.length] = 0;
7448 
7449 	return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7450 }
7451 
7452 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7453 necp_count_dots(char * __sized_by(length)string, size_t length)
7454 {
7455 	int dot_count = 0;
7456 	size_t i = 0;
7457 
7458 	for (i = 0; i < length; i++) {
7459 		if (string[i] == '.') {
7460 			dot_count++;
7461 		}
7462 	}
7463 
7464 	return dot_count;
7465 }
7466 
7467 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7468 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7469 {
7470 	if (parent.length <= suffix.length) {
7471 		return FALSE;
7472 	}
7473 
7474 	size_t length_difference = (parent.length - suffix.length);
7475 
7476 	if (require_dot_before_suffix) {
7477 		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7478 			return FALSE;
7479 		}
7480 	}
7481 
7482 	// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7483 	return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7484 }
7485 
7486 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)7487 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7488 {
7489 	if (hostname_substring.string == NULL || domain == NULL) {
7490 		return hostname_substring.string == domain;
7491 	}
7492 
7493 	struct substring domain_substring;
7494 	domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7495 	domain_substring.length = strlen(domain);
7496 
7497 	if (hostname_dot_count == domain_dot_count) {
7498 		// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7499 		if (hostname_substring.length == domain_substring.length &&
7500 		    strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7501 			return TRUE;
7502 		}
7503 	} else if (domain_dot_count < hostname_dot_count) {
7504 		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7505 			return TRUE;
7506 		}
7507 	}
7508 
7509 	return FALSE;
7510 }
7511 
7512 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7513 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7514 {
7515 	if (hostname_string == NULL ||
7516 	    domain_string == NULL) {
7517 		return false;
7518 	}
7519 
7520 	struct substring hostname_substring;
7521 	hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7522 	hostname_substring.length = strlen(hostname_string);
7523 
7524 	return necp_hostname_matches_domain(hostname_substring,
7525 	           necp_count_dots(hostname_substring.string, hostname_substring.length),
7526 	           domain_string,
7527 	           necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7528 }
7529 
7530 #define NECP_MAX_STRING_LEN 1024
7531 
7532 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7533 necp_copy_string(char * __sized_by(length)string, size_t length)
7534 {
7535 	size_t copied_string_length = 0;
7536 	char * __sized_by(copied_string_length) copied_string = NULL;
7537 
7538 	if (length > NECP_MAX_STRING_LEN) {
7539 		return NULL;
7540 	}
7541 
7542 	copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7543 	copied_string_length = length + 1;
7544 	if (copied_string == NULL) {
7545 		return NULL;
7546 	}
7547 
7548 	memcpy(copied_string, string, length);
7549 	copied_string[length] = 0;
7550 
7551 	return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7552 }
7553 
7554 static u_int32_t
necp_get_primary_direct_interface_index(void)7555 necp_get_primary_direct_interface_index(void)
7556 {
7557 	u_int32_t interface_index = IFSCOPE_NONE;
7558 
7559 	ifnet_head_lock_shared();
7560 	struct ifnet *ordered_interface = NULL;
7561 	TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7562 		const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7563 		if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7564 		    functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7565 			// All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7566 			interface_index = ordered_interface->if_index;
7567 			break;
7568 		}
7569 	}
7570 	ifnet_head_done();
7571 
7572 	return interface_index;
7573 }
7574 
7575 static inline bool
necp_task_has_match_entitlement(task_t task)7576 necp_task_has_match_entitlement(task_t task)
7577 {
7578 	return task != NULL &&
7579 	       (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7580 	       IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7581 }
7582 
7583 // Loopback traffic from certain entitled process will be dropped
7584 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7585 necp_task_has_loopback_drop_entitlement(task_t task)
7586 {
7587 	bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7588 	if (drop) {
7589 		necp_drop_loopback_count++;
7590 	}
7591 	return drop;
7592 }
7593 
7594 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7595 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7596 {
7597 	coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7598 
7599 	if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7600 		// No parent, nothing to do
7601 		return;
7602 	}
7603 
7604 	task_t __single lead_task = coalition_get_leader(coal);
7605 	if (lead_task != NULL) {
7606 		info->is_entitled = necp_task_has_match_entitlement(lead_task);
7607 		task_deallocate(lead_task);
7608 	}
7609 }
7610 
7611 // Some processes, due to particular entitlements, require using an NECP client to
7612 // access networking. Returns true if the result should be a Drop.
7613 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7614 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7615 {
7616 	if (necp_is_platform_binary(proc)) {
7617 		// This check is currently for the "on-demand-install-capable"
7618 		// entitlement, which by definition cannot be a built-in platform
7619 		// binary.
7620 		return false;
7621 	}
7622 
7623 	task_t __single task = proc_task(proc ? proc : current_proc());
7624 
7625 	if (!info->has_client &&
7626 	    task != NULL &&
7627 	    IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7628 		// Drop connections that don't use NECP clients and have the
7629 		// com.apple.developer.on-demand-install-capable entitlement.
7630 		// This effectively restricts those processes to only using
7631 		// an NECP-aware path for networking.
7632 		return true;
7633 	} else {
7634 		return false;
7635 	}
7636 }
7637 
7638 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7639 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7640 {
7641 	if (!necp_restrict_multicast || proc == NULL) {
7642 		return false;
7643 	}
7644 
7645 	// Check for multicast/broadcast here
7646 	if (info->remote_addr.sa.sa_family == AF_INET) {
7647 		if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7648 		    info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7649 			return false;
7650 		}
7651 	} else if (info->remote_addr.sa.sa_family == AF_INET6) {
7652 		if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7653 			return false;
7654 		}
7655 	} else {
7656 		// Not IPv4/IPv6
7657 		return false;
7658 	}
7659 
7660 	if (necp_is_platform_binary(proc)) {
7661 		return false;
7662 	}
7663 
7664 	const uint32_t platform = proc_platform(proc);
7665 	const uint32_t sdk = proc_sdk(proc);
7666 
7667 	// Enforce for iOS, linked on or after version 14
7668 	// If the caller set `check_minor_version`, only enforce starting at 14.5
7669 	if ((platform != PLATFORM_IOS ||
7670 	    sdk == 0 ||
7671 	    (sdk >> 16) < 14 ||
7672 	    (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7673 		return false;
7674 	}
7675 
7676 	// Allow entitled processes to use multicast
7677 	task_t __single task = proc_task(proc);
7678 	if (task != NULL &&
7679 	    IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7680 		return false;
7681 	}
7682 
7683 	const uint32_t min_sdk = proc_min_sdk(proc);
7684 	NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7685 
7686 	return true;
7687 }
7688 
7689 #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)
7690 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)7691 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account __null_terminated, char *domain __null_terminated, char *url __null_terminated, pid_t pid, int32_t pid_version, uid_t uid, uid_t real_uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, bool has_system_signed_result, proc_t real_proc, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, u_int16_t scheme_port, struct necp_socket_info *info, bool is_loopback, bool is_delegated)
7692 {
7693 	memset(info, 0, sizeof(struct necp_socket_info));
7694 
7695 	info->pid = pid;
7696 	info->pid_version = pid_version;
7697 	info->uid = uid;
7698 	info->real_uid = real_uid;
7699 	info->protocol = protocol;
7700 	info->bound_interface_index = bound_interface_index;
7701 	info->traffic_class = traffic_class;
7702 	info->has_client = has_client;
7703 	info->has_system_signed_result = has_system_signed_result;
7704 	info->drop_order = drop_order;
7705 	info->client_flags = client_flags;
7706 	info->is_loopback = is_loopback;
7707 	info->is_delegated = is_delegated;
7708 
7709 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7710 	    info->bound_interface_index != IFSCOPE_NONE) {
7711 		ifnet_head_lock_shared();
7712 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7713 		if (interface != NULL) {
7714 			info->bound_interface_flags = interface->if_flags;
7715 			info->bound_interface_eflags = interface->if_eflags;
7716 			info->bound_interface_xflags = interface->if_xflags;
7717 		}
7718 		ifnet_head_done();
7719 	}
7720 
7721 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7722 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7723 		if (existing_mapping) {
7724 			info->application_id = existing_mapping->id;
7725 		}
7726 	}
7727 
7728 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7729 		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7730 			info->real_application_id = info->application_id;
7731 		} else {
7732 			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7733 			if (existing_mapping) {
7734 				info->real_application_id = existing_mapping->id;
7735 			}
7736 		}
7737 	}
7738 
7739 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7740 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7741 		if (existing_mapping != NULL) {
7742 			info->real_application_id = info->application_id;
7743 			info->application_id = existing_mapping->id;
7744 			info->used_responsible_pid = true;
7745 		}
7746 	}
7747 
7748 	if (info->used_responsible_pid) {
7749 		proc = responsible_proc;
7750 	}
7751 
7752 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7753 		info->is_entitled = necp_task_has_match_entitlement(task);
7754 		if (!info->is_entitled) {
7755 			// Task does not have entitlement, check the parent task
7756 			necp_get_parent_is_entitled(task, info);
7757 		}
7758 	}
7759 
7760 	if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7761 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7762 		if (necp_is_platform_binary(proc)) {
7763 			info->is_platform_binary = true;
7764 		} else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7765 			info->is_platform_binary = true;
7766 			info->used_responsible_pid = true;
7767 		} else {
7768 			info->is_platform_binary = false;
7769 		}
7770 	}
7771 
7772 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7773 		info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7774 	}
7775 
7776 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7777 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7778 		if (existing_mapping) {
7779 			info->account_id = existing_mapping->id;
7780 		}
7781 	}
7782 
7783 	if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7784 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7785 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7786 		info->domain = domain;
7787 	}
7788 
7789 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7790 		info->url = url;
7791 	}
7792 
7793 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
7794 	    necp_restrict_multicast ||
7795 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7796 		if (local_addr && local_addr->sa.sa_len > 0) {
7797 			SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7798 			if (local_port != 0) {
7799 				info->local_addr.sin6.sin6_port = local_port;
7800 			}
7801 		} else {
7802 			if (remote_addr && remote_addr->sa.sa_len > 0) {
7803 				info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7804 				info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7805 			} else {
7806 				info->local_addr.sin6.sin6_family = AF_INET6;
7807 				info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7808 			}
7809 			if (local_port != 0) {
7810 				info->local_addr.sin6.sin6_port = local_port;
7811 			}
7812 		}
7813 		if (remote_addr && remote_addr->sa.sa_len > 0) {
7814 			SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7815 			if (remote_port != 0) {
7816 				info->remote_addr.sin6.sin6_port = remote_port;
7817 			}
7818 		} else if (remote_port != 0) {
7819 			info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7820 			info->remote_addr.sin6.sin6_family = AF_INET6;
7821 			info->remote_addr.sin6.sin6_port = remote_port;
7822 		}
7823 	}
7824 
7825 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7826 		info->scheme_port = scheme_port;
7827 	}
7828 }
7829 
7830 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7831 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7832 {
7833 	struct kev_netpolicy_ifdenied ev_ifdenied;
7834 
7835 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7836 
7837 	ev_ifdenied.ev_data.epid = pid;
7838 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7839 	ev_ifdenied.ev_if_functional_type = if_functional_type;
7840 
7841 	netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7842 }
7843 
7844 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7845 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7846 {
7847 	struct kev_netpolicy_netdenied ev_netdenied = {};
7848 
7849 	bzero(&ev_netdenied, sizeof(ev_netdenied));
7850 
7851 	ev_netdenied.ev_data.epid = pid;
7852 	uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7853 	ev_netdenied.ev_network_type = network_type;
7854 
7855 	netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7856 }
7857 
7858 extern char *proc_name_address(void *p);
7859 
7860 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7861 	if (!has_checked_delegation_entitlement) { \
7862 	        has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7863 	        has_checked_delegation_entitlement = TRUE; \
7864 	} \
7865 	if (!has_delegation_entitlement) { \
7866 	        NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7867 	                                          proc_name_address(_p), proc_pid(_p), _d); \
7868 	        break; \
7869 	}
7870 
7871 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)7872 necp_application_find_policy_match_internal(proc_t proc,
7873     u_int8_t * __sized_by(parameters_size)parameters,
7874     u_int32_t parameters_size,
7875     struct necp_aggregate_result *returned_result,
7876     u_int32_t *flags,
7877     u_int32_t *reason,
7878     u_int required_interface_index,
7879     const union necp_sockaddr_union *override_local_addr,
7880     const union necp_sockaddr_union *override_remote_addr,
7881     struct necp_client_endpoint *returned_v4_gateway,
7882     struct necp_client_endpoint *returned_v6_gateway,
7883     struct rtentry **returned_route, bool ignore_address,
7884     bool has_client,
7885     uuid_t *returned_override_euuid)
7886 {
7887 	int error = 0;
7888 	size_t offset = 0;
7889 
7890 	struct necp_kernel_socket_policy *matched_policy = NULL;
7891 	struct necp_socket_info info = {};
7892 	necp_kernel_policy_filter filter_control_unit = 0;
7893 	necp_kernel_policy_result service_action = 0;
7894 	necp_kernel_policy_service service = { 0, 0 };
7895 
7896 	u_int16_t protocol = 0;
7897 	u_int32_t bound_interface_index = required_interface_index;
7898 	u_int32_t traffic_class = 0;
7899 	u_int32_t client_flags = 0;
7900 	u_int16_t scheme_port = 0;
7901 	union necp_sockaddr_union local_addr;
7902 	union necp_sockaddr_union remote_addr;
7903 	bool no_remote_addr = FALSE;
7904 	u_int8_t remote_family = 0;
7905 	bool no_local_addr = FALSE;
7906 	u_int16_t local_port = 0;
7907 	u_int16_t remote_port = 0;
7908 	u_int32_t remote_endpoint_type = 0;
7909 	bool remote_address_is_empty = false;
7910 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7911 	bool is_delegated = false;
7912 
7913 	if (override_local_addr) {
7914 		memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7915 	} else {
7916 		memset(&local_addr, 0, sizeof(local_addr));
7917 	}
7918 	if (override_remote_addr) {
7919 		memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7920 	} else {
7921 		memset(&remote_addr, 0, sizeof(remote_addr));
7922 	}
7923 
7924 	// Initialize UID, PID, and UUIDs to the current process
7925 	uid_t uid = 0;
7926 	uid_t real_uid = 0;
7927 	kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7928 	if (cred != NULL) {
7929 		uid = kauth_cred_getuid(cred);
7930 		real_uid = uid;
7931 	}
7932 	task_t __single task = proc_task(proc);
7933 	pid_t pid = proc_pid(proc);
7934 	int32_t pid_version = proc_pidversion(proc);
7935 	uuid_t application_uuid;
7936 	uuid_clear(application_uuid);
7937 	uuid_t real_application_uuid;
7938 	uuid_clear(real_application_uuid);
7939 	proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7940 	uuid_copy(application_uuid, real_application_uuid);
7941 	uuid_t responsible_application_uuid;
7942 	uuid_clear(responsible_application_uuid);
7943 
7944 	char *domain __null_terminated = NULL;
7945 	char *url __null_terminated = NULL;
7946 	char *account __null_terminated = NULL;
7947 
7948 #define NECP_MAX_REQUIRED_AGENTS 16
7949 	u_int32_t num_required_agent_types = 0;
7950 	struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7951 	memset(&required_agent_types, 0, sizeof(required_agent_types));
7952 
7953 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7954 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7955 	memset(&netagent_ids, 0, sizeof(netagent_ids));
7956 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7957 	int netagent_cursor;
7958 
7959 	bool has_checked_delegation_entitlement = false;
7960 	bool has_delegation_entitlement = false;
7961 	bool has_system_signed_result = false;
7962 
7963 	proc_t responsible_proc = PROC_NULL;
7964 	proc_t effective_proc = proc;
7965 	bool release_eproc = false;
7966 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7967 
7968 	u_int32_t flow_divert_aggregate_unit = 0;
7969 
7970 	if (returned_result == NULL) {
7971 		if (cred != NULL) {
7972 			kauth_cred_unref(&cred);
7973 		}
7974 		return EINVAL;
7975 	}
7976 
7977 	if (returned_v4_gateway != NULL) {
7978 		memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7979 	}
7980 
7981 	if (returned_v6_gateway != NULL) {
7982 		memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7983 	}
7984 
7985 	if (returned_override_euuid != NULL) {
7986 		uuid_clear(*returned_override_euuid);
7987 	}
7988 
7989 	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7990 
7991 	u_int32_t drop_order = necp_process_drop_order(cred);
7992 
7993 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7994 
7995 	lck_rw_lock_shared(&necp_kernel_policy_lock);
7996 	if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7997 		if (necp_drop_all_order > 0 || drop_order > 0) {
7998 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7999 			lck_rw_done(&necp_kernel_policy_lock);
8000 			if (cred != NULL) {
8001 				kauth_cred_unref(&cred);
8002 			}
8003 			return 0;
8004 		}
8005 	}
8006 	lck_rw_done(&necp_kernel_policy_lock);
8007 
8008 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
8009 		u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
8010 		u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
8011 
8012 		if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
8013 			// If the length is larger than what can fit in the remaining parameters size, bail
8014 			NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
8015 			break;
8016 		}
8017 
8018 		if (length > 0) {
8019 			u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
8020 			if (value != NULL) {
8021 				switch (type) {
8022 				case NECP_CLIENT_PARAMETER_APPLICATION: {
8023 					if (length >= sizeof(uuid_t)) {
8024 						if (uuid_compare(application_uuid, value) == 0) {
8025 							// No delegation
8026 							break;
8027 						}
8028 
8029 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
8030 
8031 						is_delegated = true;
8032 						uuid_copy(application_uuid, value);
8033 					}
8034 					break;
8035 				}
8036 				case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
8037 					if (length >= sizeof(uuid_t)) {
8038 						if (uuid_compare(real_application_uuid, value) == 0) {
8039 							// No delegation
8040 							break;
8041 						}
8042 
8043 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
8044 
8045 						is_delegated = true;
8046 						uuid_copy(real_application_uuid, value);
8047 					}
8048 					break;
8049 				}
8050 				case NECP_CLIENT_PARAMETER_PID: {
8051 					if (length >= sizeof(pid_t)) {
8052 						if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
8053 							// No delegation
8054 							break;
8055 						}
8056 
8057 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
8058 
8059 						is_delegated = true;
8060 						memcpy(&pid, value, sizeof(pid_t));
8061 					}
8062 					break;
8063 				}
8064 				case NECP_CLIENT_PARAMETER_UID: {
8065 					if (length >= sizeof(uid_t)) {
8066 						if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
8067 							// No delegation
8068 							break;
8069 						}
8070 
8071 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
8072 
8073 						is_delegated = true;
8074 						memcpy(&uid, value, sizeof(uid_t));
8075 					}
8076 					break;
8077 				}
8078 				case NECP_CLIENT_PARAMETER_DOMAIN: {
8079 					char *ptr = (char *)value;
8080 					ptr[length - 1] = 0;
8081 					domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8082 					break;
8083 				}
8084 				case NECP_CLIENT_PARAMETER_URL: {
8085 					char *ptr = (char *)value;
8086 					ptr[length - 1] = 0;
8087 					url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8088 					break;
8089 				}
8090 				case NECP_CLIENT_PARAMETER_ACCOUNT: {
8091 					char *ptr = (char *)value;
8092 					ptr[length - 1] = 0;
8093 					account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
8094 					break;
8095 				}
8096 				case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
8097 					if (length >= sizeof(u_int32_t)) {
8098 						memcpy(&traffic_class, value, sizeof(u_int32_t));
8099 					}
8100 					break;
8101 				}
8102 				case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
8103 					if (length >= sizeof(u_int16_t)) {
8104 						memcpy(&protocol, value, sizeof(u_int16_t));
8105 					} else if (length >= sizeof(u_int8_t)) {
8106 						memcpy(&protocol, value, sizeof(u_int8_t));
8107 					}
8108 					break;
8109 				}
8110 				case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
8111 					if (length <= IFXNAMSIZ && length > 0) {
8112 						ifnet_t __single bound_interface = NULL;
8113 						char interface_name[IFXNAMSIZ];
8114 						memcpy(interface_name, value, length);
8115 						interface_name[length - 1] = 0;         // Make sure the string is NULL terminated
8116 						if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
8117 							bound_interface_index = bound_interface->if_index;
8118 							ifnet_release(bound_interface);
8119 						}
8120 					}
8121 					break;
8122 				}
8123 				case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
8124 					if (ignore_address || override_local_addr) {
8125 						break;
8126 					}
8127 
8128 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8129 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8130 						if (necp_address_is_valid(&address_struct->address.sa)) {
8131 							memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
8132 						}
8133 					}
8134 					break;
8135 				}
8136 				case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
8137 					if (ignore_address || override_remote_addr) {
8138 						break;
8139 					}
8140 
8141 					if (length >= sizeof(struct necp_policy_condition_addr)) {
8142 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
8143 						if (necp_address_is_valid(&address_struct->address.sa)) {
8144 							memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
8145 						}
8146 					}
8147 					break;
8148 				}
8149 				case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
8150 					if (ignore_address || override_local_addr) {
8151 						break;
8152 					}
8153 
8154 					if (length >= sizeof(struct necp_client_endpoint)) {
8155 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8156 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
8157 						    endpoint->u.endpoint.endpoint_port != 0) {
8158 							// Save port
8159 							local_port = endpoint->u.endpoint.endpoint_port;
8160 						}
8161 					}
8162 					break;
8163 				}
8164 				case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
8165 					if (ignore_address || override_remote_addr) {
8166 						break;
8167 					}
8168 
8169 					if (length >= sizeof(struct necp_client_endpoint)) {
8170 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
8171 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
8172 							remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
8173 							if (endpoint->u.endpoint.endpoint_port != 0) {
8174 								// Save port
8175 								remote_port = endpoint->u.endpoint.endpoint_port;
8176 							}
8177 						} else if (necp_addr_is_empty(&endpoint->u.sa)) {
8178 							remote_address_is_empty = true;
8179 						}
8180 					}
8181 					break;
8182 				}
8183 				case NECP_CLIENT_PARAMETER_FLAGS: {
8184 					if (length >= sizeof(client_flags)) {
8185 						memcpy(&client_flags, value, sizeof(client_flags));
8186 					}
8187 					break;
8188 				}
8189 				case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
8190 				case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
8191 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
8192 						break;
8193 					}
8194 					if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
8195 						memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
8196 						num_required_agent_types++;
8197 					}
8198 					break;
8199 				}
8200 				case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
8201 					if (length >= sizeof(scheme_port)) {
8202 						memcpy(&scheme_port, value, sizeof(scheme_port));
8203 					}
8204 					break;
8205 				}
8206 				case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
8207 					has_system_signed_result = true;
8208 					struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
8209 					if (length >= sizeof(struct necp_client_validatable)) {
8210 						// Check for system-signed sign_type values
8211 						if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
8212 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
8213 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
8214 							has_system_signed_result = true;
8215 						}
8216 					}
8217 					break;
8218 				}
8219 				default: {
8220 					break;
8221 				}
8222 				}
8223 			}
8224 		}
8225 
8226 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
8227 	}
8228 
8229 	// Check for loopback exception
8230 	if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
8231 		if (necp_task_has_loopback_drop_entitlement(task)) {
8232 			// Disallow certain entitled processes to send loopback traffic
8233 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8234 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8235 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8236 			if (cred != NULL) {
8237 				kauth_cred_unref(&cred);
8238 			}
8239 			return 0;
8240 		}
8241 		if (necp_pass_loopback > 0) {
8242 			bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
8243 		}
8244 	} else if (bound_interface_index != IFSCOPE_NONE) {
8245 		// Check for inter-process exception
8246 		struct sockaddr *dst = SA(&remote_addr.sa);
8247 		if (dst->sa_family == AF_INET6) {
8248 			struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
8249 			if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
8250 				ifnet_head_lock_shared();
8251 				ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
8252 				if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
8253 					bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
8254 				}
8255 				ifnet_head_done();
8256 			}
8257 		}
8258 	}
8259 
8260 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
8261 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8262 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8263 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8264 		if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
8265 			returned_result->routed_interface_index = lo_ifp->if_index;
8266 			*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8267 		} else {
8268 			returned_result->routed_interface_index = bound_interface_index;
8269 		}
8270 		if (cred != NULL) {
8271 			kauth_cred_unref(&cred);
8272 		}
8273 		return 0;
8274 	}
8275 
8276 	if (drop_order != 0) {
8277 		if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
8278 		    client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
8279 		    ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
8280 			// Allow listeners, inbound connections without remote addresses, and
8281 			// application service connections to bypass the unentitled drop order,
8282 			// to allow them to connect to application services (not directly over
8283 			// physical networking interfaces)
8284 			drop_order = 0;
8285 		}
8286 	}
8287 
8288 	if (proc_pid(effective_proc) != pid) {
8289 		proc_t found_proc = proc_find(pid);
8290 		if (found_proc != PROC_NULL) {
8291 			effective_proc = found_proc;
8292 			pid_version = proc_pidversion(effective_proc);
8293 			release_eproc = true;
8294 		}
8295 	}
8296 #if defined(XNU_TARGET_OS_OSX)
8297 	if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
8298 		proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
8299 		responsible_proc = proc_find(effective_proc->p_responsible_pid);
8300 	}
8301 #endif /* defined(XNU_TARGET_OS_OSX) */
8302 
8303 	// Lock
8304 	lck_rw_lock_shared(&necp_kernel_policy_lock);
8305 
8306 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
8307 	size_t route_rule_id_array_count = 0;
8308 	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);
8309 
8310 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
8311 	NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
8312 
8313 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
8314 	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
8315 	    &info,
8316 	    &filter_control_unit,
8317 	    route_rule_id_array,
8318 	    &route_rule_id_array_count,
8319 	    MAX_AGGREGATE_ROUTE_RULES,
8320 	    &service_action,
8321 	    &service,
8322 	    netagent_ids,
8323 	    NECP_MAX_NETAGENTS,
8324 	    netagent_use_flags,
8325 	    NECP_MAX_NETAGENTS,
8326 	    required_agent_types,
8327 	    num_required_agent_types,
8328 	    info.used_responsible_pid ? responsible_proc : effective_proc,
8329 	    0,
8330 	    &skip_policy_id,
8331 	    NULL,
8332 	    &drop_dest_policy_result,
8333 	    &drop_all_bypass,
8334 	    &flow_divert_aggregate_unit,
8335 	    NULL,
8336 	    debug);
8337 
8338 	// Check for loopback exception again after the policy match
8339 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
8340 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
8341 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
8342 		if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8343 			returned_result->filter_control_unit = 0;
8344 		} else {
8345 			returned_result->filter_control_unit = filter_control_unit;
8346 		}
8347 
8348 		if (flow_divert_aggregate_unit > 0) {
8349 			returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8350 		}
8351 
8352 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8353 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8354 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8355 		returned_result->routed_interface_index = lo_ifp->if_index;
8356 		*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8357 		error = 0;
8358 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8359 		goto done;
8360 	}
8361 
8362 	if (matched_policy) {
8363 		returned_result->policy_id = matched_policy->id;
8364 		returned_result->skip_policy_id = skip_policy_id;
8365 		returned_result->routing_result = matched_policy->result;
8366 		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8367 		if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8368 			uuid_copy(*returned_override_euuid, responsible_application_uuid);
8369 		}
8370 	} else {
8371 		bool drop_all = false;
8372 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8373 			// Mark socket as a drop if drop_all is set
8374 			drop_all = true;
8375 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8376 				drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8377 			}
8378 		}
8379 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8380 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8381 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8382 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8383 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8384 		} else {
8385 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8386 			returned_result->skip_policy_id = skip_policy_id;
8387 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8388 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8389 		}
8390 	}
8391 	if (necp_check_missing_client_drop(proc, &info) ||
8392 	    necp_check_restricted_multicast_drop(proc, &info, false)) {
8393 		// Mark as drop
8394 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8395 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8396 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8397 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8398 	}
8399 	if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8400 		returned_result->filter_control_unit = 0;
8401 	} else {
8402 		returned_result->filter_control_unit = filter_control_unit;
8403 	}
8404 
8405 	if (flow_divert_aggregate_unit > 0) {
8406 		returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8407 	}
8408 
8409 	returned_result->service_action = service_action;
8410 
8411 	// Fetch service registration
8412 	if (service.identifier != 0) {
8413 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8414 		if (mapping != NULL) {
8415 			struct necp_service_registration *service_registration = NULL;
8416 			uuid_copy(returned_result->service_uuid, mapping->uuid);
8417 			returned_result->service_data = service.data;
8418 			if (service.identifier == NECP_NULL_SERVICE_ID) {
8419 				// NULL service is always 'registered'
8420 				returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8421 			} else {
8422 				LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8423 					if (service.identifier == service_registration->service_id) {
8424 						returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8425 						break;
8426 					}
8427 				}
8428 			}
8429 		}
8430 	}
8431 
8432 	// Handle netagents
8433 	size_t netagent_i = 0;
8434 	for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8435 		struct necp_uuid_id_mapping *mapping = NULL;
8436 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
8437 		if (netagent_id == 0) {
8438 			continue;
8439 		}
8440 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8441 		if (mapping != NULL) {
8442 			uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8443 			returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8444 			netagent_i++;
8445 		}
8446 
8447 		// If the flags say to remove, clear the local copy
8448 		if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8449 			netagent_ids[netagent_cursor] = 0;
8450 		}
8451 	}
8452 
8453 	// Do routing evaluation
8454 	u_int output_bound_interface = bound_interface_index;
8455 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8456 		output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8457 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8458 		output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8459 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8460 		output_bound_interface = necp_get_primary_direct_interface_index();
8461 		if (output_bound_interface == IFSCOPE_NONE) {
8462 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8463 		} else {
8464 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8465 			returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8466 		}
8467 	}
8468 
8469 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8470 	    returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8471 		if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8472 			// Trigger the event that we dropped due to a local network policy
8473 #if defined(XNU_TARGET_OS_OSX)
8474 			bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8475 			necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8476 			    should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8477 			    NETPOLICY_NETWORKTYPE_LOCAL);
8478 #else
8479 			necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8480 #endif
8481 		}
8482 		if (reason != NULL) {
8483 			*reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8484 		}
8485 	}
8486 
8487 	if (local_addr.sa.sa_len == 0 ||
8488 	    (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8489 	    (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8490 		no_local_addr = TRUE;
8491 	}
8492 
8493 	if (remote_addr.sa.sa_len == 0 ||
8494 	    (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8495 	    (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8496 		no_remote_addr = TRUE;
8497 		remote_family = remote_addr.sa.sa_family;
8498 	}
8499 
8500 	returned_result->routed_interface_index = 0;
8501 	struct rtentry *rt = NULL;
8502 	if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8503 		// Treat the output bound interface as the routed interface for local address
8504 		// validation later.
8505 		returned_result->routed_interface_index = output_bound_interface;
8506 	} else {
8507 		if (no_remote_addr) {
8508 			memset(&remote_addr, 0, sizeof(remote_addr));
8509 			if (remote_family == AF_INET6) {
8510 				// Reset address to ::
8511 				remote_addr.sa.sa_family = AF_INET6;
8512 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8513 			} else {
8514 				// Reset address to 0.0.0.0
8515 				remote_addr.sa.sa_family = AF_INET;
8516 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8517 			}
8518 		}
8519 
8520 		rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8521 		    output_bound_interface);
8522 
8523 		if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8524 		    IS_INTF_CLAT46(rt->rt_ifp)) {
8525 			rtfree(rt);
8526 			rt = NULL;
8527 			returned_result->routed_interface_index = 0;
8528 		}
8529 
8530 		if (no_remote_addr && remote_family == AF_UNSPEC &&
8531 		    (rt == NULL || rt->rt_ifp == NULL)) {
8532 			// Route lookup for default IPv4 failed, try IPv6
8533 
8534 			// Cleanup old route if necessary
8535 			if (rt != NULL) {
8536 				rtfree(rt);
8537 				rt = NULL;
8538 			}
8539 
8540 			// Reset address to ::
8541 			memset(&remote_addr, 0, sizeof(remote_addr));
8542 			remote_addr.sa.sa_family = AF_INET6;
8543 			remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8544 
8545 			// Get route
8546 			rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8547 			    output_bound_interface);
8548 		}
8549 
8550 		if (rt != NULL &&
8551 		    rt->rt_ifp != NULL) {
8552 			returned_result->routed_interface_index = rt->rt_ifp->if_index;
8553 			/*
8554 			 * For local addresses, we allow the interface scope to be
8555 			 * either the loopback interface or the interface hosting the
8556 			 * local address.
8557 			 */
8558 			if (bound_interface_index != IFSCOPE_NONE &&
8559 			    rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8560 			    (output_bound_interface == lo_ifp->if_index ||
8561 			    rt->rt_ifp->if_index == lo_ifp->if_index ||
8562 			    rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8563 				struct sockaddr_storage dst;
8564 				unsigned int ifscope = bound_interface_index;
8565 
8566 				/*
8567 				 * Transform dst into the internal routing table form
8568 				 */
8569 				(void) sa_copy(SA(&remote_addr),
8570 				    &dst, &ifscope);
8571 
8572 				if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8573 				    rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8574 					returned_result->routed_interface_index =
8575 					    bound_interface_index;
8576 				}
8577 			}
8578 		}
8579 	}
8580 
8581 	if (returned_result->routed_interface_index != 0 &&
8582 	    returned_result->routed_interface_index != lo_ifp->if_index &&     // Loopback can accept any local address
8583 	    !no_local_addr) {
8584 		// Transform local_addr into the ifaddr form
8585 		// IPv6 Scope IDs are always embedded in the ifaddr list
8586 		struct sockaddr_storage local_address_sanitized;
8587 		u_int ifscope = IFSCOPE_NONE;
8588 		(void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8589 		SIN(&local_address_sanitized)->sin_port = 0;
8590 		if (local_address_sanitized.ss_family == AF_INET6) {
8591 			if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8592 				SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8593 			}
8594 		}
8595 
8596 		// Validate local address on routed interface
8597 		struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8598 		if (ifa == NULL) {
8599 			// Interface address not found, reject route
8600 			returned_result->routed_interface_index = 0;
8601 			if (rt != NULL) {
8602 				rtfree(rt);
8603 				rt = NULL;
8604 			}
8605 		} else {
8606 			ifaddr_release(ifa);
8607 			ifa = NULL;
8608 		}
8609 	}
8610 
8611 	if (flags != NULL) {
8612 #if SKYWALK
8613 		if (kernel_is_macos_or_server()) {
8614 			enum net_filter_event_subsystems filters = net_filter_event_get_state();
8615 
8616 			if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8617 				*flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8618 			}
8619 			if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8620 				*flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8621 			}
8622 			if (filters & NET_FILTER_EVENT_ALF) {
8623 				*flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8624 			}
8625 			if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8626 				*flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8627 			}
8628 		}
8629 #endif /* SKYWALK */
8630 		if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8631 			// Check for local/direct
8632 			bool is_local = FALSE;
8633 			if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8634 				is_local = TRUE;
8635 			} else if (returned_result->routed_interface_index != 0 &&
8636 			    !no_remote_addr) {
8637 				// Clean up the address before comparison with interface addresses
8638 
8639 				// Transform remote_addr into the ifaddr form
8640 				// IPv6 Scope IDs are always embedded in the ifaddr list
8641 				struct sockaddr_storage remote_address_sanitized;
8642 				u_int ifscope = IFSCOPE_NONE;
8643 				(void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8644 				SIN(&remote_address_sanitized)->sin_port = 0;
8645 				if (remote_address_sanitized.ss_family == AF_INET6) {
8646 					if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8647 						SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8648 					}
8649 				}
8650 
8651 				// Check if remote address is an interface address
8652 				struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8653 				if (ifa != NULL && ifa->ifa_ifp != NULL) {
8654 					u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8655 					if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8656 					    if_index_for_remote_addr == lo_ifp->if_index) {
8657 						is_local = TRUE;
8658 					}
8659 				}
8660 				if (ifa != NULL) {
8661 					ifaddr_release(ifa);
8662 					ifa = NULL;
8663 				}
8664 			}
8665 
8666 			if (is_local) {
8667 				*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8668 			} else if (rt != NULL) {
8669 				if (rt->rt_flags & RTF_GLOBAL) {
8670 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8671 				} else if (!(rt->rt_flags & RTF_GATEWAY) &&
8672 				    (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8673 					// Route is directly accessible
8674 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8675 				}
8676 			}
8677 
8678 			if (rt != NULL &&
8679 			    rt->rt_ifp != NULL) {
8680 				// Check probe status
8681 				if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8682 					*flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8683 				}
8684 
8685 				if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8686 					struct if_cellular_status_v1 *ifsr;
8687 
8688 					ifnet_lock_shared(rt->rt_ifp);
8689 					lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8690 
8691 					if (rt->rt_ifp->if_link_status != NULL) {
8692 						ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8693 
8694 						if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8695 							if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8696 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8697 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8698 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8699 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8700 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8701 							}
8702 						}
8703 					}
8704 					lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8705 					ifnet_lock_done(rt->rt_ifp);
8706 				}
8707 
8708 				// Check link quality
8709 				if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8710 				    (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8711 				    rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8712 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8713 				}
8714 
8715 				// Check QoS marking (fastlane)
8716 				for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8717 					if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8718 						*flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8719 						// If the route can use QoS markings, stop iterating route rules
8720 						break;
8721 					}
8722 				}
8723 
8724 				if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8725 					*flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8726 				}
8727 
8728 				if (traffic_class == SO_TC_BK_SYS) {
8729 					// Block BK_SYS traffic if interface is throttled
8730 					u_int32_t throttle_level = 0;
8731 					if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8732 						if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8733 							returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8734 							memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8735 						}
8736 					}
8737 				}
8738 			}
8739 		}
8740 
8741 		u_int interface_to_check = returned_result->routed_interface_index;
8742 		if (interface_to_check == 0) {
8743 			interface_to_check = output_bound_interface;
8744 		}
8745 		union necp_sockaddr_union default_address;
8746 		struct rtentry *v4Route = NULL;
8747 		struct rtentry *v6Route = NULL;
8748 
8749 		memset(&default_address, 0, sizeof(default_address));
8750 
8751 		// Reset address to 0.0.0.0
8752 		default_address.sa.sa_family = AF_INET;
8753 		default_address.sa.sa_len = sizeof(struct sockaddr_in);
8754 		v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8755 		    returned_result->routed_interface_index);
8756 
8757 		// Reset address to ::
8758 		default_address.sa.sa_family = AF_INET6;
8759 		default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8760 		v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8761 		    returned_result->routed_interface_index);
8762 
8763 		if (v4Route != NULL) {
8764 			if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8765 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8766 			}
8767 			if (returned_v4_gateway != NULL &&
8768 			    v4Route->rt_gateway != NULL &&
8769 			    v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8770 				memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8771 				memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8772 			}
8773 			rtfree(v4Route);
8774 			v4Route = NULL;
8775 		}
8776 
8777 		if (v6Route != NULL) {
8778 			if (v6Route->rt_ifp != NULL) {
8779 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8780 
8781 				if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8782 					*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8783 				}
8784 			}
8785 			if (returned_v6_gateway != NULL &&
8786 			    v6Route->rt_gateway != NULL &&
8787 			    v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8788 				SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8789 			}
8790 			rtfree(v6Route);
8791 			v6Route = NULL;
8792 		}
8793 	}
8794 
8795 	// Take two passes through the rule list: first for rules that don't match based on agents,
8796 	// second for rules that match based on agents. Since rules can modify the agent list itself,
8797 	// this makes the logic more deterministic. This allows a non-agent matching rule to remove
8798 	// an agent before it is used for matching later.
8799 	size_t route_rule_index = 0;
8800 	bool second_pass = false;
8801 	while (route_rule_index < route_rule_id_array_count) {
8802 		bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8803 		if (rule_matches_agents != second_pass) {
8804 			// Process rules that match based on agents only in the second pass
8805 			route_rule_index++;
8806 			if (route_rule_index == route_rule_id_array_count && !second_pass) {
8807 				route_rule_index = 0;
8808 				second_pass = true;
8809 			}
8810 			continue;
8811 		}
8812 
8813 		u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8814 		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);
8815 		if (!route_is_allowed) {
8816 			// If the route is blocked, treat the lookup as a drop
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 			if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8821 				if (reason != NULL) {
8822 					if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8823 						*reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8824 					} else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8825 						*reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8826 					}
8827 				}
8828 				necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8829 			}
8830 			// If the route gets denied, stop matching rules
8831 			break;
8832 		}
8833 
8834 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8835 		if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8836 			u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8837 			    route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8838 			if (flow_divert_control_unit != 0) {
8839 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8840 				returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8841 			}
8842 			if (flow_divert_aggregate_unit != 0) {
8843 				returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8844 			}
8845 		}
8846 
8847 		// Check if there is a route rule that adds or removes an agent
8848 		bool remove = false;
8849 		u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8850 		if (netagent_id != 0) {
8851 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8852 			if (mapping != NULL) {
8853 				bool agent_already_present = false;
8854 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8855 					if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8856 						// Found the agent already present
8857 						agent_already_present = true;
8858 						if (remove) {
8859 							// Mark as remove if necessary
8860 							returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8861 						}
8862 					} else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8863 						// Found open slot
8864 						if (!agent_already_present) {
8865 							uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8866 							if (remove) {
8867 								returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8868 							} else {
8869 								returned_result->netagent_use_flags[netagent_cursor] = 0;
8870 							}
8871 						}
8872 						break;
8873 					}
8874 				}
8875 			}
8876 
8877 			// Update the local netagent_ids array for future evaluations
8878 			if (remove) {
8879 				// Check if the agent ID is in the array, and remove it
8880 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8881 					if (netagent_id == netagent_ids[netagent_cursor]) {
8882 						netagent_ids[netagent_cursor] = 0;
8883 					}
8884 				}
8885 			} else {
8886 				// Check if the agent ID is not yet in the array, and add it
8887 				bool found = false;
8888 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8889 					if (netagent_id == netagent_ids[netagent_cursor]) {
8890 						found = true;
8891 						break;
8892 					}
8893 				}
8894 				if (!found) {
8895 					for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8896 						if (netagent_ids[netagent_cursor] == 0) {
8897 							// Empty slot, add the agent
8898 							netagent_ids[netagent_cursor] = netagent_id;
8899 							break;
8900 						}
8901 					}
8902 				}
8903 			}
8904 		}
8905 
8906 		route_rule_index++;
8907 		if (route_rule_index == route_rule_id_array_count && !second_pass) {
8908 			route_rule_index = 0;
8909 			second_pass = true;
8910 		}
8911 	}
8912 
8913 	if (rt != NULL && rt->rt_ifp != NULL) {
8914 		const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8915 		const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8916 		const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8917 		    IFNET_IS_EXPENSIVE(rt->rt_ifp));
8918 		const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8919 		    IFNET_IS_CONSTRAINED(rt->rt_ifp));
8920 		const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8921 		    IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8922 		    !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8923 
8924 		const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8925 		if (!is_listener && !is_browser) {
8926 			if (reason != NULL) {
8927 				if (expensive_prohibited) {
8928 					*reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8929 				} else if (constrained_prohibited) {
8930 					*reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8931 				} else if (ultra_constrained_not_allowed) {
8932 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8933 				}
8934 			}
8935 			if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8936 				// If a property of the interface was not allowed, treat it as a drop
8937 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8938 				memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8939 			}
8940 		}
8941 	}
8942 
8943 	if (rt != NULL) {
8944 		if (returned_route != NULL) {
8945 			*returned_route = rt;
8946 		} else {
8947 			rtfree(rt);
8948 		}
8949 		rt = NULL;
8950 	}
8951 
8952 done:
8953 	// Unlock
8954 	lck_rw_done(&necp_kernel_policy_lock);
8955 
8956 	if (release_eproc && effective_proc != PROC_NULL) {
8957 		proc_rele(effective_proc);
8958 	}
8959 #if defined(XNU_TARGET_OS_OSX)
8960 	if (responsible_proc != PROC_NULL) {
8961 		proc_rele(responsible_proc);
8962 	}
8963 #endif
8964 
8965 	if (cred != NULL) {
8966 		kauth_cred_unref(&cred);
8967 	}
8968 
8969 	return error;
8970 }
8971 
8972 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8973 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8974 {
8975 	struct rtentry *rt = NULL;
8976 	bool is_local = FALSE;
8977 
8978 	if (remote_addr == NULL) {
8979 		return NULL;
8980 	}
8981 
8982 	if (remote_addr->sa.sa_len == 0 ||
8983 	    (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8984 	    (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8985 		return FALSE;
8986 	}
8987 
8988 	// Lookup route regardless of the scoped interface to check if
8989 	// remote address is in a local network.
8990 	rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8991 
8992 	if (rt == NULL) {
8993 		goto done;
8994 	}
8995 	if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8996 		goto free_rt;
8997 	}
8998 	is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
8999 
9000 free_rt:
9001 	rtfree(rt);
9002 
9003 done:
9004 	return is_local;
9005 }
9006 
9007 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)9008 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
9009     necp_app_id app_id,
9010     necp_app_id real_app_id,
9011     uint8_t is_entitled,
9012     u_int32_t account_id,
9013     struct substring domain,
9014     u_int8_t domain_dot_count,
9015     const char *url __null_terminated,
9016     pid_t pid,
9017     int32_t pid_version,
9018     uid_t uid,
9019     uid_t real_uid,
9020     u_int32_t bound_interface_index,
9021     u_int32_t traffic_class,
9022     u_int16_t protocol,
9023     union necp_sockaddr_union *local,
9024     union necp_sockaddr_union *remote,
9025     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9026     u_int32_t num_required_agent_types,
9027     bool has_client,
9028     uint32_t client_flags,
9029     int is_platform_binary,
9030     bool has_signed_result,
9031     proc_t proc,
9032     u_int16_t pf_tag,
9033     u_int16_t scheme_port,
9034     struct rtentry *rt,
9035     bool is_loopback,
9036     int debug,
9037     bool real_is_platform_binary,
9038     u_int32_t bound_interface_flags,
9039     u_int32_t bound_interface_eflags,
9040     u_int32_t bound_interface_xflags,
9041     struct necp_socket_info *info,
9042     bool is_delegated,
9043     struct socket *socket)
9044 {
9045 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9046 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9047 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9048 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9049 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
9050 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9051 				if (bound_interface_index == cond_bound_interface_index) {
9052 					// No match, matches forbidden interface
9053 					return FALSE;
9054 				}
9055 			} else {
9056 				if (bound_interface_index != cond_bound_interface_index) {
9057 					// No match, does not match required interface
9058 					return FALSE;
9059 				}
9060 			}
9061 		}
9062 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9063 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9064 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9065 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9066 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9067 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9068 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9069 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9070 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9071 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9072 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9073 					// No match, matches some forbidden interface flags
9074 					return FALSE;
9075 				}
9076 			} else {
9077 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9078 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9079 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9080 					// No match, does not match some required interface xflags
9081 					return FALSE;
9082 				}
9083 			}
9084 		}
9085 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9086 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9087 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
9088 			if (bound_interface_index != 0) {
9089 				// No match, requires a non-bound packet
9090 				return FALSE;
9091 			}
9092 		}
9093 	}
9094 
9095 	if (kernel_policy->condition_mask == 0) {
9096 		return TRUE;
9097 	}
9098 
9099 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9100 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
9101 		    "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
9102 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
9103 			if (app_id == kernel_policy->cond_app_id) {
9104 				// No match, matches forbidden application
9105 				return FALSE;
9106 			}
9107 		} else {
9108 			if (app_id != kernel_policy->cond_app_id) {
9109 				// No match, does not match required application
9110 				return FALSE;
9111 			}
9112 		}
9113 
9114 		// Check signing identifier only after APP ID matched
9115 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
9116 		    kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9117 			u_int8_t matched = necp_boolean_state_false;
9118 			const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
9119 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
9120 			    "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
9121 			    kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
9122 			    signing_id ? signing_id : "<n/a>");
9123 			if (signing_id != NULL) {
9124 				if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
9125 					matched = necp_boolean_state_true;
9126 				}
9127 			}
9128 
9129 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
9130 				if (matched == necp_boolean_state_true) {
9131 					return FALSE;
9132 				}
9133 			} else {
9134 				if (matched != necp_boolean_state_true) {
9135 					return FALSE;
9136 				}
9137 			}
9138 		}
9139 	}
9140 
9141 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9142 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
9143 		    "NECP_KERNEL_CONDITION_REAL_APP_ID",
9144 		    kernel_policy->cond_real_app_id, real_app_id);
9145 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9146 			if (real_app_id == kernel_policy->cond_real_app_id) {
9147 				// No match, matches forbidden application
9148 				return FALSE;
9149 			}
9150 		} else {
9151 			if (real_app_id != kernel_policy->cond_real_app_id) {
9152 				// No match, does not match required application
9153 				return FALSE;
9154 			}
9155 		}
9156 	}
9157 
9158 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9159 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
9160 		if (!has_client) {
9161 			return FALSE;
9162 		}
9163 	}
9164 
9165 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9166 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
9167 		if (!is_entitled) {
9168 			// Process is missing entitlement
9169 			return FALSE;
9170 		}
9171 	}
9172 
9173 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9174 		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);
9175 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9176 			if (is_platform_binary) {
9177 				// Process is platform binary
9178 				return FALSE;
9179 			}
9180 		} else {
9181 			if (!is_platform_binary) {
9182 				// Process is not platform binary
9183 				return FALSE;
9184 			}
9185 		}
9186 	}
9187 
9188 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9189 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
9190 		if (has_signed_result == 0) {
9191 			// Client did not have a system-signed result
9192 			return FALSE;
9193 		}
9194 	}
9195 
9196 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
9197 		if (proc != NULL) {
9198 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
9199 			    kernel_policy->cond_sdk_version.platform,
9200 			    kernel_policy->cond_sdk_version.min_version,
9201 			    kernel_policy->cond_sdk_version.version,
9202 			    proc_platform(proc),
9203 			    proc_min_sdk(proc),
9204 			    proc_sdk(proc));
9205 			if (kernel_policy->cond_sdk_version.platform != 0) {
9206 				if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
9207 					// Process does not match platform
9208 					return FALSE;
9209 				}
9210 			}
9211 
9212 			if (kernel_policy->cond_sdk_version.min_version != 0) {
9213 				if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
9214 					// Process min version is older than required min version
9215 					return FALSE;
9216 				}
9217 			}
9218 
9219 			if (kernel_policy->cond_sdk_version.version != 0) {
9220 				if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
9221 					// Process SDK version is older than required version
9222 					return FALSE;
9223 				}
9224 			}
9225 		}
9226 	}
9227 
9228 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
9229 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
9230 		if (kernel_policy->cond_custom_entitlement != NULL) {
9231 			if (proc == NULL) {
9232 				// No process found, cannot check entitlement
9233 				return FALSE;
9234 			}
9235 			task_t __single task = proc_task(proc);
9236 			if (task == NULL ||
9237 			    !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
9238 				// Process is missing custom entitlement
9239 				return FALSE;
9240 			}
9241 		}
9242 	}
9243 
9244 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9245 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
9246 		    "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
9247 		// Exact match requires the number of dots to match (no suffix matching allowed)
9248 		bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
9249 		    necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
9250 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
9251 			if (domain_matches) {
9252 				// No match, matches forbidden domain
9253 				return FALSE;
9254 			}
9255 		} else {
9256 			if (!domain_matches) {
9257 				// No match, does not match required domain
9258 				return FALSE;
9259 			}
9260 		}
9261 	} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9262 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
9263 		    "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
9264 		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
9265 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
9266 			if (domain_matches) {
9267 				// No match, matches forbidden domain
9268 				return FALSE;
9269 			}
9270 		} else {
9271 			if (!domain_matches) {
9272 				// No match, does not match required domain
9273 				return FALSE;
9274 			}
9275 		}
9276 	}
9277 
9278 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9279 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9280 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (ID)", kernel_policy->cond_domain_filter, 0);
9281 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER,
9282 		    "NECP_KERNEL_CONDITION_DOMAIN_FILTER (domain)", "<n/a>", domain.string);
9283 		bool domain_matches = false;
9284 		if (NECP_IS_DOMAIN_FILTER_ID(kernel_policy->cond_domain_filter)) {
9285 			struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
9286 			if (filter != NULL && filter->filter != NULL) {
9287 				domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
9288 			}
9289 		} else {
9290 			domain_matches = necp_match_domain_with_trie(&necp_global_domain_trie_list, kernel_policy->cond_domain_filter, domain.string, domain.length);
9291 			if (debug) {
9292 				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);
9293 			}
9294 		}
9295 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
9296 			if (domain_matches) {
9297 				// No match, matches forbidden domain
9298 				return FALSE;
9299 			}
9300 		} else {
9301 			if (!domain_matches) {
9302 				// No match, does not match required domain
9303 				return FALSE;
9304 			}
9305 		}
9306 	}
9307 
9308 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
9309 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
9310 		    "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
9311 		bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
9312 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
9313 			if (url_matches) {
9314 				// No match, matches forbidden url
9315 				return FALSE;
9316 			}
9317 		} else {
9318 			if (!url_matches) {
9319 				// No match, does not match required url
9320 				return FALSE;
9321 			}
9322 		}
9323 	}
9324 
9325 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9326 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
9327 		    "NECP_KERNEL_CONDITION_ACCOUNT_ID",
9328 		    kernel_policy->cond_account_id, account_id);
9329 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
9330 			if (account_id == kernel_policy->cond_account_id) {
9331 				// No match, matches forbidden account
9332 				return FALSE;
9333 			}
9334 		} else {
9335 			if (account_id != kernel_policy->cond_account_id) {
9336 				// No match, does not match required account
9337 				return FALSE;
9338 			}
9339 		}
9340 	}
9341 
9342 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
9343 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
9344 		    "NECP_KERNEL_CONDITION_PID",
9345 		    kernel_policy->cond_pid, pid);
9346 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
9347 			if (pid == kernel_policy->cond_pid) {
9348 				// No match, matches forbidden pid
9349 				return FALSE;
9350 			}
9351 			if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
9352 				return FALSE;
9353 			}
9354 		} else {
9355 			if (pid != kernel_policy->cond_pid) {
9356 				// No match, does not match required pid
9357 				return FALSE;
9358 			}
9359 			if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
9360 				return FALSE;
9361 			}
9362 		}
9363 	}
9364 
9365 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9366 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9367 		    "NECP_KERNEL_CONDITION_UID",
9368 		    kernel_policy->cond_uid, uid);
9369 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9370 			if (uid == kernel_policy->cond_uid) {
9371 				// No match, matches forbidden uid
9372 				return FALSE;
9373 			}
9374 		} else {
9375 			if (uid != kernel_policy->cond_uid) {
9376 				// No match, does not match required uid
9377 				return FALSE;
9378 			}
9379 		}
9380 	}
9381 
9382 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9383 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9384 		    "NECP_KERNEL_CONDITION_REAL_UID",
9385 		    kernel_policy->cond_real_uid, real_uid);
9386 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9387 			if (real_uid == kernel_policy->cond_real_uid) {
9388 				// No match, matches forbidden uid
9389 				return FALSE;
9390 			}
9391 		} else {
9392 			if (real_uid != kernel_policy->cond_real_uid) {
9393 				// No match, does not match required uid
9394 				return FALSE;
9395 			}
9396 		}
9397 	}
9398 
9399 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9400 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9401 		    kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9402 		    traffic_class, 0, 0);
9403 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9404 			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9405 			    traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9406 				// No match, matches forbidden traffic class
9407 				return FALSE;
9408 			}
9409 		} else {
9410 			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9411 			    traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9412 				// No match, does not match required traffic class
9413 				return FALSE;
9414 			}
9415 		}
9416 	}
9417 
9418 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9419 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9420 		    "NECP_KERNEL_CONDITION_PROTOCOL",
9421 		    kernel_policy->cond_protocol, protocol);
9422 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9423 			if (protocol == kernel_policy->cond_protocol) {
9424 				// No match, matches forbidden protocol
9425 				return FALSE;
9426 			}
9427 		} else {
9428 			if (protocol != kernel_policy->cond_protocol) {
9429 				// No match, does not match required protocol
9430 				return FALSE;
9431 			}
9432 		}
9433 	}
9434 
9435 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9436 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9437 		    kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9438 		    "n/a", "n/a", "n/a");
9439 		bool matches_agent_type = FALSE;
9440 		for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9441 			struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9442 			if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9443 			    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) &&
9444 			    (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9445 			    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)) {
9446 				// Found a required agent that matches
9447 				matches_agent_type = TRUE;
9448 				break;
9449 			}
9450 		}
9451 		if (!matches_agent_type) {
9452 			return FALSE;
9453 		}
9454 	}
9455 
9456 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9457 		bool is_local = FALSE;
9458 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9459 
9460 		if (rt != NULL) {
9461 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9462 		} else {
9463 			is_local = necp_is_route_local(remote, include_local_addresses);
9464 		}
9465 		if (info != NULL) {
9466 			info->is_local = is_local;
9467 		}
9468 
9469 		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);
9470 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9471 			if (is_local) {
9472 				// Match local-networks, fail
9473 				return FALSE;
9474 			}
9475 		} else {
9476 			if (!is_local) {
9477 				// Either no route to validate or no match for local networks
9478 				return FALSE;
9479 			}
9480 		}
9481 	}
9482 
9483 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9484 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9485 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9486 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9487 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9488 				if (inRange) {
9489 					return FALSE;
9490 				}
9491 			} else {
9492 				if (!inRange) {
9493 					return FALSE;
9494 				}
9495 			}
9496 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9497 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9498 			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);
9499 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9500 				if (inSubnet) {
9501 					return FALSE;
9502 				}
9503 			} else {
9504 				if (!inSubnet) {
9505 					return FALSE;
9506 				}
9507 			}
9508 		}
9509 	}
9510 
9511 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9512 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9513 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9514 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9515 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9516 				if (inRange) {
9517 					return FALSE;
9518 				}
9519 			} else {
9520 				if (!inRange) {
9521 					return FALSE;
9522 				}
9523 			}
9524 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9525 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9526 			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);
9527 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9528 				if (inSubnet) {
9529 					return FALSE;
9530 				}
9531 			} else {
9532 				if (!inSubnet) {
9533 					return FALSE;
9534 				}
9535 			}
9536 		}
9537 	}
9538 
9539 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9540 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9541 		    "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9542 		    kernel_policy->cond_client_flags, client_flags);
9543 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9544 			if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9545 				// Flags do match, and condition is negative, fail.
9546 				return FALSE;
9547 			}
9548 		} else {
9549 			if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9550 				// Flags do not match, fail.
9551 				return FALSE;
9552 			}
9553 		}
9554 	}
9555 
9556 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9557 		bool isEmpty = necp_addr_is_empty(SA(local));
9558 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9559 		    "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9560 		    0, isEmpty);
9561 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9562 			if (isEmpty) {
9563 				return FALSE;
9564 			}
9565 		} else {
9566 			if (!isEmpty) {
9567 				return FALSE;
9568 			}
9569 		}
9570 	}
9571 
9572 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9573 		bool isEmpty = necp_addr_is_empty(SA(remote));
9574 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9575 		    "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9576 		    0, isEmpty);
9577 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9578 			if (isEmpty) {
9579 				return FALSE;
9580 			}
9581 		} else {
9582 			if (!isEmpty) {
9583 				return FALSE;
9584 			}
9585 		}
9586 	}
9587 
9588 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9589 		u_int16_t remote_port = 0;
9590 		if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9591 			remote_port = SIN(remote)->sin_port;
9592 		}
9593 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9594 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
9595 		    scheme_port, remote_port);
9596 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9597 			if (kernel_policy->cond_scheme_port == scheme_port ||
9598 			    kernel_policy->cond_scheme_port == remote_port) {
9599 				return FALSE;
9600 			}
9601 		} else {
9602 			if (kernel_policy->cond_scheme_port != scheme_port &&
9603 			    kernel_policy->cond_scheme_port != remote_port) {
9604 				return FALSE;
9605 			}
9606 		}
9607 	}
9608 
9609 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9610 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9611 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9612 		    kernel_policy->cond_packet_filter_tags,
9613 		    pf_tag);
9614 		bool tags_matched = false;
9615 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9616 			if (pf_tag == PF_TAG_ID_STACK_DROP) {
9617 				tags_matched = true;
9618 			}
9619 		}
9620 
9621 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9622 			if (tags_matched) {
9623 				return FALSE;
9624 			}
9625 		} else {
9626 			if (!tags_matched) {
9627 				return FALSE;
9628 			}
9629 		}
9630 	}
9631 
9632 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9633 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9634 		    "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9635 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9636 			if (is_loopback) {
9637 				return FALSE;
9638 			}
9639 		} else {
9640 			if (!is_loopback) {
9641 				return FALSE;
9642 			}
9643 		}
9644 	}
9645 
9646 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9647 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9648 		    "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9649 		if (is_delegated) {
9650 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9651 				if (real_is_platform_binary) {
9652 					return FALSE;
9653 				}
9654 			} else {
9655 				if (!real_is_platform_binary) {
9656 					return FALSE;
9657 				}
9658 			}
9659 		} else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9660 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9661 			// If the connection is not delegated, and the policy did not specify a particular effective process UUID
9662 			// or PID, check the process directly
9663 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9664 				if (is_platform_binary) {
9665 					return FALSE;
9666 				}
9667 			} else {
9668 				if (!is_platform_binary) {
9669 					return FALSE;
9670 				}
9671 			}
9672 		}
9673 	}
9674 
9675 	return TRUE;
9676 }
9677 
9678 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9679 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9680 {
9681 	return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9682 }
9683 
9684 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)9685 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)
9686 {
9687 	struct socket *so = NULL;
9688 	proc_t sock_proc = NULL;
9689 	proc_t curr_proc = current_proc();
9690 
9691 	memset(info, 0, sizeof(struct necp_socket_info));
9692 
9693 	so = inp->inp_socket;
9694 
9695 	info->drop_order = drop_order;
9696 	info->is_loopback = is_loopback;
9697 	info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9698 
9699 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9700 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9701 		info->uid = kauth_cred_getuid(so->so_cred);
9702 		info->real_uid = info->uid;
9703 	}
9704 
9705 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9706 		info->traffic_class = so->so_traffic_class;
9707 	}
9708 
9709 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9710 		info->has_client = !uuid_is_null(inp->necp_client_uuid);
9711 	}
9712 
9713 	if (inp->inp_ip_p) {
9714 		info->protocol = inp->inp_ip_p;
9715 	} else {
9716 		info->protocol = SOCK_PROTO(so);
9717 	}
9718 
9719 	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9720 		u_int32_t responsible_application_id = 0;
9721 
9722 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9723 		if (existing_mapping) {
9724 			info->application_id = existing_mapping->id;
9725 		}
9726 
9727 #if defined(XNU_TARGET_OS_OSX)
9728 		if (so->so_rpid > 0) {
9729 			existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9730 			if (existing_mapping != NULL) {
9731 				responsible_application_id = existing_mapping->id;
9732 			}
9733 		}
9734 #endif
9735 
9736 		if (responsible_application_id > 0) {
9737 			info->real_application_id = info->application_id;
9738 			info->application_id = responsible_application_id;
9739 			info->used_responsible_pid = true;
9740 		} else if (!(so->so_flags & SOF_DELEGATED)) {
9741 			info->real_application_id = info->application_id;
9742 		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9743 			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9744 			if (real_existing_mapping) {
9745 				info->real_application_id = real_existing_mapping->id;
9746 			}
9747 		}
9748 	}
9749 
9750 	pid_t socket_pid =
9751 #if defined(XNU_TARGET_OS_OSX)
9752 	    info->used_responsible_pid ? so->so_rpid :
9753 #endif
9754 	    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9755 	if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9756 		sock_proc = proc_find(socket_pid);
9757 		if (socket_proc) {
9758 			*socket_proc = sock_proc;
9759 		}
9760 	}
9761 
9762 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9763 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9764 		info->is_entitled = necp_task_has_match_entitlement(task);
9765 		if (!info->is_entitled) {
9766 			// Task does not have entitlement, check the parent task
9767 			necp_get_parent_is_entitled(task, info);
9768 		}
9769 	}
9770 
9771 	info->pid = socket_pid;
9772 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9773 		info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9774 	}
9775 
9776 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9777 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9778 		if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9779 			info->is_platform_binary = true;
9780 		} else if (so->so_rpid != 0) {
9781 			proc_t responsible_proc = proc_find(so->so_rpid);
9782 			if (responsible_proc != NULL) {
9783 				if (necp_is_platform_binary(responsible_proc)) {
9784 					info->is_platform_binary = true;
9785 					info->used_responsible_pid = true;
9786 				}
9787 				proc_rele(responsible_proc);
9788 			}
9789 		}
9790 	}
9791 
9792 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9793 		proc_t real_proc = curr_proc;
9794 		bool release_real_proc = false;
9795 		if (so->last_pid != proc_pid(real_proc)) {
9796 			if (so->last_pid == socket_pid && sock_proc != NULL) {
9797 				real_proc = sock_proc;
9798 			} else {
9799 				proc_t last_proc = proc_find(so->last_pid);
9800 				if (last_proc != NULL) {
9801 					real_proc = last_proc;
9802 					release_real_proc = true;
9803 				}
9804 			}
9805 		}
9806 		if (real_proc != NULL) {
9807 			if (real_proc == kernproc) {
9808 				info->real_is_platform_binary = true;
9809 			} else {
9810 				info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9811 			}
9812 			if (release_real_proc) {
9813 				proc_rele(real_proc);
9814 			}
9815 		}
9816 	}
9817 
9818 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9819 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9820 		if (existing_mapping) {
9821 			info->account_id = existing_mapping->id;
9822 		}
9823 	}
9824 
9825 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9826 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9827 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9828 		info->domain = inp->inp_necp_attributes.inp_domain;
9829 	}
9830 
9831 	if (override_bound_interface) {
9832 		info->bound_interface_index = override_bound_interface;
9833 	} else {
9834 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9835 			info->bound_interface_index = inp->inp_boundifp->if_index;
9836 		}
9837 	}
9838 
9839 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9840 	    info->bound_interface_index != IFSCOPE_NONE) {
9841 		ifnet_head_lock_shared();
9842 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9843 		if (interface != NULL) {
9844 			info->bound_interface_flags = interface->if_flags;
9845 			info->bound_interface_eflags = interface->if_eflags;
9846 			info->bound_interface_xflags = interface->if_xflags;
9847 		}
9848 		ifnet_head_done();
9849 	}
9850 
9851 	bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9852 	    uuid_is_null(inp->necp_client_uuid) &&
9853 	    necp_socket_has_resolver_signature(inp));
9854 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
9855 	    necp_restrict_multicast ||
9856 	    needs_address_for_signature ||
9857 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS) ||
9858 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS)) {
9859 		if (override_local_addr != NULL) {
9860 			if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9861 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9862 				if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9863 					struct sockaddr_in sin;
9864 					in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9865 					memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9866 					memcpy(&info->local_addr, &sin, sin.sin_len);
9867 				}
9868 			} else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9869 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9870 			}
9871 		} else {
9872 			if (inp->inp_vflag & INP_IPV6) {
9873 				SIN6(&info->local_addr)->sin6_family = AF_INET6;
9874 				SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9875 				SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9876 				memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9877 			} else if (inp->inp_vflag & INP_IPV4) {
9878 				SIN(&info->local_addr)->sin_family = AF_INET;
9879 				SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9880 				SIN(&info->local_addr)->sin_port = inp->inp_lport;
9881 				memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9882 			}
9883 		}
9884 
9885 		if (override_remote_addr != NULL) {
9886 			if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9887 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9888 				if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9889 					struct sockaddr_in sin;
9890 					in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9891 					memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9892 					memcpy(&info->remote_addr, &sin, sin.sin_len);
9893 				}
9894 			} else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9895 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9896 			}
9897 		} else {
9898 			if (inp->inp_vflag & INP_IPV6) {
9899 				SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9900 				SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9901 				SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9902 				memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9903 			} else if (inp->inp_vflag & INP_IPV4) {
9904 				SIN(&info->remote_addr)->sin_family = AF_INET;
9905 				SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9906 				SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9907 				memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9908 			}
9909 		}
9910 		// Clear the embedded scope id from v6 addresses
9911 		if (info->local_addr.sa.sa_family == AF_INET6) {
9912 			struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9913 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9914 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9915 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9916 					sin6->sin6_addr.s6_addr16[1] = 0;
9917 				}
9918 			}
9919 		}
9920 		if (info->remote_addr.sa.sa_family == AF_INET6) {
9921 			struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9922 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9923 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9924 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9925 					sin6->sin6_addr.s6_addr16[1] = 0;
9926 				}
9927 			}
9928 		}
9929 	}
9930 
9931 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9932 		// For checking sockets, only validate that there is an NECP client present. It will have
9933 		// already checked for the signature.
9934 		if (!uuid_is_null(inp->necp_client_uuid)) {
9935 			info->has_system_signed_result = true;
9936 		} else {
9937 			info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9938 		}
9939 	}
9940 
9941 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9942 		info->client_flags = 0;
9943 		if (INP_NO_CONSTRAINED(inp)) {
9944 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9945 		}
9946 		if (INP_NO_EXPENSIVE(inp)) {
9947 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9948 		}
9949 		if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9950 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9951 		}
9952 		if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9953 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9954 		}
9955 		if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9956 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9957 		}
9958 		if (NEED_DGRAM_FLOW_TRACKING(so)) {
9959 			if (!necp_socket_is_connected(inp)) {
9960 				// If the socket has a flow entry for this 4-tuple then check if the flow is outgoing
9961 				// and set the inbound flag accordingly. Otherwise use the direction to set the inbound flag.
9962 				struct soflow_hash_entry *flow = soflow_get_flow(so, &info->local_addr.sa, &info->remote_addr.sa, NULL, 0, override_direction, input_ifindex);
9963 				if (flow != NULL) {
9964 					if (!flow->soflow_outgoing) {
9965 						info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9966 					}
9967 					soflow_free_flow(flow);
9968 				} else if (override_direction == SOFLOW_DIRECTION_INBOUND) {
9969 					info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9970 				}
9971 			}
9972 		} else {
9973 			// If the socket is explicitly marked as inbound then set the inbound flag.
9974 			if (inp->inp_socket->so_flags1 & SOF1_INBOUND) {
9975 				info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9976 			}
9977 		}
9978 		if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9979 		    inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9980 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9981 		}
9982 		if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
9983 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
9984 		}
9985 		if (inp->inp_socket->so_options & SO_REUSEPORT) {
9986 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
9987 		}
9988 	}
9989 }
9990 
9991 #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)
9992 
9993 static inline struct necp_kernel_socket_policy *
necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,struct necp_socket_info * info,necp_kernel_policy_filter * return_filter,u_int32_t * __counted_by (route_rule_id_array_count)return_route_rule_id_array,size_t * return_route_rule_id_array_count,size_t route_rule_id_array_count,necp_kernel_policy_result * return_service_action,necp_kernel_policy_service * return_service,u_int32_t * __counted_by (netagent_array_count)return_netagent_array,size_t netagent_array_count,u_int32_t * __counted_by (netagent_use_flags_array_count)return_netagent_use_flags_array,size_t netagent_use_flags_array_count,struct necp_client_parameter_netagent_type * __counted_by (num_required_agent_types)required_agent_types,u_int32_t num_required_agent_types,proc_t proc,u_int16_t pf_tag,necp_kernel_policy_id * skip_policy_id,struct rtentry * rt,necp_kernel_policy_result * return_drop_dest_policy_result,necp_drop_all_bypass_check_result_t * return_drop_all_bypass,u_int32_t * return_flow_divert_aggregate_unit,struct socket * so,int debug)9994 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
9995     struct necp_socket_info *info,
9996     necp_kernel_policy_filter *return_filter,
9997     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
9998     size_t *return_route_rule_id_array_count,
9999     size_t route_rule_id_array_count,
10000     necp_kernel_policy_result *return_service_action,
10001     necp_kernel_policy_service *return_service,
10002     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
10003     size_t netagent_array_count,
10004     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
10005     size_t netagent_use_flags_array_count,
10006     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
10007     u_int32_t num_required_agent_types,
10008     proc_t proc,
10009     u_int16_t pf_tag,
10010     necp_kernel_policy_id *skip_policy_id,
10011     struct rtentry *rt,
10012     necp_kernel_policy_result *return_drop_dest_policy_result,
10013     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
10014     u_int32_t *return_flow_divert_aggregate_unit,
10015     struct socket *so,
10016     int debug)
10017 {
10018 	struct necp_kernel_socket_policy *matched_policy = NULL;
10019 	u_int32_t skip_order = 0;
10020 	u_int32_t skip_session_order = 0;
10021 	bool skipped_ip_result = false;
10022 	size_t route_rule_id_count = 0;
10023 	int i;
10024 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10025 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
10026 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10027 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
10028 	size_t netagent_cursor = 0;
10029 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10030 	size_t netagent_array_count_adjusted = netagent_array_count;
10031 	if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
10032 		netagent_array_count_adjusted = netagent_use_flags_array_count;
10033 	}
10034 
10035 	if (return_drop_all_bypass != NULL) {
10036 		*return_drop_all_bypass = drop_all_bypass;
10037 	}
10038 
10039 	if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
10040 		netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
10041 	}
10042 
10043 	// Pre-process domain for quick matching
10044 	struct substring domain_substring = {};
10045 	u_int8_t domain_dot_count = 0;
10046 	if (info->domain != NULL) {
10047 		domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
10048 		domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
10049 	}
10050 
10051 	if (return_filter != NULL) {
10052 		*return_filter = 0;
10053 	}
10054 
10055 	if (return_route_rule_id_array_count != NULL) {
10056 		*return_route_rule_id_array_count = 0;
10057 	}
10058 
10059 	if (return_service_action != NULL) {
10060 		*return_service_action = 0;
10061 	}
10062 
10063 	if (return_service != NULL) {
10064 		return_service->identifier = 0;
10065 		return_service->data = 0;
10066 	}
10067 
10068 	// Do not subject layer-2 filter to NECP policies, return a PASS policy
10069 	if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
10070 		return &pass_policy;
10071 	}
10072 
10073 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10074 
10075 	if (policy_search_array != NULL) {
10076 		for (i = 0; policy_search_array[i] != NULL; i++) {
10077 			NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
10078 
10079 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10080 				// We've hit a drop all rule
10081 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10082 					drop_all_bypass = necp_check_drop_all_bypass_result(proc);
10083 					if (return_drop_all_bypass != NULL) {
10084 						*return_drop_all_bypass = drop_all_bypass;
10085 					}
10086 				}
10087 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10088 					NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
10089 					break;
10090 				}
10091 			}
10092 			if (necp_drop_dest_policy.entry_count != 0 &&
10093 			    necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
10094 				// We've hit a drop by destination address rule
10095 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10096 				break;
10097 			}
10098 			if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
10099 				// We've hit a drop order for this socket
10100 				break;
10101 			}
10102 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10103 				// Done skipping
10104 				skip_order = 0;
10105 				skip_session_order = 0;
10106 				// If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
10107 				if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
10108 					*skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10109 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
10110 				}
10111 			}
10112 			if (skip_order) {
10113 				if (policy_search_array[i]->order < skip_order) {
10114 					// Skip this policy
10115 					// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10116 					// didn't, clear out the return value for skip ID when we are done with each session.'
10117 					if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10118 						skipped_ip_result = true;
10119 						NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10120 					}
10121 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
10122 					continue;
10123 				} else {
10124 					// Done skipping
10125 					skip_order = 0;
10126 					skip_session_order = 0;
10127 				}
10128 			} else if (skip_session_order) {
10129 				// Skip this policy
10130 				// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
10131 				// didn't, clear out the return value for skip ID when we are done with each session.'
10132 				if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
10133 					skipped_ip_result = true;
10134 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
10135 				}
10136 				NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
10137 				continue;
10138 			}
10139 
10140 			if (necp_socket_check_policy(policy_search_array[i],
10141 			    info->application_id,
10142 			    info->real_application_id,
10143 			    info->is_entitled,
10144 			    info->account_id,
10145 			    domain_substring,
10146 			    domain_dot_count,
10147 			    info->url,
10148 			    info->pid,
10149 			    info->pid_version,
10150 			    info->uid,
10151 			    info->real_uid,
10152 			    info->bound_interface_index,
10153 			    info->traffic_class,
10154 			    info->protocol,
10155 			    &info->local_addr,
10156 			    &info->remote_addr,
10157 			    required_agent_types,
10158 			    num_required_agent_types,
10159 			    info->has_client,
10160 			    info->client_flags,
10161 			    info->is_platform_binary,
10162 			    info->has_system_signed_result,
10163 			    proc,
10164 			    pf_tag,
10165 			    info->scheme_port,
10166 			    rt,
10167 			    info->is_loopback,
10168 			    debug,
10169 			    info->real_is_platform_binary,
10170 			    info->bound_interface_flags,
10171 			    info->bound_interface_eflags,
10172 			    info->bound_interface_xflags,
10173 			    info,
10174 			    info->is_delegated,
10175 			    so)) {
10176 				if (!debug && necp_data_tracing_session_order) {
10177 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10178 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10179 						NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
10180 					}
10181 				}
10182 
10183 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
10184 					if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
10185 						necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
10186 						if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
10187 							*return_filter = control_unit;
10188 						} else {
10189 							// Preserve pre-existing connections only if all filters preserve.
10190 							bool preserve_bit_off = false;
10191 							if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
10192 							    (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
10193 								preserve_bit_off = true;
10194 							}
10195 							*return_filter |= control_unit;
10196 							if (preserve_bit_off == true) {
10197 								*return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
10198 							}
10199 						}
10200 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10201 							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, policy_search_array[i]->result_parameter.filter_control_unit);
10202 						}
10203 					}
10204 					continue;
10205 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10206 					if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
10207 						return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10208 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10209 							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);
10210 						}
10211 					}
10212 					continue;
10213 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
10214 				    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10215 					if (netagent_cursor < netagent_array_count_adjusted) {
10216 						bool agent_already_present = false;
10217 						for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10218 							if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10219 								// Already present. Mark the "SCOPED" flag if flags are necessary.
10220 								agent_already_present = true;
10221 								if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
10222 								    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10223 									netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
10224 								}
10225 							}
10226 						}
10227 
10228 						if (!agent_already_present) {
10229 							netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10230 							if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
10231 								netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
10232 							}
10233 							netagent_cursor++;
10234 						}
10235 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10236 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
10237 							    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10238 							    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
10239 							    policy_search_array[i]->result_parameter.netagent_id);
10240 						}
10241 					}
10242 					continue;
10243 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
10244 					bool agent_already_present = false;
10245 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
10246 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
10247 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
10248 							agent_already_present = true;
10249 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
10250 						}
10251 					}
10252 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
10253 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
10254 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
10255 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
10256 						netagent_cursor++;
10257 					}
10258 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10259 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
10260 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
10261 						    policy_search_array[i]->result_parameter.netagent_id);
10262 					}
10263 					continue;
10264 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
10265 					u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
10266 					if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
10267 						/* For transparent proxies, accumulate the control unit and continue to the next policy */
10268 						if (return_flow_divert_aggregate_unit != NULL) {
10269 							*return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
10270 							if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10271 								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);
10272 							}
10273 						}
10274 						continue;
10275 					}
10276 				}
10277 
10278 				// Matched policy is a skip. Do skip and continue.
10279 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10280 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
10281 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10282 					skip_session_order = policy_search_array[i]->session_order + 1;
10283 					if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
10284 						*skip_policy_id = policy_search_array[i]->id;
10285 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10286 							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);
10287 						}
10288 					}
10289 					continue;
10290 				}
10291 
10292 				// Matched an allow unentitled, which clears any drop order
10293 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
10294 					info->drop_order = 0;
10295 					continue;
10296 				}
10297 
10298 				// Passed all tests, found a match
10299 				matched_policy = policy_search_array[i];
10300 				NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
10301 				break;
10302 			}
10303 		}
10304 	}
10305 
10306 	if (return_netagent_array != NULL) {
10307 		if (return_netagent_use_flags_array != NULL) {
10308 			memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
10309 			memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
10310 		} else {
10311 			for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
10312 				if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
10313 					return_netagent_array[netagent_i] = netagent_ids[netagent_i];
10314 				} else {
10315 					return_netagent_array[netagent_i] = 0;
10316 				}
10317 			}
10318 		}
10319 	}
10320 
10321 	if (return_route_rule_id_array_count != NULL) {
10322 		*return_route_rule_id_array_count = route_rule_id_count;
10323 	}
10324 	return matched_policy;
10325 }
10326 
10327 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)10328 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
10329 {
10330 	bool found_match = FALSE;
10331 	ifaddr_t ifa;
10332 	union necp_sockaddr_union address_storage;
10333 	int family = AF_INET;
10334 
10335 	ifnet_head_lock_shared();
10336 	ifnet_t interface = ifindex2ifnet[interface_index];
10337 	ifnet_head_done();
10338 
10339 	if (inp == NULL || interface == NULL) {
10340 		return FALSE;
10341 	}
10342 
10343 	if (inp->inp_vflag & INP_IPV4) {
10344 		family = AF_INET;
10345 	} else if (inp->inp_vflag & INP_IPV6) {
10346 		family = AF_INET6;
10347 	} else {
10348 		return FALSE;
10349 	}
10350 
10351 	// Match socket address against interface addresses
10352 	ifnet_lock_shared(interface);
10353 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
10354 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
10355 			if (address_storage.sa.sa_family != family) {
10356 				continue;
10357 			}
10358 
10359 			if (family == AF_INET) {
10360 				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
10361 					found_match = TRUE;
10362 					break;
10363 				}
10364 			} else if (family == AF_INET6) {
10365 				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
10366 					found_match = TRUE;
10367 					break;
10368 				}
10369 			}
10370 		}
10371 	}
10372 	ifnet_lock_done(interface);
10373 
10374 	return found_match;
10375 }
10376 
10377 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10378 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10379 {
10380 	if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10381 		proc_t curr_proc = current_proc();
10382 		proc_t sock_proc = NULL;
10383 		struct socket *so = inp ? inp->inp_socket : NULL;
10384 		pid_t socket_pid = (so == NULL) ? 0 :
10385 #if defined(XNU_TARGET_OS_OSX)
10386 		    so->so_rpid ? so->so_rpid :
10387 #endif
10388 		    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10389 		if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10390 			sock_proc = proc_find(socket_pid);
10391 		}
10392 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10393 		if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10394 			if (sock_proc) {
10395 				proc_rele(sock_proc);
10396 			}
10397 			return NECP_BYPASS_TYPE_DROP;
10398 		}
10399 		if (sock_proc) {
10400 			proc_rele(sock_proc);
10401 		}
10402 
10403 		if (necp_pass_loopback > 0) {
10404 			return NECP_BYPASS_TYPE_LOOPBACK;
10405 		}
10406 	} else if (necp_is_intcoproc(inp, NULL)) {
10407 		return NECP_BYPASS_TYPE_INTCOPROC;
10408 	}
10409 
10410 	return NECP_BYPASS_TYPE_NONE;
10411 }
10412 
10413 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10414 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10415 {
10416 	u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10417 	ifnet_t tunnel_interface = NULL;
10418 
10419 	ifnet_head_lock_shared();
10420 	tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10421 	ifnet_head_done();
10422 
10423 	if (tunnel_interface != NULL) {
10424 		tcp_set_tso(intotcpcb(inp), tunnel_interface);
10425 	}
10426 }
10427 
10428 static inline void
necp_unscope(struct inpcb * inp)10429 necp_unscope(struct inpcb *inp)
10430 {
10431 	// If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10432 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10433 		inp->inp_flags &= ~INP_BOUND_IF;
10434 		inp->inp_boundifp = NULL;
10435 	}
10436 }
10437 
10438 static inline void
necp_clear_tunnel(struct inpcb * inp)10439 necp_clear_tunnel(struct inpcb *inp)
10440 {
10441 	if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10442 		inp->inp_flags &= ~INP_BOUND_IF;
10443 		inp->inp_boundifp = NULL;
10444 	}
10445 }
10446 
10447 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10448 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10449 {
10450 	// Verify netagents
10451 	for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10452 		struct necp_uuid_id_mapping *mapping = NULL;
10453 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
10454 		if (netagent_id == 0) {
10455 			continue;
10456 		}
10457 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10458 		if (mapping != NULL) {
10459 			u_int32_t agent_flags = 0;
10460 			agent_flags = netagent_get_flags(mapping->uuid);
10461 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10462 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10463 					continue;
10464 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10465 					if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10466 						int trigger_error = 0;
10467 						trigger_error = netagent_kernel_trigger(mapping->uuid);
10468 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10469 							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);
10470 						}
10471 					}
10472 					return false;
10473 				}
10474 			}
10475 		}
10476 	}
10477 	return true;
10478 }
10479 
10480 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)10481 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10482 {
10483 	struct socket *so = NULL;
10484 	necp_kernel_policy_filter filter_control_unit = 0;
10485 	struct necp_kernel_socket_policy *matched_policy = NULL;
10486 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10487 	necp_kernel_policy_result service_action = 0;
10488 	necp_kernel_policy_service service = { 0, 0 };
10489 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10490 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10491 	proc_t __single socket_proc = NULL;
10492 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10493 
10494 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10495 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10496 
10497 	struct necp_socket_info info = {};
10498 
10499 	u_int32_t flow_divert_aggregate_unit = 0;
10500 
10501 	if (inp == NULL) {
10502 		return NECP_KERNEL_POLICY_ID_NONE;
10503 	}
10504 
10505 	// Ignore invalid addresses
10506 	if (override_local_addr != NULL &&
10507 	    !necp_address_is_valid(override_local_addr)) {
10508 		override_local_addr = NULL;
10509 	}
10510 	if (override_remote_addr != NULL &&
10511 	    !necp_address_is_valid(override_remote_addr)) {
10512 		override_remote_addr = NULL;
10513 	}
10514 
10515 	so = inp->inp_socket;
10516 
10517 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10518 
10519 	// Don't lock. Possible race condition, but we don't want the performance hit.
10520 	if (necp_drop_management_order == 0 &&
10521 	    (necp_kernel_socket_policies_count == 0 ||
10522 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10523 		if (necp_drop_all_order > 0 || drop_order > 0) {
10524 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10525 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10526 			inp->inp_policyresult.policy_gencount = 0;
10527 			inp->inp_policyresult.app_id = 0;
10528 			inp->inp_policyresult.flowhash = 0;
10529 			inp->inp_policyresult.results.filter_control_unit = 0;
10530 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10531 			inp->inp_policyresult.results.route_rule_id = 0;
10532 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10533 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10534 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10535 			} else {
10536 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10537 			}
10538 		}
10539 		return NECP_KERNEL_POLICY_ID_NONE;
10540 	}
10541 
10542 	// Check for loopback exception
10543 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10544 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10545 		// Mark socket as a drop
10546 		necp_unscope(inp);
10547 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10548 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10549 		inp->inp_policyresult.policy_gencount = 0;
10550 		inp->inp_policyresult.app_id = 0;
10551 		inp->inp_policyresult.flowhash = 0;
10552 		inp->inp_policyresult.results.filter_control_unit = 0;
10553 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10554 		inp->inp_policyresult.results.route_rule_id = 0;
10555 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10556 		return NECP_KERNEL_POLICY_ID_NONE;
10557 	}
10558 
10559 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10560 		// Mark socket as a pass
10561 		necp_unscope(inp);
10562 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10563 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10564 		inp->inp_policyresult.policy_gencount = 0;
10565 		inp->inp_policyresult.app_id = 0;
10566 		inp->inp_policyresult.flowhash = 0;
10567 		inp->inp_policyresult.results.filter_control_unit = 0;
10568 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10569 		inp->inp_policyresult.results.route_rule_id = 0;
10570 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10571 		return NECP_KERNEL_POLICY_ID_NONE;
10572 	}
10573 
10574 	// Lock
10575 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10576 	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);
10577 
10578 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10579 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10580 
10581 	// Check info
10582 	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10583 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10584 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10585 	    inp->inp_policyresult.flowhash == flowhash) {
10586 		// If already matched this socket on this generation of table, skip
10587 
10588 		// Unlock
10589 		lck_rw_done(&necp_kernel_policy_lock);
10590 
10591 		if (socket_proc) {
10592 			proc_rele(socket_proc);
10593 		}
10594 
10595 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10596 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10597 			    inp->inp_socket, info.bound_interface_index, info.protocol,
10598 			    inp->inp_policyresult.policy_id,
10599 			    inp->inp_policyresult.results.result,
10600 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10601 		}
10602 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10603 		return inp->inp_policyresult.policy_id;
10604 	}
10605 
10606 	inp->inp_policyresult.app_id = info.application_id;
10607 
10608 	// Match socket to policy
10609 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10610 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10611 	size_t route_rule_id_array_count = 0;
10612 
10613 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10614 	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)],
10615 	    &info,
10616 	    &filter_control_unit,
10617 	    route_rule_id_array,
10618 	    &route_rule_id_array_count,
10619 	    MAX_AGGREGATE_ROUTE_RULES,
10620 	    &service_action,
10621 	    &service,
10622 	    netagent_ids,
10623 	    NECP_MAX_NETAGENTS,
10624 	    NULL,
10625 	    0,
10626 	    NULL,
10627 	    0,
10628 	    effective_proc,
10629 	    0,
10630 	    &skip_policy_id,
10631 	    inp->inp_route.ro_rt,
10632 	    &drop_dest_policy_result,
10633 	    &drop_all_bypass,
10634 	    &flow_divert_aggregate_unit,
10635 	    so,
10636 	    debug);
10637 
10638 	// Check for loopback exception again after the policy match
10639 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10640 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10641 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10642 		// Mark socket as a pass
10643 		necp_unscope(inp);
10644 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10645 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10646 		inp->inp_policyresult.policy_gencount = 0;
10647 		inp->inp_policyresult.app_id = 0;
10648 		inp->inp_policyresult.flowhash = 0;
10649 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10650 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10651 		inp->inp_policyresult.results.route_rule_id = 0;
10652 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10653 
10654 		// Unlock
10655 		lck_rw_done(&necp_kernel_policy_lock);
10656 
10657 		if (socket_proc) {
10658 			proc_rele(socket_proc);
10659 		}
10660 
10661 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10662 		return NECP_KERNEL_POLICY_ID_NONE;
10663 	}
10664 
10665 	// Verify netagents
10666 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10667 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10668 			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);
10669 		}
10670 
10671 		// Mark socket as a drop if required agent is not active
10672 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10673 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10674 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10675 		inp->inp_policyresult.flowhash = flowhash;
10676 		inp->inp_policyresult.results.filter_control_unit = 0;
10677 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10678 		inp->inp_policyresult.results.route_rule_id = 0;
10679 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10680 
10681 		// Unlock
10682 		lck_rw_done(&necp_kernel_policy_lock);
10683 
10684 		if (socket_proc) {
10685 			proc_rele(socket_proc);
10686 		}
10687 
10688 		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);
10689 		return NECP_KERNEL_POLICY_ID_NONE;
10690 	}
10691 
10692 	u_int32_t route_rule_id = 0;
10693 	if (route_rule_id_array_count == 1) {
10694 		route_rule_id = route_rule_id_array[0];
10695 	} else if (route_rule_id_array_count > 1) {
10696 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10697 	}
10698 
10699 	bool reset_tcp_tunnel_interface = false;
10700 	bool send_local_network_denied_event = false;
10701 	if (matched_policy) {
10702 		// For PASS policy result, clear previous rescope / tunnel inteface
10703 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10704 		    (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10705 			necp_unscope(inp);
10706 			necp_clear_tunnel(inp);
10707 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10708 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10709 			}
10710 		}
10711 		matched_policy_id = matched_policy->id;
10712 		inp->inp_policyresult.policy_id = matched_policy->id;
10713 		inp->inp_policyresult.skip_policy_id = skip_policy_id;
10714 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10715 		inp->inp_policyresult.flowhash = flowhash;
10716 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10717 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10718 		inp->inp_policyresult.results.route_rule_id = route_rule_id;
10719 		inp->inp_policyresult.results.result = matched_policy->result;
10720 		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10721 
10722 		if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10723 			inp->inp_policyresult.app_id = info.real_application_id;
10724 		}
10725 
10726 		if (necp_socket_is_connected(inp) &&
10727 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10728 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10729 			NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10730 			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10731 		} else if (necp_socket_is_connected(inp) &&
10732 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10733 		    info.protocol == IPPROTO_TCP) {
10734 			// Reset TCP socket interface based parameters if tunnel policy changes
10735 			reset_tcp_tunnel_interface = true;
10736 		}
10737 
10738 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10739 			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);
10740 		}
10741 
10742 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10743 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10744 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10745 			// Trigger the event that we dropped due to a local network policy
10746 			send_local_network_denied_event = true;
10747 		}
10748 	} else {
10749 		bool drop_all = false;
10750 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10751 			// Mark socket as a drop if set
10752 			drop_all = true;
10753 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10754 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10755 			}
10756 		}
10757 
10758 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10759 		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);
10760 		if (flow_divert_control_unit != 0) {
10761 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10762 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10763 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10764 			inp->inp_policyresult.flowhash = flowhash;
10765 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10766 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10767 			inp->inp_policyresult.results.route_rule_id = route_rule_id;
10768 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10769 			inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10770 			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);
10771 		} else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10772 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10773 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10774 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10775 			inp->inp_policyresult.flowhash = flowhash;
10776 			inp->inp_policyresult.results.filter_control_unit = 0;
10777 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10778 			inp->inp_policyresult.results.route_rule_id = 0;
10779 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10780 			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);
10781 		} else {
10782 			// Mark non-matching socket so we don't re-check it
10783 			necp_unscope(inp);
10784 			if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10785 				necp_clear_tunnel(inp);
10786 			}
10787 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10788 				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);
10789 			}
10790 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10791 			inp->inp_policyresult.skip_policy_id = skip_policy_id;
10792 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10793 			inp->inp_policyresult.flowhash = flowhash;
10794 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10795 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10796 			inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10797 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10798 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10799 		}
10800 	}
10801 
10802 	if (necp_check_missing_client_drop(effective_proc, &info) ||
10803 	    necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10804 		// Mark as drop
10805 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10806 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10807 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10808 		inp->inp_policyresult.flowhash = flowhash;
10809 		inp->inp_policyresult.results.filter_control_unit = 0;
10810 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10811 		inp->inp_policyresult.results.route_rule_id = 0;
10812 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10813 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10814 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10815 		}
10816 	}
10817 
10818 	// Unlock
10819 	lck_rw_done(&necp_kernel_policy_lock);
10820 
10821 	if (reset_tcp_tunnel_interface) {
10822 		// Update MSS when not holding the policy lock to avoid recursive locking
10823 		tcp_mtudisc(inp, 0);
10824 
10825 		// Update TSO flag based on the tunnel interface
10826 		necp_socket_ip_tunnel_tso(inp);
10827 	}
10828 
10829 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10830 		inp->inp_policyresult.network_denied_notifies++;
10831 #if defined(XNU_TARGET_OS_OSX)
10832 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10833 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10834 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10835 		    NETPOLICY_NETWORKTYPE_LOCAL);
10836 #else
10837 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10838 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10839 		    NETPOLICY_NETWORKTYPE_LOCAL);
10840 #endif
10841 	}
10842 
10843 	if (socket_proc) {
10844 		proc_rele(socket_proc);
10845 	}
10846 
10847 	return matched_policy_id;
10848 }
10849 
10850 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)10851 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)
10852 {
10853 	u_int32_t bound_interface_flags = 0;
10854 	u_int32_t bound_interface_eflags = 0;
10855 	u_int32_t bound_interface_xflags = 0;
10856 
10857 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10858 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10859 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10860 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10861 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10862 			    cond_bound_interface_index, bound_interface_index);
10863 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10864 				if (bound_interface_index == cond_bound_interface_index) {
10865 					// No match, matches forbidden interface
10866 					return FALSE;
10867 				}
10868 			} else {
10869 				if (bound_interface_index != cond_bound_interface_index) {
10870 					// No match, does not match required interface
10871 					return FALSE;
10872 				}
10873 			}
10874 		}
10875 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10876 			if (bound_interface_index != IFSCOPE_NONE) {
10877 				ifnet_head_lock_shared();
10878 				ifnet_t interface = ifindex2ifnet[bound_interface_index];
10879 				if (interface != NULL) {
10880 					bound_interface_flags = interface->if_flags;
10881 					bound_interface_eflags = interface->if_eflags;
10882 					bound_interface_xflags = interface->if_xflags;
10883 				}
10884 				ifnet_head_done();
10885 			}
10886 
10887 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10888 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10889 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10890 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10891 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10892 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10893 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10894 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10895 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10896 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10897 					// No match, matches some forbidden interface flags
10898 					return FALSE;
10899 				}
10900 			} else {
10901 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10902 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10903 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10904 					// No match, does not match some required interface xflags
10905 					return FALSE;
10906 				}
10907 			}
10908 		}
10909 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10910 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10911 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10912 			if (bound_interface_index != 0) {
10913 				// No match, requires a non-bound packet
10914 				return FALSE;
10915 			}
10916 		}
10917 	}
10918 
10919 	if (kernel_policy->condition_mask == 0) {
10920 		return TRUE;
10921 	}
10922 
10923 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10924 		necp_kernel_policy_id matched_policy_id =
10925 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10926 		NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10927 		    "NECP_KERNEL_CONDITION_POLICY_ID",
10928 		    kernel_policy->cond_policy_id, 0, 0,
10929 		    matched_policy_id, socket_policy_id, socket_skip_policy_id);
10930 		if (matched_policy_id != kernel_policy->cond_policy_id) {
10931 			// No match, does not match required id
10932 			return FALSE;
10933 		}
10934 	}
10935 
10936 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10937 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10938 		    "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10939 		    kernel_policy->cond_last_interface_index, last_interface_index);
10940 		if (last_interface_index != kernel_policy->cond_last_interface_index) {
10941 			return FALSE;
10942 		}
10943 	}
10944 
10945 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10946 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10947 		    "NECP_KERNEL_CONDITION_PROTOCOL",
10948 		    kernel_policy->cond_protocol, protocol);
10949 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10950 			if (protocol == kernel_policy->cond_protocol) {
10951 				// No match, matches forbidden protocol
10952 				return FALSE;
10953 			}
10954 		} else {
10955 			if (protocol != kernel_policy->cond_protocol) {
10956 				// No match, does not match required protocol
10957 				return FALSE;
10958 			}
10959 		}
10960 	}
10961 
10962 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10963 		bool is_local = FALSE;
10964 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
10965 
10966 		if (rt != NULL) {
10967 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
10968 		} else {
10969 			is_local = necp_is_route_local(remote, include_local_addresses);
10970 		}
10971 		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);
10972 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10973 			if (is_local) {
10974 				// Match local-networks, fail
10975 				return FALSE;
10976 			}
10977 		} else {
10978 			if (!is_local) {
10979 				// Either no route to validate or no match for local networks
10980 				return FALSE;
10981 			}
10982 		}
10983 	}
10984 
10985 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
10986 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10987 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
10988 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
10989 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10990 				if (inRange) {
10991 					return FALSE;
10992 				}
10993 			} else {
10994 				if (!inRange) {
10995 					return FALSE;
10996 				}
10997 			}
10998 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10999 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
11000 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
11001 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
11002 				if (inSubnet) {
11003 					return FALSE;
11004 				}
11005 			} else {
11006 				if (!inSubnet) {
11007 					return FALSE;
11008 				}
11009 			}
11010 		}
11011 	}
11012 
11013 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
11014 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11015 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
11016 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
11017 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
11018 				if (inRange) {
11019 					return FALSE;
11020 				}
11021 			} else {
11022 				if (!inRange) {
11023 					return FALSE;
11024 				}
11025 			}
11026 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11027 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
11028 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
11029 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
11030 				if (inSubnet) {
11031 					return FALSE;
11032 				}
11033 			} else {
11034 				if (!inSubnet) {
11035 					return FALSE;
11036 				}
11037 			}
11038 		}
11039 	}
11040 
11041 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11042 		u_int16_t remote_port = 0;
11043 		if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
11044 			remote_port = SIN(remote)->sin_port;
11045 		}
11046 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
11047 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
11048 		    0, remote_port);
11049 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
11050 			if (kernel_policy->cond_scheme_port == remote_port) {
11051 				return FALSE;
11052 			}
11053 		} else {
11054 			if (kernel_policy->cond_scheme_port != remote_port) {
11055 				return FALSE;
11056 			}
11057 		}
11058 	}
11059 
11060 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11061 		bool tags_matched = false;
11062 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
11063 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
11064 		    kernel_policy->cond_packet_filter_tags, pf_tag);
11065 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
11066 			if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
11067 				tags_matched = true;
11068 			}
11069 
11070 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
11071 				if (tags_matched) {
11072 					return FALSE;
11073 				}
11074 			} else {
11075 				if (!tags_matched) {
11076 					return FALSE;
11077 				}
11078 			}
11079 		}
11080 	}
11081 
11082 	return TRUE;
11083 }
11084 
11085 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)11086 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)
11087 {
11088 	u_int32_t skip_order = 0;
11089 	u_int32_t skip_session_order = 0;
11090 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11091 	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)];
11092 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11093 	size_t route_rule_id_count = 0;
11094 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11095 	if (return_drop_all_bypass != NULL) {
11096 		*return_drop_all_bypass = drop_all_bypass;
11097 	}
11098 
11099 	if (return_route_rule_id != NULL) {
11100 		*return_route_rule_id = 0;
11101 	}
11102 
11103 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11104 
11105 	if (policy_search_array != NULL) {
11106 		for (int i = 0; policy_search_array[i] != NULL; i++) {
11107 			NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
11108 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
11109 				// We've hit a drop all rule
11110 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11111 					drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11112 					if (return_drop_all_bypass != NULL) {
11113 						*return_drop_all_bypass = drop_all_bypass;
11114 					}
11115 				}
11116 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11117 					NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
11118 					break;
11119 				}
11120 			}
11121 			if (necp_drop_dest_policy.entry_count > 0 &&
11122 			    necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
11123 				// We've hit a drop by destination address rule
11124 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
11125 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
11126 				break;
11127 			}
11128 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
11129 				// Done skipping
11130 				skip_order = 0;
11131 				skip_session_order = 0;
11132 			}
11133 			if (skip_order) {
11134 				if (policy_search_array[i]->order < skip_order) {
11135 					// Skip this policy
11136 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
11137 					continue;
11138 				} else {
11139 					// Done skipping
11140 					skip_order = 0;
11141 					skip_session_order = 0;
11142 				}
11143 			} else if (skip_session_order) {
11144 				// Skip this policy
11145 				NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
11146 				continue;
11147 			}
11148 
11149 			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)) {
11150 				if (!debug && necp_data_tracing_session_order) {
11151 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
11152 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
11153 						NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
11154 					}
11155 				}
11156 
11157 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
11158 					if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
11159 						route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
11160 					}
11161 					continue;
11162 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
11163 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
11164 					skip_session_order = policy_search_array[i]->session_order + 1;
11165 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
11166 					continue;
11167 				}
11168 
11169 				// Passed all tests, found a match
11170 				matched_policy = policy_search_array[i];
11171 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
11172 				break;
11173 			}
11174 		}
11175 	}
11176 
11177 	if (route_rule_id_count == 1) {
11178 		*return_route_rule_id = route_rule_id_array[0];
11179 	} else if (route_rule_id_count > 1) {
11180 		*return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11181 	}
11182 
11183 	return matched_policy;
11184 }
11185 
11186 static inline bool
necp_output_bypass(struct mbuf * packet)11187 necp_output_bypass(struct mbuf *packet)
11188 {
11189 	if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
11190 		return true;
11191 	}
11192 	if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
11193 		return true;
11194 	}
11195 	if (necp_is_intcoproc(NULL, packet)) {
11196 		return true;
11197 	}
11198 	return false;
11199 }
11200 
11201 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)11202 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
11203     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11204 {
11205 	struct ip *ip = NULL;
11206 	int hlen = sizeof(struct ip);
11207 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11208 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11209 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11210 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11211 	u_int16_t protocol = 0;
11212 	u_int32_t bound_interface_index = 0;
11213 	u_int32_t last_interface_index = 0;
11214 	union necp_sockaddr_union local_addr = { };
11215 	union necp_sockaddr_union remote_addr = { };
11216 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11217 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11218 	u_int16_t pf_tag = 0;
11219 
11220 	if (result) {
11221 		*result = 0;
11222 	}
11223 
11224 	if (result_parameter) {
11225 		memset(result_parameter, 0, sizeof(*result_parameter));
11226 	}
11227 
11228 	if (packet == NULL) {
11229 		return NECP_KERNEL_POLICY_ID_NONE;
11230 	}
11231 
11232 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11233 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11234 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11235 
11236 	// Exit early for an empty list
11237 	// Don't lock. Possible race condition, but we don't want the performance hit.
11238 	if (necp_kernel_ip_output_policies_count == 0 ||
11239 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
11240 		if (necp_drop_all_order > 0) {
11241 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11242 			if (result) {
11243 				if (necp_output_bypass(packet)) {
11244 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11245 				} else {
11246 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11247 				}
11248 			}
11249 		}
11250 
11251 		return matched_policy_id;
11252 	}
11253 
11254 	// Check for loopback exception
11255 	if (necp_output_bypass(packet)) {
11256 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11257 		if (result) {
11258 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11259 		}
11260 		return matched_policy_id;
11261 	}
11262 
11263 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11264 
11265 	// Process packet to get relevant fields
11266 	ip = mtod(packet, struct ip *);
11267 #ifdef _IP_VHL
11268 	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
11269 #else
11270 	hlen = ip->ip_hl << 2;
11271 #endif
11272 
11273 	protocol = ip->ip_p;
11274 
11275 	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
11276 	    (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
11277 	    ipoa->ipoa_boundif != IFSCOPE_NONE) {
11278 		bound_interface_index = ipoa->ipoa_boundif;
11279 	}
11280 
11281 	local_addr.sin.sin_family = AF_INET;
11282 	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
11283 	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
11284 
11285 	remote_addr.sin.sin_family = AF_INET;
11286 	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
11287 	memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
11288 
11289 	switch (protocol) {
11290 	case IPPROTO_TCP: {
11291 		struct tcphdr th;
11292 		if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
11293 			m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
11294 			SIN(&local_addr)->sin_port = th.th_sport;
11295 			SIN(&remote_addr)->sin_port = th.th_dport;
11296 		}
11297 		break;
11298 	}
11299 	case IPPROTO_UDP: {
11300 		struct udphdr uh;
11301 		if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
11302 			m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
11303 			SIN(&local_addr)->sin_port = uh.uh_sport;
11304 			SIN(&remote_addr)->sin_port = uh.uh_dport;
11305 		}
11306 		break;
11307 	}
11308 	default: {
11309 		SIN(&local_addr)->sin_port = 0;
11310 		SIN(&remote_addr)->sin_port = 0;
11311 		break;
11312 	}
11313 	}
11314 
11315 	// Match packet to policy
11316 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11317 	u_int32_t route_rule_id = 0;
11318 
11319 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11320 	NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
11321 
11322 	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);
11323 	if (matched_policy) {
11324 		matched_policy_id = matched_policy->id;
11325 		if (result) {
11326 			*result = matched_policy->result;
11327 		}
11328 
11329 		if (result_parameter) {
11330 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11331 		}
11332 
11333 		if (route_rule_id != 0 &&
11334 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11335 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11336 		}
11337 
11338 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11339 			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);
11340 		}
11341 	} else {
11342 		bool drop_all = false;
11343 		/*
11344 		 * Apply drop-all only to packets which have never matched a primary policy (check
11345 		 * if the packet saved policy id is none or falls within the socket policy id range).
11346 		 */
11347 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11348 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11349 			drop_all = true;
11350 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11351 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11352 			}
11353 		}
11354 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11355 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11356 			if (result) {
11357 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11358 				NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
11359 			}
11360 		} else if (route_rule_id != 0 &&
11361 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11362 			// If we matched a route rule, mark it
11363 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11364 		}
11365 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11366 			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);
11367 		}
11368 	}
11369 
11370 	lck_rw_done(&necp_kernel_policy_lock);
11371 
11372 	return matched_policy_id;
11373 }
11374 
11375 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)11376 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11377     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11378 {
11379 	struct ip6_hdr *ip6 = NULL;
11380 	int next = -1;
11381 	int offset = 0;
11382 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11383 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11384 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11385 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11386 	u_int16_t protocol = 0;
11387 	u_int32_t bound_interface_index = 0;
11388 	u_int32_t last_interface_index = 0;
11389 	union necp_sockaddr_union local_addr = { };
11390 	union necp_sockaddr_union remote_addr = { };
11391 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11392 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11393 	u_int16_t pf_tag = 0;
11394 
11395 	if (result) {
11396 		*result = 0;
11397 	}
11398 
11399 	if (result_parameter) {
11400 		memset(result_parameter, 0, sizeof(*result_parameter));
11401 	}
11402 
11403 	if (packet == NULL) {
11404 		return NECP_KERNEL_POLICY_ID_NONE;
11405 	}
11406 
11407 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11408 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11409 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11410 
11411 	// Exit early for an empty list
11412 	// Don't lock. Possible race condition, but we don't want the performance hit.
11413 	if (necp_drop_management_order == 0 &&
11414 	    (necp_kernel_ip_output_policies_count == 0 ||
11415 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11416 		if (necp_drop_all_order > 0) {
11417 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11418 			if (result) {
11419 				if (necp_output_bypass(packet)) {
11420 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11421 				} else {
11422 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11423 				}
11424 			}
11425 		}
11426 
11427 		return matched_policy_id;
11428 	}
11429 
11430 	// Check for loopback exception
11431 	if (necp_output_bypass(packet)) {
11432 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11433 		if (result) {
11434 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11435 		}
11436 		return matched_policy_id;
11437 	}
11438 
11439 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11440 
11441 	// Process packet to get relevant fields
11442 	ip6 = mtod(packet, struct ip6_hdr *);
11443 
11444 	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11445 	    (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11446 	    ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11447 		bound_interface_index = ip6oa->ip6oa_boundif;
11448 	}
11449 
11450 	SIN6(&local_addr)->sin6_family = AF_INET6;
11451 	SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11452 	memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11453 
11454 	SIN6(&remote_addr)->sin6_family = AF_INET6;
11455 	SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11456 	memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11457 
11458 	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11459 	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11460 		protocol = next;
11461 		switch (protocol) {
11462 		case IPPROTO_TCP: {
11463 			struct tcphdr th;
11464 			if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11465 				m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11466 				SIN6(&local_addr)->sin6_port = th.th_sport;
11467 				SIN6(&remote_addr)->sin6_port = th.th_dport;
11468 			}
11469 			break;
11470 		}
11471 		case IPPROTO_UDP: {
11472 			struct udphdr uh;
11473 			if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11474 				m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11475 				SIN6(&local_addr)->sin6_port = uh.uh_sport;
11476 				SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11477 			}
11478 			break;
11479 		}
11480 		default: {
11481 			SIN6(&local_addr)->sin6_port = 0;
11482 			SIN6(&remote_addr)->sin6_port = 0;
11483 			break;
11484 		}
11485 		}
11486 	}
11487 
11488 	// Match packet to policy
11489 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11490 	u_int32_t route_rule_id = 0;
11491 
11492 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11493 	NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11494 
11495 	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);
11496 	if (matched_policy) {
11497 		matched_policy_id = matched_policy->id;
11498 		if (result) {
11499 			*result = matched_policy->result;
11500 		}
11501 
11502 		if (result_parameter) {
11503 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11504 		}
11505 
11506 		if (route_rule_id != 0 &&
11507 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11508 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11509 		}
11510 
11511 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11512 			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);
11513 		}
11514 	} else {
11515 		bool drop_all = false;
11516 		/*
11517 		 * Apply drop-all only to packets which have never matched a primary policy (check
11518 		 * if the packet saved policy id is none or falls within the socket policy id range).
11519 		 */
11520 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11521 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11522 			drop_all = true;
11523 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11524 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11525 			}
11526 		}
11527 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11528 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11529 			if (result) {
11530 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11531 				NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11532 			}
11533 		} else if (route_rule_id != 0 &&
11534 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11535 			// If we matched a route rule, mark it
11536 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11537 		}
11538 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11539 			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);
11540 		}
11541 	}
11542 
11543 	lck_rw_done(&necp_kernel_policy_lock);
11544 
11545 	return matched_policy_id;
11546 }
11547 
11548 // Utilities
11549 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11550 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11551 {
11552 	int cmp = 0;
11553 
11554 	if (addr == NULL || range_start == NULL || range_end == NULL) {
11555 		return FALSE;
11556 	}
11557 
11558 	/* Must be greater than or equal to start */
11559 	cmp = necp_addr_compare(addr, range_start, 1);
11560 	if (cmp != 0 && cmp != 1) {
11561 		return FALSE;
11562 	}
11563 
11564 	/* Must be less than or equal to end */
11565 	cmp = necp_addr_compare(addr, range_end, 1);
11566 	if (cmp != 0 && cmp != -1) {
11567 		return FALSE;
11568 	}
11569 
11570 	return TRUE;
11571 }
11572 
11573 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)11574 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11575 {
11576 	int cmp = 0;
11577 
11578 	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11579 		return FALSE;
11580 	}
11581 
11582 	/* Must be greater than or equal to start */
11583 	cmp = necp_addr_compare(inner_range_start, range_start, 1);
11584 	if (cmp != 0 && cmp != 1) {
11585 		return FALSE;
11586 	}
11587 
11588 	/* Must be less than or equal to end */
11589 	cmp = necp_addr_compare(inner_range_end, range_end, 1);
11590 	if (cmp != 0 && cmp != -1) {
11591 		return FALSE;
11592 	}
11593 
11594 	return TRUE;
11595 }
11596 
11597 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11598 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11599 {
11600 	if (addr == NULL || subnet_addr == NULL) {
11601 		return FALSE;
11602 	}
11603 
11604 	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11605 		return FALSE;
11606 	}
11607 
11608 	switch (addr->sa_family) {
11609 	case AF_INET: {
11610 		if (satosin(subnet_addr)->sin_port != 0 &&
11611 		    satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11612 			return FALSE;
11613 		}
11614 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11615 	}
11616 	case AF_INET6: {
11617 		if (satosin6(subnet_addr)->sin6_port != 0 &&
11618 		    satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11619 			return FALSE;
11620 		}
11621 		if (satosin6(addr)->sin6_scope_id &&
11622 		    satosin6(subnet_addr)->sin6_scope_id &&
11623 		    satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11624 			return FALSE;
11625 		}
11626 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11627 	}
11628 	default: {
11629 		return FALSE;
11630 	}
11631 	}
11632 
11633 	return FALSE;
11634 }
11635 
11636 /*
11637  * Return values:
11638  * -1: sa1 < sa2
11639  * 0: sa1 == sa2
11640  * 1: sa1 > sa2
11641  * 2: Not comparable or error
11642  */
11643 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11644 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11645 {
11646 	int result = 0;
11647 	int port_result = 0;
11648 
11649 	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11650 		return 2;
11651 	}
11652 
11653 	if (sa1->sa_len == 0) {
11654 		return 0;
11655 	}
11656 
11657 	switch (sa1->sa_family) {
11658 	case AF_INET: {
11659 		if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11660 			return 2;
11661 		}
11662 
11663 		result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11664 
11665 		if (check_port) {
11666 			if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11667 				port_result = -1;
11668 			} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11669 				port_result = 1;
11670 			}
11671 
11672 			if (result == 0) {
11673 				result = port_result;
11674 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11675 				return 2;
11676 			}
11677 		}
11678 
11679 		break;
11680 	}
11681 	case AF_INET6: {
11682 		if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11683 			return 2;
11684 		}
11685 
11686 		if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11687 			return 2;
11688 		}
11689 
11690 		result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11691 
11692 		if (check_port) {
11693 			if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11694 				port_result = -1;
11695 			} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11696 				port_result = 1;
11697 			}
11698 
11699 			if (result == 0) {
11700 				result = port_result;
11701 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11702 				return 2;
11703 			}
11704 		}
11705 
11706 		break;
11707 	}
11708 	default: {
11709 		result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11710 		break;
11711 	}
11712 	}
11713 
11714 	if (result < 0) {
11715 		result = (-1);
11716 	} else if (result > 0) {
11717 		result = (1);
11718 	}
11719 
11720 	return result;
11721 }
11722 
11723 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11724 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11725 {
11726 	u_int8_t mask;
11727 
11728 	/* Handle null pointers */
11729 	if (p1 == NULL || p2 == NULL) {
11730 		return p1 == p2;
11731 	}
11732 
11733 	while (bits >= 8) {
11734 		if (*p1++ != *p2++) {
11735 			return FALSE;
11736 		}
11737 		bits -= 8;
11738 	}
11739 
11740 	if (bits > 0) {
11741 		mask = ~((1 << (8 - bits)) - 1);
11742 		if ((*p1 & mask) != (*p2 & mask)) {
11743 			return FALSE;
11744 		}
11745 	}
11746 	return TRUE;
11747 }
11748 
11749 static bool
necp_addr_is_empty(struct sockaddr * addr)11750 necp_addr_is_empty(struct sockaddr *addr)
11751 {
11752 	if (addr == NULL) {
11753 		return TRUE;
11754 	}
11755 
11756 	if (addr->sa_len == 0) {
11757 		return TRUE;
11758 	}
11759 
11760 	switch (addr->sa_family) {
11761 	case AF_INET: {
11762 		static struct sockaddr_in ipv4_empty_address = {
11763 			.sin_len = sizeof(struct sockaddr_in),
11764 			.sin_family = AF_INET,
11765 			.sin_port = 0,
11766 			.sin_addr = { .s_addr = 0 }, // 0.0.0.0
11767 			.sin_zero = {0},
11768 		};
11769 		if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11770 			return TRUE;
11771 		} else {
11772 			return FALSE;
11773 		}
11774 	}
11775 	case AF_INET6: {
11776 		static struct sockaddr_in6 ipv6_empty_address = {
11777 			.sin6_len = sizeof(struct sockaddr_in6),
11778 			.sin6_family = AF_INET6,
11779 			.sin6_port = 0,
11780 			.sin6_flowinfo = 0,
11781 			.sin6_addr = IN6ADDR_ANY_INIT, // ::
11782 			.sin6_scope_id = 0,
11783 		};
11784 		if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11785 			return TRUE;
11786 		} else {
11787 			return FALSE;
11788 		}
11789 	}
11790 	default:
11791 		return FALSE;
11792 	}
11793 
11794 	return FALSE;
11795 }
11796 
11797 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)11798 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)
11799 {
11800 	bool qos_marking = FALSE;
11801 	int exception_index = 0;
11802 	struct necp_route_rule *route_rule = NULL;
11803 
11804 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11805 	if (route_rule == NULL) {
11806 		qos_marking = FALSE;
11807 		goto done;
11808 	}
11809 
11810 	if (route_rule->match_netagent_id != 0) {
11811 		if (netagent_array == NULL || netagent_array_count == 0) {
11812 			// No agents, ignore rule
11813 			goto done;
11814 		}
11815 		bool found_match = FALSE;
11816 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11817 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11818 				found_match = TRUE;
11819 				break;
11820 			}
11821 		}
11822 		if (!found_match) {
11823 			// Agents don't match, ignore rule
11824 			goto done;
11825 		}
11826 	}
11827 
11828 	qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11829 
11830 	if (ifp == NULL) {
11831 		goto done;
11832 	}
11833 
11834 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11835 		if (route_rule->exception_if_indices[exception_index] == 0) {
11836 			break;
11837 		}
11838 		if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11839 			continue;
11840 		}
11841 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11842 			qos_marking = TRUE;
11843 			if (necp_debug > 2) {
11844 				NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11845 				    route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11846 			}
11847 			goto done;
11848 		}
11849 	}
11850 
11851 	if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11852 	    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11853 	    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11854 	    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11855 	    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11856 	    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11857 	    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11858 		qos_marking = TRUE;
11859 		if (necp_debug > 2) {
11860 			NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11861 			    route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11862 			    route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11863 		}
11864 		goto done;
11865 	}
11866 done:
11867 	if (necp_debug > 1) {
11868 		NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11869 		    route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11870 	}
11871 	return qos_marking;
11872 }
11873 
11874 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)11875 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)
11876 {
11877 	bool new_qos_marking = old_qos_marking;
11878 	struct ifnet *ifp = interface;
11879 
11880 	if (net_qos_policy_restricted == 0) {
11881 		return new_qos_marking;
11882 	}
11883 
11884 	/*
11885 	 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11886 	 */
11887 	if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11888 		return new_qos_marking;
11889 	}
11890 
11891 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11892 
11893 	if (ifp == NULL && route != NULL) {
11894 		ifp = route->rt_ifp;
11895 	}
11896 	/*
11897 	 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11898 	 */
11899 	if (ifp == NULL || route_rule_id == 0) {
11900 		new_qos_marking = FALSE;
11901 		goto done;
11902 	}
11903 
11904 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11905 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11906 		if (aggregate_route_rule != NULL) {
11907 			int index = 0;
11908 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11909 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11910 				if (sub_route_rule_id == 0) {
11911 					break;
11912 				}
11913 				new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11914 				if (new_qos_marking == TRUE) {
11915 					break;
11916 				}
11917 			}
11918 		}
11919 	} else {
11920 		new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11921 	}
11922 	/*
11923 	 * Now that we have an interface we remember the gencount
11924 	 */
11925 	*qos_marking_gencount = necp_kernel_socket_policies_gencount;
11926 
11927 done:
11928 	lck_rw_done(&necp_kernel_policy_lock);
11929 	return new_qos_marking;
11930 }
11931 
11932 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11933 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11934 {
11935 	bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11936 
11937 	if (net_qos_policy_restricted == 0) {
11938 		return;
11939 	}
11940 	if (inp->inp_socket == NULL) {
11941 		return;
11942 	}
11943 	if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11944 		return;
11945 	}
11946 
11947 	qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11948 
11949 	if (qos_marking == TRUE) {
11950 		inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11951 	} else {
11952 		inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11953 	}
11954 }
11955 
11956 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)11957 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11958 {
11959 	if (ifp != NULL &&
11960 	    (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11961 	    ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11962 		return true;
11963 	}
11964 	if (delegated_ifp != NULL &&
11965 	    (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11966 	    delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11967 		return true;
11968 	}
11969 	return false;
11970 }
11971 
11972 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)11973 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,
11974     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11975 {
11976 	bool default_is_allowed = TRUE;
11977 	u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
11978 	int exception_index = 0;
11979 	struct ifnet *delegated_ifp = NULL;
11980 	struct necp_route_rule *route_rule = NULL;
11981 
11982 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11983 	if (route_rule == NULL) {
11984 		return TRUE;
11985 	}
11986 
11987 	if (route_rule->match_netagent_id != 0) {
11988 		if (netagent_array == NULL || netagent_array_count == 0) {
11989 			// No agents, ignore rule
11990 			return TRUE;
11991 		}
11992 		bool found_match = FALSE;
11993 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11994 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11995 				found_match = TRUE;
11996 				break;
11997 			}
11998 		}
11999 		if (!found_match) {
12000 			// Agents don't match, ignore rule
12001 			return TRUE;
12002 		}
12003 	}
12004 
12005 	default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
12006 	if (ifp == NULL && route != NULL) {
12007 		ifp = route->rt_ifp;
12008 	}
12009 	if (ifp == NULL) {
12010 		if (necp_debug > 1 && !default_is_allowed) {
12011 			NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12012 		}
12013 		return default_is_allowed;
12014 	}
12015 
12016 	delegated_ifp = ifp->if_delegated.ifp;
12017 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12018 		if (route_rule->exception_if_indices[exception_index] == 0) {
12019 			break;
12020 		}
12021 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
12022 		    (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
12023 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12024 				const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
12025 				if (necp_debug > 1 && lqm_abort) {
12026 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
12027 					    route_rule->exception_if_indices[exception_index], route_rule_id);
12028 				}
12029 				return false;
12030 			} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
12031 				if (necp_debug > 1) {
12032 					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));
12033 				}
12034 				if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
12035 					*interface_type_denied = route_rule->effective_type;
12036 				}
12037 				return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
12038 			}
12039 		}
12040 	}
12041 
12042 	if (IFNET_IS_CELLULAR(ifp)) {
12043 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12044 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12045 				if (interface_type_denied != NULL) {
12046 					*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12047 					if (route_rule->effective_type != 0) {
12048 						*interface_type_denied = route_rule->effective_type;
12049 					}
12050 				}
12051 				// Mark aggregate action as deny
12052 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12053 			}
12054 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
12055 			if (interface_type_denied != NULL) {
12056 				*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
12057 				if (route_rule->effective_type != 0) {
12058 					*interface_type_denied = route_rule->effective_type;
12059 				}
12060 			}
12061 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12062 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12063 			    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
12064 				// Deny wins if there is a conflict
12065 				type_aggregate_action = route_rule->cellular_action;
12066 			}
12067 		}
12068 	}
12069 
12070 	if (IFNET_IS_WIFI(ifp)) {
12071 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12072 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12073 				if (interface_type_denied != NULL) {
12074 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12075 					if (route_rule->effective_type != 0) {
12076 						*interface_type_denied = route_rule->effective_type;
12077 					}
12078 				}
12079 				// Mark aggregate action as deny
12080 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12081 			}
12082 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
12083 			if (interface_type_denied != NULL) {
12084 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
12085 				if (route_rule->effective_type != 0) {
12086 					*interface_type_denied = route_rule->effective_type;
12087 				}
12088 			}
12089 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12090 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12091 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
12092 				// Deny wins if there is a conflict
12093 				type_aggregate_action = route_rule->wifi_action;
12094 			}
12095 		}
12096 	}
12097 
12098 	if (IFNET_IS_COMPANION_LINK(ifp) ||
12099 	    (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
12100 		if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12101 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12102 				if (interface_type_denied != NULL) {
12103 					*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12104 					if (route_rule->effective_type != 0) {
12105 						*interface_type_denied = route_rule->effective_type;
12106 					}
12107 				}
12108 				// Mark aggregate action as deny
12109 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12110 			}
12111 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
12112 			if (interface_type_denied != NULL) {
12113 				*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
12114 				if (route_rule->effective_type != 0) {
12115 					*interface_type_denied = route_rule->effective_type;
12116 				}
12117 			}
12118 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12119 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12120 			    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
12121 				// Deny wins if there is a conflict
12122 				type_aggregate_action = route_rule->companion_action;
12123 			}
12124 		}
12125 	}
12126 
12127 	if (IFNET_IS_WIRED(ifp)) {
12128 		if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12129 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12130 				if (interface_type_denied != NULL) {
12131 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12132 					if (route_rule->effective_type != 0) {
12133 						*interface_type_denied = route_rule->effective_type;
12134 					}
12135 				}
12136 				// Mark aggregate action as deny
12137 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12138 			}
12139 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
12140 			if (interface_type_denied != NULL) {
12141 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
12142 				if (route_rule->effective_type != 0) {
12143 					*interface_type_denied = route_rule->effective_type;
12144 				}
12145 			}
12146 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12147 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12148 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
12149 				// Deny wins if there is a conflict
12150 				type_aggregate_action = route_rule->wired_action;
12151 			}
12152 		}
12153 	}
12154 
12155 	if (IFNET_IS_EXPENSIVE(ifp)) {
12156 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12157 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12158 				// Mark aggregate action as deny
12159 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12160 			}
12161 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
12162 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12163 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12164 			    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
12165 				// Deny wins if there is a conflict
12166 				type_aggregate_action = route_rule->expensive_action;
12167 			}
12168 		}
12169 	}
12170 
12171 	if (IFNET_IS_CONSTRAINED(ifp)) {
12172 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12173 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12174 				// Mark aggregate action as deny
12175 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12176 			}
12177 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
12178 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12179 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12180 			    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
12181 				// Deny wins if there is a conflict
12182 				type_aggregate_action = route_rule->constrained_action;
12183 			}
12184 		}
12185 	}
12186 
12187 	if (IFNET_IS_VPN(ifp)) {
12188 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
12189 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
12190 				// Mark aggregate action as deny
12191 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
12192 			}
12193 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
12194 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
12195 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
12196 			    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
12197 				// Deny wins if there is a conflict
12198 				type_aggregate_action = route_rule->vpn_action;
12199 			}
12200 		}
12201 	}
12202 
12203 	if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
12204 		if (necp_debug > 1) {
12205 			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));
12206 		}
12207 		return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
12208 	}
12209 
12210 	if (necp_debug > 1 && !default_is_allowed) {
12211 		NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
12212 	}
12213 	return default_is_allowed;
12214 }
12215 
12216 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)12217 necp_proc_is_allowed_on_management_interface(proc_t proc)
12218 {
12219 	bool allowed = false;
12220 	const task_t __single task = proc_task(proc);
12221 
12222 	if (task != NULL) {
12223 		if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
12224 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
12225 #if DEBUG || DEVELOPMENT
12226 		    || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
12227 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
12228 #endif /* DEBUG || DEVELOPMENT */
12229 		    ) {
12230 			allowed = true;
12231 		}
12232 	}
12233 	return allowed;
12234 }
12235 
12236 __attribute__((noinline))
12237 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)12238 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12239 {
12240 	char buf[128];
12241 
12242 	if (inp != NULL) {
12243 		inp_snprintf_tuple(inp, buf, sizeof(buf));
12244 	} else {
12245 		*buf = 0;
12246 	}
12247 	os_log(OS_LOG_DEFAULT,
12248 	    "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
12249 	    proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
12250 	    proc != NULL ? proc_getpid(proc) : proc_selfpid(),
12251 	    inp != NULL ? buf : "",
12252 	    ifp->if_xname);
12253 }
12254 
12255 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)12256 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
12257 {
12258 	if (if_management_interface_check_needed == false) {
12259 		return true;
12260 	}
12261 	if (necp_drop_management_order == 0) {
12262 		return true;
12263 	}
12264 	if (ifp == NULL && route != NULL) {
12265 		ifp = route->rt_ifp;
12266 	}
12267 	if (ifp == NULL) {
12268 		return true;
12269 	}
12270 
12271 	if (IFNET_IS_MANAGEMENT(ifp)) {
12272 		bool allowed = true;
12273 
12274 		if (inp != NULL) {
12275 			/*
12276 			 * The entitlement check is already performed for socket flows
12277 			 */
12278 			allowed = INP_MANAGEMENT_ALLOWED(inp);
12279 		} else if (proc != NULL) {
12280 			allowed = necp_proc_is_allowed_on_management_interface(proc);
12281 		}
12282 		if (__improbable(if_management_verbose > 1 && allowed == false)) {
12283 			necp_log_interface_not_allowed(ifp, proc, inp);
12284 		}
12285 		return allowed;
12286 	}
12287 	return true;
12288 }
12289 
12290 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)12291 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,
12292     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
12293 {
12294 	if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
12295 		if (necp_debug > 1) {
12296 			NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
12297 		}
12298 		return TRUE;
12299 	}
12300 
12301 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12302 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12303 		if (aggregate_route_rule != NULL) {
12304 			int index = 0;
12305 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12306 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12307 				if (sub_route_rule_id == 0) {
12308 					break;
12309 				}
12310 				if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
12311 					return FALSE;
12312 				}
12313 			}
12314 		}
12315 	} else {
12316 		return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
12317 	}
12318 
12319 	return TRUE;
12320 }
12321 
12322 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)12323 necp_route_rule_matches_agents(u_int32_t route_rule_id)
12324 {
12325 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12326 	if (route_rule == NULL) {
12327 		return false;
12328 	}
12329 
12330 	return route_rule->match_netagent_id != 0;
12331 }
12332 
12333 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)12334 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)
12335 {
12336 	if (remove == NULL) {
12337 		return 0;
12338 	}
12339 
12340 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12341 	if (route_rule == NULL) {
12342 		return 0;
12343 	}
12344 
12345 	// No netagent, skip
12346 	if (route_rule->netagent_id == 0) {
12347 		return 0;
12348 	}
12349 
12350 	if (route_rule->match_netagent_id != 0) {
12351 		if (netagent_array == NULL || netagent_array_count == 0) {
12352 			// No agents, ignore rule
12353 			return 0;
12354 		}
12355 		bool found_match = FALSE;
12356 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12357 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12358 				found_match = TRUE;
12359 				break;
12360 			}
12361 		}
12362 		if (!found_match) {
12363 			// Agents don't match, ignore rule
12364 			return 0;
12365 		}
12366 	}
12367 
12368 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12369 	if (ifp == NULL) {
12370 		// No interface, apply the default action
12371 		if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12372 		    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12373 			*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12374 			return route_rule->netagent_id;
12375 		}
12376 		return 0;
12377 	}
12378 
12379 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12380 		if (route_rule->exception_if_indices[exception_index] == 0) {
12381 			break;
12382 		}
12383 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12384 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12385 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12386 			    route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12387 				*remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12388 				return route_rule->netagent_id;
12389 			}
12390 			return 0;
12391 		}
12392 	}
12393 
12394 	if (ifp->if_type == IFT_CELLULAR &&
12395 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12396 		if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12397 		    route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12398 			*remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12399 			return route_rule->netagent_id;
12400 		}
12401 		return 0;
12402 	}
12403 
12404 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12405 	    route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12406 		if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12407 		    route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12408 			*remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12409 			return route_rule->netagent_id;
12410 		}
12411 		return 0;
12412 	}
12413 
12414 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12415 	    route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12416 		if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12417 		    route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12418 			*remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12419 			return route_rule->netagent_id;
12420 		}
12421 		return 0;
12422 	}
12423 
12424 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12425 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12426 		if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12427 		    route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12428 			*remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12429 			return route_rule->netagent_id;
12430 		}
12431 		return 0;
12432 	}
12433 
12434 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12435 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12436 		if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12437 		    route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12438 			*remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12439 			return route_rule->netagent_id;
12440 		}
12441 		return 0;
12442 	}
12443 
12444 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12445 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12446 		if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12447 		    route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12448 			*remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12449 			return route_rule->netagent_id;
12450 		}
12451 		return 0;
12452 	}
12453 
12454 	if (ifp->if_xflags & IFXF_IS_VPN &&
12455 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12456 		if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12457 		    route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12458 			*remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12459 			return route_rule->netagent_id;
12460 		}
12461 		return 0;
12462 	}
12463 
12464 	// No more specific case matched, apply the default action
12465 	if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12466 	    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12467 		*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12468 		return route_rule->netagent_id;
12469 	}
12470 
12471 	return 0;
12472 }
12473 
12474 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)12475 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)
12476 {
12477 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12478 	if (route_rule == NULL) {
12479 		return 0;
12480 	}
12481 
12482 	// No control unit, skip
12483 	if (route_rule->control_unit == 0) {
12484 		return 0;
12485 	}
12486 
12487 	if (route_rule->match_netagent_id != 0) {
12488 		if (netagent_array == NULL || netagent_array_count == 0) {
12489 			// No agents, ignore rule
12490 			return 0;
12491 		}
12492 		bool found_match = FALSE;
12493 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12494 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12495 				found_match = TRUE;
12496 				break;
12497 			}
12498 		}
12499 		if (!found_match) {
12500 			// Agents don't match, ignore rule
12501 			return 0;
12502 		}
12503 	}
12504 
12505 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12506 	if (ifp == NULL) {
12507 		// No interface, apply the default action
12508 		if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12509 			return route_rule->control_unit;
12510 		}
12511 		return 0;
12512 	}
12513 
12514 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12515 		if (route_rule->exception_if_indices[exception_index] == 0) {
12516 			break;
12517 		}
12518 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12519 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12520 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12521 				return route_rule->control_unit;
12522 			}
12523 			return 0;
12524 		}
12525 	}
12526 
12527 	if (ifp->if_type == IFT_CELLULAR &&
12528 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12529 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12530 			return route_rule->control_unit;
12531 		}
12532 		return 0;
12533 	}
12534 
12535 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12536 	    route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12537 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12538 			return route_rule->control_unit;
12539 		}
12540 		return 0;
12541 	}
12542 
12543 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12544 	    route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12545 		if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12546 			return route_rule->control_unit;
12547 		}
12548 		return 0;
12549 	}
12550 
12551 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12552 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12553 		if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12554 			return route_rule->control_unit;
12555 		}
12556 		return 0;
12557 	}
12558 
12559 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12560 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12561 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12562 			return route_rule->control_unit;
12563 		}
12564 		return 0;
12565 	}
12566 
12567 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12568 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12569 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12570 			return route_rule->control_unit;
12571 		}
12572 		return 0;
12573 	}
12574 
12575 	if (ifp->if_xflags & IFXF_IS_VPN &&
12576 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12577 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12578 			return route_rule->control_unit;
12579 		}
12580 		return 0;
12581 	}
12582 
12583 	// No more specific case matched, apply the default action
12584 	if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12585 		return route_rule->control_unit;
12586 	}
12587 	return 0;
12588 }
12589 
12590 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)12591 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,
12592     u_int32_t *flow_divert_aggregate_unit)
12593 {
12594 	if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12595 		return 0;
12596 	}
12597 
12598 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12599 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12600 		if (aggregate_route_rule != NULL) {
12601 			int index = 0;
12602 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12603 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12604 				if (sub_route_rule_id == 0) {
12605 					break;
12606 				}
12607 				uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12608 				if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12609 					// For transparent proxies, accumulate the control unit and continue to the next route rule
12610 					*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12611 					continue;
12612 				}
12613 
12614 				if (control_unit != 0) {
12615 					return control_unit;
12616 				}
12617 			}
12618 		}
12619 	} else {
12620 		uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12621 		if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12622 			// For transparent proxies, accumulate the control unit and let the caller continue
12623 			*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12624 			return 0;
12625 		}
12626 		return control_unit;
12627 	}
12628 
12629 	return 0;
12630 }
12631 
12632 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12633 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12634 {
12635 	bool is_allowed = true;
12636 	u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12637 	if (route_rule_id != 0 &&
12638 	    interface != NULL) {
12639 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12640 		is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12641 		lck_rw_done(&necp_kernel_policy_lock);
12642 	}
12643 	return is_allowed;
12644 }
12645 
12646 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12647 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12648 {
12649 	size_t netagent_cursor;
12650 	for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12651 		struct necp_uuid_id_mapping *mapping = NULL;
12652 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
12653 		if (netagent_id == 0) {
12654 			continue;
12655 		}
12656 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12657 		if (mapping != NULL) {
12658 			u_int32_t agent_flags = 0;
12659 			agent_flags = netagent_get_flags(mapping->uuid);
12660 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12661 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12662 					continue;
12663 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12664 					return FALSE;
12665 				}
12666 			}
12667 		}
12668 	}
12669 	return TRUE;
12670 }
12671 
12672 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12673 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12674 {
12675 	bool allowed_to_receive = TRUE;
12676 
12677 	if (pf_tag == PF_TAG_ID_STACK_DROP &&
12678 	    (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12679 		allowed_to_receive = FALSE;
12680 	}
12681 
12682 	return allowed_to_receive;
12683 }
12684 
12685 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)12686 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)
12687 {
12688 	u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12689 	bool allowed_to_receive = TRUE;
12690 	struct necp_socket_info info = {};
12691 	u_int32_t flowhash = 0;
12692 	necp_kernel_policy_result service_action = 0;
12693 	necp_kernel_policy_service service = { 0, 0 };
12694 	u_int32_t route_rule_id = 0;
12695 	struct rtentry *route = NULL;
12696 	u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12697 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12698 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12699 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12700 	proc_t __single socket_proc = NULL;
12701 	necp_kernel_policy_filter filter_control_unit = 0;
12702 	u_int32_t pass_flags = 0;
12703 	u_int32_t flow_divert_aggregate_unit = 0;
12704 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12705 	int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12706 
12707 	memset(&netagent_ids, 0, sizeof(netagent_ids));
12708 
12709 	if (return_policy_id) {
12710 		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12711 	}
12712 	if (return_skip_policy_id) {
12713 		*return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12714 	}
12715 	if (return_route_rule_id) {
12716 		*return_route_rule_id = 0;
12717 	}
12718 	if (return_pass_flags) {
12719 		*return_pass_flags = 0;
12720 	}
12721 
12722 	if (inp == NULL) {
12723 		goto done;
12724 	}
12725 
12726 	route = inp->inp_route.ro_rt;
12727 
12728 	struct socket *so = inp->inp_socket;
12729 
12730 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12731 
12732 	// Don't lock. Possible race condition, but we don't want the performance hit.
12733 	if (necp_drop_management_order == 0 &&
12734 	    (necp_kernel_socket_policies_count == 0 ||
12735 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12736 		if (necp_drop_all_order > 0 || drop_order > 0) {
12737 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12738 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12739 				allowed_to_receive = TRUE;
12740 			} else {
12741 				allowed_to_receive = FALSE;
12742 			}
12743 		}
12744 		goto done;
12745 	}
12746 
12747 	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
12748 	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12749 		bool policies_have_changed = FALSE;
12750 		bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12751 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12752 			policies_have_changed = TRUE;
12753 		} else {
12754 			if (inp->inp_policyresult.results.route_rule_id != 0) {
12755 				lck_rw_lock_shared(&necp_kernel_policy_lock);
12756 				if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12757 					route_allowed = FALSE;
12758 				}
12759 				lck_rw_done(&necp_kernel_policy_lock);
12760 			}
12761 		}
12762 
12763 		if (!policies_have_changed) {
12764 			if (debug) {
12765 				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);
12766 				debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12767 			}
12768 
12769 			if (!route_allowed ||
12770 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12771 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12772 			    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12773 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12774 				allowed_to_receive = FALSE;
12775 				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);
12776 			} else {
12777 				if (return_policy_id) {
12778 					*return_policy_id = inp->inp_policyresult.policy_id;
12779 				}
12780 				if (return_skip_policy_id) {
12781 					*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12782 				}
12783 				if (return_route_rule_id) {
12784 					*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12785 				}
12786 				if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12787 					pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12788 				}
12789 				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);
12790 			}
12791 			goto done;
12792 		}
12793 	}
12794 
12795 	// Check for loopback exception
12796 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12797 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12798 		allowed_to_receive = FALSE;
12799 		goto done;
12800 	}
12801 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12802 		allowed_to_receive = TRUE;
12803 		goto done;
12804 	}
12805 
12806 	// Actually calculate policy result
12807 	lck_rw_lock_shared(&necp_kernel_policy_lock);
12808 	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);
12809 
12810 	debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12811 	NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12812 
12813 	flowhash = necp_socket_calc_flowhash_locked(&info);
12814 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12815 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12816 	    inp->inp_policyresult.flowhash == flowhash) {
12817 		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12818 		    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12819 		    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12820 		    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12821 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12822 		    (inp->inp_policyresult.results.route_rule_id != 0 &&
12823 		    !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12824 			allowed_to_receive = FALSE;
12825 			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);
12826 		} else {
12827 			if (return_policy_id) {
12828 				*return_policy_id = inp->inp_policyresult.policy_id;
12829 			}
12830 			if (return_route_rule_id) {
12831 				*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12832 			}
12833 			if (return_skip_policy_id) {
12834 				*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12835 			}
12836 			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12837 				pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12838 			}
12839 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12840 				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",
12841 				    inp->inp_socket, info.bound_interface_index, info.protocol,
12842 				    inp->inp_policyresult.policy_id,
12843 				    inp->inp_policyresult.skip_policy_id,
12844 				    inp->inp_policyresult.results.result,
12845 				    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12846 			}
12847 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12848 			    return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12849 		}
12850 		lck_rw_done(&necp_kernel_policy_lock);
12851 		goto done;
12852 	}
12853 
12854 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12855 	size_t route_rule_id_array_count = 0;
12856 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12857 	struct necp_kernel_socket_policy *matched_policy =
12858 	    necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12859 	    &info,
12860 	    &filter_control_unit,
12861 	    route_rule_id_array,
12862 	    &route_rule_id_array_count,
12863 	    MAX_AGGREGATE_ROUTE_RULES,
12864 	    &service_action,
12865 	    &service,
12866 	    netagent_ids,
12867 	    NECP_MAX_NETAGENTS,
12868 	    NULL,
12869 	    0,
12870 	    NULL,
12871 	    0,
12872 	    effective_proc,
12873 	    pf_tag,
12874 	    return_skip_policy_id,
12875 	    inp->inp_route.ro_rt,
12876 	    &drop_dest_policy_result,
12877 	    &drop_all_bypass,
12878 	    &flow_divert_aggregate_unit,
12879 	    so,
12880 	    debug);
12881 
12882 	// Check for loopback exception again after the policy match
12883 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12884 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12885 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12886 		// If policies haven't changed since last evaluation, do not update filter result in order to
12887 		// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12888 		// allow content filter to detect and drop pre-existing flows.
12889 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12890 		    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12891 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12892 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12893 		}
12894 		if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12895 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12896 		}
12897 		allowed_to_receive = TRUE;
12898 		lck_rw_done(&necp_kernel_policy_lock);
12899 
12900 		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);
12901 		goto done;
12902 	}
12903 
12904 	if (info.protocol != IPPROTO_UDP) {
12905 		goto skip_agent_check;
12906 	}
12907 
12908 	// Verify netagents
12909 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12910 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12911 			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);
12912 		}
12913 
12914 		// Mark socket as a drop if required agent is not active
12915 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12916 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12917 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12918 		inp->inp_policyresult.flowhash = flowhash;
12919 		inp->inp_policyresult.results.filter_control_unit = 0;
12920 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12921 		inp->inp_policyresult.results.route_rule_id = 0;
12922 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12923 
12924 		// Unlock
12925 		allowed_to_receive = FALSE;
12926 		lck_rw_done(&necp_kernel_policy_lock);
12927 
12928 		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);
12929 
12930 		goto done;
12931 	}
12932 
12933 skip_agent_check:
12934 
12935 	if (route_rule_id_array_count == 1) {
12936 		route_rule_id = route_rule_id_array[0];
12937 	} else if (route_rule_id_array_count > 1) {
12938 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
12939 	}
12940 
12941 	bool send_local_network_denied_event = false;
12942 	if (matched_policy != NULL) {
12943 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
12944 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
12945 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
12946 			// Trigger the event that we dropped due to a local network policy
12947 			send_local_network_denied_event = true;
12948 		}
12949 
12950 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
12951 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12952 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12953 		    matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
12954 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12955 		    (route_rule_id != 0 &&
12956 		    !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
12957 		    !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
12958 			allowed_to_receive = FALSE;
12959 		} else {
12960 			if (return_policy_id) {
12961 				*return_policy_id = matched_policy->id;
12962 			}
12963 			if (return_route_rule_id) {
12964 				*return_route_rule_id = route_rule_id;
12965 			}
12966 			if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
12967 				pass_flags = matched_policy->result_parameter.pass_flags;
12968 			}
12969 			// If policies haven't changed since last evaluation, do not update filter result in order to
12970 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12971 			// allow content filter to detect and drop pre-existing flows.
12972 			if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12973 			    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12974 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12975 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12976 			}
12977 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12978 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12979 			}
12980 		}
12981 
12982 		if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
12983 			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>",
12984 			    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);
12985 		}
12986 	} else {
12987 		bool drop_all = false;
12988 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
12989 			drop_all = true;
12990 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
12991 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
12992 			}
12993 		}
12994 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
12995 			allowed_to_receive = FALSE;
12996 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
12997 		} else {
12998 			if (return_policy_id) {
12999 				*return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13000 			}
13001 			if (return_route_rule_id) {
13002 				*return_route_rule_id = route_rule_id;
13003 			}
13004 
13005 			// If policies haven't changed since last evaluation, do not update filter result in order to
13006 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
13007 			// allow content filter to detect and drop pre-existing flows.
13008 			if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
13009 			    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
13010 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
13011 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
13012 			}
13013 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
13014 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
13015 			}
13016 			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);
13017 		}
13018 	}
13019 
13020 	if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
13021 		allowed_to_receive = FALSE;
13022 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
13023 	}
13024 
13025 	lck_rw_done(&necp_kernel_policy_lock);
13026 
13027 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
13028 		inp->inp_policyresult.network_denied_notifies++;
13029 #if defined(XNU_TARGET_OS_OSX)
13030 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
13031 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13032 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13033 		    NETPOLICY_NETWORKTYPE_LOCAL);
13034 #else
13035 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
13036 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
13037 		    NETPOLICY_NETWORKTYPE_LOCAL);
13038 #endif
13039 	}
13040 
13041 done:
13042 	if (return_pass_flags != NULL) {
13043 		*return_pass_flags = pass_flags;
13044 	}
13045 
13046 	if (pf_tag != 0 && allowed_to_receive) {
13047 		allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
13048 	}
13049 
13050 	if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
13051 		soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
13052 	}
13053 
13054 	if (socket_proc) {
13055 		proc_rele(socket_proc);
13056 	}
13057 
13058 	return allowed_to_receive;
13059 }
13060 
13061 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)13062 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)
13063 {
13064 	struct sockaddr_in local = {};
13065 	struct sockaddr_in remote = {};
13066 	local.sin_family = remote.sin_family = AF_INET;
13067 	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
13068 	local.sin_port = local_port;
13069 	remote.sin_port = remote_port;
13070 	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
13071 	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
13072 
13073 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13074 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13075 }
13076 
13077 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)13078 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)
13079 {
13080 	struct sockaddr_in6 local = {};
13081 	struct sockaddr_in6 remote = {};
13082 	local.sin6_family = remote.sin6_family = AF_INET6;
13083 	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
13084 	local.sin6_port = local_port;
13085 	remote.sin6_port = remote_port;
13086 	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
13087 	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
13088 
13089 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
13090 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
13091 }
13092 
13093 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)13094 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,
13095     u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
13096 {
13097 	return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
13098 	           return_policy_id, return_route_rule_id,
13099 	           return_skip_policy_id, return_pass_flags);
13100 }
13101 
13102 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)13103 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
13104     necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
13105 {
13106 	if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
13107 		return EINVAL;
13108 	}
13109 
13110 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13111 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
13112 		    policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
13113 	}
13114 
13115 	// Mark ID for Pass and IP Tunnel
13116 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13117 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13118 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
13119 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
13120 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13121 	} else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
13122 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
13123 		// This case is same as a PASS
13124 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
13125 	} else {
13126 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13127 	}
13128 	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
13129 	if (route_rule_id != 0) {
13130 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
13131 	} else {
13132 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
13133 	}
13134 	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);
13135 
13136 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13137 	    skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13138 		// Only mark the skip policy if it is a valid policy ID
13139 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13140 	} else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
13141 	    inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
13142 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
13143 	} else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
13144 		// Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
13145 		// to indicate that NECP_FILTER_UNIT_NO_FILTER was set
13146 		// See necp_get_skip_policy_id_from_packet() and
13147 		// necp_packet_should_skip_filters().
13148 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
13149 	} else {
13150 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13151 	}
13152 
13153 	if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
13154 	    ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
13155 		m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
13156 	}
13157 
13158 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
13159 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
13160 		    packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
13161 	}
13162 
13163 	return 0;
13164 }
13165 
13166 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)13167 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
13168 {
13169 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13170 		return EINVAL;
13171 	}
13172 
13173 	// Mark ID for Pass and IP Tunnel
13174 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13175 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13176 	} else {
13177 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13178 	}
13179 
13180 	return 0;
13181 }
13182 
13183 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)13184 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
13185 {
13186 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13187 		return EINVAL;
13188 	}
13189 
13190 	// Mark ID for Pass and IP Tunnel
13191 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13192 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
13193 	} else {
13194 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13195 	}
13196 
13197 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
13198 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
13199 	} else {
13200 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
13201 	}
13202 	return 0;
13203 }
13204 
13205 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)13206 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
13207 {
13208 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13209 		return EINVAL;
13210 	}
13211 
13212 	// Mark ID for Pass and IP Tunnel
13213 	if (interface != NULL) {
13214 		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
13215 	}
13216 
13217 	return 0;
13218 }
13219 
13220 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)13221 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
13222 {
13223 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13224 		return EINVAL;
13225 	}
13226 
13227 	if (is_keepalive) {
13228 		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
13229 	} else {
13230 		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
13231 	}
13232 
13233 	return 0;
13234 }
13235 
13236 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)13237 necp_get_policy_id_from_packet(struct mbuf *packet)
13238 {
13239 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13240 		return NECP_KERNEL_POLICY_ID_NONE;
13241 	}
13242 
13243 	return packet->m_pkthdr.necp_mtag.necp_policy_id;
13244 }
13245 
13246 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)13247 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
13248 {
13249 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13250 		return NECP_KERNEL_POLICY_ID_NONE;
13251 	}
13252 
13253 	// Check for overloaded value. See necp_mark_packet_from_socket().
13254 	if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
13255 		return NECP_KERNEL_POLICY_ID_NONE;
13256 	}
13257 
13258 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
13259 }
13260 
13261 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)13262 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
13263 {
13264 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13265 		return 0;
13266 	}
13267 
13268 	return m_pftag(packet)->pftag_tag;
13269 }
13270 
13271 bool
necp_packet_should_skip_filters(struct mbuf * packet)13272 necp_packet_should_skip_filters(struct mbuf *packet)
13273 {
13274 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13275 		return false;
13276 	}
13277 
13278 	// Check for overloaded value. See necp_mark_packet_from_socket().
13279 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
13280 }
13281 
13282 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)13283 necp_get_last_interface_index_from_packet(struct mbuf *packet)
13284 {
13285 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13286 		return 0;
13287 	}
13288 
13289 	return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
13290 }
13291 
13292 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)13293 necp_get_route_rule_id_from_packet(struct mbuf *packet)
13294 {
13295 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13296 		return 0;
13297 	}
13298 
13299 	return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
13300 }
13301 
13302 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)13303 necp_get_app_uuid_from_packet(struct mbuf *packet,
13304     uuid_t app_uuid)
13305 {
13306 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13307 		return EINVAL;
13308 	}
13309 
13310 	bool found_mapping = FALSE;
13311 	if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
13312 		lck_rw_lock_shared(&necp_kernel_policy_lock);
13313 		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);
13314 		struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
13315 		if (entry != NULL) {
13316 			uuid_copy(app_uuid, entry->uuid);
13317 			found_mapping = true;
13318 		}
13319 		lck_rw_done(&necp_kernel_policy_lock);
13320 	}
13321 	if (!found_mapping) {
13322 		uuid_clear(app_uuid);
13323 	}
13324 	return 0;
13325 }
13326 
13327 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)13328 necp_get_is_keepalive_from_packet(struct mbuf *packet)
13329 {
13330 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
13331 		return FALSE;
13332 	}
13333 
13334 	return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
13335 }
13336 
13337 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)13338 necp_socket_get_content_filter_control_unit(struct socket *so)
13339 {
13340 	struct inpcb *inp = sotoinpcb(so);
13341 
13342 	if (inp == NULL) {
13343 		return 0;
13344 	}
13345 	return inp->inp_policyresult.results.filter_control_unit;
13346 }
13347 
13348 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)13349 necp_socket_get_policy_gencount(struct socket *so)
13350 {
13351 	struct inpcb *inp = so ? sotoinpcb(so) : NULL;
13352 
13353 	if (inp == NULL) {
13354 		return 0;
13355 	}
13356 	return inp->inp_policyresult.policy_gencount;
13357 }
13358 
13359 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)13360 necp_socket_should_use_flow_divert(struct inpcb *inp)
13361 {
13362 	if (inp == NULL) {
13363 		return FALSE;
13364 	}
13365 
13366 	return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
13367 	       (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
13368 	       (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
13369 }
13370 
13371 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)13372 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
13373 {
13374 	if (inp == NULL) {
13375 		return 0;
13376 	}
13377 
13378 	if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13379 		return 0;
13380 	}
13381 
13382 	if (aggregate_unit != NULL &&
13383 	    inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13384 		*aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13385 	}
13386 
13387 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13388 		return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13389 	}
13390 
13391 	return 0;
13392 }
13393 
13394 bool
necp_socket_should_rescope(struct inpcb * inp)13395 necp_socket_should_rescope(struct inpcb *inp)
13396 {
13397 	if (inp == NULL) {
13398 		return FALSE;
13399 	}
13400 
13401 	return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13402 	       inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13403 }
13404 
13405 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13406 necp_socket_get_rescope_if_index(struct inpcb *inp)
13407 {
13408 	if (inp == NULL) {
13409 		return 0;
13410 	}
13411 
13412 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13413 		return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13414 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13415 		return necp_get_primary_direct_interface_index();
13416 	}
13417 
13418 	return 0;
13419 }
13420 
13421 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13422 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13423 {
13424 	if (inp == NULL) {
13425 		return current_mtu;
13426 	}
13427 
13428 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13429 	    (inp->inp_flags & INP_BOUND_IF) &&
13430 	    inp->inp_boundifp) {
13431 		u_int bound_interface_index = inp->inp_boundifp->if_index;
13432 		u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13433 
13434 		// The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13435 		if (bound_interface_index != tunnel_interface_index) {
13436 			ifnet_t tunnel_interface = NULL;
13437 
13438 			ifnet_head_lock_shared();
13439 			tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13440 			ifnet_head_done();
13441 
13442 			if (tunnel_interface != NULL) {
13443 				u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13444 				u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13445 				const char ipsec_prefix[] = "ipsec";
13446 				if (delegate_tunnel_mtu != 0 &&
13447 				    strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13448 					// For ipsec interfaces, calculate the overhead from the delegate interface
13449 					u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13450 					if (delegate_tunnel_mtu > tunnel_overhead) {
13451 						delegate_tunnel_mtu -= tunnel_overhead;
13452 					}
13453 
13454 					if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13455 						// If the (delegate - overhead) < direct, return (delegate - overhead)
13456 						return delegate_tunnel_mtu;
13457 					} else {
13458 						// Otherwise return direct
13459 						return direct_tunnel_mtu;
13460 					}
13461 				} else {
13462 					// For non-ipsec interfaces, just return the tunnel MTU
13463 					return direct_tunnel_mtu;
13464 				}
13465 			}
13466 		}
13467 	}
13468 
13469 	// By default, just return the MTU passed in
13470 	return current_mtu;
13471 }
13472 
13473 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13474 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13475 {
13476 	if (result_parameter == NULL) {
13477 		return NULL;
13478 	}
13479 
13480 	return ifindex2ifnet[result_parameter->tunnel_interface_index];
13481 }
13482 
13483 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13484 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13485 {
13486 	bool found_match = FALSE;
13487 	bool can_rebind = FALSE;
13488 	ifaddr_t ifa;
13489 	union necp_sockaddr_union address_storage;
13490 
13491 	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13492 		return FALSE;
13493 	}
13494 
13495 	// Match source address against interface addresses
13496 	ifnet_lock_shared(interface);
13497 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13498 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13499 			if (address_storage.sa.sa_family != family) {
13500 				continue;
13501 			}
13502 
13503 			if (family == AF_INET) {
13504 				struct ip *ip = mtod(packet, struct ip *);
13505 				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13506 					found_match = TRUE;
13507 					break;
13508 				}
13509 			} else if (family == AF_INET6) {
13510 				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13511 				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13512 					found_match = TRUE;
13513 					break;
13514 				}
13515 			}
13516 		}
13517 	}
13518 	const uint32_t if_idx = interface->if_index;
13519 	ifnet_lock_done(interface);
13520 
13521 	// If source address matched, attempt to construct a route to the destination address
13522 	if (found_match) {
13523 		ROUTE_RELEASE(new_route);
13524 
13525 		if (family == AF_INET) {
13526 			struct ip *ip = mtod(packet, struct ip *);
13527 			struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13528 			dst4->sin_family = AF_INET;
13529 			dst4->sin_len = sizeof(struct sockaddr_in);
13530 			dst4->sin_addr = ip->ip_dst;
13531 			rtalloc_scoped(new_route, if_idx);
13532 			if (!ROUTE_UNUSABLE(new_route)) {
13533 				can_rebind = TRUE;
13534 			}
13535 		} else if (family == AF_INET6) {
13536 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13537 			struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13538 			dst6->sin6_family = AF_INET6;
13539 			dst6->sin6_len = sizeof(struct sockaddr_in6);
13540 			dst6->sin6_addr = ip6->ip6_dst;
13541 			rtalloc_scoped(new_route, if_idx);
13542 			if (!ROUTE_UNUSABLE(new_route)) {
13543 				can_rebind = TRUE;
13544 			}
13545 		}
13546 	}
13547 
13548 	return can_rebind;
13549 }
13550 
13551 static bool
necp_addr_is_loopback(struct sockaddr * address)13552 necp_addr_is_loopback(struct sockaddr *address)
13553 {
13554 	if (address == NULL) {
13555 		return FALSE;
13556 	}
13557 
13558 	if (address->sa_family == AF_INET) {
13559 		return ntohl(SIN(address)->sin_addr.s_addr) == INADDR_LOOPBACK;
13560 	} else if (address->sa_family == AF_INET6) {
13561 		if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13562 			return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13563 		} else {
13564 			// Match ::ffff:127.0.0.1 loopback address
13565 			in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13566 			return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13567 		}
13568 	}
13569 
13570 	return FALSE;
13571 }
13572 
13573 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)13574 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13575 {
13576 	// Note: This function only checks for the loopback addresses.
13577 	// In the future, we may want to expand to also allow any traffic
13578 	// going through the loopback interface, but until then, this
13579 	// check is cheaper.
13580 
13581 	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13582 		return TRUE;
13583 	}
13584 
13585 	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13586 		return TRUE;
13587 	}
13588 
13589 	if (inp != NULL) {
13590 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13591 			return TRUE;
13592 		}
13593 		if (inp->inp_vflag & INP_IPV4) {
13594 			if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
13595 			    ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
13596 				return TRUE;
13597 			}
13598 		} else if (inp->inp_vflag & INP_IPV6) {
13599 			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13600 			    IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13601 				return TRUE;
13602 			}
13603 		}
13604 	} else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13605 		return TRUE;
13606 	}
13607 
13608 	if (packet != NULL) {
13609 		struct ip *ip = mtod(packet, struct ip *);
13610 		if (ip->ip_v == 4) {
13611 			if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
13612 				return TRUE;
13613 			}
13614 			if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
13615 				return TRUE;
13616 			}
13617 		} else if (ip->ip_v == 6) {
13618 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13619 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13620 				return TRUE;
13621 			}
13622 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13623 				return TRUE;
13624 			}
13625 		}
13626 	}
13627 
13628 	return FALSE;
13629 }
13630 
13631 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13632 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13633 {
13634 	if (inp != NULL) {
13635 		if (!(inp->inp_vflag & INP_IPV6)) {
13636 			return false;
13637 		}
13638 		if (INP_INTCOPROC_ALLOWED(inp)) {
13639 			return true;
13640 		}
13641 		if ((inp->inp_flags & INP_BOUND_IF) &&
13642 		    IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13643 			return true;
13644 		}
13645 		return false;
13646 	}
13647 	if (packet != NULL) {
13648 		struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13649 		struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13650 		if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13651 		    NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13652 			return true;
13653 		}
13654 	}
13655 
13656 	return false;
13657 }
13658 
13659 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13660 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13661 {
13662 	char dest_str[MAX_IPv6_STR_LEN];
13663 
13664 	if (necp_drop_dest_debug > 0) {
13665 		if (sau->sa.sa_family == AF_INET) {
13666 			(void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13667 		} else if (sau->sa.sa_family == AF_INET6) {
13668 			(void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13669 		} else {
13670 			dest_str[0] = 0;
13671 		}
13672 	}
13673 	for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13674 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13675 		struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13676 
13677 		if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13678 			if (necp_drop_dest_debug > 0) {
13679 				char subnet_str[MAX_IPv6_STR_LEN];
13680 				struct proc *p = current_proc();
13681 				pid_t pid = proc_pid(p);
13682 
13683 				if (sau->sa.sa_family == AF_INET) {
13684 					(void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13685 					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);
13686 				} else if (sau->sa.sa_family == AF_INET6) {
13687 					(void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13688 					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);
13689 				}
13690 			}
13691 			return true;
13692 		}
13693 	}
13694 	if (necp_drop_dest_debug > 1) {
13695 		struct proc *p = current_proc();
13696 		pid_t pid = proc_pid(p);
13697 
13698 		os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13699 	}
13700 	return false;
13701 }
13702 
13703 static int
13704 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13705 {
13706 #pragma unused(arg1, arg2, oidp)
13707 	int changed = 0;
13708 	int error = 0;
13709 	struct necp_drop_dest_policy tmp_drop_dest_policy;
13710 	struct proc *p = current_proc();
13711 	pid_t pid = proc_pid(p);
13712 
13713 	if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13714 	    priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13715 		NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13716 		return EPERM;
13717 	}
13718 	if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13719 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13720 		return EINVAL;
13721 	}
13722 
13723 	memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13724 	error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13725 	if (error != 0) {
13726 		NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13727 		return error;
13728 	}
13729 	if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13730 		return error;
13731 	}
13732 
13733 	//
13734 	// Validate the passed parameters
13735 	//
13736 	if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13737 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13738 		return EINVAL;
13739 	}
13740 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13741 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13742 		struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13743 
13744 		switch (tmp_drop_dest_entry->level) {
13745 		case NECP_SESSION_PRIORITY_UNKNOWN:
13746 			if (tmp_drop_dest_policy.entry_count != 0) {
13747 				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);
13748 				return EINVAL;
13749 			}
13750 			break;
13751 		case NECP_SESSION_PRIORITY_CONTROL:
13752 		case NECP_SESSION_PRIORITY_CONTROL_1:
13753 		case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13754 		case NECP_SESSION_PRIORITY_HIGH:
13755 		case NECP_SESSION_PRIORITY_HIGH_1:
13756 		case NECP_SESSION_PRIORITY_HIGH_2:
13757 		case NECP_SESSION_PRIORITY_HIGH_3:
13758 		case NECP_SESSION_PRIORITY_HIGH_4:
13759 		case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13760 		case NECP_SESSION_PRIORITY_DEFAULT:
13761 		case NECP_SESSION_PRIORITY_LOW:
13762 			if (tmp_drop_dest_policy.entry_count == 0) {
13763 				NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13764 				return EINVAL;
13765 			}
13766 			break;
13767 		default: {
13768 			NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13769 			return EINVAL;
13770 		}
13771 		}
13772 
13773 		switch (npca->address.sa.sa_family) {
13774 		case AF_INET: {
13775 			if (npca->prefix > 32) {
13776 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13777 				return EINVAL;
13778 			}
13779 			if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13780 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13781 				return EINVAL;
13782 			}
13783 			if (npca->address.sin.sin_port != 0) {
13784 				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);
13785 				return EINVAL;
13786 			}
13787 			break;
13788 		}
13789 		case AF_INET6: {
13790 			if (npca->prefix > 128) {
13791 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13792 				return EINVAL;
13793 			}
13794 			if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13795 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13796 				return EINVAL;
13797 			}
13798 			if (npca->address.sin6.sin6_port != 0) {
13799 				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);
13800 				return EINVAL;
13801 			}
13802 			if (npca->address.sin6.sin6_flowinfo != 0) {
13803 				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);
13804 				return EINVAL;
13805 			}
13806 			if (npca->address.sin6.sin6_scope_id != 0) {
13807 				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);
13808 				return EINVAL;
13809 			}
13810 			break;
13811 		}
13812 		default: {
13813 			return EINVAL;
13814 		}
13815 		}
13816 	}
13817 
13818 	//
13819 	// Commit the changed policy
13820 	//
13821 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13822 	memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13823 
13824 	necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13825 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13826 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13827 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13828 
13829 		memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13830 
13831 		necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13832 	}
13833 	lck_rw_done(&necp_kernel_policy_lock);
13834 
13835 	return 0;
13836 }
13837 
13838 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13839 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13840 {
13841 	uint16_t fam = address->sa.sa_family;
13842 	memset(addr_str, 0, MAX_IPv6_STR_LEN);
13843 	if (fam == AF_INET) {
13844 		(void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13845 	} else if (fam == AF_INET6) {
13846 		(void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13847 	}
13848 	return __unsafe_null_terminated_from_indexable(addr_str);
13849 }
13850