xref: /xnu-11215.41.3/bsd/net/necp.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*
2  * Copyright (c) 2013-2023 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 
80 #include <net/sockaddr_utils.h>
81 
82 /*
83  * NECP - Network Extension Control Policy database
84  * ------------------------------------------------
85  * The goal of this module is to allow clients connecting via a
86  * policy file descriptor to create high-level policy sessions, which
87  * are ingested into low-level kernel policies that control and tag
88  * traffic at the application, socket, and IP layers.
89  *
90  * ------------------------------------------------
91  * Sessions
92  * ------------------------------------------------
93  * Each session owns a list of session policies, each of which can
94  * specify any combination of conditions and a single result. Each
95  * session also has a priority level (such as High, Default, or Low)
96  * which is requested by the client. Based on the requested level,
97  * a session order value is assigned to the session, which will be used
98  * to sort kernel policies generated by the session. The session client
99  * can specify the sub-order for each policy it creates which will be
100  * used to further sort the kernel policies.
101  *
102  *  Policy fd --> 1 necp_session --> list of necp_session_policy structs
103  *
104  * ------------------------------------------------
105  * Kernel Policies
106  * ------------------------------------------------
107  * Whenever a session send the Apply command, its policies are ingested
108  * and generate kernel policies. There are two phases of kernel policy
109  * ingestion.
110  *
111  * 1. The session policy is parsed to create kernel policies at the socket
112  *	  and IP layers, when applicable. For example, a policy that requires
113  *    all traffic from App1 to Pass will generate a socket kernel policy to
114  *    match App1 and mark packets with ID1, and also an IP policy to match
115  *    ID1 and let the packet pass. This is handled in necp_apply_policy. The
116  *    resulting kernel policies are added to the global socket and IP layer
117  *    policy lists.
118  *  necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
119  *                                      ||                             ||
120  *                                      \/                             \/
121  *                          necp_kernel_socket_policies   necp_kernel_ip_output_policies
122  *
123  * 2. Once the global lists of kernel policies have been filled out, each
124  *    list is traversed to create optimized sub-lists ("Maps") which are used during
125  *    data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
126  *    which hashes incoming packets based on marked socket-layer policies, and removes
127  *    duplicate or overlapping policies. Socket policies are sent into two maps,
128  *    necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
129  *    The app layer map is used for policy checks coming in from user space, and is one
130  *    list with duplicate and overlapping policies removed. The socket map hashes based
131  *    on app UUID, and removes duplicate and overlapping policies.
132  *  necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
133  *                            |-> necp_kernel_socket_policies_map
134  *
135  *  necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
136  *
137  * ------------------------------------------------
138  * Drop All Level
139  * ------------------------------------------------
140  * The Drop All Level is a sysctl that controls the level at which policies are allowed
141  * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
142  * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
143  * by a session with a priority level better than (numerically less than) the
144  * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
145  * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
146  * session orders to be dropped.
147  */
148 
149 u_int32_t necp_drop_all_order = 0;
150 u_int32_t necp_drop_all_level = 0;
151 
152 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
153 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
154 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
155 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
156 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
157 
158 u_int32_t necp_drop_unentitled_order = 0;
159 #ifdef XNU_TARGET_OS_WATCH
160 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
161 #else // XNU_TARGET_OS_WATCH
162 u_int32_t necp_drop_unentitled_level = 0;
163 #endif // XNU_TARGET_OS_WATCH
164 
165 u_int32_t necp_drop_management_order = 0;
166 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
167 
168 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
169 
170 os_log_t necp_log_handle = NULL;
171 os_log_t necp_data_trace_log_handle = NULL;
172 
173 u_int32_t necp_session_count = 0;
174 
175 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
176     struct necp_session_policy, NET_KT_DEFAULT);
177 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
178     struct necp_kernel_socket_policy, NET_KT_DEFAULT);
179 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
180     struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
181 
182 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do {          \
183 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) {  \
184 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
185 	} else {                                                                                                                                                \
186 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
187 	                if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) {      \
188 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
189 	                        break;                                                                                                                          \
190 	                }                                                                                                                                               \
191 	        }                                                                                                                                                       \
192 	}                                                                                                                                                               \
193 } while (0)
194 
195 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do {      \
196 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) {                                                                                                               \
197 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
198 	} else {                                                                                                                                                \
199 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
200 	                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))) {         \
201 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
202 	                        break;                                                                                                                          \
203 	                }                                                                                                                                               \
204 	        }                                                                                                                                                       \
205 	}                                                                                                                                                               \
206 } while (0)
207 
208 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
209 	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))) {                                                                                                                      \
210 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
211 	} else {                                                                                                                                                \
212 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
213 	                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)))	{ \
214 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
215 	                        break;                                                                                                                          \
216 	                }                                                                                                                                               \
217 	        }                                                                                                                                                       \
218 	}                                                                                                                                                               \
219 } while (0)
220 
221 #define IS_NECP_ROUTE_RULE_DENY(x)     ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
222 
223 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x)     (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
224 
225 #define NECP_KERNEL_CONDITION_ALL_INTERFACES            0x000001
226 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE           0x000002
227 #define NECP_KERNEL_CONDITION_PROTOCOL                          0x000004
228 #define NECP_KERNEL_CONDITION_LOCAL_START                       0x000008
229 #define NECP_KERNEL_CONDITION_LOCAL_END                         0x000010
230 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX                      0x000020
231 #define NECP_KERNEL_CONDITION_REMOTE_START                      0x000040
232 #define NECP_KERNEL_CONDITION_REMOTE_END                        0x000080
233 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX                     0x000100
234 #define NECP_KERNEL_CONDITION_APP_ID                            0x000200
235 #define NECP_KERNEL_CONDITION_REAL_APP_ID                       0x000400
236 #define NECP_KERNEL_CONDITION_DOMAIN                            0x000800
237 #define NECP_KERNEL_CONDITION_ACCOUNT_ID                        0x001000
238 #define NECP_KERNEL_CONDITION_POLICY_ID                         0x002000
239 #define NECP_KERNEL_CONDITION_PID                                       0x004000
240 #define NECP_KERNEL_CONDITION_UID                                       0x008000
241 #define NECP_KERNEL_CONDITION_LAST_INTERFACE            0x010000                        // Only set from packets looping between interfaces
242 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS                     0x020000
243 #define NECP_KERNEL_CONDITION_ENTITLEMENT                       0x040000
244 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT        0x080000
245 #define NECP_KERNEL_CONDITION_AGENT_TYPE                        0x100000
246 #define NECP_KERNEL_CONDITION_HAS_CLIENT                        0x200000
247 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS                    0x400000
248 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS                      0x800000
249 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY                       0x1000000
250 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY                      0x2000000
251 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY                   0x4000000
252 #define NECP_KERNEL_CONDITION_SDK_VERSION                       0x8000000
253 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER                0x10000000
254 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS                0x20000000
255 #define NECP_KERNEL_CONDITION_IS_LOOPBACK                       0x40000000
256 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY       0x80000000
257 #define NECP_KERNEL_CONDITION_SCHEME_PORT                       0x100000000
258 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER                     0x200000000
259 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT              0x400000000
260 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN                      0x800000000
261 #define NECP_KERNEL_CONDITION_REAL_UID                          0x1000000000
262 #define NECP_KERNEL_CONDITION_URL                               0x2000000000
263 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS             0x4000000000
264 
265 #define NECP_MAX_POLICY_RESULT_SIZE                                     512
266 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE                         1024
267 #define NECP_MAX_CONDITIONS_ARRAY_SIZE                          4096
268 #define NECP_MAX_POLICY_LIST_COUNT                                      1024
269 
270 #define NECP_MAX_DOMAIN_FILTER_SIZE                             65536 // Allows room for 100K domains
271 
272 typedef enum {
273 	NECP_BYPASS_TYPE_NONE = 0,
274 	NECP_BYPASS_TYPE_INTCOPROC = 1,
275 	NECP_BYPASS_TYPE_LOOPBACK = 2,
276 	NECP_BYPASS_TYPE_DROP = 3, // Drop now without hitting necp policies
277 } necp_socket_bypass_type_t;
278 
279 // Cap the policy size at the max result + conditions size, with room for extra TLVs
280 #define NECP_MAX_POLICY_SIZE                                            (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
281 
282 struct necp_service_registration {
283 	LIST_ENTRY(necp_service_registration)   session_chain;
284 	LIST_ENTRY(necp_service_registration)   kernel_chain;
285 	u_int32_t                                                               service_id;
286 };
287 
288 struct necp_domain_filter {
289 	LIST_ENTRY(necp_domain_filter) owner_chain;
290 	LIST_ENTRY(necp_domain_filter) chain;
291 	u_int32_t       id;
292 	struct net_bloom_filter *filter;
293 	os_refcnt_t     refcount;
294 };
295 static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
296 
297 struct necp_session {
298 	u_int8_t                                        necp_fd_type;
299 	u_int32_t                                       control_unit;
300 	u_int32_t                                       session_priority; // Descriptive priority rating
301 	u_int32_t                                       session_order;
302 
303 	necp_policy_id                          last_policy_id;
304 
305 	decl_lck_mtx_data(, lock);
306 
307 	bool                                            proc_locked; // Messages must come from proc_uuid
308 	uuid_t                                          proc_uuid;
309 	int                                                     proc_pid;
310 
311 	bool                                            dirty;
312 	LIST_HEAD(_policies, necp_session_policy) policies;
313 
314 	LIST_HEAD(_services, necp_service_registration) services;
315 	struct necp_domain_filter_list domain_filters;
316 
317 	TAILQ_ENTRY(necp_session) chain;
318 };
319 
320 #define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
321 #define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
322 
323 static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
324 
325 struct necp_socket_info {
326 	pid_t pid;
327 	int32_t pid_version;
328 	uid_t uid;
329 	uid_t real_uid;
330 	union necp_sockaddr_union local_addr;
331 	union necp_sockaddr_union remote_addr;
332 	u_int32_t bound_interface_index;
333 	u_int32_t bound_interface_flags;
334 	u_int32_t bound_interface_eflags;
335 	u_int32_t bound_interface_xflags;
336 	u_int32_t traffic_class;
337 	u_int16_t protocol;
338 	u_int16_t scheme_port;
339 	u_int32_t application_id;
340 	u_int32_t real_application_id;
341 	u_int32_t account_id;
342 	u_int32_t drop_order;
343 	u_int32_t client_flags;
344 	char *domain __null_terminated;
345 	char *url __null_terminated;
346 	unsigned is_entitled : 1;
347 	unsigned has_client : 1;
348 	unsigned has_system_signed_result : 1;
349 	unsigned is_platform_binary : 1;
350 	unsigned used_responsible_pid : 1;
351 	unsigned is_loopback : 1;
352 	unsigned real_is_platform_binary : 1;
353 	unsigned is_delegated : 1;
354 	unsigned is_local : 1;
355 	unsigned __pad_bits : 7;
356 };
357 
358 static  LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
359 static  LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
360 static  LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
361     &necp_kernel_policy_mtx_attr);
362 
363 static  LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
364 static  LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
365 
366 os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
367 
368 /*
369  * On modification, invalidate cached lookups by bumping the generation count.
370  * Other calls will need to take the slowpath of taking
371  * the subsystem lock.
372  */
373 static volatile int32_t necp_kernel_socket_policies_gencount;
374 #define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do {                                                     \
375 	if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) {      \
376 	        necp_kernel_socket_policies_gencount = 1;                                                                               \
377 	}                                                                                                                                                               \
378 } while (0)
379 
380 /*
381  * Drop-all Bypass:
382  * Allow priviledged processes to bypass the default drop-all
383  * via entitlement check.  For OSX, since entitlement check is
384  * not supported for configd, configd signing identity is checked
385  * instead.
386  */
387 #define SIGNING_ID_CONFIGD "com.apple.configd"
388 #define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
389 
390 typedef enum {
391 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
392 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
393 	NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
394 } necp_drop_all_bypass_check_result_t;
395 
396 static u_int64_t necp_kernel_application_policies_condition_mask;
397 static size_t necp_kernel_application_policies_count;
398 static u_int64_t necp_kernel_socket_policies_condition_mask;
399 static size_t necp_kernel_socket_policies_count;
400 static size_t necp_kernel_socket_policies_non_app_count;
401 static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
402 #define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
403 #define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
404 static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
405 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
406 static size_t necp_kernel_socket_policies_app_layer_map_count;
407 static struct necp_kernel_socket_policy ** __indexable necp_kernel_socket_policies_app_layer_map;
408 /*
409  * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
410  * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
411  * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
412  *
413  * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
414  */
415 
416 static u_int64_t necp_kernel_ip_output_policies_condition_mask;
417 static size_t necp_kernel_ip_output_policies_count;
418 static size_t necp_kernel_ip_output_policies_non_id_count;
419 static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
420 #define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
421 #define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
422 static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
423 static struct necp_kernel_ip_output_policy ** __indexable necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
424 static struct necp_kernel_socket_policy pass_policy =
425 {
426 	.id = NECP_KERNEL_POLICY_ID_NO_MATCH,
427 	.result = NECP_KERNEL_POLICY_RESULT_PASS,
428 };
429 
430 static struct necp_session *necp_create_session(void);
431 static void necp_delete_session(struct necp_session *session);
432 
433 static necp_policy_id necp_handle_policy_add(struct necp_session *session,
434     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
435 static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
436 
437 #define MAX_RESULT_STRING_LEN 64
438 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);
439 
440 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);
441 static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
442 static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
443 static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
444 static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
445 static void necp_policy_apply_all(struct necp_session *session);
446 
447 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);
448 static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
449 static bool necp_kernel_socket_policies_reprocess(void);
450 static bool necp_kernel_socket_policies_update_uuid_table(void);
451 static inline struct necp_kernel_socket_policy * necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
452     struct necp_socket_info *info,
453     necp_kernel_policy_filter *return_filter,
454     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
455     size_t *return_route_rule_id_array_count,
456     size_t route_rule_id_array_count,
457     necp_kernel_policy_result *return_service_action,
458     necp_kernel_policy_service *return_service,
459     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
460     size_t netagent_array_count,
461     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
462     size_t netagent_use_flags_array_count,
463     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
464     u_int32_t num_required_agent_types,
465     proc_t proc,
466     u_int16_t pf_tag,
467     necp_kernel_policy_id *skip_policy_id,
468     struct rtentry *rt,
469     necp_kernel_policy_result *return_drop_dest_policy_result,
470     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
471     u_int32_t *return_flow_divert_aggregate_unit,
472     struct socket *so,
473     int debug);
474 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);
475 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
476 static bool necp_kernel_ip_output_policies_reprocess(void);
477 
478 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
479 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);
480 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
481 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
482 static bool necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits);
483 static bool necp_addr_is_empty(struct sockaddr *addr);
484 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);
485 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
486 
487 struct necp_uuid_id_mapping {
488 	LIST_ENTRY(necp_uuid_id_mapping) chain;
489 	uuid_t          uuid;
490 	u_int32_t       id;
491 	os_refcnt_t     refcount;
492 	u_int32_t       table_usecount; // Add to UUID policy table count
493 };
494 static size_t necp_num_uuid_app_id_mappings;
495 static bool necp_uuid_app_id_mappings_dirty;
496 #define NECP_UUID_APP_ID_HASH_SIZE 64
497 static u_long necp_uuid_app_id_hash_mask;
498 static u_long necp_uuid_app_id_hash_num_buckets;
499 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
500 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
501 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
502 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
503 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
504 
505 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
506 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
507 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
508 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
509 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
510 
511 struct necp_string_id_mapping {
512 	LIST_ENTRY(necp_string_id_mapping) chain;
513 	char            *string __null_terminated;
514 	necp_app_id     id;
515 	os_refcnt_t     refcount;
516 };
517 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
518 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
519 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain __null_terminated);
520 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
521 
522 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);
523 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
524 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
525 
526 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
527 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
528 
529 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
530 
531 static char * __null_terminated necp_create_trimmed_domain(char * __sized_by(length)string, size_t length);
532 static inline int necp_count_dots(char * __sized_by(length)string, size_t length);
533 
534 static char * __null_terminated necp_copy_string(char * __sized_by(length)string, size_t length);
535 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);
536 
537 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
538 
539 #define MAX_ROUTE_RULE_INTERFACES 10
540 struct necp_route_rule {
541 	LIST_ENTRY(necp_route_rule) chain;
542 	u_int32_t       id;
543 	u_int32_t       netagent_id;
544 	u_int32_t       control_unit;
545 	u_int32_t       match_netagent_id;
546 	u_int32_t       effective_type;
547 	u_int8_t        default_action;
548 	u_int8_t        cellular_action;
549 	u_int8_t        wifi_action;
550 	u_int8_t        wired_action;
551 	u_int8_t        expensive_action;
552 	u_int8_t        constrained_action;
553 	u_int8_t        companion_action;
554 	u_int8_t        vpn_action;
555 	u_int           exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
556 	u_int8_t        exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
557 	os_refcnt_t     refcount;
558 };
559 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
560 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);
561 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
562 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
563 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,
564     u_int32_t route_rule_id, u_int32_t *interface_type_denied);
565 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);
566 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
567 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);
568 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
569 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
570 
571 #define MAX_AGGREGATE_ROUTE_RULES 16
572 struct necp_aggregate_route_rule {
573 	LIST_ENTRY(necp_aggregate_route_rule) chain;
574 	u_int32_t       id;
575 	u_int32_t       rule_ids[MAX_AGGREGATE_ROUTE_RULES];
576 };
577 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
578 static u_int32_t necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids);
579 
580 // Sysctl definitions
581 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
582 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
583 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
584 
585 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
586 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
587 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
588 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
589 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
590 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
591 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
592 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", "");
593 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", "");
594 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", "");
595 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
596 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, "");
597 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
598 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
599 
600 static struct necp_drop_dest_policy necp_drop_dest_policy;
601 static int necp_drop_dest_debug = 0;    // 0: off, 1: match, >1: every evaluation
602 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
603 
604 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
605 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
606     0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
607 
608 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
609 
610 /*
611  * data tracing control -
612  *
613  * necp_data_tracing_level    : 1 for brief trace, 2 for policy details, 3 for condition details
614  * necp_data_tracing_port     : match traffic with specified port
615  * necp_data_tracing_proto    : match traffic with specified protocol
616  * necp_data_tracing_pid      : match traffic with specified pid (only applied at socket level)
617  * necp_data_tracing_ifindex  : match traffic on specified ifindex
618  * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched.  Default is 0 to trace traffic if any specified attributes matched.
619  * data_tracing_session_order     : match policies in the specified session - log traffic that hit these policies
620  * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
621  */
622 static int necp_data_tracing_level = 0;
623 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
624 
625 static int necp_data_tracing_port = 0;
626 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
627 
628 static int necp_data_tracing_proto = 0;
629 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
630 
631 static int necp_data_tracing_pid = 0;
632 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
633 
634 static int necp_data_tracing_ifindex = 0;
635 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
636 
637 static int necp_data_tracing_match_all = 0;
638 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
639 
640 static int necp_data_tracing_session_order = 0;
641 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
642 
643 static int necp_data_tracing_policy_order = 0;
644 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
645 
646 #define NECP_DATA_TRACE_LEVEL_BRIEF     1
647 #define NECP_DATA_TRACE_LEVEL_POLICY    2
648 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
649 #define NECP_DATA_TRACE_LEVEL_DP        4
650 
651 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
652     (pid == necp_data_tracing_pid)
653 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
654     (protocol == necp_data_tracing_proto)
655 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
656     (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
657 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
658     (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
659 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
660 	(ifindex == necp_data_tracing_ifindex)
661 
662 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
663     ((necp_data_tracing_level && \
664 	((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
665 	(necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
666 	(necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
667 	(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)
668 
669 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
670     ((necp_data_tracing_level && \
671 	((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
672 	(!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
673 	(!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
674 	(!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)
675 
676 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
677     (necp_data_tracing_match_all ? \
678 	NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
679 	NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
680 
681 #define NECP_DATA_TRACE_ON(debug) (debug)
682 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
683 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
684 #define NECP_DATA_TRACE_DP_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_CONDITION)
685 
686 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
687 
688 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
689     if (NECP_DATA_TRACE_ON(debug)) { \
690     char laddr_str[MAX_IPv6_STR_LEN]; \
691     char raddr_str[MAX_IPv6_STR_LEN]; \
692     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>", \
693 	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); \
694     }
695 
696 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
697     if (NECP_DATA_TRACE_ON(debug)) { \
698     char laddr_str[MAX_IPv6_STR_LEN]; \
699     char raddr_str[MAX_IPv6_STR_LEN]; \
700     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>", \
701 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); \
702     }
703 
704 #define NECP_DATA_TRACE_LOG_SOCKET_DP(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
705     if (NECP_DATA_TRACE_ON(debug)) { \
706     char laddr_str[MAX_IPv6_STR_LEN]; \
707     char raddr_str[MAX_IPv6_STR_LEN]; \
708     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>", \
709 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); \
710     }
711 
712 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
713     if (NECP_DATA_TRACE_ON(debug)) { \
714     char laddr_str[MAX_IPv6_STR_LEN]; \
715     char raddr_str[MAX_IPv6_STR_LEN]; \
716     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)", \
717 	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]); \
718     }
719 
720 #define NECP_DATA_TRACE_LOG_SOCKET_BRIEF(debug, socket, caller, log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id) \
721     if (NECP_DATA_TRACE_ON(debug)) { \
722     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - <policy_id %d skip_policy_id %d> <cached policy_id %d skip_policy_id %d>", \
723 caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), log_msg, policy_id, skip_policy_id, cached_policy_id, cached_skip_policy_id); \
724     }
725 
726 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
727     if (NECP_DATA_TRACE_ON(debug)) { \
728     char laddr_str[MAX_IPv6_STR_LEN]; \
729     char raddr_str[MAX_IPv6_STR_LEN]; \
730     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>", \
731 	        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)); \
732     }
733 
734 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
735     if (NECP_DATA_TRACE_ON(debug)) { \
736     char laddr_str[MAX_IPv6_STR_LEN]; \
737     char raddr_str[MAX_IPv6_STR_LEN]; \
738     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>", \
739 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); \
740     }
741 
742 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
743     if (NECP_DATA_TRACE_ON(debug)) { \
744     char laddr_str[MAX_IPv6_STR_LEN]; \
745     char raddr_str[MAX_IPv6_STR_LEN]; \
746     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)", \
747 	    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]); \
748     }
749 
750 #define NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, socket, caller, log_msg) \
751     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
752     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)", \
753 	    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); \
754     }
755 
756 #define NECP_DATA_TRACE_LOG_POLICY_IP(debug, caller, log_msg) \
757     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
758     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)", \
759 	        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); \
760     }
761 
762 #define NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
763     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
764     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)>", \
765 	        caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
766     }
767 
768 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
769     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
770     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
771 	    caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
772 	    input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
773     }
774 
775 #define NECP_DATA_TRACE_LOG_CONDITION_IP(debug, caller, negate, name, val, input) \
776     NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
777 
778 #define NECP_DATA_TRACE_LOG_CONDITION_IP_STR(debug, caller, negate, name, val, input) \
779     NECP_DATA_TRACE_LOG_CONDITION_IP_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
780 
781 
782 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
783     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
784     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)>", \
785 	    caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
786     }
787 
788 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val1, val2, val3, input1, input2, input3) \
789     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
790     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
791 	caller, (uint64_t)VM_KERNEL_ADDRPERM(socket), negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
792 	input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
793     }
794 
795 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, caller, negate, name, val, input) \
796     NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, caller, negate, name, val, 0, 0, input, 0, 0)
797 
798 #define NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, caller, negate, name, val, input) \
799     NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
800 
801 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
802     (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
803      addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
804 
805 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
806 	"INVALID",
807 	"PASS",
808 	"SKIP",
809 	"DROP",
810 	"SOCKET_DIVERT",
811 	"SOCKET_FILTER",
812 	"IP_TUNNEL",
813 	"IP_FILTER",
814 	"TRIGGER",
815 	"TRIGGER_IF_NEEDED",
816 	"TRIGGER_SCOPED",
817 	"NO_TRIGGER_SCOPED",
818 	"SOCKET_SCOPED",
819 	"ROUTE_RULES",
820 	"USE_NETAGENT",
821 	"NETAGENT_SCOPED",
822 	"SCOPED_DIRECT",
823 	"ALLOW_UNENTITLED",
824 	"REMOVE_NETAGENT"
825 };
826 
827 
828 #define NECP_DDE_ENTITLEMENT "com.apple.developer.media-device-discovery-extension"
829 
830 static int necp_drop_loopback_count = 0;
831 SYSCTL_INT(_net_necp, OID_AUTO, drop_loopback_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_drop_loopback_count, 0, "");
832 
833 static bool
necp_address_is_local_interface_address(union necp_sockaddr_union * addr)834 necp_address_is_local_interface_address(union necp_sockaddr_union *addr)
835 {
836 	bool is_interface_address = false;
837 	if (addr == NULL) {
838 		return false;
839 	}
840 
841 	// Clean up the address before comparison with interface addresses
842 	// Transform remote_addr into the ifaddr form
843 	// IPv6 Scope IDs are always embedded in the ifaddr list
844 	struct sockaddr_storage remote_address_sanitized;
845 	u_int ifscope = IFSCOPE_NONE;
846 	(void)sa_copy(SA(addr), &remote_address_sanitized, &ifscope);
847 	SIN(&remote_address_sanitized)->sin_port = 0;
848 	if (remote_address_sanitized.ss_family == AF_INET6) {
849 		if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
850 			SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
851 		}
852 	}
853 
854 	// Check if remote address is an interface address
855 	struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
856 	if (ifa != NULL && ifa->ifa_ifp != NULL) {
857 		is_interface_address = true;
858 	}
859 	if (ifa != NULL) {
860 		ifaddr_release(ifa);
861 		ifa = NULL;
862 	}
863 
864 	return is_interface_address;
865 }
866 
867 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, addr, include_local_addresses) \
868     ((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)))
869 
870 // Session order allocation
871 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)872 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
873 {
874 	u_int32_t new_order = 0;
875 
876 	// For now, just allocate 1000 orders for each priority
877 	if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
878 		priority = NECP_SESSION_PRIORITY_DEFAULT;
879 	}
880 
881 	// Use the control unit to decide the offset into the priority list
882 	new_order = (control_unit) + ((priority - 1) * 1000);
883 
884 	return new_order;
885 }
886 
887 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)888 necp_get_first_order_for_priority(u_int32_t priority)
889 {
890 	if (priority == 0) {
891 		return 0;
892 	}
893 	return ((priority - 1) * 1000) + 1;
894 }
895 
896 // Sysctl handler
897 static int
898 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
899 {
900 #pragma unused(arg1, arg2)
901 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
902 	necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
903 	return error;
904 }
905 
906 static int
907 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
908 {
909 #pragma unused(arg1, arg2)
910 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
911 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
912 	return error;
913 }
914 
915 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
916 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)917 _necp_process_drop_order_inner(kauth_cred_t cred)
918 {
919 	if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
920 	    priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
921 		return necp_drop_unentitled_order;
922 	} else {
923 		return 0;
924 	}
925 }
926 
927 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
928 #pragma GCC poison _necp_process_drop_order_inner
929 
930 static int
931 sysctl_handle_necp_management_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_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
936 	return error;
937 }
938 
939 // Session fd
940 
941 static int necp_session_op_close(struct fileglob *, vfs_context_t);
942 
943 static const struct fileops necp_session_fd_ops = {
944 	.fo_type     = DTYPE_NETPOLICY,
945 	.fo_read     = fo_no_read,
946 	.fo_write    = fo_no_write,
947 	.fo_ioctl    = fo_no_ioctl,
948 	.fo_select   = fo_no_select,
949 	.fo_close    = necp_session_op_close,
950 	.fo_drain    = fo_no_drain,
951 	.fo_kqfilter = fo_no_kqfilter,
952 };
953 
954 static inline int
necp_is_platform_binary(proc_t proc)955 necp_is_platform_binary(proc_t proc)
956 {
957 	return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
958 }
959 
960 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)961 necp_check_drop_all_bypass_result(proc_t proc)
962 {
963 	if (proc == NULL) {
964 		proc = current_proc();
965 		if (proc == NULL) {
966 			return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
967 		}
968 	}
969 
970 #if defined(XNU_TARGET_OS_OSX)
971 	const char *signing_id __null_terminated = NULL;
972 	const bool isConfigd = (necp_is_platform_binary(proc) &&
973 	    (signing_id = cs_identity_get(proc)) &&
974 	    (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
975 	    (strcmp(signing_id, SIGNING_ID_CONFIGD) == 0));
976 	if (isConfigd) {
977 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
978 	}
979 #endif
980 
981 	const task_t __single task = proc_task(proc);
982 	if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
983 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
984 	} else {
985 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
986 	}
987 }
988 
989 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)990 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
991 {
992 #pragma unused(uap)
993 	int error = 0;
994 	struct necp_session *session = NULL;
995 	struct fileproc * __single fp = NULL;
996 	int fd = -1;
997 	uid_t uid = kauth_cred_getuid(kauth_cred_get());
998 
999 	if (!necp_is_platform_binary(p)) {
1000 		NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
1001 		error = EACCES;
1002 		goto done;
1003 	}
1004 
1005 	if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
1006 		NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
1007 		error = EACCES;
1008 		goto done;
1009 	}
1010 
1011 	error = falloc(p, &fp, &fd);
1012 	if (error != 0) {
1013 		goto done;
1014 	}
1015 
1016 	session = necp_create_session();
1017 	if (session == NULL) {
1018 		error = ENOMEM;
1019 		goto done;
1020 	}
1021 
1022 	fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
1023 	fp->fp_glob->fg_flag = 0;
1024 	fp->fp_glob->fg_ops = &necp_session_fd_ops;
1025 	fp_set_data(fp, session);
1026 
1027 	proc_fdlock(p);
1028 	procfdtbl_releasefd(p, fd, NULL);
1029 	fp_drop(p, fd, fp, 1);
1030 	proc_fdunlock(p);
1031 
1032 	*retval = fd;
1033 done:
1034 	if (error != 0) {
1035 		if (fp != NULL) {
1036 			fp_free(p, fd, fp);
1037 			fp = NULL;
1038 		}
1039 	}
1040 
1041 	return error;
1042 }
1043 
1044 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)1045 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
1046 {
1047 #pragma unused(ctx)
1048 	struct necp_session *session = (struct necp_session *)fg_get_data(fg);
1049 	fg_set_data(fg, NULL);
1050 
1051 	if (session != NULL) {
1052 		necp_policy_mark_all_for_deletion(session);
1053 		necp_policy_apply_all(session);
1054 		necp_delete_session(session);
1055 		return 0;
1056 	} else {
1057 		return ENOENT;
1058 	}
1059 }
1060 
1061 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)1062 necp_session_find_from_fd(struct proc *p, int fd,
1063     struct fileproc **fpp, struct necp_session **session)
1064 {
1065 	struct fileproc * __single fp = NULL;
1066 	int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
1067 
1068 	if (error == 0) {
1069 		*fpp = fp;
1070 		*session = (struct necp_session *)fp_get_data(fp);
1071 		if ((*session)->necp_fd_type != necp_fd_type_session) {
1072 			// Not a client fd, ignore
1073 			fp_drop(p, fd, fp, 0);
1074 			error = EINVAL;
1075 		}
1076 	}
1077 
1078 	return error;
1079 }
1080 
1081 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1082 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1083 {
1084 	int error = 0;
1085 	u_int8_t * __indexable tlv_buffer = NULL;
1086 
1087 	if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
1088 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1089 		error = EINVAL;
1090 		goto done;
1091 	}
1092 
1093 	if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
1094 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1095 		error = EINVAL;
1096 		goto done;
1097 	}
1098 
1099 	if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
1100 		error = ENOMEM;
1101 		goto done;
1102 	}
1103 
1104 	error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
1105 	if (error != 0) {
1106 		NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1107 		goto done;
1108 	}
1109 
1110 	necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1111 	if (error != 0) {
1112 		NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1113 		goto done;
1114 	}
1115 
1116 	error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1117 	if (error != 0) {
1118 		NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1119 		goto done;
1120 	}
1121 
1122 done:
1123 	if (tlv_buffer != NULL) {
1124 		kfree_data(tlv_buffer, uap->in_buffer_length);
1125 		tlv_buffer = NULL;
1126 	}
1127 	*retval = error;
1128 
1129 	return error;
1130 }
1131 
1132 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1133 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1134 {
1135 	int error = 0;
1136 	u_int8_t * __indexable response = NULL;
1137 
1138 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1139 		NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1140 		error = EINVAL;
1141 		goto done;
1142 	}
1143 
1144 	necp_policy_id policy_id = 0;
1145 	error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1146 	if (error != 0) {
1147 		NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1148 		goto done;
1149 	}
1150 
1151 	struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1152 	if (policy == NULL || policy->pending_deletion) {
1153 		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1154 		error = ENOENT;
1155 		goto done;
1156 	}
1157 
1158 	u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1159 	u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1160 	u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1161 
1162 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1163 		NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1164 		error = EINVAL;
1165 		goto done;
1166 	}
1167 
1168 	if (response_size > NECP_MAX_POLICY_SIZE) {
1169 		NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1170 		error = EINVAL;
1171 		goto done;
1172 	}
1173 
1174 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1175 	if (response == NULL) {
1176 		error = ENOMEM;
1177 		goto done;
1178 	}
1179 
1180 	u_int8_t *cursor = response;
1181 	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1182 	if (result_tlv_size) {
1183 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, (void *)&policy->result, response, response_size);
1184 	}
1185 	if (policy->conditions_size) {
1186 		memcpy(response + (cursor - response), policy->conditions, policy->conditions_size);
1187 	}
1188 
1189 	error = copyout(response, uap->out_buffer, response_size);
1190 	if (error != 0) {
1191 		NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1192 		goto done;
1193 	}
1194 
1195 done:
1196 	if (response != NULL) {
1197 		kfree_data(response, response_size);
1198 		response = NULL;
1199 	}
1200 	*retval = error;
1201 
1202 	return error;
1203 }
1204 
1205 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1206 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1207 {
1208 	int error = 0;
1209 
1210 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1211 		NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1212 		error = EINVAL;
1213 		goto done;
1214 	}
1215 
1216 	necp_policy_id delete_policy_id = 0;
1217 	error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1218 	if (error != 0) {
1219 		NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1220 		goto done;
1221 	}
1222 
1223 	struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1224 	if (policy == NULL || policy->pending_deletion) {
1225 		NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1226 		error = ENOENT;
1227 		goto done;
1228 	}
1229 
1230 	necp_policy_mark_for_deletion(session, policy);
1231 done:
1232 	*retval = error;
1233 	return error;
1234 }
1235 
1236 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1237 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1238 {
1239 #pragma unused(uap)
1240 	necp_policy_apply_all(session);
1241 	*retval = 0;
1242 	return 0;
1243 }
1244 
1245 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1246 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1247 {
1248 	u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1249 	u_int32_t response_size = 0;
1250 	u_int8_t * __indexable response = NULL;
1251 	int num_policies = 0;
1252 	int cur_policy_index = 0;
1253 	int error = 0;
1254 	struct necp_session_policy *policy;
1255 
1256 	LIST_FOREACH(policy, &session->policies, chain) {
1257 		if (!policy->pending_deletion) {
1258 			num_policies++;
1259 		}
1260 	}
1261 
1262 	if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1263 		NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1264 		error = EINVAL;
1265 		goto done;
1266 	}
1267 
1268 	response_size = num_policies * tlv_size;
1269 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1270 		NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1271 		error = EINVAL;
1272 		goto done;
1273 	}
1274 
1275 	// Create a response with one Policy ID TLV for each policy
1276 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1277 	if (response == NULL) {
1278 		error = ENOMEM;
1279 		goto done;
1280 	}
1281 
1282 	u_int8_t *cursor = response;
1283 	LIST_FOREACH(policy, &session->policies, chain) {
1284 		if (!policy->pending_deletion && cur_policy_index < num_policies) {
1285 			cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1286 			cur_policy_index++;
1287 		}
1288 	}
1289 
1290 	error = copyout(response, uap->out_buffer, response_size);
1291 	if (error != 0) {
1292 		NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1293 		goto done;
1294 	}
1295 
1296 done:
1297 	if (response != NULL) {
1298 		kfree_data(response, response_size);
1299 		response = NULL;
1300 	}
1301 	*retval = error;
1302 
1303 	return error;
1304 }
1305 
1306 
1307 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1308 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1309 {
1310 #pragma unused(uap)
1311 	necp_policy_mark_all_for_deletion(session);
1312 	*retval = 0;
1313 	return 0;
1314 }
1315 
1316 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1317 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1318 {
1319 	int error = 0;
1320 	struct necp_session_policy *policy = NULL;
1321 	struct necp_session_policy *temp_policy = NULL;
1322 
1323 	if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1324 		NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1325 		error = EINVAL;
1326 		goto done;
1327 	}
1328 
1329 	necp_session_priority requested_session_priority = 0;
1330 	error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1331 	if (error != 0) {
1332 		NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1333 		goto done;
1334 	}
1335 
1336 	// Enforce special session priorities with entitlements
1337 	if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1338 	    requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1339 	    requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1340 	    requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1341 		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1342 		if (cred_result != 0) {
1343 			NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1344 			error = EPERM;
1345 			goto done;
1346 		}
1347 	}
1348 
1349 	if (session->session_priority != requested_session_priority) {
1350 		session->session_priority = requested_session_priority;
1351 		session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1352 		session->dirty = TRUE;
1353 
1354 		// Mark all policies as needing updates
1355 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1356 			policy->pending_update = TRUE;
1357 		}
1358 	}
1359 
1360 done:
1361 	*retval = error;
1362 	return error;
1363 }
1364 
1365 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1366 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1367 {
1368 #pragma unused(uap)
1369 	session->proc_locked = TRUE;
1370 	*retval = 0;
1371 	return 0;
1372 }
1373 
1374 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1375 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1376 {
1377 	int error = 0;
1378 	struct necp_service_registration *new_service = NULL;
1379 
1380 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1381 		NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1382 		error = EINVAL;
1383 		goto done;
1384 	}
1385 
1386 	uuid_t service_uuid;
1387 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1388 	if (error != 0) {
1389 		NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1390 		goto done;
1391 	}
1392 
1393 	new_service = kalloc_type(struct necp_service_registration,
1394 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
1395 
1396 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1397 	new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1398 	LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1399 	LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1400 	lck_rw_done(&necp_kernel_policy_lock);
1401 
1402 done:
1403 	*retval = error;
1404 	return error;
1405 }
1406 
1407 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1408 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1409 {
1410 	int error = 0;
1411 	struct necp_service_registration * __single service = NULL;
1412 	struct necp_service_registration *temp_service = NULL;
1413 	struct necp_uuid_id_mapping *mapping = NULL;
1414 
1415 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1416 		NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1417 		error = EINVAL;
1418 		goto done;
1419 	}
1420 
1421 	uuid_t service_uuid;
1422 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1423 	if (error != 0) {
1424 		NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1425 		goto done;
1426 	}
1427 
1428 	// Remove all matching services for this session
1429 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1430 	mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1431 	if (mapping != NULL) {
1432 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1433 			if (service->service_id == mapping->id) {
1434 				LIST_REMOVE(service, session_chain);
1435 				LIST_REMOVE(service, kernel_chain);
1436 				kfree_type(struct necp_service_registration, service);
1437 			}
1438 		}
1439 		necp_remove_uuid_service_id_mapping(service_uuid);
1440 	}
1441 	lck_rw_done(&necp_kernel_policy_lock);
1442 
1443 done:
1444 	*retval = error;
1445 	return error;
1446 }
1447 
1448 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1449 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1450 {
1451 #pragma unused(session)
1452 	int error = 0;
1453 
1454 	if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1455 		NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1456 		error = EINVAL;
1457 		goto done;
1458 	}
1459 
1460 	error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1461 done:
1462 	*retval = error;
1463 	return error;
1464 }
1465 
1466 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1467 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1468 {
1469 	int error = 0;
1470 	struct net_bloom_filter *bloom_filter = NULL;
1471 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1472 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1473 
1474 	if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1475 	    in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1476 	    uap->in_buffer == 0) {
1477 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1478 		error = EINVAL;
1479 		goto done;
1480 	}
1481 
1482 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1483 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1484 		error = EINVAL;
1485 		goto done;
1486 	}
1487 
1488 	bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1489 	if (bloom_filter == NULL) {
1490 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1491 		error = ENOMEM;
1492 		goto done;
1493 	}
1494 
1495 	error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1496 	if (error != 0) {
1497 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1498 		goto done;
1499 	}
1500 
1501 	size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1502 	if (expected_filter_size != in_buffer_length) {
1503 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1504 		error = EINVAL;
1505 		goto done;
1506 	}
1507 
1508 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1509 	u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1510 	lck_rw_done(&necp_kernel_policy_lock);
1511 
1512 	if (filter_id == 0) {
1513 		error = ENOMEM;
1514 	} else {
1515 		// Bloom filter is taken over by the new filter entry, clear the local pointer
1516 		bloom_filter = NULL;
1517 
1518 		error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1519 		if (error != 0) {
1520 			NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1521 			goto done;
1522 		}
1523 	}
1524 
1525 done:
1526 	*retval = error;
1527 	if (error != 0 && bloom_filter != NULL) {
1528 		uint8_t * __single filter_buffer = (uint8_t *)bloom_filter;
1529 		kfree_data(filter_buffer, in_buffer_length);
1530 		bloom_filter = NULL;
1531 	}
1532 	return error;
1533 }
1534 
1535 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1536 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1537 {
1538 	int error = 0;
1539 
1540 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1541 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1542 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1543 		error = EINVAL;
1544 		goto done;
1545 	}
1546 
1547 	u_int32_t filter_id;
1548 	error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1549 	if (error != 0) {
1550 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1551 		goto done;
1552 	}
1553 
1554 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1555 	bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1556 	if (!removed) {
1557 		error = ENOENT;
1558 	}
1559 	lck_rw_done(&necp_kernel_policy_lock);
1560 
1561 done:
1562 	*retval = error;
1563 	return error;
1564 }
1565 
1566 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1567 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1568 {
1569 #pragma unused(uap)
1570 
1571 	struct necp_domain_filter * __single filter = NULL;
1572 	struct necp_domain_filter *temp_filter = NULL;
1573 	LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1574 		if (os_ref_release_locked(&filter->refcount) == 0) {
1575 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1576 			LIST_REMOVE(filter, chain);
1577 			lck_rw_done(&necp_kernel_policy_lock);
1578 			LIST_REMOVE(filter, owner_chain);
1579 			net_bloom_filter_destroy(filter->filter);
1580 			kfree_type(struct necp_domain_filter, filter);
1581 		}
1582 	}
1583 
1584 	*retval = 0;
1585 	return 0;
1586 }
1587 
1588 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1589 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1590 {
1591 	struct fileproc * __single fp;
1592 	int error = 0;
1593 	int return_value = 0;
1594 	struct necp_session * __single session = NULL;
1595 
1596 	error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1597 	if (error != 0) {
1598 		NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1599 		return error;
1600 	}
1601 
1602 	NECP_SESSION_LOCK(session);
1603 
1604 	if (session->proc_locked) {
1605 		// Verify that the calling process is allowed to do actions
1606 		uuid_t proc_uuid;
1607 		proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1608 		if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1609 			error = EPERM;
1610 			goto done;
1611 		}
1612 	} else {
1613 		// If not locked, update the proc_uuid and proc_pid of the session
1614 		proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1615 		session->proc_pid = proc_pid(current_proc());
1616 	}
1617 
1618 	u_int32_t action = uap->action;
1619 	switch (action) {
1620 	case NECP_SESSION_ACTION_POLICY_ADD: {
1621 		return_value = necp_session_add_policy(session, uap, retval);
1622 		break;
1623 	}
1624 	case NECP_SESSION_ACTION_POLICY_GET: {
1625 		return_value = necp_session_get_policy(session, uap, retval);
1626 		break;
1627 	}
1628 	case NECP_SESSION_ACTION_POLICY_DELETE:  {
1629 		return_value = necp_session_delete_policy(session, uap, retval);
1630 		break;
1631 	}
1632 	case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1633 		return_value = necp_session_apply_all(session, uap, retval);
1634 		break;
1635 	}
1636 	case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1637 		return_value = necp_session_list_all(session, uap, retval);
1638 		break;
1639 	}
1640 	case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1641 		return_value = necp_session_delete_all(session, uap, retval);
1642 		break;
1643 	}
1644 	case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1645 		return_value = necp_session_set_session_priority(session, uap, retval);
1646 		break;
1647 	}
1648 	case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1649 		return_value = necp_session_lock_to_process(session, uap, retval);
1650 		break;
1651 	}
1652 	case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1653 		return_value = necp_session_register_service(session, uap, retval);
1654 		break;
1655 	}
1656 	case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1657 		return_value = necp_session_unregister_service(session, uap, retval);
1658 		break;
1659 	}
1660 	case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1661 		return_value = necp_session_dump_all(session, uap, retval);
1662 		break;
1663 	}
1664 	case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1665 		return_value = necp_session_add_domain_filter(session, uap, retval);
1666 		break;
1667 	}
1668 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1669 		return_value = necp_session_remove_domain_filter(session, uap, retval);
1670 		break;
1671 	}
1672 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1673 		return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1674 		break;
1675 	}
1676 	default: {
1677 		NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1678 		return_value = EINVAL;
1679 		break;
1680 	}
1681 	}
1682 
1683 done:
1684 	NECP_SESSION_UNLOCK(session);
1685 	fp_drop(p, uap->necp_fd, fp, 0);
1686 	return return_value;
1687 }
1688 
1689 struct necp_resolver_key_state {
1690 	const struct ccdigest_info *digest_info;
1691 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1692 };
1693 static struct necp_resolver_key_state s_necp_resolver_key_state;
1694 
1695 static void
necp_generate_resolver_key(void)1696 necp_generate_resolver_key(void)
1697 {
1698 	s_necp_resolver_key_state.digest_info = ccsha256_di();
1699 	cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1700 }
1701 
1702 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)1703 necp_sign_update_context(const struct ccdigest_info *di,
1704     cchmac_ctx_t ctx,
1705     uuid_t client_id,
1706     u_int32_t sign_type,
1707     u_int8_t *data,
1708     size_t data_length)
1709 {
1710 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1711 	const char * __null_terminated context_string = "NECP Resolver Binder";
1712 	uint8_t separator = 0;
1713 	cchmac_update(di, ctx, sizeof(context), context);
1714 	cchmac_update(di, ctx, strlen(context_string), __unsafe_null_terminated_to_indexable(context_string));
1715 	cchmac_update(di, ctx, sizeof(separator), &separator);
1716 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1717 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1718 	cchmac_update(di, ctx, data_length, data);
1719 }
1720 
1721 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)1722 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1723     u_int8_t *data, size_t data_length,
1724     u_int8_t *tag, size_t *out_tag_length)
1725 {
1726 	if (s_necp_resolver_key_state.digest_info == NULL) {
1727 		return EINVAL;
1728 	}
1729 
1730 	if (data == NULL ||
1731 	    data_length == 0 ||
1732 	    tag == NULL ||
1733 	    out_tag_length == NULL) {
1734 		return EINVAL;
1735 	}
1736 
1737 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1738 	if (*out_tag_length < required_tag_length) {
1739 		return ERANGE;
1740 	}
1741 
1742 	*out_tag_length = required_tag_length;
1743 
1744 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1745 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1746 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1747 	    sizeof(s_necp_resolver_key_state.key),
1748 	    s_necp_resolver_key_state.key);
1749 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1750 	    ctx, client_id, sign_type, data, data_length);
1751 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1752 
1753 	return 0;
1754 }
1755 
1756 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)1757 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1758     u_int8_t * __sized_by(data_length)data, size_t data_length,
1759     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1760 {
1761 	if (s_necp_resolver_key_state.digest_info == NULL) {
1762 		return false;
1763 	}
1764 
1765 	if (data == NULL ||
1766 	    data_length == 0 ||
1767 	    tag == NULL ||
1768 	    tag_length == 0) {
1769 		return false;
1770 	}
1771 
1772 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1773 	if (tag_length != required_tag_length) {
1774 		return false;
1775 	}
1776 
1777 	uint8_t actual_tag[required_tag_length];
1778 
1779 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1780 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1781 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1782 	    sizeof(s_necp_resolver_key_state.key),
1783 	    s_necp_resolver_key_state.key);
1784 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1785 	    ctx, client_id, sign_type, data, data_length);
1786 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
1787 
1788 	return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
1789 }
1790 
1791 struct necp_application_id_key_state {
1792 	const struct ccdigest_info *digest_info;
1793 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1794 };
1795 static struct necp_application_id_key_state s_necp_application_id_key_state;
1796 
1797 static void
necp_generate_application_id_key(void)1798 necp_generate_application_id_key(void)
1799 {
1800 	s_necp_application_id_key_state.digest_info = ccsha256_di();
1801 	cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
1802 }
1803 
1804 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)1805 necp_sign_application_id_update_context(const struct ccdigest_info *di,
1806     cchmac_ctx_t ctx,
1807     uuid_t client_id,
1808     u_int32_t sign_type)
1809 {
1810 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1811 	const char context_string[] = "NECP Application ID";
1812 	uint8_t separator = 0;
1813 	cchmac_update(di, ctx, sizeof(context), context);
1814 	cchmac_update(di, ctx, sizeof(context_string) - 1, context_string);
1815 	cchmac_update(di, ctx, sizeof(separator), &separator);
1816 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1817 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1818 }
1819 
1820 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)1821 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
1822     u_int8_t *__counted_by(*out_tag_length)tag, size_t *out_tag_length)
1823 {
1824 	if (s_necp_application_id_key_state.digest_info == NULL) {
1825 		return EINVAL;
1826 	}
1827 
1828 	if (tag == NULL ||
1829 	    out_tag_length == NULL) {
1830 		return EINVAL;
1831 	}
1832 
1833 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1834 	if (*out_tag_length < required_tag_length) {
1835 		return ERANGE;
1836 	}
1837 
1838 	*out_tag_length = required_tag_length;
1839 
1840 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1841 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
1842 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1843 	    sizeof(s_necp_application_id_key_state.key),
1844 	    s_necp_application_id_key_state.key);
1845 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1846 	    ctx, client_id, sign_type);
1847 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
1848 
1849 	return 0;
1850 }
1851 
1852 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)1853 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
1854     u_int8_t * __sized_by(tag_length)tag, size_t tag_length)
1855 {
1856 	if (s_necp_application_id_key_state.digest_info == NULL) {
1857 		return false;
1858 	}
1859 
1860 	if (tag == NULL ||
1861 	    tag_length == 0) {
1862 		return false;
1863 	}
1864 
1865 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1866 	if (tag_length != required_tag_length) {
1867 		return false;
1868 	}
1869 
1870 	uint8_t actual_tag[required_tag_length];
1871 
1872 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1873 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
1874 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1875 	    sizeof(s_necp_application_id_key_state.key),
1876 	    s_necp_application_id_key_state.key);
1877 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1878 	    ctx, client_id, sign_type);
1879 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
1880 
1881 	return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
1882 }
1883 
1884 void
necp_init(void)1885 necp_init(void)
1886 {
1887 	necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
1888 	necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
1889 
1890 	necp_client_init();
1891 
1892 	TAILQ_INIT(&necp_session_list);
1893 
1894 	LIST_INIT(&necp_kernel_socket_policies);
1895 	LIST_INIT(&necp_kernel_ip_output_policies);
1896 
1897 	LIST_INIT(&necp_account_id_list);
1898 
1899 	LIST_INIT(&necp_uuid_service_id_list);
1900 
1901 	LIST_INIT(&necp_registered_service_list);
1902 
1903 	LIST_INIT(&necp_route_rules);
1904 	LIST_INIT(&necp_aggregate_route_rules);
1905 
1906 	LIST_INIT(&necp_global_domain_filter_list);
1907 
1908 	necp_generate_resolver_key();
1909 	necp_generate_application_id_key();
1910 
1911 	necp_uuid_app_id_hashtbl = __unsafe_forge_bidi_indexable(struct necp_uuid_id_mapping_head *,
1912 	    hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask),
1913 	    NECP_UUID_APP_ID_HASH_SIZE * sizeof(void*));
1914 	necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
1915 	necp_num_uuid_app_id_mappings = 0;
1916 	necp_uuid_app_id_mappings_dirty = FALSE;
1917 
1918 	necp_kernel_application_policies_condition_mask = 0;
1919 	necp_kernel_socket_policies_condition_mask = 0;
1920 	necp_kernel_ip_output_policies_condition_mask = 0;
1921 
1922 	necp_kernel_application_policies_count = 0;
1923 	necp_kernel_socket_policies_count = 0;
1924 	necp_kernel_socket_policies_non_app_count = 0;
1925 	necp_kernel_ip_output_policies_count = 0;
1926 	necp_kernel_ip_output_policies_non_id_count = 0;
1927 
1928 	necp_kernel_socket_policies_gencount = 1;
1929 
1930 	memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
1931 	memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
1932 	necp_kernel_socket_policies_app_layer_map = NULL;
1933 
1934 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
1935 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
1936 }
1937 
1938 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)1939 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
1940 {
1941 	struct kev_msg ev_msg;
1942 	memset(&ev_msg, 0, sizeof(ev_msg));
1943 
1944 	ev_msg.vendor_code      = KEV_VENDOR_APPLE;
1945 	ev_msg.kev_class        = KEV_NETWORK_CLASS;
1946 	ev_msg.kev_subclass     = KEV_NECP_SUBCLASS;
1947 	ev_msg.event_code       = KEV_NECP_POLICIES_CHANGED;
1948 
1949 	ev_msg.dv[0].data_ptr    = necp_event_data;
1950 	ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
1951 	ev_msg.dv[1].data_length = 0;
1952 
1953 	kev_post_msg(&ev_msg);
1954 }
1955 
1956 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)1957 necp_buffer_write_tlv_validate(u_int8_t * __indexable cursor, u_int8_t type, u_int32_t length,
1958     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
1959 {
1960 	if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
1961 		NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
1962 		return false;
1963 	}
1964 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1965 	if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
1966 	    (uintptr_t)(next_tlv - buffer) > buffer_length) {     // make sure the next TLV has enough room in buffer
1967 		NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1968 		    length, buffer_length);
1969 		return false;
1970 	}
1971 	return true;
1972 }
1973 
1974 u_int8_t * __counted_by(0)
1975 necp_buffer_write_tlv_if_different(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
1976     u_int32_t length, const void * __sized_by(length)value, bool *updated,
1977     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
1978 {
1979 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
1980 	u_int8_t * cursor = buffer + (cursor_ - buffer);
1981 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1982 		// If we can't fit this TLV, return the current cursor
1983 		return cursor;
1984 	}
1985 	u_int8_t * __indexable next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1986 	if (*updated || *(u_int8_t *)(cursor) != type) {
1987 		*(u_int8_t *)(cursor) = type;
1988 		*updated = TRUE;
1989 	}
1990 	if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
1991 		*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1992 		*updated = TRUE;
1993 	}
1994 	if (length > 0) {
1995 		if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
1996 			memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
1997 			*updated = TRUE;
1998 		}
1999 	}
2000 	return next_tlv;
2001 }
2002 
2003 u_int8_t * __counted_by(0)
2004 necp_buffer_write_tlv(u_int8_t * __counted_by(0)cursor_, u_int8_t type,
2005     u_int32_t length, const void * __sized_by(length)value,
2006     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2007 {
2008 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2009 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2010 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
2011 		return NULL;
2012 	}
2013 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
2014 	*(u_int8_t *)(cursor) = type;
2015 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2016 	if (length > 0) {
2017 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
2018 	}
2019 
2020 	return next_tlv;
2021 }
2022 
2023 static u_int8_t * __counted_by(0)
2024 necp_buffer_write_tlv_with_flags(u_int8_t * __counted_by(0)cursor_, u_int8_t type, u_int8_t flags,
2025     u_int32_t length, const void * __sized_by(length)value,
2026     u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length)
2027 {
2028 	// Use __counted_by(0) for cursor_ to avoid using __indexable in parameter list that causes ABI issue
2029 	// Add one extra byte to 'length' to account for the flags byte for validation.
2030 	u_int8_t * cursor = buffer + (cursor_ - buffer);
2031 	if (!necp_buffer_write_tlv_validate(cursor, type, length + 1, buffer, buffer_length)) {
2032 		return NULL;
2033 	}
2034 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(flags) + sizeof(length) + length);
2035 
2036 	// TLV with flags format: type, length, flags, value (added 1 byte for the leading flags)
2037 	*(u_int8_t *)(cursor) = type;
2038 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
2039 	*(u_int8_t *)(cursor + sizeof(type) + sizeof(length)) = flags;
2040 	if (length > 0) {
2041 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length) + sizeof(flags)), value, length);
2042 	}
2043 
2044 	return next_tlv;
2045 }
2046 
2047 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)2048 necp_buffer_get_tlv_type(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2049 {
2050 	u_int8_t * __indexable type = NULL;
2051 	uint64_t end_offset = 0;
2052 
2053 	if (buffer == NULL ||
2054 	    os_add_overflow(tlv_offset, sizeof(u_int8_t), &end_offset) || buffer_length < end_offset) {
2055 		return 0;
2056 	}
2057 
2058 	type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
2059 	return type ? *type : 0;
2060 }
2061 
2062 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)2063 necp_buffer_get_tlv_length(u_int8_t * __counted_by(buffer_length)buffer, size_t buffer_length, u_int32_t tlv_offset)
2064 {
2065 	u_int32_t * __indexable length = NULL;
2066 	uint64_t end_offset = 0;
2067 
2068 	if (buffer == NULL ||
2069 	    os_add_overflow(tlv_offset, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2070 		return 0;
2071 	}
2072 
2073 	length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
2074 	return length ? *length : 0;
2075 }
2076 
2077 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)2078 __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)
2079 {
2080 	u_int8_t * __indexable value = NULL;
2081 	uint64_t end_offset = 0;
2082 
2083 	if (buffer == NULL) {
2084 		return NULL;
2085 	}
2086 
2087 	u_int32_t length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2088 	if (length == 0) {
2089 		return NULL;
2090 	}
2091 
2092 	if (os_add3_overflow(tlv_offset, length, sizeof(u_int8_t) + sizeof(u_int32_t), &end_offset) || buffer_length < end_offset) {
2093 		return NULL;
2094 	}
2095 
2096 	if (value_size) {
2097 		*value_size = length;
2098 	}
2099 
2100 	value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2101 	return value;
2102 }
2103 
2104 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)2105 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)
2106 {
2107 	if (err != NULL) {
2108 		*err = ENOENT;
2109 	}
2110 	if (offset < 0) {
2111 		if (err != NULL) {
2112 			*err = EINVAL;
2113 		}
2114 		return -1;
2115 	}
2116 	int cursor = offset;
2117 	int next_cursor;
2118 	u_int32_t curr_length;
2119 	u_int8_t curr_type;
2120 
2121 	while (TRUE) {
2122 		if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
2123 			return -1;
2124 		}
2125 		if (!next) {
2126 			curr_type = necp_buffer_get_tlv_type(buffer, buffer_length, cursor);
2127 		} else {
2128 			next = 0;
2129 			curr_type = NECP_TLV_NIL;
2130 		}
2131 		curr_length = necp_buffer_get_tlv_length(buffer, buffer_length, cursor);
2132 		if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
2133 			return -1;
2134 		}
2135 
2136 		next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
2137 		if (curr_type == type) {
2138 			// check if entire TLV fits inside buffer
2139 			if (((u_int32_t)next_cursor) <= buffer_length) {
2140 				if (err != NULL) {
2141 					*err = 0;
2142 				}
2143 				return cursor;
2144 			} else {
2145 				return -1;
2146 			}
2147 		}
2148 		cursor = next_cursor;
2149 	}
2150 }
2151 
2152 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)2153 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)
2154 {
2155 	int cursor = -1;
2156 	if (buffer != NULL) {
2157 		cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2158 	}
2159 	return cursor;
2160 }
2161 
2162 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)2163 necp_get_tlv_at_offset(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2164     int tlv_offset, u_int32_t out_buffer_length, void * __indexable out_buffer, u_int32_t *value_size)
2165 {
2166 	if (buffer == NULL) {
2167 		NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2168 		return EINVAL;
2169 	}
2170 
2171 	// Handle buffer parsing
2172 
2173 	// Validate that buffer has enough room for any TLV
2174 	if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2175 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2176 		    buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2177 		return EINVAL;
2178 	}
2179 
2180 	// Validate that buffer has enough room for this TLV
2181 	u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, buffer_length, tlv_offset);
2182 	if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2183 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2184 		    tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2185 		return EINVAL;
2186 	}
2187 
2188 	if (out_buffer != NULL && out_buffer_length > 0) {
2189 		// Validate that out buffer is large enough for  value
2190 		if (out_buffer_length < tlv_length) {
2191 			NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2192 			    out_buffer_length, tlv_length);
2193 			return EINVAL;
2194 		}
2195 
2196 		// Get value pointer
2197 		u_int8_t * __indexable tlv_value = necp_buffer_get_tlv_value(buffer, buffer_length, tlv_offset, NULL);
2198 		if (tlv_value == NULL) {
2199 			NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2200 			return ENOENT;
2201 		}
2202 
2203 		// Copy value
2204 		memcpy(out_buffer, tlv_value, tlv_length);
2205 	}
2206 
2207 	// Copy out length
2208 	if (value_size != NULL) {
2209 		*value_size = tlv_length;
2210 	}
2211 
2212 	return 0;
2213 }
2214 
2215 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)2216 necp_get_tlv(u_int8_t * __sized_by(buffer_length)buffer, u_int32_t buffer_length,
2217     int offset, u_int8_t type, u_int32_t buff_len, void * __indexable buff, u_int32_t *value_size)
2218 {
2219 	int error = 0;
2220 
2221 	int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2222 	if (tlv_offset < 0) {
2223 		return error;
2224 	}
2225 
2226 	return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2227 }
2228 
2229 // Session Management
2230 
2231 static struct necp_session *
necp_create_session(void)2232 necp_create_session(void)
2233 {
2234 	struct necp_session *new_session = NULL;
2235 
2236 	new_session = kalloc_type(struct necp_session,
2237 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2238 
2239 	new_session->necp_fd_type = necp_fd_type_session;
2240 	new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2241 	new_session->dirty = FALSE;
2242 	LIST_INIT(&new_session->policies);
2243 	LIST_INIT(&new_session->services);
2244 	LIST_INIT(&new_session->domain_filters);
2245 	lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2246 
2247 	// Take the lock
2248 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2249 
2250 	// Find the next available control unit
2251 	u_int32_t control_unit = 1;
2252 	struct necp_session *next_session = NULL;
2253 	TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2254 		if (next_session->control_unit > control_unit) {
2255 			// Found a gap, grab this control unit
2256 			break;
2257 		}
2258 
2259 		// Try the next control unit, loop around
2260 		control_unit = next_session->control_unit + 1;
2261 	}
2262 
2263 	new_session->control_unit = control_unit;
2264 	new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2265 
2266 	if (next_session != NULL) {
2267 		TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2268 	} else {
2269 		TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2270 	}
2271 
2272 	necp_session_count++;
2273 	lck_rw_done(&necp_kernel_policy_lock);
2274 
2275 	if (necp_debug) {
2276 		NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2277 	}
2278 
2279 	return new_session;
2280 }
2281 
2282 static void
necp_delete_session(struct necp_session * session)2283 necp_delete_session(struct necp_session *session)
2284 {
2285 	if (session != NULL) {
2286 		struct necp_service_registration * __single service = NULL;
2287 		struct necp_service_registration *temp_service = NULL;
2288 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2289 			LIST_REMOVE(service, session_chain);
2290 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2291 			LIST_REMOVE(service, kernel_chain);
2292 			lck_rw_done(&necp_kernel_policy_lock);
2293 			kfree_type(struct necp_service_registration, service);
2294 		}
2295 		struct necp_domain_filter * __single filter = NULL;
2296 		struct necp_domain_filter *temp_filter = NULL;
2297 		LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2298 			if (os_ref_release_locked(&filter->refcount) == 0) {
2299 				lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2300 				LIST_REMOVE(filter, chain);
2301 				lck_rw_done(&necp_kernel_policy_lock);
2302 				LIST_REMOVE(filter, owner_chain);
2303 				net_bloom_filter_destroy(filter->filter);
2304 				kfree_type(struct necp_domain_filter, filter);
2305 			}
2306 		}
2307 		if (necp_debug) {
2308 			NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2309 		}
2310 
2311 		lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2312 		TAILQ_REMOVE(&necp_session_list, session, chain);
2313 		necp_session_count--;
2314 		lck_rw_done(&necp_kernel_policy_lock);
2315 
2316 		lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2317 		kfree_type(struct necp_session, session);
2318 	}
2319 }
2320 
2321 // Session Policy Management
2322 
2323 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2324 necp_policy_result_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2325 {
2326 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2327 }
2328 
2329 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2330 necp_policy_result_get_parameter_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2331 {
2332 	return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2333 }
2334 
2335 static inline u_int8_t * __indexable
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2336 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2337 {
2338 	return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2339 }
2340 
2341 static bool
necp_policy_result_requires_route_rules(u_int8_t * __sized_by (length)buffer,u_int32_t length)2342 necp_policy_result_requires_route_rules(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2343 {
2344 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2345 	if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2346 		return TRUE;
2347 	}
2348 	return FALSE;
2349 }
2350 
2351 static inline bool
_necp_address_is_valid(struct sockaddr * address)2352 _necp_address_is_valid(struct sockaddr *address)
2353 {
2354 	if (address->sa_family == AF_INET) {
2355 		return address->sa_len == sizeof(struct sockaddr_in);
2356 	} else if (address->sa_family == AF_INET6) {
2357 		return address->sa_len == sizeof(struct sockaddr_in6);
2358 	} else {
2359 		return FALSE;
2360 	}
2361 }
2362 
2363 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2364 
2365 static bool
necp_policy_result_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,bool * is_pass_skip)2366 necp_policy_result_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, bool *is_pass_skip)
2367 {
2368 	bool validated = FALSE;
2369 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2370 	u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2371 	*is_pass_skip = FALSE;
2372 	switch (type) {
2373 	case NECP_POLICY_RESULT_PASS: {
2374 		*is_pass_skip = TRUE;
2375 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2376 			validated = TRUE;
2377 		}
2378 		break;
2379 	}
2380 	case NECP_POLICY_RESULT_DROP: {
2381 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2382 			validated = TRUE;
2383 		}
2384 		break;
2385 	}
2386 	case NECP_POLICY_RESULT_ROUTE_RULES:
2387 	case NECP_POLICY_RESULT_SCOPED_DIRECT:
2388 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2389 		validated = TRUE;
2390 		break;
2391 	}
2392 	case NECP_POLICY_RESULT_SKIP:
2393 		*is_pass_skip = TRUE;
2394 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
2395 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
2396 		if (parameter_length >= sizeof(u_int32_t)) {
2397 			validated = TRUE;
2398 		}
2399 		break;
2400 	}
2401 	case NECP_POLICY_RESULT_IP_TUNNEL: {
2402 		if (parameter_length > sizeof(u_int32_t)) {
2403 			validated = TRUE;
2404 		}
2405 		break;
2406 	}
2407 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2408 		if (parameter_length > 0) {
2409 			validated = TRUE;
2410 		}
2411 		break;
2412 	}
2413 	case NECP_POLICY_RESULT_USE_NETAGENT:
2414 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2415 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2416 		if (parameter_length >= sizeof(uuid_t)) {
2417 			validated = TRUE;
2418 		}
2419 		break;
2420 	}
2421 	default: {
2422 		validated = FALSE;
2423 		break;
2424 	}
2425 	}
2426 
2427 	if (necp_debug) {
2428 		NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2429 	}
2430 
2431 	return validated;
2432 }
2433 
2434 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2435 necp_policy_condition_get_type_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2436 {
2437 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2438 }
2439 
2440 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2441 necp_policy_condition_get_flags_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2442 {
2443 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2444 }
2445 
2446 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by (length)buffer,u_int32_t length)2447 necp_policy_condition_get_value_length_from_buffer(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2448 {
2449 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2450 }
2451 
2452 static inline u_int8_t * __indexable
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer,u_int32_t length)2453 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * __indexable buffer, u_int32_t length)
2454 {
2455 	return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2456 }
2457 
2458 static inline bool
necp_policy_condition_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2459 necp_policy_condition_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2460 {
2461 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2462 }
2463 
2464 static inline bool
necp_policy_condition_is_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2465 necp_policy_condition_is_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2466 {
2467 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2468 }
2469 
2470 static inline bool
necp_policy_condition_is_real_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2471 necp_policy_condition_is_real_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2472 {
2473 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2474 }
2475 
2476 static inline bool
necp_policy_condition_requires_application(u_int8_t * __sized_by (length)buffer,u_int32_t length)2477 necp_policy_condition_requires_application(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2478 {
2479 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2480 	return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2481 }
2482 
2483 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2484 necp_policy_condition_is_kernel_pid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2485 {
2486 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2487 	u_int32_t condition_length = 0;
2488 	pid_t *condition_value = NULL;
2489 
2490 	if (type == NECP_POLICY_CONDITION_PID) {
2491 		condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2492 		if (condition_length >= sizeof(pid_t)) {
2493 			condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2494 			return *condition_value == 0;
2495 		}
2496 	}
2497 	return false;
2498 }
2499 
2500 static bool
necp_policy_condition_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length,u_int8_t policy_result_type)2501 necp_policy_condition_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length, u_int8_t policy_result_type)
2502 {
2503 	bool validated = FALSE;
2504 	bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2505 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2506 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2507 	    policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2508 	    policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2509 	    policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2510 	    policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2511 	    policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2512 	    policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2513 	u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2514 	u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2515 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2516 	u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2517 	switch (type) {
2518 	case NECP_POLICY_CONDITION_APPLICATION:
2519 	case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2520 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2521 		    condition_length >= sizeof(uuid_t) &&
2522 		    condition_value != NULL &&
2523 		    !uuid_is_null(condition_value)) {
2524 			validated = TRUE;
2525 		}
2526 		break;
2527 	}
2528 	case NECP_POLICY_CONDITION_DOMAIN:
2529 	case NECP_POLICY_CONDITION_ACCOUNT:
2530 	case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2531 	case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2532 	case NECP_POLICY_CONDITION_URL: {
2533 		if (condition_length > 0) {
2534 			validated = TRUE;
2535 		}
2536 		break;
2537 	}
2538 	case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2539 		if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2540 			validated = TRUE;
2541 		}
2542 		break;
2543 	}
2544 	case NECP_POLICY_CONDITION_DEFAULT:
2545 	case NECP_POLICY_CONDITION_ALL_INTERFACES:
2546 	case NECP_POLICY_CONDITION_ENTITLEMENT:
2547 	case NECP_POLICY_CONDITION_HAS_CLIENT:
2548 	case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
2549 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2550 			validated = TRUE;
2551 		}
2552 		break;
2553 	}
2554 	case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2555 		if (condition_length == 0 || condition_length >= sizeof(u_int8_t)) {
2556 			validated = TRUE;
2557 		}
2558 		break;
2559 	}
2560 	case NECP_POLICY_CONDITION_SDK_VERSION: {
2561 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2562 		    condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2563 			validated = TRUE;
2564 		}
2565 		break;
2566 	}
2567 	case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2568 		if (condition_length >= sizeof(u_int16_t)) {
2569 			validated = TRUE;
2570 		}
2571 		break;
2572 	}
2573 	case NECP_POLICY_CONDITION_PID: {
2574 		if (condition_length >= sizeof(pid_t) &&
2575 		    condition_value != NULL) {
2576 			validated = TRUE;
2577 		}
2578 		break;
2579 	}
2580 	case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2581 		if (condition_length >= sizeof(u_int32_t)) {
2582 			validated = TRUE;
2583 		}
2584 		break;
2585 	}
2586 	case NECP_POLICY_CONDITION_UID:
2587 	case NECP_POLICY_CONDITION_REAL_UID: {
2588 		if (condition_length >= sizeof(uid_t)) {
2589 			validated = TRUE;
2590 		}
2591 		break;
2592 	}
2593 	case NECP_POLICY_CONDITION_LOCAL_ADDR:
2594 	case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2595 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2596 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2597 			validated = TRUE;
2598 		}
2599 		break;
2600 	}
2601 	case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2602 	case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2603 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2604 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2605 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2606 			validated = TRUE;
2607 		}
2608 		break;
2609 	}
2610 	case NECP_POLICY_CONDITION_AGENT_TYPE: {
2611 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2612 		    condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2613 			validated = TRUE;
2614 		}
2615 		break;
2616 	}
2617 	case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2618 		if (condition_length >= sizeof(u_int16_t)) {
2619 			validated = TRUE;
2620 		}
2621 		break;
2622 	}
2623 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2624 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2625 		if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2626 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2627 			validated = TRUE;
2628 		}
2629 		break;
2630 	}
2631 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2632 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2633 		if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2634 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2635 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2636 			validated = TRUE;
2637 		}
2638 		break;
2639 	}
2640 	case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2641 		if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2642 			validated = TRUE;
2643 		}
2644 		break;
2645 	}
2646 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2647 		validated = TRUE;
2648 		break;
2649 	}
2650 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2651 		validated = TRUE;
2652 		break;
2653 	}
2654 	case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2655 		if (condition_length >= sizeof(u_int16_t)) {
2656 			u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2657 			if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2658 				validated = TRUE;
2659 			}
2660 		}
2661 		break;
2662 	}
2663 	case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2664 		validated = TRUE;
2665 		break;
2666 	}
2667 	case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
2668 		validated = TRUE;
2669 		break;
2670 	}
2671 	case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2672 		validated = TRUE;
2673 		break;
2674 	}
2675 	case NECP_POLICY_CONDITION_SCHEME_PORT: {
2676 		if (condition_length >= sizeof(u_int16_t)) {
2677 			validated = TRUE;
2678 		}
2679 		break;
2680 	}
2681 	case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2682 		if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2683 			validated = TRUE;
2684 		}
2685 		break;
2686 	}
2687 	default: {
2688 		validated = FALSE;
2689 		break;
2690 	}
2691 	}
2692 
2693 	if (necp_debug) {
2694 		NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2695 	}
2696 
2697 	return validated;
2698 }
2699 
2700 static bool
necp_policy_route_rule_is_default(u_int8_t * __sized_by (length)buffer,u_int32_t length)2701 necp_policy_route_rule_is_default(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2702 {
2703 	return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2704 	       necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2705 }
2706 
2707 static bool
necp_policy_route_rule_is_valid(u_int8_t * __sized_by (length)buffer,u_int32_t length)2708 necp_policy_route_rule_is_valid(u_int8_t * __sized_by(length)buffer, u_int32_t length)
2709 {
2710 	bool validated = FALSE;
2711 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2712 	switch (type) {
2713 	case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2714 		validated = TRUE;
2715 		break;
2716 	}
2717 	case NECP_ROUTE_RULE_DENY_INTERFACE: {
2718 		validated = TRUE;
2719 		break;
2720 	}
2721 	case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2722 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2723 		validated = (rule_length >= sizeof(u_int32_t));
2724 		break;
2725 	}
2726 	case NECP_ROUTE_RULE_QOS_MARKING: {
2727 		validated = TRUE;
2728 		break;
2729 	}
2730 	case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2731 		validated = TRUE;
2732 		break;
2733 	}
2734 	case NECP_ROUTE_RULE_USE_NETAGENT:
2735 	case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2736 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2737 		validated = (rule_length >= sizeof(uuid_t));
2738 		break;
2739 	}
2740 	case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2741 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2742 		validated = (rule_length >= sizeof(uint32_t));
2743 		break;
2744 	}
2745 	default: {
2746 		validated = FALSE;
2747 		break;
2748 	}
2749 	}
2750 
2751 	if (necp_debug) {
2752 		NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2753 	}
2754 
2755 	return validated;
2756 }
2757 
2758 static int
necp_get_posix_error_for_necp_error(int response_error)2759 necp_get_posix_error_for_necp_error(int response_error)
2760 {
2761 	switch (response_error) {
2762 	case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2763 	case NECP_ERROR_INVALID_TLV:
2764 	case NECP_ERROR_POLICY_RESULT_INVALID:
2765 	case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2766 	case NECP_ERROR_ROUTE_RULES_INVALID: {
2767 		return EINVAL;
2768 	}
2769 	case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2770 		return ENOENT;
2771 	}
2772 	case NECP_ERROR_INVALID_PROCESS: {
2773 		return EPERM;
2774 	}
2775 	case NECP_ERROR_INTERNAL:
2776 	default: {
2777 		return ENOMEM;
2778 	}
2779 	}
2780 }
2781 
2782 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)2783 necp_handle_policy_add(struct necp_session *session,
2784     u_int8_t * __sized_by(tlv_buffer_length)tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2785 {
2786 	bool has_default_condition = FALSE;
2787 	bool has_non_default_condition = FALSE;
2788 	bool has_application_condition = FALSE;
2789 	bool has_real_application_condition = FALSE;
2790 	bool requires_application_condition = FALSE;
2791 	bool has_kernel_pid = FALSE;
2792 	bool is_pass_skip = FALSE;
2793 	u_int32_t conditions_array_size = 0;
2794 	u_int8_t *conditions_array = NULL;
2795 	int conditions_array_cursor;
2796 
2797 	bool has_default_route_rule = FALSE;
2798 	u_int32_t route_rules_array_size = 0;
2799 	u_int8_t *route_rules_array = NULL;
2800 	int route_rules_array_cursor;
2801 
2802 	int cursor;
2803 	int error = 0;
2804 	u_int32_t response_error = NECP_ERROR_INTERNAL;
2805 
2806 	necp_policy_order order = 0;
2807 	struct necp_session_policy *policy = NULL;
2808 	u_int32_t policy_result_size = 0;
2809 	u_int8_t *policy_result = NULL;
2810 
2811 	// Read policy order
2812 	error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
2813 	if (error) {
2814 		NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2815 		response_error = NECP_ERROR_INVALID_TLV;
2816 		goto fail;
2817 	}
2818 
2819 	// Read policy result
2820 	cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
2821 	if (error || cursor < 0) {
2822 		NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2823 		response_error = NECP_ERROR_INVALID_TLV;
2824 		goto fail;
2825 	}
2826 
2827 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
2828 	if (error || policy_result_size == 0) {
2829 		NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2830 		response_error = NECP_ERROR_INVALID_TLV;
2831 		goto fail;
2832 	}
2833 	if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2834 		NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2835 		response_error = NECP_ERROR_INVALID_TLV;
2836 		goto fail;
2837 	}
2838 	policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2839 	if (policy_result == NULL) {
2840 		NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2841 		response_error = NECP_ERROR_INTERNAL;
2842 		goto fail;
2843 	}
2844 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
2845 	if (error) {
2846 		NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2847 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2848 		goto fail;
2849 	}
2850 	if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
2851 		NECPLOG0(LOG_ERR, "Failed to validate policy result");
2852 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2853 		goto fail;
2854 	}
2855 
2856 	if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
2857 		// Read route rules conditions
2858 
2859 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2860 		    cursor >= 0;
2861 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2862 			u_int32_t route_rule_size = 0;
2863 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2864 			if (os_add_overflow(route_rules_array_size,
2865 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
2866 			    &route_rules_array_size)) {
2867 				NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
2868 				response_error = NECP_ERROR_INVALID_TLV;
2869 				goto fail;
2870 			}
2871 		}
2872 
2873 		if (route_rules_array_size == 0) {
2874 			NECPLOG0(LOG_ERR, "Failed to get policy route rules");
2875 			response_error = NECP_ERROR_INVALID_TLV;
2876 			goto fail;
2877 		}
2878 		if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
2879 			NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
2880 			response_error = NECP_ERROR_INVALID_TLV;
2881 			goto fail;
2882 		}
2883 		route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
2884 		if (route_rules_array == NULL) {
2885 			NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
2886 			response_error = NECP_ERROR_INTERNAL;
2887 			goto fail;
2888 		}
2889 
2890 		route_rules_array_cursor = 0;
2891 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2892 		    cursor >= 0;
2893 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2894 			u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
2895 			u_int32_t route_rule_size = 0;
2896 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2897 			if (route_rule_size > 0 &&
2898 			    (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
2899 				// Add type
2900 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
2901 				route_rules_array_cursor += sizeof(route_rule_type);
2902 
2903 				// Add length
2904 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
2905 				route_rules_array_cursor += sizeof(route_rule_size);
2906 
2907 				// Add value
2908 				necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
2909 
2910 				if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2911 					NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
2912 					response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2913 					goto fail;
2914 				}
2915 
2916 				if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2917 					if (has_default_route_rule) {
2918 						NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
2919 						response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2920 						goto fail;
2921 					}
2922 					has_default_route_rule = TRUE;
2923 				}
2924 
2925 				route_rules_array_cursor += route_rule_size;
2926 			}
2927 		}
2928 	}
2929 
2930 	// Read policy conditions
2931 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2932 	    cursor >= 0;
2933 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2934 		u_int32_t condition_size = 0;
2935 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2936 
2937 		if (condition_size > 0) {
2938 			if (os_add_overflow(conditions_array_size,
2939 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
2940 			    &conditions_array_size)) {
2941 				NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
2942 				response_error = NECP_ERROR_INVALID_TLV;
2943 				goto fail;
2944 			}
2945 		}
2946 	}
2947 
2948 	if (conditions_array_size == 0) {
2949 		NECPLOG0(LOG_ERR, "Failed to get policy conditions");
2950 		response_error = NECP_ERROR_INVALID_TLV;
2951 		goto fail;
2952 	}
2953 	if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
2954 		NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
2955 		response_error = NECP_ERROR_INVALID_TLV;
2956 		goto fail;
2957 	}
2958 	conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
2959 	if (conditions_array == NULL) {
2960 		NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
2961 		response_error = NECP_ERROR_INTERNAL;
2962 		goto fail;
2963 	}
2964 
2965 	conditions_array_cursor = 0;
2966 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2967 	    cursor >= 0;
2968 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2969 		u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
2970 		u_int32_t condition_size = 0;
2971 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2972 		if (condition_size > 0 &&
2973 		    (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
2974 			// Add type
2975 			memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
2976 			conditions_array_cursor += sizeof(condition_type);
2977 
2978 			// Add length
2979 			memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
2980 			conditions_array_cursor += sizeof(condition_size);
2981 
2982 			// Add value
2983 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
2984 			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))) {
2985 				NECPLOG0(LOG_ERR, "Failed to validate policy condition");
2986 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2987 				goto fail;
2988 			}
2989 
2990 			if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
2991 				has_default_condition = TRUE;
2992 			} else {
2993 				has_non_default_condition = TRUE;
2994 			}
2995 			if (has_default_condition && has_non_default_condition) {
2996 				NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
2997 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2998 				goto fail;
2999 			}
3000 
3001 			if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
3002 				has_application_condition = TRUE;
3003 			}
3004 
3005 			if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
3006 				has_real_application_condition = TRUE;
3007 			}
3008 
3009 			if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
3010 				requires_application_condition = TRUE;
3011 			}
3012 
3013 			if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
3014 				has_kernel_pid = TRUE;
3015 			}
3016 
3017 			conditions_array_cursor += condition_size;
3018 		}
3019 	}
3020 
3021 	if (requires_application_condition && !has_application_condition) {
3022 		NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
3023 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3024 		goto fail;
3025 	}
3026 
3027 	if (has_kernel_pid && !is_pass_skip) {
3028 		NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
3029 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
3030 		goto fail;
3031 	}
3032 
3033 	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) {
3034 		response_error = NECP_ERROR_INTERNAL;
3035 		goto fail;
3036 	}
3037 
3038 	return policy->local_id;
3039 
3040 fail:
3041 	if (policy_result != NULL) {
3042 		kfree_data_sized_by(policy_result, policy_result_size);
3043 	}
3044 	if (conditions_array != NULL) {
3045 		kfree_data_sized_by(conditions_array, conditions_array_size);
3046 	}
3047 	if (route_rules_array != NULL) {
3048 		kfree_data_sized_by(route_rules_array, route_rules_array_size);
3049 	}
3050 
3051 	if (return_error != NULL) {
3052 		*return_error = necp_get_posix_error_for_necp_error(response_error);
3053 	}
3054 	return 0;
3055 }
3056 
3057 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)3058 necp_policy_get_new_id(struct necp_session *session)
3059 {
3060 	session->last_policy_id++;
3061 	if (session->last_policy_id < 1) {
3062 		session->last_policy_id = 1;
3063 	}
3064 
3065 	necp_policy_id newid = session->last_policy_id;
3066 
3067 	if (newid == 0) {
3068 		NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
3069 		return 0;
3070 	}
3071 
3072 	return newid;
3073 }
3074 
3075 /*
3076  *	For the policy dump response this is the structure:
3077  *
3078  *	<NECP_PACKET_HEADER>
3079  *	{
3080  *		type	:	NECP_TLV_POLICY_DUMP
3081  *		length	:	...
3082  *		value	:
3083  *		{
3084  *			{
3085  *				type	:	NECP_TLV_POLICY_ID
3086  *				len		:	...
3087  *				value	:	...
3088  *			}
3089  *			{
3090  *				type	:	NECP_TLV_POLICY_ORDER
3091  *				len		:	...
3092  *				value	:	...
3093  *			}
3094  *			{
3095  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3096  *				len		:	...
3097  *				value	:	...
3098  *			}
3099  *			{
3100  *				type	:	NECP_TLV_POLICY_OWNER
3101  *				len		:	...
3102  *				value	:	...
3103  *			}
3104  *			{
3105  *				type	:	NECP_TLV_POLICY_CONDITION
3106  *				len		:	...
3107  *				value	:
3108  *				{
3109  *					{
3110  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3111  *						len		:	...
3112  *						value	:	...
3113  *					}
3114  *					{
3115  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3116  *						len		:	...
3117  *						value	:	...
3118  *					}
3119  *					...
3120  *				}
3121  *			}
3122  *		}
3123  *	}
3124  *	{
3125  *		type	:	NECP_TLV_POLICY_DUMP
3126  *		length	:	...
3127  *		value	:
3128  *		{
3129  *			{
3130  *				type	:	NECP_TLV_POLICY_ID
3131  *				len		:	...
3132  *				value	:	...
3133  *			}
3134  *			{
3135  *				type	:	NECP_TLV_POLICY_ORDER
3136  *				len		:	...
3137  *				value	:	...
3138  *			}
3139  *			{
3140  *				type	:	NECP_TLV_POLICY_RESULT_STRING
3141  *				len		:	...
3142  *				value	:	...
3143  *			}
3144  *			{
3145  *				type	:	NECP_TLV_POLICY_OWNER
3146  *				len		:	...
3147  *				value	:	...
3148  *			}
3149  *			{
3150  *				type	:	NECP_TLV_POLICY_CONDITION
3151  *				len		:	...
3152  *				value	:
3153  *				{
3154  *					{
3155  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
3156  *						len		:	...
3157  *						value	:	...
3158  *					}
3159  *					{
3160  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3161  *						len		:	...
3162  *						value	:	...
3163  *					}
3164  *					...
3165  *				}
3166  *			}
3167  *		}
3168  *	}
3169  *	...
3170  */
3171 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3172 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3173 {
3174 	struct necp_kernel_socket_policy * __single policy = NULL;
3175 	int policy_i;
3176 	int policy_count = 0;
3177 	u_int8_t * __indexable * __indexable tlv_buffer_pointers = NULL;
3178 	u_int32_t * __indexable tlv_buffer_lengths = NULL;
3179 	u_int32_t total_tlv_len = 0;
3180 	u_int8_t * __indexable result_buf = NULL;
3181 	u_int8_t *result_buf_cursor = result_buf;
3182 	char result_string[MAX_RESULT_STRING_LEN];
3183 	char proc_name_string[MAXCOMLEN + 1];
3184 
3185 	int error_code = 0;
3186 	bool error_occured = false;
3187 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3188 
3189 #define REPORT_ERROR(error) error_occured = true;               \
3190 	                                                response_error = error;         \
3191 	                                                goto done
3192 
3193 #define UNLOCK_AND_REPORT_ERROR(lock, error)    lck_rw_done(lock);      \
3194 	                                                                                        REPORT_ERROR(error)
3195 
3196 	errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3197 	if (cred_result != 0) {
3198 		NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3199 		REPORT_ERROR(NECP_ERROR_INTERNAL);
3200 	}
3201 
3202 	// LOCK
3203 	lck_rw_lock_shared(&necp_kernel_policy_lock);
3204 
3205 	if (necp_debug) {
3206 		NECPLOG0(LOG_DEBUG, "Gathering policies");
3207 	}
3208 
3209 	policy_count = necp_kernel_application_policies_count;
3210 
3211 	tlv_buffer_pointers = kalloc_type(u_int8_t * __indexable, policy_count, M_WAITOK | Z_ZERO);
3212 	if (tlv_buffer_pointers == NULL) {
3213 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3214 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3215 	}
3216 
3217 	tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3218 	if (tlv_buffer_lengths == NULL) {
3219 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3220 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3221 	}
3222 
3223 	for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3224 		policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3225 
3226 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
3227 		memset(proc_name_string, 0, MAXCOMLEN + 1);
3228 
3229 		necp_get_result_description(result_string, policy->result, policy->result_parameter);
3230 		proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3231 
3232 		u_int16_t proc_name_len = strbuflen(proc_name_string, sizeof(proc_name_string) - 1) + 1;
3233 		u_int16_t result_string_len = strbuflen(result_string, sizeof(result_string) - 1) + 1;
3234 
3235 		if (necp_debug) {
3236 			NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3237 		}
3238 
3239 		u_int32_t total_allocated_bytes =       sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) +                                     // NECP_TLV_POLICY_ID
3240 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) +                                                                                              // NECP_TLV_POLICY_ORDER
3241 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) +                                                                              // NECP_TLV_POLICY_SESSION_ORDER
3242 		    sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len +                                                                                                          // NECP_TLV_POLICY_RESULT_STRING
3243 		    sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len +                                                                                                              // NECP_TLV_POLICY_OWNER
3244 		    sizeof(u_int8_t) + sizeof(u_int32_t);                                                                                                                                               // NECP_TLV_POLICY_CONDITION
3245 
3246 		// We now traverse the condition_mask to see how much space we need to allocate
3247 		u_int64_t condition_mask = policy->condition_mask;
3248 		u_int64_t condition_negated_mask = policy->condition_negated_mask;
3249 		u_int8_t num_conditions = 0;
3250 		struct necp_string_id_mapping *account_id_entry = NULL;
3251 		char if_name[IFXNAMSIZ];
3252 		u_int32_t condition_tlv_length = 0;
3253 		memset(if_name, 0, sizeof(if_name));
3254 
3255 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3256 			num_conditions++;
3257 		} else {
3258 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3259 				num_conditions++;
3260 			}
3261 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3262 				num_conditions++;
3263 			}
3264 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3265 				snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3266 				condition_tlv_length += strbuflen(if_name, sizeof(if_name) - 1) + 1;
3267 				num_conditions++;
3268 			}
3269 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3270 				condition_tlv_length += sizeof(policy->cond_protocol);
3271 				num_conditions++;
3272 			}
3273 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3274 				condition_tlv_length += sizeof(uuid_t);
3275 				num_conditions++;
3276 			}
3277 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3278 				condition_tlv_length += sizeof(uuid_t);
3279 				num_conditions++;
3280 			}
3281 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3282 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3283 				u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3284 				condition_tlv_length += domain_len;
3285 				num_conditions++;
3286 			}
3287 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3288 				condition_tlv_length += sizeof(u_int32_t);
3289 				num_conditions++;
3290 			}
3291 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3292 				u_int32_t url_len = strlen(policy->cond_url) + 1;
3293 				condition_tlv_length += url_len;
3294 				num_conditions++;
3295 			}
3296 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3297 				account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3298 				u_int32_t account_id_len = 0;
3299 				if (account_id_entry) {
3300 					account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3301 				}
3302 				condition_tlv_length += account_id_len;
3303 				num_conditions++;
3304 			}
3305 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3306 				condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3307 				num_conditions++;
3308 			}
3309 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3310 				condition_tlv_length += sizeof(uid_t);
3311 				num_conditions++;
3312 			}
3313 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3314 				condition_tlv_length += sizeof(uid_t);
3315 				num_conditions++;
3316 			}
3317 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3318 				condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3319 				num_conditions++;
3320 			}
3321 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3322 				num_conditions++;
3323 			}
3324 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3325 				u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3326 				condition_tlv_length += entitlement_len;
3327 				num_conditions++;
3328 			}
3329 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3330 				num_conditions++;
3331 			}
3332 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3333 				num_conditions++;
3334 			}
3335 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3336 				condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3337 				num_conditions++;
3338 			}
3339 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3340 				condition_tlv_length += sizeof(policy->cond_local_networks_flags);
3341 				num_conditions++;
3342 			}
3343 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3344 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3345 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3346 				} else {
3347 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3348 				}
3349 				num_conditions++;
3350 			}
3351 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3352 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3353 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3354 				} else {
3355 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3356 				}
3357 				num_conditions++;
3358 			}
3359 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3360 				condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3361 				num_conditions++;
3362 			}
3363 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3364 				condition_tlv_length += sizeof(u_int32_t);
3365 				num_conditions++;
3366 			}
3367 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3368 				num_conditions++;
3369 			}
3370 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3371 				num_conditions++;
3372 			}
3373 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3374 				u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3375 				condition_tlv_length += identifier_len;
3376 				num_conditions++;
3377 			}
3378 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3379 				condition_tlv_length += sizeof(u_int16_t);
3380 				num_conditions++;
3381 			}
3382 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3383 				num_conditions++;
3384 			}
3385 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3386 				num_conditions++;
3387 			}
3388 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3389 				condition_tlv_length += sizeof(u_int16_t);
3390 				num_conditions++;
3391 			}
3392 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3393 				condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3394 				num_conditions++;
3395 			}
3396 		}
3397 
3398 		// These are for the condition TLVs (id, length, flags).  The space for "value" is already accounted for above.
3399 		condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(u_int8_t));
3400 		total_allocated_bytes += condition_tlv_length;
3401 
3402 		u_int8_t * __indexable tlv_buffer;
3403 		tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3404 		if (tlv_buffer == NULL) {
3405 			NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3406 			continue;
3407 		}
3408 
3409 		u_int8_t *cursor = tlv_buffer;
3410 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3411 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3412 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3413 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3414 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3415 
3416 #define N_QUICK 256
3417 		u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3418 
3419 		u_int8_t * __indexable cond_buf; // To be used for condition TLVs
3420 		if (condition_tlv_length <= N_QUICK) {
3421 			cond_buf = q_cond_buf;
3422 		} else {
3423 			cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3424 			if (cond_buf == NULL) {
3425 				NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3426 				kfree_data(tlv_buffer, total_allocated_bytes);
3427 				continue;
3428 			}
3429 		}
3430 
3431 		memset(cond_buf, 0, condition_tlv_length);
3432 		u_int8_t *cond_buf_cursor = cond_buf;
3433 		u_int8_t cond_flags = 0;
3434 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3435 			cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, cond_flags, 0, "", cond_buf, condition_tlv_length);
3436 		} else {
3437 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3438 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3439 				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);
3440 			}
3441 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3442 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3443 				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);
3444 			}
3445 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3446 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3447 				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);
3448 			}
3449 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3450 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3451 				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,
3452 				    if_name, cond_buf, condition_tlv_length);
3453 			}
3454 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3455 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3456 				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,
3457 				    cond_buf, condition_tlv_length);
3458 			}
3459 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3460 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3461 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3462 				if (entry != NULL) {
3463 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3464 					    cond_buf, condition_tlv_length);
3465 				}
3466 			}
3467 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3468 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3469 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3470 				if (entry != NULL) {
3471 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, cond_flags, sizeof(entry->uuid), entry->uuid,
3472 					    cond_buf, condition_tlv_length);
3473 				}
3474 			}
3475 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3476 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3477 				cond_flags = ((condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) || (condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3478 				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);
3479 			}
3480 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3481 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3482 				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,
3483 				    cond_buf, condition_tlv_length);
3484 			}
3485 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3486 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_URL) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3487 				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);
3488 			}
3489 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3490 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3491 				if (account_id_entry != NULL) {
3492 					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);
3493 				}
3494 			}
3495 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3496 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3497 				uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3498 				memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3499 				memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3500 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_PID, cond_flags, sizeof(pid_buffer), &pid_buffer,
3501 				    cond_buf, condition_tlv_length);
3502 			}
3503 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3504 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3505 				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,
3506 				    cond_buf, condition_tlv_length);
3507 			}
3508 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3509 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3510 				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,
3511 				    cond_buf, condition_tlv_length);
3512 			}
3513 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3514 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3515 				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,
3516 				    cond_buf, condition_tlv_length);
3517 			}
3518 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3519 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3520 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, cond_flags, 0, "",
3521 				    cond_buf, condition_tlv_length);
3522 			}
3523 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3524 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3525 				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);
3526 			}
3527 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3528 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3529 				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);
3530 			}
3531 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3532 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3533 				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);
3534 			}
3535 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3536 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SDK_VERSION) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3537 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION, cond_flags,
3538 				    sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3539 				    cond_buf, condition_tlv_length);
3540 			}
3541 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3542 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3543 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3544 					struct necp_policy_condition_addr_range range;
3545 					memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3546 					memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3547 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, cond_flags, sizeof(range), &range,
3548 					    cond_buf, condition_tlv_length);
3549 				} else {
3550 					struct necp_policy_condition_addr addr;
3551 					addr.prefix = policy->cond_local_prefix;
3552 					memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3553 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, cond_flags, sizeof(addr), &addr,
3554 					    cond_buf, condition_tlv_length);
3555 				}
3556 			}
3557 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3558 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_START) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3559 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3560 					struct necp_policy_condition_addr_range range;
3561 					memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3562 					memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3563 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, cond_flags, sizeof(range), &range,
3564 					    cond_buf, condition_tlv_length);
3565 				} else {
3566 					struct necp_policy_condition_addr addr;
3567 					addr.prefix = policy->cond_remote_prefix;
3568 					memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3569 					cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, cond_flags, sizeof(addr), &addr,
3570 					    cond_buf, condition_tlv_length);
3571 				}
3572 			}
3573 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3574 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3575 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE, cond_flags,
3576 				    sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3577 				    cond_buf, condition_tlv_length);
3578 			}
3579 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3580 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3581 				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);
3582 			}
3583 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3584 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3585 				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);
3586 			}
3587 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3588 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3589 				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);
3590 			}
3591 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3592 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3593 				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);
3594 			}
3595 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3596 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3597 				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);
3598 			}
3599 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3600 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3601 				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);
3602 			}
3603 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3604 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3605 				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);
3606 			}
3607 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3608 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3609 				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);
3610 			}
3611 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3612 				cond_flags = (condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) ? NECP_POLICY_CONDITION_FLAGS_NEGATIVE : 0;
3613 				uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3614 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3615 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3616 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3617 				cond_buf_cursor = necp_buffer_write_tlv_with_flags(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, cond_flags, sizeof(flags), &flags,
3618 				    cond_buf, condition_tlv_length);
3619 			}
3620 		}
3621 
3622 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3623 		if (cond_buf != q_cond_buf) {
3624 			kfree_data(cond_buf, condition_tlv_length);
3625 		}
3626 
3627 		tlv_buffer_pointers[policy_i] = tlv_buffer;
3628 		tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3629 
3630 		// This is the length of the TLV for NECP_TLV_POLICY_DUMP
3631 		total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3632 	}
3633 
3634 	// UNLOCK
3635 	lck_rw_done(&necp_kernel_policy_lock);
3636 
3637 	// Copy out
3638 	if (out_buffer != 0) {
3639 		if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3640 			NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3641 			REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3642 		}
3643 
3644 		// Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3645 		result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3646 		if (result_buf == NULL) {
3647 			NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3648 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3649 		}
3650 
3651 		// Add four bytes for total length at the start
3652 		memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3653 
3654 		// Copy the TLVs
3655 		result_buf_cursor = result_buf + sizeof(u_int32_t);
3656 		for (int i = 0; i < policy_count; i++) {
3657 			if (tlv_buffer_pointers[i] != NULL) {
3658 				result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3659 				    result_buf, total_tlv_len + sizeof(u_int32_t));
3660 			}
3661 		}
3662 
3663 		int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3664 		if (copy_error) {
3665 			NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3666 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3667 		}
3668 	}
3669 
3670 done:
3671 
3672 	if (error_occured) {
3673 		error_code = necp_get_posix_error_for_necp_error(response_error);
3674 	}
3675 
3676 	if (result_buf != NULL) {
3677 		kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3678 	}
3679 
3680 	if (tlv_buffer_pointers != NULL) {
3681 		for (int i = 0; i < policy_count; i++) {
3682 			if (tlv_buffer_pointers[i] != NULL) {
3683 				kfree_data_addr(tlv_buffer_pointers[i]);
3684 				tlv_buffer_pointers[i] = NULL;
3685 			}
3686 		}
3687 		kfree_type(u_int8_t * __indexable, policy_count, tlv_buffer_pointers);
3688 	}
3689 
3690 	if (tlv_buffer_lengths != NULL) {
3691 		kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3692 	}
3693 #undef N_QUICK
3694 #undef RESET_COND_BUF
3695 #undef REPORT_ERROR
3696 #undef UNLOCK_AND_REPORT_ERROR
3697 
3698 	return error_code;
3699 }
3700 
3701 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)3702 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)
3703 {
3704 	struct necp_session_policy *new_policy = NULL;
3705 	struct necp_session_policy *tmp_policy = NULL;
3706 
3707 	if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3708 		goto done;
3709 	}
3710 
3711 	new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3712 	new_policy->applied = FALSE;
3713 	new_policy->pending_deletion = FALSE;
3714 	new_policy->pending_update = FALSE;
3715 	new_policy->order = order;
3716 	new_policy->conditions = conditions_array;
3717 	new_policy->conditions_size = conditions_array_size;
3718 	new_policy->route_rules = route_rules_array;
3719 	new_policy->route_rules_size = route_rules_array_size;
3720 	new_policy->result = result;
3721 	new_policy->result_size = result_size;
3722 	new_policy->local_id = necp_policy_get_new_id(session);
3723 
3724 	LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3725 
3726 	session->dirty = TRUE;
3727 
3728 	if (necp_debug) {
3729 		NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3730 	}
3731 done:
3732 	return new_policy;
3733 }
3734 
3735 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3736 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3737 {
3738 	struct necp_session_policy *policy = NULL;
3739 	if (policy_id == 0) {
3740 		return NULL;
3741 	}
3742 
3743 	LIST_FOREACH(policy, &session->policies, chain) {
3744 		if (policy->local_id == policy_id) {
3745 			return policy;
3746 		}
3747 	}
3748 
3749 	return NULL;
3750 }
3751 
3752 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3753 necp_policy_get_result_type(struct necp_session_policy *policy)
3754 {
3755 	return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3756 }
3757 
3758 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3759 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3760 {
3761 	return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3762 }
3763 
3764 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)3765 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)
3766 {
3767 	if (policy) {
3768 		u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3769 		if (parameter_buffer_length >= parameter_length) {
3770 			u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3771 			if (parameter && parameter_buffer) {
3772 				memcpy(parameter_buffer, parameter, parameter_length);
3773 				return TRUE;
3774 			}
3775 		}
3776 	}
3777 
3778 	return FALSE;
3779 }
3780 
3781 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)3782 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3783 {
3784 	if (session == NULL || policy == NULL) {
3785 		return FALSE;
3786 	}
3787 
3788 	policy->pending_deletion = TRUE;
3789 	session->dirty = TRUE;
3790 
3791 	if (necp_debug) {
3792 		NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3793 	}
3794 	return TRUE;
3795 }
3796 
3797 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)3798 necp_policy_mark_all_for_deletion(struct necp_session *session)
3799 {
3800 	struct necp_session_policy *policy = NULL;
3801 	struct necp_session_policy *temp_policy = NULL;
3802 
3803 	LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3804 		necp_policy_mark_for_deletion(session, policy);
3805 	}
3806 
3807 	return TRUE;
3808 }
3809 
3810 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)3811 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3812 {
3813 	if (session == NULL || policy == NULL) {
3814 		return FALSE;
3815 	}
3816 
3817 	LIST_REMOVE(policy, chain);
3818 
3819 	if (policy->result) {
3820 		kfree_data_sized_by(policy->result, policy->result_size);
3821 		policy->result = NULL;
3822 		policy->result_size = 0;
3823 	}
3824 
3825 	if (policy->conditions) {
3826 		kfree_data_sized_by(policy->conditions, policy->conditions_size);
3827 		policy->conditions = NULL;
3828 		policy->conditions_size = 0;
3829 	}
3830 
3831 	if (policy->route_rules) {
3832 		kfree_data_sized_by(policy->route_rules, policy->route_rules_size);
3833 		policy->route_rules = NULL;
3834 		policy->route_rules_size = 0;
3835 	}
3836 
3837 	zfree(necp_session_policy_zone, policy);
3838 
3839 	if (necp_debug) {
3840 		NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3841 	}
3842 	return TRUE;
3843 }
3844 
3845 static bool
necp_policy_unapply(struct necp_session_policy * policy)3846 necp_policy_unapply(struct necp_session_policy *policy)
3847 {
3848 	int i = 0;
3849 	if (policy == NULL) {
3850 		return FALSE;
3851 	}
3852 
3853 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3854 
3855 	// Release local uuid mappings
3856 	if (!uuid_is_null(policy->applied_app_uuid)) {
3857 		bool removed_mapping = FALSE;
3858 		if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
3859 			necp_uuid_app_id_mappings_dirty = TRUE;
3860 			necp_num_uuid_app_id_mappings--;
3861 		}
3862 		uuid_clear(policy->applied_app_uuid);
3863 	}
3864 	if (!uuid_is_null(policy->applied_real_app_uuid)) {
3865 		necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
3866 		uuid_clear(policy->applied_real_app_uuid);
3867 	}
3868 	if (!uuid_is_null(policy->applied_result_uuid)) {
3869 		necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
3870 		uuid_clear(policy->applied_result_uuid);
3871 	}
3872 
3873 	// Release string mappings
3874 	if (policy->applied_account != NULL) {
3875 		necp_remove_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(policy->applied_account));
3876 		kfree_data_sized_by(policy->applied_account, policy->applied_account_size);
3877 		policy->applied_account = NULL;
3878 		policy->applied_account_size = 0;
3879 	}
3880 
3881 	// Release route rule
3882 	if (policy->applied_route_rules_id != 0) {
3883 		necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
3884 		policy->applied_route_rules_id = 0;
3885 	}
3886 
3887 	// Remove socket policies
3888 	for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
3889 		if (policy->kernel_socket_policies[i] != 0) {
3890 			necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
3891 			policy->kernel_socket_policies[i] = 0;
3892 		}
3893 	}
3894 
3895 	// Remove IP output policies
3896 	for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
3897 		if (policy->kernel_ip_output_policies[i] != 0) {
3898 			necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
3899 			policy->kernel_ip_output_policies[i] = 0;
3900 		}
3901 	}
3902 
3903 	policy->applied = FALSE;
3904 
3905 	return TRUE;
3906 }
3907 
3908 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION                 0
3909 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION             1
3910 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION                                2
3911 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS                   3
3912 struct necp_policy_result_ip_tunnel {
3913 	u_int32_t secondary_result;
3914 	char interface_name[IFXNAMSIZ];
3915 } __attribute__((__packed__));
3916 
3917 struct necp_policy_result_service {
3918 	uuid_t identifier;
3919 	u_int32_t data;
3920 } __attribute__((__packed__));
3921 
3922 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)3923 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
3924 {
3925 	bool socket_only_conditions = FALSE;
3926 	bool socket_ip_conditions = FALSE;
3927 
3928 	bool socket_layer_non_id_conditions = FALSE;
3929 	bool ip_output_layer_non_id_conditions = FALSE;
3930 	bool ip_output_layer_non_id_only = FALSE;
3931 	bool ip_output_layer_id_condition = FALSE;
3932 	bool ip_output_layer_tunnel_condition_from_id = FALSE;
3933 	bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
3934 	necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
3935 
3936 	u_int64_t master_condition_mask = 0;
3937 	u_int64_t master_condition_negated_mask = 0;
3938 	ifnet_t __single cond_bound_interface = NULL;
3939 	u_int32_t cond_account_id = 0;
3940 	char *cond_domain __null_terminated = NULL;
3941 	u_int32_t cond_domain_filter = 0;
3942 	char *cond_url __null_terminated = NULL;
3943 	char *cond_custom_entitlement __null_terminated = NULL;
3944 	char *cond_signing_identifier __null_terminated = NULL;
3945 	pid_t cond_pid = 0;
3946 	int32_t cond_pid_version = 0;
3947 	uid_t cond_uid = 0;
3948 	uid_t cond_real_uid = 0;
3949 	necp_app_id cond_app_id = 0;
3950 	necp_app_id cond_real_app_id = 0;
3951 	struct necp_policy_condition_tc_range cond_traffic_class;
3952 	cond_traffic_class.start_tc = 0;
3953 	cond_traffic_class.end_tc = 0;
3954 	u_int16_t cond_protocol = 0;
3955 	union necp_sockaddr_union cond_local_start;
3956 	union necp_sockaddr_union cond_local_end;
3957 	u_int8_t cond_local_prefix = 0;
3958 	union necp_sockaddr_union cond_remote_start;
3959 	union necp_sockaddr_union cond_remote_end;
3960 	u_int8_t cond_remote_prefix = 0;
3961 	u_int32_t cond_client_flags = 0;
3962 	u_int8_t cond_local_networks_flags = 0;
3963 	u_int32_t offset = 0;
3964 	u_int8_t ultimate_result = 0;
3965 	u_int32_t secondary_result = 0;
3966 	struct necp_policy_condition_agent_type cond_agent_type = {};
3967 	struct necp_policy_condition_sdk_version cond_sdk_version = {};
3968 	u_int16_t cond_packet_filter_tags = 0;
3969 	u_int16_t cond_scheme_port = 0;
3970 	u_int32_t cond_bound_interface_flags = 0;
3971 	u_int32_t cond_bound_interface_eflags = 0;
3972 	u_int32_t cond_bound_interface_xflags = 0;
3973 	necp_kernel_policy_result_parameter secondary_result_parameter;
3974 	memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
3975 	u_int32_t cond_last_interface_index = 0;
3976 	necp_kernel_policy_result_parameter ultimate_result_parameter;
3977 	memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
3978 
3979 	if (policy == NULL) {
3980 		return FALSE;
3981 	}
3982 
3983 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3984 
3985 	// Process conditions
3986 	while (offset < policy->conditions_size) {
3987 		u_int32_t length = 0;
3988 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(policy->conditions, policy->conditions_size, offset, &length);
3989 
3990 		u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
3991 		u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
3992 		bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
3993 		u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
3994 		u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
3995 		switch (condition_type) {
3996 		case NECP_POLICY_CONDITION_DEFAULT: {
3997 			socket_ip_conditions = TRUE;
3998 			break;
3999 		}
4000 		case NECP_POLICY_CONDITION_ALL_INTERFACES: {
4001 			master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
4002 			socket_ip_conditions = TRUE;
4003 			break;
4004 		}
4005 		case NECP_POLICY_CONDITION_HAS_CLIENT: {
4006 			master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
4007 			socket_only_conditions = TRUE;
4008 			break;
4009 		}
4010 		case NECP_POLICY_CONDITION_ENTITLEMENT: {
4011 			if (condition_length > 0) {
4012 				if (cond_custom_entitlement == NULL) {
4013 					cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
4014 					if (cond_custom_entitlement != NULL) {
4015 						master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
4016 						socket_only_conditions = TRUE;
4017 					}
4018 				}
4019 			} else {
4020 				master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
4021 				socket_only_conditions = TRUE;
4022 			}
4023 			break;
4024 		}
4025 		case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
4026 			master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4027 			if (condition_is_negative) {
4028 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
4029 			}
4030 			socket_only_conditions = TRUE;
4031 			break;
4032 		}
4033 		case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
4034 			master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
4035 			socket_only_conditions = TRUE;
4036 			break;
4037 		}
4038 		case NECP_POLICY_CONDITION_SDK_VERSION: {
4039 			if (condition_length >= sizeof(cond_sdk_version)) {
4040 				master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
4041 				memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
4042 				socket_only_conditions = TRUE;
4043 			}
4044 			break;
4045 		}
4046 		case NECP_POLICY_CONDITION_DOMAIN: {
4047 			// Make sure there is only one such rule
4048 			if (condition_length > 0 && cond_domain == NULL) {
4049 				const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
4050 
4051 				u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
4052 				cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
4053 				if (cond_domain != NULL) {
4054 					master_condition_mask |= mask_value;
4055 					if (condition_is_negative) {
4056 						master_condition_negated_mask |= mask_value;
4057 					}
4058 					socket_only_conditions = TRUE;
4059 				}
4060 			}
4061 			break;
4062 		}
4063 		case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
4064 			// Make sure there is only one such rule
4065 			if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
4066 				memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
4067 				if (cond_domain_filter != 0) {
4068 					master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4069 					if (condition_is_negative) {
4070 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
4071 					}
4072 					socket_only_conditions = TRUE;
4073 				}
4074 			}
4075 			break;
4076 		}
4077 		case NECP_POLICY_CONDITION_URL: {
4078 			// Make sure there is only one such rule
4079 			if (condition_length > 0 && cond_url == NULL) {
4080 				u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
4081 				cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
4082 				if (cond_url != NULL) {
4083 					master_condition_mask |= mask_value;
4084 					if (condition_is_negative) {
4085 						master_condition_negated_mask |= mask_value;
4086 					}
4087 					socket_only_conditions = TRUE;
4088 				}
4089 			}
4090 			break;
4091 		}
4092 		case NECP_POLICY_CONDITION_ACCOUNT: {
4093 			// Make sure there is only one such rule
4094 			if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
4095 				size_t string_buffer_size = 0;
4096 				char * __sized_by(string_buffer_size) string = NULL;
4097 				string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
4098 				string_buffer_size = condition_length + 1;
4099 				if (string != NULL) {
4100 					memcpy(string, condition_value, condition_length);
4101 					string[condition_length] = 0;
4102 					cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, __unsafe_null_terminated_from_indexable(string, &string[condition_length]));
4103 					if (cond_account_id != 0) {
4104 						policy->applied_account = string;         // Save the string in parent policy
4105 						policy->applied_account_size = string_buffer_size;
4106 						master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4107 						if (condition_is_negative) {
4108 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
4109 						}
4110 						socket_only_conditions = TRUE;
4111 					} else {
4112 						kfree_data_sized_by(string, string_buffer_size);
4113 					}
4114 				}
4115 			}
4116 			break;
4117 		}
4118 		case NECP_POLICY_CONDITION_APPLICATION: {
4119 			// Make sure there is only one such rule, because we save the uuid in the policy
4120 			if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
4121 				bool allocated_mapping = FALSE;
4122 				uuid_t application_uuid;
4123 				memcpy(application_uuid, condition_value, sizeof(uuid_t));
4124 				cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
4125 				if (cond_app_id != 0) {
4126 					if (allocated_mapping) {
4127 						necp_uuid_app_id_mappings_dirty = TRUE;
4128 						necp_num_uuid_app_id_mappings++;
4129 					}
4130 					uuid_copy(policy->applied_app_uuid, application_uuid);
4131 					master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
4132 					if (condition_is_negative) {
4133 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
4134 					}
4135 					socket_only_conditions = TRUE;
4136 				}
4137 			}
4138 			break;
4139 		}
4140 		case NECP_POLICY_CONDITION_REAL_APPLICATION: {
4141 			// Make sure there is only one such rule, because we save the uuid in the policy
4142 			if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
4143 				uuid_t real_application_uuid;
4144 				memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
4145 				cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
4146 				if (cond_real_app_id != 0) {
4147 					uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
4148 					master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4149 					if (condition_is_negative) {
4150 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
4151 					}
4152 					socket_only_conditions = TRUE;
4153 				}
4154 			}
4155 			break;
4156 		}
4157 		case NECP_POLICY_CONDITION_PID: {
4158 			if (condition_length >= sizeof(pid_t)) {
4159 				master_condition_mask |= NECP_KERNEL_CONDITION_PID;
4160 				if (condition_is_negative) {
4161 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
4162 				}
4163 				memcpy(&cond_pid, condition_value, sizeof(cond_pid));
4164 				if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
4165 					memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
4166 				}
4167 				socket_only_conditions = TRUE;
4168 			}
4169 			break;
4170 		}
4171 		case NECP_POLICY_CONDITION_UID: {
4172 			if (condition_length >= sizeof(uid_t)) {
4173 				master_condition_mask |= NECP_KERNEL_CONDITION_UID;
4174 				if (condition_is_negative) {
4175 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
4176 				}
4177 				memcpy(&cond_uid, condition_value, sizeof(cond_uid));
4178 				socket_only_conditions = TRUE;
4179 			}
4180 			break;
4181 		}
4182 		case NECP_POLICY_CONDITION_REAL_UID: {
4183 			if (condition_length >= sizeof(uid_t)) {
4184 				master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4185 				if (condition_is_negative) {
4186 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
4187 				}
4188 				memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
4189 				socket_only_conditions = TRUE;
4190 			}
4191 			break;
4192 		}
4193 		case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
4194 			if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
4195 				master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4196 				if (condition_is_negative) {
4197 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
4198 				}
4199 				memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
4200 				socket_only_conditions = TRUE;
4201 			}
4202 			break;
4203 		}
4204 		case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4205 			if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4206 				char interface_name[IFXNAMSIZ];
4207 				memcpy(interface_name, condition_value, condition_length);
4208 				interface_name[condition_length - 1] = 0;         // Make sure the string is NULL terminated
4209 				if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[condition_length - 1]), &cond_bound_interface) == 0) {
4210 					master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4211 					if (condition_is_negative) {
4212 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4213 					}
4214 				}
4215 				socket_ip_conditions = TRUE;
4216 			}
4217 			break;
4218 		}
4219 		case NECP_POLICY_CONDITION_IP_PROTOCOL:
4220 		case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4221 			if (condition_length >= sizeof(u_int16_t)) {
4222 				master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4223 				if (condition_is_negative) {
4224 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4225 				}
4226 				memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4227 				if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4228 					socket_only_conditions = TRUE;
4229 				} else {
4230 					socket_ip_conditions = TRUE;
4231 				}
4232 			}
4233 			break;
4234 		}
4235 		case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4236 			if (condition_is_negative) {
4237 				master_condition_negated_mask |= NECP_POLICY_CONDITION_LOCAL_NETWORKS;
4238 			}
4239 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4240 			socket_ip_conditions = TRUE;
4241 			if (condition_length >= sizeof(u_int8_t)) {
4242 				memcpy(&cond_local_networks_flags, condition_value, sizeof(cond_local_networks_flags));
4243 			}
4244 			break;
4245 		}
4246 		case NECP_POLICY_CONDITION_LOCAL_ADDR:
4247 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4248 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4249 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4250 				break;
4251 			}
4252 
4253 			cond_local_prefix = address_struct->prefix;
4254 			memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4255 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4256 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4257 			if (condition_is_negative) {
4258 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4259 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4260 			}
4261 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4262 				socket_only_conditions = TRUE;
4263 			} else {
4264 				socket_ip_conditions = TRUE;
4265 			}
4266 			break;
4267 		}
4268 		case NECP_POLICY_CONDITION_REMOTE_ADDR:
4269 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4270 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4271 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4272 				break;
4273 			}
4274 
4275 			cond_remote_prefix = address_struct->prefix;
4276 			memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4277 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4278 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4279 			if (condition_is_negative) {
4280 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4281 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4282 			}
4283 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4284 				socket_only_conditions = TRUE;
4285 			} else {
4286 				socket_ip_conditions = TRUE;
4287 			}
4288 			break;
4289 		}
4290 		case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4291 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4292 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4293 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4294 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4295 				break;
4296 			}
4297 
4298 			memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4299 			memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4300 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4301 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4302 			if (condition_is_negative) {
4303 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4304 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4305 			}
4306 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4307 				socket_only_conditions = TRUE;
4308 			} else {
4309 				socket_ip_conditions = TRUE;
4310 			}
4311 			break;
4312 		}
4313 		case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4314 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4315 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4316 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4317 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4318 				break;
4319 			}
4320 
4321 			memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4322 			memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4323 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4324 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4325 			if (condition_is_negative) {
4326 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4327 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4328 			}
4329 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4330 				socket_only_conditions = TRUE;
4331 			} else {
4332 				socket_ip_conditions = TRUE;
4333 			}
4334 			break;
4335 		}
4336 		case NECP_POLICY_CONDITION_AGENT_TYPE: {
4337 			if (condition_length >= sizeof(cond_agent_type)) {
4338 				master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4339 				memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4340 				socket_only_conditions = TRUE;
4341 			}
4342 			break;
4343 		}
4344 		case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4345 			if (condition_is_negative) {
4346 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4347 			}
4348 			master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4349 			socket_only_conditions = TRUE;
4350 			if (condition_length >= sizeof(u_int32_t)) {
4351 				memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4352 			} else {
4353 				// Empty means match on fallback traffic
4354 				cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4355 			}
4356 			break;
4357 		}
4358 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4359 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4360 			if (condition_is_negative) {
4361 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4362 			}
4363 			socket_only_conditions = TRUE;
4364 			break;
4365 		}
4366 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4367 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4368 			if (condition_is_negative) {
4369 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4370 			}
4371 			socket_only_conditions = TRUE;
4372 			break;
4373 		}
4374 		case NECP_POLICY_CONDITION_SCHEME_PORT: {
4375 			master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4376 			if (condition_is_negative) {
4377 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4378 			}
4379 			memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4380 			socket_ip_conditions = TRUE;
4381 			break;
4382 		}
4383 		case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4384 			if (condition_length > 0) {
4385 				if (cond_signing_identifier == NULL) {
4386 					cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4387 					if (cond_signing_identifier != NULL) {
4388 						master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4389 						socket_only_conditions = TRUE;
4390 						if (condition_is_negative) {
4391 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4392 						}
4393 					}
4394 				}
4395 			}
4396 			break;
4397 		}
4398 		case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4399 			if (condition_length >= sizeof(u_int16_t)) {
4400 				master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4401 				if (condition_is_negative) {
4402 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4403 				}
4404 				memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4405 				socket_ip_conditions = TRUE;
4406 			}
4407 			break;
4408 		}
4409 		case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4410 			master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4411 			if (condition_is_negative) {
4412 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4413 			}
4414 			socket_only_conditions = TRUE;
4415 			break;
4416 		}
4417 		case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4418 			master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4419 			if (condition_is_negative) {
4420 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4421 			}
4422 			socket_only_conditions = TRUE;
4423 			break;
4424 		}
4425 		case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4426 			if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4427 				u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4428 				memcpy(&flags, condition_value, sizeof(flags));
4429 				cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4430 				cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4431 				cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4432 				master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4433 				if (condition_is_negative) {
4434 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4435 				}
4436 				socket_ip_conditions = TRUE;
4437 			}
4438 			break;
4439 		}
4440 		default: {
4441 			break;
4442 		}
4443 		}
4444 
4445 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4446 	}
4447 
4448 	// Process result
4449 	ultimate_result = necp_policy_get_result_type(policy);
4450 	switch (ultimate_result) {
4451 	case NECP_POLICY_RESULT_PASS: {
4452 		u_int32_t pass_flags = 0;
4453 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4454 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4455 				ultimate_result_parameter.pass_flags = pass_flags;
4456 			}
4457 		}
4458 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4459 			socket_layer_non_id_conditions = TRUE;
4460 			ip_output_layer_id_condition = TRUE;
4461 		} else if (socket_ip_conditions) {
4462 			socket_layer_non_id_conditions = TRUE;
4463 			ip_output_layer_id_condition = TRUE;
4464 			ip_output_layer_non_id_conditions = TRUE;
4465 		}
4466 		break;
4467 	}
4468 	case NECP_POLICY_RESULT_DROP: {
4469 		u_int32_t drop_flags = 0;
4470 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4471 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4472 				ultimate_result_parameter.drop_flags = drop_flags;
4473 			}
4474 		}
4475 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4476 			socket_layer_non_id_conditions = TRUE;
4477 		} else if (socket_ip_conditions) {
4478 			socket_layer_non_id_conditions = TRUE;
4479 			ip_output_layer_non_id_conditions = TRUE;
4480 			ip_output_layer_non_id_only = TRUE;         // Only apply drop to packets that didn't go through socket layer
4481 		}
4482 		break;
4483 	}
4484 	case NECP_POLICY_RESULT_SKIP: {
4485 		u_int32_t skip_policy_order = 0;
4486 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4487 			ultimate_result_parameter.skip_policy_order = skip_policy_order;
4488 		}
4489 
4490 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4491 			socket_layer_non_id_conditions = TRUE;
4492 			ip_output_layer_id_condition = TRUE;
4493 		} else if (socket_ip_conditions) {
4494 			socket_layer_non_id_conditions = TRUE;
4495 			ip_output_layer_non_id_conditions = TRUE;
4496 		}
4497 		break;
4498 	}
4499 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
4500 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
4501 		u_int32_t control_unit = 0;
4502 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4503 			ultimate_result_parameter.flow_divert_control_unit = control_unit;
4504 		}
4505 		socket_layer_non_id_conditions = TRUE;
4506 		break;
4507 	}
4508 	case NECP_POLICY_RESULT_IP_TUNNEL: {
4509 		struct necp_policy_result_ip_tunnel tunnel_parameters;
4510 		u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4511 		if (tunnel_parameters_length > sizeof(u_int32_t) &&
4512 		    tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4513 		    necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4514 			ifnet_t __single tunnel_interface = NULL;
4515 			tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0;         // Make sure the string is NULL terminated
4516 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(tunnel_parameters.interface_name), &tunnel_interface) == 0) {
4517 				ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4518 				ifnet_release(tunnel_interface);
4519 			}
4520 
4521 			secondary_result = tunnel_parameters.secondary_result;
4522 			if (secondary_result) {
4523 				cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4524 			}
4525 		}
4526 
4527 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4528 			socket_layer_non_id_conditions = TRUE;
4529 			ip_output_layer_id_condition = TRUE;
4530 			if (secondary_result) {
4531 				ip_output_layer_tunnel_condition_from_id = TRUE;
4532 			}
4533 		} else if (socket_ip_conditions) {
4534 			socket_layer_non_id_conditions = TRUE;
4535 			ip_output_layer_id_condition = TRUE;
4536 			ip_output_layer_non_id_conditions = TRUE;
4537 			if (secondary_result) {
4538 				ip_output_layer_tunnel_condition_from_id = TRUE;
4539 				ip_output_layer_tunnel_condition_from_non_id = TRUE;
4540 			}
4541 		}
4542 		break;
4543 	}
4544 	case NECP_POLICY_RESULT_USE_NETAGENT:
4545 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4546 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4547 		uuid_t netagent_uuid;
4548 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4549 			ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4550 			if (ultimate_result_parameter.netagent_id != 0) {
4551 				uuid_copy(policy->applied_result_uuid, netagent_uuid);
4552 				socket_layer_non_id_conditions = TRUE;
4553 			}
4554 		}
4555 		break;
4556 	}
4557 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4558 		u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4559 		if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4560 			char interface_name[IFXNAMSIZ];
4561 			ifnet_t __single scope_interface = NULL;
4562 			necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4563 			interface_name[interface_name_length - 1] = 0;         // Make sure the string is NULL terminated
4564 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[interface_name_length - 1]), &scope_interface) == 0) {
4565 				ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4566 				socket_layer_non_id_conditions = TRUE;
4567 				ifnet_release(scope_interface);
4568 			}
4569 		}
4570 		break;
4571 	}
4572 	case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4573 		socket_layer_non_id_conditions = TRUE;
4574 		break;
4575 	}
4576 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4577 		socket_layer_non_id_conditions = TRUE;
4578 		break;
4579 	}
4580 	case NECP_POLICY_RESULT_ROUTE_RULES: {
4581 		if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4582 			bool has_socket_only_actions = FALSE;
4583 			u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4584 			if (route_rule_id > 0) {
4585 				policy->applied_route_rules_id = route_rule_id;
4586 				ultimate_result_parameter.route_rule_id = route_rule_id;
4587 				if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4588 					socket_layer_non_id_conditions = TRUE;
4589 				} else if (socket_ip_conditions) {
4590 					socket_layer_non_id_conditions = TRUE;
4591 					ip_output_layer_non_id_conditions = TRUE;
4592 					ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4593 				}
4594 			}
4595 		}
4596 		break;
4597 	}
4598 	default: {
4599 		break;
4600 	}
4601 	}
4602 
4603 	if (socket_layer_non_id_conditions) {
4604 		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);
4605 
4606 		if (policy_id == 0) {
4607 			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4608 			goto fail;
4609 		}
4610 
4611 		cond_ip_output_layer_id = policy_id;
4612 		policy->kernel_socket_policies[0] = policy_id;
4613 	}
4614 
4615 	if (ip_output_layer_non_id_conditions) {
4616 		u_int64_t condition_mask = master_condition_mask;
4617 		if (ip_output_layer_non_id_only) {
4618 			condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4619 		}
4620 
4621 		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);
4622 
4623 		if (policy_id == 0) {
4624 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4625 			goto fail;
4626 		}
4627 
4628 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4629 	}
4630 
4631 	if (ip_output_layer_id_condition) {
4632 		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);
4633 
4634 		if (policy_id == 0) {
4635 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4636 			goto fail;
4637 		}
4638 
4639 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4640 	}
4641 
4642 	// Extra policies for IP Output tunnels for when packets loop back
4643 	if (ip_output_layer_tunnel_condition_from_id) {
4644 		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);
4645 
4646 		if (policy_id == 0) {
4647 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4648 			goto fail;
4649 		}
4650 
4651 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4652 	}
4653 
4654 	if (ip_output_layer_tunnel_condition_from_id) {
4655 		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);
4656 
4657 		if (policy_id == 0) {
4658 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4659 			goto fail;
4660 		}
4661 
4662 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4663 	}
4664 
4665 	policy->applied = TRUE;
4666 	policy->pending_update = FALSE;
4667 	return TRUE;
4668 
4669 fail:
4670 	return FALSE;
4671 }
4672 
4673 static void
necp_policy_apply_all(struct necp_session * session)4674 necp_policy_apply_all(struct necp_session *session)
4675 {
4676 	struct necp_session_policy *policy = NULL;
4677 	struct necp_session_policy *temp_policy = NULL;
4678 	struct kev_necp_policies_changed_data kev_data;
4679 	kev_data.changed_count = 0;
4680 
4681 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4682 
4683 	// Remove exisiting applied policies
4684 	if (session->dirty) {
4685 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4686 			if (policy->pending_deletion) {
4687 				if (policy->applied) {
4688 					necp_policy_unapply(policy);
4689 				}
4690 				// Delete the policy
4691 				necp_policy_delete(session, policy);
4692 			} else if (!policy->applied) {
4693 				necp_policy_apply(session, policy);
4694 			} else if (policy->pending_update) {
4695 				// Must have been applied, but needs an update. Remove and re-add.
4696 				necp_policy_unapply(policy);
4697 				necp_policy_apply(session, policy);
4698 			}
4699 		}
4700 
4701 		necp_kernel_socket_policies_update_uuid_table();
4702 		necp_kernel_socket_policies_reprocess();
4703 		necp_kernel_ip_output_policies_reprocess();
4704 
4705 		// Clear dirty bit flags
4706 		session->dirty = FALSE;
4707 	}
4708 
4709 	lck_rw_done(&necp_kernel_policy_lock);
4710 
4711 	necp_update_all_clients();
4712 	necp_post_change_event(&kev_data);
4713 
4714 	if (necp_debug) {
4715 		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4716 	}
4717 }
4718 
4719 // Kernel Policy Management
4720 // ---------------------
4721 // Kernel policies are derived from session policies
4722 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4723 necp_kernel_policy_get_new_id(bool socket_level)
4724 {
4725 	static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4726 	static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4727 
4728 	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4729 
4730 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4731 
4732 	if (socket_level) {
4733 		bool wrapped = FALSE;
4734 		do {
4735 			necp_last_kernel_socket_policy_id++;
4736 			if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4737 			    necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4738 				if (wrapped) {
4739 					// Already wrapped, give up
4740 					NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4741 					return NECP_KERNEL_POLICY_ID_NONE;
4742 				}
4743 				necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4744 				wrapped = TRUE;
4745 			}
4746 			newid = necp_last_kernel_socket_policy_id;
4747 		} while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4748 	} else {
4749 		bool wrapped = FALSE;
4750 		do {
4751 			necp_last_kernel_ip_policy_id++;
4752 			if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4753 				if (wrapped) {
4754 					// Already wrapped, give up
4755 					NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4756 					return NECP_KERNEL_POLICY_ID_NONE;
4757 				}
4758 				necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4759 				wrapped = TRUE;
4760 			}
4761 			newid = necp_last_kernel_ip_policy_id;
4762 		} while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4763 	}
4764 
4765 	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4766 		NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4767 		return NECP_KERNEL_POLICY_ID_NONE;
4768 	}
4769 
4770 	return newid;
4771 }
4772 
4773 #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)
4774 
4775 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)4776 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)
4777 {
4778 	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4779 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4780 
4781 	new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4782 
4783 	new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4784 	new_kernel_policy->order = order;
4785 	new_kernel_policy->session_order = session_order;
4786 	new_kernel_policy->session_pid = session_pid;
4787 
4788 	// Sanitize condition mask
4789 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4790 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4791 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4792 	}
4793 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4794 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4795 	}
4796 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4797 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4798 	}
4799 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4800 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4801 	}
4802 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4803 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4804 	}
4805 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4806 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4807 	}
4808 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4809 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4810 	}
4811 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4812 
4813 	// Set condition values
4814 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4815 		new_kernel_policy->cond_app_id = cond_app_id;
4816 	}
4817 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4818 		new_kernel_policy->cond_real_app_id = cond_real_app_id;
4819 	}
4820 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4821 		new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4822 	}
4823 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4824 		new_kernel_policy->cond_account_id = cond_account_id;
4825 	}
4826 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
4827 	    (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
4828 		new_kernel_policy->cond_domain = cond_domain;
4829 		new_kernel_policy->cond_domain_dot_count = necp_count_dots(__unsafe_null_terminated_to_indexable(cond_domain), strlen(cond_domain));
4830 	}
4831 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
4832 		new_kernel_policy->cond_domain_filter = cond_domain_filter;
4833 	}
4834 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
4835 		new_kernel_policy->cond_url = cond_url;
4836 	}
4837 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4838 		new_kernel_policy->cond_pid = cond_pid;
4839 		new_kernel_policy->cond_pid_version = cond_pid_version;
4840 	}
4841 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4842 		new_kernel_policy->cond_uid = cond_uid;
4843 	}
4844 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
4845 		new_kernel_policy->cond_real_uid = cond_real_uid;
4846 	}
4847 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4848 		if (cond_bound_interface) {
4849 			ifnet_reference(cond_bound_interface);
4850 		}
4851 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
4852 	}
4853 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4854 		new_kernel_policy->cond_traffic_class = cond_traffic_class;
4855 	}
4856 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4857 		new_kernel_policy->cond_protocol = cond_protocol;
4858 	}
4859 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4860 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
4861 	}
4862 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4863 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
4864 	}
4865 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4866 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
4867 	}
4868 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4869 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
4870 	}
4871 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4872 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
4873 	}
4874 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4875 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
4876 	}
4877 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
4878 		memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
4879 	}
4880 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
4881 		memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
4882 	}
4883 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
4884 		new_kernel_policy->cond_client_flags = cond_client_flags;
4885 	}
4886 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
4887 		new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
4888 	}
4889 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
4890 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
4891 	}
4892 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
4893 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
4894 	}
4895 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
4896 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
4897 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
4898 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
4899 	}
4900 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
4901 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
4902 	}
4903 
4904 	new_kernel_policy->result = result;
4905 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
4906 
4907 	if (necp_debug) {
4908 		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
4909 	}
4910 	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
4911 
4912 	return new_kernel_policy ? new_kernel_policy->id : 0;
4913 }
4914 
4915 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)4916 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
4917 {
4918 	struct necp_kernel_socket_policy *kernel_policy = NULL;
4919 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4920 
4921 	if (policy_id == 0) {
4922 		return NULL;
4923 	}
4924 
4925 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
4926 		if (kernel_policy->id == policy_id) {
4927 			return kernel_policy;
4928 		}
4929 	}
4930 
4931 	return NULL;
4932 }
4933 
4934 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)4935 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
4936 {
4937 	struct necp_kernel_socket_policy * __single policy = NULL;
4938 	char * __indexable buffer = NULL;
4939 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4940 
4941 	policy = necp_kernel_socket_policy_find(policy_id);
4942 	if (policy) {
4943 		LIST_REMOVE(policy, chain);
4944 
4945 		if (policy->cond_bound_interface) {
4946 			ifnet_release(policy->cond_bound_interface);
4947 			policy->cond_bound_interface = NULL;
4948 		}
4949 
4950 		if (policy->cond_domain) {
4951 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_domain);
4952 			kfree_data_addr(buffer);
4953 			policy->cond_domain = NULL;
4954 		}
4955 
4956 		if (policy->cond_url) {
4957 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_url);
4958 			kfree_data_addr(buffer);
4959 			policy->cond_url = NULL;
4960 		}
4961 
4962 		if (policy->cond_custom_entitlement) {
4963 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_custom_entitlement);
4964 			kfree_data_addr(buffer);
4965 			policy->cond_custom_entitlement = NULL;
4966 		}
4967 
4968 		if (policy->cond_signing_identifier) {
4969 			buffer = __unsafe_null_terminated_to_indexable(policy->cond_signing_identifier);
4970 			kfree_data_addr(buffer);
4971 			policy->cond_signing_identifier = NULL;
4972 		}
4973 
4974 		zfree(necp_socket_policy_zone, policy);
4975 		return TRUE;
4976 	}
4977 
4978 	return FALSE;
4979 }
4980 
4981 static inline const char *
__sized_by(MAX_RESULT_STRING_LEN)4982 __sized_by(MAX_RESULT_STRING_LEN)
4983 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)
4984 {
4985 	uuid_string_t uuid_string;
4986 	switch (result) {
4987 	case NECP_KERNEL_POLICY_RESULT_NONE: {
4988 		snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
4989 		break;
4990 	}
4991 	case NECP_KERNEL_POLICY_RESULT_PASS: {
4992 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
4993 		break;
4994 	}
4995 	case NECP_KERNEL_POLICY_RESULT_SKIP: {
4996 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
4997 		break;
4998 	}
4999 	case NECP_KERNEL_POLICY_RESULT_DROP: {
5000 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
5001 		break;
5002 	}
5003 	case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
5004 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
5005 		break;
5006 	}
5007 	case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
5008 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
5009 		break;
5010 	}
5011 	case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
5012 		ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
5013 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5014 		break;
5015 	}
5016 	case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
5017 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
5018 		break;
5019 	}
5020 	case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
5021 		ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
5022 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
5023 		break;
5024 	}
5025 	case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
5026 		snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
5027 		break;
5028 	}
5029 	case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
5030 		snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
5031 		break;
5032 	}
5033 	case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
5034 		int index = 0;
5035 		char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
5036 		struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
5037 		if (route_rule != NULL) {
5038 			for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
5039 				if (route_rule->exception_if_indices[index] != 0) {
5040 					ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
5041 					snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
5042 				} else {
5043 					memset(interface_names[index], 0, IFXNAMSIZ);
5044 				}
5045 			}
5046 			switch (route_rule->default_action) {
5047 			case NECP_ROUTE_RULE_DENY_INTERFACE:
5048 			case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
5049 				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)",
5050 				    (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
5051 				    (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
5052 				    (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
5053 				    (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
5054 				    (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
5055 				    (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
5056 				    (route_rule->vpn_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "VPN " : "",
5057 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
5058 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5059 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
5060 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5061 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
5062 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5063 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
5064 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5065 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
5066 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5067 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
5068 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5069 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
5070 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5071 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
5072 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5073 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
5074 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
5075 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
5076 				break;
5077 			case NECP_ROUTE_RULE_ALLOW_INTERFACE:
5078 				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)",
5079 				    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
5080 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
5081 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
5082 				    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
5083 				    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
5084 				    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
5085 				    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action) ? "!VPN " : "",
5086 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
5087 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
5088 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
5089 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
5090 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
5091 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
5092 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
5093 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
5094 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
5095 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
5096 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
5097 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
5098 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
5099 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
5100 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
5101 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
5102 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
5103 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
5104 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
5105 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
5106 				break;
5107 			case NECP_ROUTE_RULE_QOS_MARKING:
5108 				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)",
5109 				    (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
5110 				    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
5111 				    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
5112 				    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
5113 				    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
5114 				    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
5115 				    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING) ? "VPN " : "",
5116 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
5117 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5118 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
5119 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5120 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
5121 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5122 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
5123 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5124 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
5125 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5126 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
5127 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5128 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
5129 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5130 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
5131 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5132 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
5133 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
5134 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
5135 				break;
5136 			default:
5137 				snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
5138 				break;
5139 			}
5140 		}
5141 		break;
5142 	}
5143 	case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
5144 		bool found_mapping = FALSE;
5145 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5146 		if (mapping != NULL) {
5147 			uuid_unparse(mapping->uuid, uuid_string);
5148 			found_mapping = TRUE;
5149 		}
5150 		snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5151 		break;
5152 	}
5153 	case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
5154 		bool found_mapping = FALSE;
5155 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5156 		if (mapping != NULL) {
5157 			uuid_unparse(mapping->uuid, uuid_string);
5158 			found_mapping = TRUE;
5159 		}
5160 		snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
5161 		break;
5162 	}
5163 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
5164 		bool found_mapping = FALSE;
5165 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
5166 		if (mapping != NULL) {
5167 			uuid_unparse(mapping->uuid, uuid_string);
5168 			found_mapping = TRUE;
5169 		}
5170 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
5171 		break;
5172 	}
5173 	default: {
5174 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
5175 		break;
5176 	}
5177 	}
5178 	return result_string;
5179 }
5180 
5181 static void
necp_kernel_socket_policies_dump_all(void)5182 necp_kernel_socket_policies_dump_all(void)
5183 {
5184 	if (necp_debug) {
5185 		struct necp_kernel_socket_policy *policy = NULL;
5186 		int policy_i;
5187 		int app_i;
5188 		char result_string[MAX_RESULT_STRING_LEN];
5189 		char proc_name_string[MAXCOMLEN + 1];
5190 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
5191 		memset(proc_name_string, 0, MAXCOMLEN + 1);
5192 
5193 		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
5194 		NECPLOG0(LOG_DEBUG, "-----------\n");
5195 		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
5196 			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
5197 			proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5198 			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));
5199 		}
5200 		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
5201 			NECPLOG0(LOG_DEBUG, "-----------\n");
5202 		}
5203 
5204 		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
5205 		NECPLOG0(LOG_DEBUG, "-----------\n");
5206 		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5207 			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
5208 			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
5209 				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
5210 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
5211 				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));
5212 			}
5213 			NECPLOG0(LOG_DEBUG, "-----------\n");
5214 		}
5215 	}
5216 }
5217 
5218 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5219 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5220 {
5221 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5222 		// Drop always cancels out lower policies
5223 		return TRUE;
5224 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5225 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5226 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5227 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5228 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5229 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5230 		// Filters and route rules never cancel out lower policies
5231 		return FALSE;
5232 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5233 		if (upper_policy->session_order != lower_policy->session_order) {
5234 			// A skip cannot override a policy of a different session
5235 			return FALSE;
5236 		} else {
5237 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
5238 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5239 				// This policy is beyond the skip
5240 				return FALSE;
5241 			} else {
5242 				// This policy is inside the skip
5243 				return TRUE;
5244 			}
5245 		}
5246 	}
5247 
5248 	// A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5249 	return TRUE;
5250 }
5251 
5252 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)5253 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy ** __indexable policy_array, int valid_indices)
5254 {
5255 	bool can_skip = FALSE;
5256 	u_int32_t highest_skip_session_order = 0;
5257 	u_int32_t highest_skip_order = 0;
5258 	int i;
5259 	for (i = 0; i < valid_indices; i++) {
5260 		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5261 
5262 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
5263 		if (can_skip) {
5264 			if (highest_skip_session_order != compared_policy->session_order ||
5265 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5266 				// If we've moved on to the next session, or passed the skip window
5267 				highest_skip_session_order = 0;
5268 				highest_skip_order = 0;
5269 				can_skip = FALSE;
5270 			} else {
5271 				// If this policy is also a skip, in can increase the skip window
5272 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5273 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5274 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5275 					}
5276 				}
5277 				continue;
5278 			}
5279 		}
5280 
5281 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5282 			// This policy is a skip. Set the skip window accordingly
5283 			can_skip = TRUE;
5284 			highest_skip_session_order = compared_policy->session_order;
5285 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5286 		}
5287 
5288 		// The result of the compared policy must be able to block out this policy result
5289 		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5290 			continue;
5291 		}
5292 
5293 		// If new policy matches All Interfaces, compared policy must also
5294 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5295 			continue;
5296 		}
5297 
5298 		// If new policy matches Local Networks, compared policy must also
5299 		if (((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) ||
5300 		    policy->cond_local_networks_flags != compared_policy->cond_local_networks_flags) {
5301 			continue;
5302 		}
5303 
5304 		// Default makes lower policies unecessary always
5305 		if (compared_policy->condition_mask == 0) {
5306 			return TRUE;
5307 		}
5308 
5309 		// Compared must be more general than policy, and include only conditions within policy
5310 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5311 			continue;
5312 		}
5313 
5314 		// Negative conditions must match for the overlapping conditions
5315 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5316 			continue;
5317 		}
5318 
5319 		if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5320 		    compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5321 		    strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5322 			continue;
5323 		}
5324 
5325 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5326 		    compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5327 			continue;
5328 		}
5329 
5330 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5331 		    strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5332 			continue;
5333 		}
5334 
5335 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5336 		    strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5337 			continue;
5338 		}
5339 
5340 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5341 		    compared_policy->cond_account_id != policy->cond_account_id) {
5342 			continue;
5343 		}
5344 
5345 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5346 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
5347 			continue;
5348 		}
5349 
5350 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5351 		    compared_policy->cond_app_id != policy->cond_app_id) {
5352 			continue;
5353 		}
5354 
5355 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5356 		    compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5357 			continue;
5358 		}
5359 
5360 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5361 		    (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5362 			continue;
5363 		}
5364 
5365 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5366 		    compared_policy->cond_uid != policy->cond_uid) {
5367 			continue;
5368 		}
5369 
5370 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5371 		    compared_policy->cond_real_uid != policy->cond_real_uid) {
5372 			continue;
5373 		}
5374 
5375 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5376 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5377 			continue;
5378 		}
5379 
5380 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5381 		    compared_policy->cond_protocol != policy->cond_protocol) {
5382 			continue;
5383 		}
5384 
5385 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5386 		    compared_policy->cond_client_flags != policy->cond_client_flags) {
5387 			continue;
5388 		}
5389 
5390 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5391 		    !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5392 		    compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5393 			continue;
5394 		}
5395 
5396 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5397 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5398 				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))) {
5399 					continue;
5400 				}
5401 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5402 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5403 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
5404 					continue;
5405 				}
5406 			}
5407 		}
5408 
5409 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5410 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5411 				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))) {
5412 					continue;
5413 				}
5414 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5415 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5416 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
5417 					continue;
5418 				}
5419 			}
5420 		}
5421 
5422 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5423 		    memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5424 			continue;
5425 		}
5426 
5427 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5428 		    memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5429 			continue;
5430 		}
5431 
5432 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5433 		    memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5434 			continue;
5435 		}
5436 
5437 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5438 		    memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5439 			continue;
5440 		}
5441 
5442 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5443 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5444 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5445 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5446 			continue;
5447 		}
5448 
5449 		return TRUE;
5450 	}
5451 
5452 	return FALSE;
5453 }
5454 
5455 static bool
necp_kernel_socket_policies_reprocess(void)5456 necp_kernel_socket_policies_reprocess(void)
5457 {
5458 	int app_i;
5459 	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5460 	int app_layer_current_free_index = 0;
5461 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5462 
5463 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5464 
5465 	// Reset mask to 0
5466 	necp_kernel_application_policies_condition_mask = 0;
5467 	necp_kernel_socket_policies_condition_mask = 0;
5468 	necp_kernel_application_policies_count = 0;
5469 	necp_kernel_socket_policies_count = 0;
5470 	necp_kernel_socket_policies_non_app_count = 0;
5471 
5472 	// Reset all maps to NULL
5473 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5474 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5475 			kfree_type(struct necp_kernel_socket_policy *,
5476 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5477 			    necp_kernel_socket_policies_map[app_i]);
5478 			necp_kernel_socket_policies_map[app_i] = NULL;
5479 		}
5480 
5481 		// Init counts
5482 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5483 	}
5484 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5485 		kfree_type(struct necp_kernel_socket_policy *,
5486 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5487 		    necp_kernel_socket_policies_app_layer_map);
5488 	}
5489 	necp_kernel_socket_policies_app_layer_map = NULL;
5490 	necp_kernel_socket_policies_app_layer_map_count = 0;
5491 
5492 	// Create masks and counts
5493 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5494 		// App layer mask/count
5495 		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5496 		necp_kernel_application_policies_count++;
5497 		necp_kernel_socket_policies_app_layer_map_count++;
5498 
5499 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5500 			// Agent type conditions only apply to app layer
5501 			continue;
5502 		}
5503 
5504 		// Update socket layer bucket mask/counts
5505 		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5506 		necp_kernel_socket_policies_count++;
5507 
5508 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5509 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5510 			necp_kernel_socket_policies_non_app_count++;
5511 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5512 				necp_kernel_socket_policies_map_counts[app_i]++;
5513 			}
5514 		} else {
5515 			necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5516 		}
5517 	}
5518 
5519 	// Allocate maps
5520 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5521 		if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5522 			// Allocate a NULL-terminated array of policy pointers for each bucket
5523 			necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5524 			    necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5525 			if (necp_kernel_socket_policies_map[app_i] == NULL) {
5526 				goto fail;
5527 			}
5528 		}
5529 		bucket_current_free_index[app_i] = 0;
5530 	}
5531 	necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5532 	    necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5533 	if (necp_kernel_socket_policies_app_layer_map == NULL) {
5534 		goto fail;
5535 	}
5536 
5537 	// Fill out maps
5538 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5539 		// Add app layer policies
5540 		if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5541 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5542 			app_layer_current_free_index++;
5543 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5544 		}
5545 
5546 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5547 			// Agent type conditions only apply to app layer
5548 			continue;
5549 		}
5550 
5551 		// Add socket policies
5552 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5553 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5554 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5555 				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])) {
5556 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5557 					bucket_current_free_index[app_i]++;
5558 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5559 				}
5560 			}
5561 		} else {
5562 			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5563 			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])) {
5564 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5565 				bucket_current_free_index[app_i]++;
5566 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5567 			}
5568 		}
5569 	}
5570 	necp_kernel_socket_policies_dump_all();
5571 	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5572 	return TRUE;
5573 
5574 fail:
5575 	// Free memory, reset masks to 0
5576 	necp_kernel_application_policies_condition_mask = 0;
5577 	necp_kernel_socket_policies_condition_mask = 0;
5578 	necp_kernel_application_policies_count = 0;
5579 	necp_kernel_socket_policies_count = 0;
5580 	necp_kernel_socket_policies_non_app_count = 0;
5581 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5582 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5583 			kfree_type(struct necp_kernel_socket_policy *,
5584 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5585 			    necp_kernel_socket_policies_map[app_i]);
5586 			necp_kernel_socket_policies_map[app_i] = NULL;
5587 		}
5588 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5589 	}
5590 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5591 		kfree_type(struct necp_kernel_socket_policy *,
5592 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5593 		    necp_kernel_socket_policies_app_layer_map);
5594 		necp_kernel_socket_policies_app_layer_map = NULL;
5595 	}
5596 	necp_kernel_socket_policies_app_layer_map_count = 0;
5597 	return FALSE;
5598 }
5599 
5600 static u_int32_t
necp_get_new_string_id(void)5601 necp_get_new_string_id(void)
5602 {
5603 	static u_int32_t necp_last_string_id = 0;
5604 
5605 	u_int32_t newid = 0;
5606 
5607 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5608 
5609 	bool wrapped = FALSE;
5610 	do {
5611 		necp_last_string_id++;
5612 		if (necp_last_string_id < 1) {
5613 			if (wrapped) {
5614 				// Already wrapped, give up
5615 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5616 				return 0;
5617 			}
5618 			necp_last_string_id = 1;
5619 			wrapped = TRUE;
5620 		}
5621 		newid = necp_last_string_id;
5622 	} while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5623 
5624 	if (newid == 0) {
5625 		NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5626 		return 0;
5627 	}
5628 
5629 	return newid;
5630 }
5631 
5632 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string __null_terminated)5633 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5634 {
5635 	struct necp_string_id_mapping *searchentry = NULL;
5636 	struct necp_string_id_mapping *foundentry = NULL;
5637 
5638 	LIST_FOREACH(searchentry, list, chain) {
5639 		if (strcmp(searchentry->string, string) == 0) {
5640 			foundentry = searchentry;
5641 			break;
5642 		}
5643 	}
5644 
5645 	return foundentry;
5646 }
5647 
5648 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5649 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5650 {
5651 	struct necp_string_id_mapping *searchentry = NULL;
5652 	struct necp_string_id_mapping *foundentry = NULL;
5653 
5654 	LIST_FOREACH(searchentry, list, chain) {
5655 		if (searchentry->id == local_id) {
5656 			foundentry = searchentry;
5657 			break;
5658 		}
5659 	}
5660 
5661 	return foundentry;
5662 }
5663 
5664 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5665 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5666 {
5667 	u_int32_t string_id = 0;
5668 	struct necp_string_id_mapping *existing_mapping = NULL;
5669 
5670 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5671 
5672 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5673 	if (existing_mapping != NULL) {
5674 		string_id = existing_mapping->id;
5675 		os_ref_retain_locked(&existing_mapping->refcount);
5676 	} else {
5677 		struct necp_string_id_mapping * __single new_mapping = NULL;
5678 		new_mapping = kalloc_type(struct necp_string_id_mapping,
5679 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5680 
5681 		size_t length = strlen(string) + 1;
5682 		char *buffer = kalloc_data(length, Z_WAITOK);
5683 		if (buffer != NULL) {
5684 			strlcpy(buffer, string, length);
5685 			new_mapping->string = __unsafe_null_terminated_from_indexable(buffer, &buffer[length - 1]);
5686 			new_mapping->id = necp_get_new_string_id();
5687 			os_ref_init(&new_mapping->refcount, &necp_refgrp);
5688 			LIST_INSERT_HEAD(list, new_mapping, chain);
5689 			string_id = new_mapping->id;
5690 		} else {
5691 			kfree_type(struct necp_string_id_mapping, new_mapping);
5692 			new_mapping = NULL;
5693 		}
5694 	}
5695 	return string_id;
5696 }
5697 
5698 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string __null_terminated)5699 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string __null_terminated)
5700 {
5701 	struct necp_string_id_mapping * __single existing_mapping = NULL;
5702 	char * __indexable buffer = NULL;
5703 
5704 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5705 
5706 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5707 	if (existing_mapping != NULL) {
5708 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5709 			LIST_REMOVE(existing_mapping, chain);
5710 			buffer = __unsafe_null_terminated_to_indexable(existing_mapping->string);
5711 			kfree_data_addr(buffer);
5712 			kfree_type(struct necp_string_id_mapping, existing_mapping);
5713 		}
5714 		return TRUE;
5715 	}
5716 
5717 	return FALSE;
5718 }
5719 
5720 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5721 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5722 {
5723 	struct necp_domain_filter *searchfilter = NULL;
5724 	struct necp_domain_filter *foundfilter = NULL;
5725 
5726 	LIST_FOREACH(searchfilter, list, chain) {
5727 		if (searchfilter->id == filter_id) {
5728 			foundfilter = searchfilter;
5729 			break;
5730 		}
5731 	}
5732 
5733 	return foundfilter;
5734 }
5735 
5736 static u_int32_t
necp_get_new_domain_filter_id(void)5737 necp_get_new_domain_filter_id(void)
5738 {
5739 	static u_int32_t necp_last_filter_id = 0;
5740 
5741 	u_int32_t newid = 0;
5742 
5743 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5744 
5745 	bool wrapped = FALSE;
5746 	do {
5747 		necp_last_filter_id++;
5748 		if (necp_last_filter_id < 1) {
5749 			if (wrapped) {
5750 				// Already wrapped, give up
5751 				NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5752 				return 0;
5753 			}
5754 			necp_last_filter_id = 1;
5755 			wrapped = TRUE;
5756 		}
5757 		newid = necp_last_filter_id;
5758 	} while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5759 
5760 	if (newid == 0) {
5761 		NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5762 		return 0;
5763 	}
5764 
5765 	return newid;
5766 }
5767 
5768 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)5769 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5770 {
5771 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5772 
5773 	struct necp_domain_filter *new_filter = NULL;
5774 	new_filter = kalloc_type(struct necp_domain_filter,
5775 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5776 
5777 	new_filter->filter = filter;
5778 	new_filter->id = necp_get_new_domain_filter_id();
5779 	LIST_INSERT_HEAD(list, new_filter, chain);
5780 	LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5781 	os_ref_init(&new_filter->refcount, &necp_refgrp);
5782 
5783 	return new_filter->id;
5784 }
5785 
5786 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)5787 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5788 {
5789 	struct necp_domain_filter * __single existing_filter = NULL;
5790 
5791 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5792 
5793 	existing_filter = necp_lookup_domain_filter(list, filter_id);
5794 	if (existing_filter != NULL) {
5795 		if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5796 			LIST_REMOVE(existing_filter, chain);
5797 			LIST_REMOVE(existing_filter, owner_chain);
5798 			net_bloom_filter_destroy(existing_filter->filter);
5799 			kfree_type(struct necp_domain_filter, existing_filter);
5800 		}
5801 		return true;
5802 	}
5803 
5804 	return false;
5805 }
5806 
5807 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
5808 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
5809 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)5810 necp_get_new_route_rule_id(bool aggregate)
5811 {
5812 	static u_int32_t necp_last_route_rule_id = 0;
5813 	static u_int32_t necp_last_aggregate_route_rule_id = 0;
5814 
5815 	u_int32_t newid = 0;
5816 
5817 	if (!aggregate) {
5818 		// Main necp_kernel_policy_lock protects non-aggregate rule IDs
5819 		LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5820 
5821 		bool wrapped = FALSE;
5822 		do {
5823 			necp_last_route_rule_id++;
5824 			if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
5825 			    necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5826 				if (wrapped) {
5827 					// Already wrapped, give up
5828 					NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
5829 					return 0;
5830 				}
5831 				necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
5832 				wrapped = TRUE;
5833 			}
5834 			newid = necp_last_route_rule_id;
5835 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5836 	} else {
5837 		// necp_route_rule_lock protects aggregate rule IDs
5838 		LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
5839 
5840 		bool wrapped = FALSE;
5841 		do {
5842 			necp_last_aggregate_route_rule_id++;
5843 			if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5844 				if (wrapped) {
5845 					// Already wrapped, give up
5846 					NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
5847 					return 0;
5848 				}
5849 				necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
5850 				wrapped = TRUE;
5851 			}
5852 			newid = necp_last_aggregate_route_rule_id;
5853 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5854 	}
5855 
5856 	if (newid == 0) {
5857 		NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
5858 		return 0;
5859 	}
5860 
5861 	return newid;
5862 }
5863 
5864 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)5865 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5866 {
5867 	struct necp_route_rule *searchentry = NULL;
5868 	struct necp_route_rule *foundentry = NULL;
5869 
5870 	LIST_FOREACH(searchentry, list, chain) {
5871 		if (searchentry->id == route_rule_id) {
5872 			foundentry = searchentry;
5873 			break;
5874 		}
5875 	}
5876 
5877 	return foundentry;
5878 }
5879 
5880 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)5881 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)
5882 {
5883 	struct necp_route_rule *searchentry = NULL;
5884 	struct necp_route_rule *foundentry = NULL;
5885 
5886 	LIST_FOREACH(searchentry, list, chain) {
5887 		if (searchentry->default_action == default_action &&
5888 		    searchentry->cellular_action == cellular_action &&
5889 		    searchentry->wifi_action == wifi_action &&
5890 		    searchentry->wired_action == wired_action &&
5891 		    searchentry->expensive_action == expensive_action &&
5892 		    searchentry->constrained_action == constrained_action &&
5893 		    searchentry->companion_action == companion_action &&
5894 		    searchentry->vpn_action == vpn_action &&
5895 		    searchentry->control_unit == control_unit &&
5896 		    searchentry->effective_type == effective_type) {
5897 			bool match_failed = FALSE;
5898 			size_t index_a = 0;
5899 			size_t index_b = 0;
5900 			size_t count_a = 0;
5901 			size_t count_b = 0;
5902 			for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
5903 				bool found_index = FALSE;
5904 				if (searchentry->exception_if_indices[index_a] == 0) {
5905 					break;
5906 				}
5907 				count_a++;
5908 				for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
5909 					if (if_indices[index_b] == 0) {
5910 						break;
5911 					}
5912 					if (index_b >= count_b) {
5913 						count_b = index_b + 1;
5914 					}
5915 					if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
5916 					    searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
5917 						found_index = TRUE;
5918 						break;
5919 					}
5920 				}
5921 				if (!found_index) {
5922 					match_failed = TRUE;
5923 					break;
5924 				}
5925 			}
5926 
5927 			if (match_failed || count_a != count_b) {
5928 				continue;
5929 			}
5930 
5931 			bool has_agent_a = !uuid_is_null(netagent_uuid);
5932 			bool has_agent_b = (searchentry->netagent_id != 0);
5933 			if (has_agent_a != has_agent_b) {
5934 				continue;
5935 			}
5936 
5937 			if (has_agent_a) {
5938 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
5939 				if (mapping == NULL) {
5940 					// Bad mapping, doesn't match
5941 					continue;
5942 				}
5943 				if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
5944 					// UUIDs don't match
5945 					continue;
5946 				}
5947 			}
5948 
5949 			bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
5950 			bool has_match_agent_b = (searchentry->match_netagent_id != 0);
5951 			if (has_match_agent_a != has_match_agent_b) {
5952 				continue;
5953 			}
5954 
5955 			if (has_match_agent_a) {
5956 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
5957 				if (mapping == NULL) {
5958 					// Bad mapping, doesn't match
5959 					continue;
5960 				}
5961 				if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
5962 					// UUIDs don't match
5963 					continue;
5964 				}
5965 			}
5966 
5967 			// Rules match!
5968 			foundentry = searchentry;
5969 			break;
5970 		}
5971 	}
5972 
5973 	return foundentry;
5974 }
5975 
5976 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)5977 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,
5978     bool *has_socket_only_actions)
5979 {
5980 	size_t offset = 0;
5981 	u_int32_t route_rule_id = 0;
5982 	struct necp_route_rule *existing_rule = NULL;
5983 	u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
5984 	u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
5985 	u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
5986 	u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
5987 	u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
5988 	u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
5989 	u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
5990 	u_int8_t vpn_action = NECP_ROUTE_RULE_NONE;
5991 	u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
5992 	size_t num_valid_indices = 0;
5993 	memset(&if_indices, 0, sizeof(if_indices));
5994 	u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
5995 	memset(&if_actions, 0, sizeof(if_actions));
5996 
5997 	uuid_t netagent_uuid = {};
5998 
5999 	uuid_t match_netagent_uuid = {};
6000 	uint32_t control_unit = 0;
6001 	uint32_t effective_type = 0;
6002 
6003 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6004 
6005 	if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
6006 		return 0;
6007 	}
6008 
6009 	// Process rules
6010 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
6011 		ifnet_t __single rule_interface = NULL;
6012 		char interface_name[IFXNAMSIZ];
6013 		u_int32_t length = 0;
6014 		u_int8_t * __indexable value = necp_buffer_get_tlv_value(route_rules_array, route_rules_array_size, offset, &length);
6015 
6016 		if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
6017 			// Invalid TLV goes beyond end of the rules array
6018 			break;
6019 		}
6020 
6021 		// Increment offset for the next time through the loop
6022 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
6023 
6024 		u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
6025 		u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
6026 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
6027 		u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
6028 
6029 		if (rule_action == NECP_ROUTE_RULE_NONE) {
6030 			// Don't allow an explicit rule to be None action
6031 			continue;
6032 		}
6033 
6034 		if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
6035 		    rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
6036 			if (rule_length < sizeof(uuid_t)) {
6037 				// Too short, skip
6038 				continue;
6039 			}
6040 
6041 			if (!uuid_is_null(netagent_uuid)) {
6042 				if (uuid_compare(netagent_uuid, rule_value) != 0) {
6043 					// UUIDs don't match, skip
6044 					continue;
6045 				}
6046 			} else {
6047 				// Copy out agent UUID
6048 				memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
6049 			}
6050 
6051 			// Adjust remaining length
6052 			rule_value += sizeof(netagent_uuid);
6053 			rule_length -= sizeof(netagent_uuid);
6054 			*has_socket_only_actions = true;
6055 		} else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
6056 			if (rule_length < sizeof(control_unit)) {
6057 				// Too short, skip
6058 				continue;
6059 			}
6060 
6061 			memcpy(&control_unit, rule_value, sizeof(control_unit));
6062 
6063 			// Adjust remaining length
6064 			rule_value += sizeof(control_unit);
6065 			rule_length -= sizeof(control_unit);
6066 			*has_socket_only_actions = true;
6067 		} else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
6068 			if (rule_length < sizeof(effective_type)) {
6069 				// Too short, skip
6070 				continue;
6071 			}
6072 
6073 			memcpy(&effective_type, rule_value, sizeof(effective_type));
6074 
6075 			// Adjust remaining length
6076 			rule_value += sizeof(effective_type);
6077 			rule_length -= sizeof(effective_type);
6078 		}
6079 
6080 		if (rule_length == 0) {
6081 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
6082 				cellular_action = rule_action;
6083 			}
6084 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
6085 				wifi_action = rule_action;
6086 			}
6087 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
6088 				wired_action = rule_action;
6089 			}
6090 			if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
6091 				expensive_action = rule_action;
6092 			}
6093 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
6094 				constrained_action = rule_action;
6095 			}
6096 			if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
6097 				companion_action = rule_action;
6098 			}
6099 			if (rule_flags & NECP_ROUTE_RULE_FLAG_VPN) {
6100 				vpn_action = rule_action;
6101 			}
6102 			if (rule_flags == 0) {
6103 				default_action = rule_action;
6104 			}
6105 			continue;
6106 		} else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
6107 			if (rule_length < sizeof(uuid_t)) {
6108 				// Too short, skip
6109 				continue;
6110 			}
6111 
6112 			// Store the netagent UUID to match
6113 			memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
6114 			// If the data is exactly a UUID, this is the default action
6115 			if (rule_length == sizeof(uuid_t)) {
6116 				default_action = rule_action;
6117 				continue;
6118 			}
6119 
6120 			// If the data is longer than a UUID, this also includes an interface name
6121 			// Adjust remaining length to make sure the interface name is picked up below
6122 			rule_value += sizeof(uuid_t);
6123 			rule_length -= sizeof(uuid_t);
6124 		}
6125 
6126 		if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
6127 			continue;
6128 		}
6129 
6130 		if (rule_length <= IFXNAMSIZ) {
6131 			memcpy(interface_name, rule_value, rule_length);
6132 			interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
6133 			if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[rule_length - 1]), &rule_interface) == 0) {
6134 				if_actions[num_valid_indices] = rule_action;
6135 				if_indices[num_valid_indices++] = rule_interface->if_index;
6136 				ifnet_release(rule_interface);
6137 			}
6138 		}
6139 	}
6140 
6141 	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);
6142 	if (existing_rule != NULL) {
6143 		route_rule_id = existing_rule->id;
6144 		os_ref_retain_locked(&existing_rule->refcount);
6145 	} else {
6146 		struct necp_route_rule *new_rule = NULL;
6147 		new_rule = kalloc_type(struct necp_route_rule,
6148 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6149 		route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
6150 		if (!uuid_is_null(netagent_uuid)) {
6151 			new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
6152 		}
6153 		if (!uuid_is_null(match_netagent_uuid)) {
6154 			new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
6155 		}
6156 		new_rule->effective_type = effective_type;
6157 		new_rule->control_unit = control_unit;
6158 		new_rule->default_action = default_action;
6159 		new_rule->cellular_action = cellular_action;
6160 		new_rule->wifi_action = wifi_action;
6161 		new_rule->wired_action = wired_action;
6162 		new_rule->expensive_action = expensive_action;
6163 		new_rule->constrained_action =  constrained_action;
6164 		new_rule->companion_action =  companion_action;
6165 		new_rule->vpn_action =  vpn_action;
6166 		memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
6167 		memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
6168 		os_ref_init(&new_rule->refcount, &necp_refgrp);
6169 		LIST_INSERT_HEAD(list, new_rule, chain);
6170 	}
6171 	return route_rule_id;
6172 }
6173 
6174 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)6175 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
6176 {
6177 	if (rule_id) {
6178 		lck_rw_lock_exclusive(&necp_route_rule_lock);
6179 
6180 		struct necp_aggregate_route_rule * __single existing_rule = NULL;
6181 		struct necp_aggregate_route_rule *tmp_rule = NULL;
6182 
6183 		LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
6184 			int index = 0;
6185 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
6186 				u_int32_t route_rule_id = existing_rule->rule_ids[index];
6187 				if (route_rule_id == rule_id) {
6188 					LIST_REMOVE(existing_rule, chain);
6189 					kfree_type(struct necp_aggregate_route_rule, existing_rule);
6190 					break;
6191 				}
6192 			}
6193 		}
6194 
6195 		lck_rw_done(&necp_route_rule_lock);
6196 	}
6197 }
6198 
6199 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)6200 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
6201 {
6202 	struct necp_route_rule * __single existing_rule = NULL;
6203 
6204 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6205 
6206 	existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
6207 	if (existing_rule != NULL) {
6208 		if (os_ref_release_locked(&existing_rule->refcount) == 0) {
6209 			necp_remove_aggregate_route_rule_for_id(existing_rule->id);
6210 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
6211 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
6212 			LIST_REMOVE(existing_rule, chain);
6213 			kfree_type(struct necp_route_rule, existing_rule);
6214 		}
6215 		return TRUE;
6216 	}
6217 
6218 	return FALSE;
6219 }
6220 
6221 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)6222 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
6223 {
6224 	struct necp_aggregate_route_rule *searchentry = NULL;
6225 	struct necp_aggregate_route_rule *foundentry = NULL;
6226 
6227 	lck_rw_lock_shared(&necp_route_rule_lock);
6228 
6229 	LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
6230 		if (searchentry->id == route_rule_id) {
6231 			foundentry = searchentry;
6232 			break;
6233 		}
6234 	}
6235 
6236 	lck_rw_done(&necp_route_rule_lock);
6237 
6238 	return foundentry;
6239 }
6240 
6241 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * __counted_by (MAX_AGGREGATE_ROUTE_RULES)rule_ids)6242 necp_create_aggregate_route_rule(u_int32_t * __counted_by(MAX_AGGREGATE_ROUTE_RULES)rule_ids)
6243 {
6244 	u_int32_t aggregate_route_rule_id = 0;
6245 	struct necp_aggregate_route_rule *new_rule = NULL;
6246 	struct necp_aggregate_route_rule *existing_rule = NULL;
6247 
6248 	lck_rw_lock_exclusive(&necp_route_rule_lock);
6249 
6250 	// Check if the rule already exists
6251 	LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6252 		if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6253 			lck_rw_done(&necp_route_rule_lock);
6254 			return existing_rule->id;
6255 		}
6256 	}
6257 
6258 	new_rule = kalloc_type(struct necp_aggregate_route_rule,
6259 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6260 	aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6261 	new_rule->id = aggregate_route_rule_id;
6262 	memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6263 	LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6264 	lck_rw_done(&necp_route_rule_lock);
6265 
6266 	return aggregate_route_rule_id;
6267 }
6268 
6269 #define NECP_NULL_SERVICE_ID 1
6270 #define NECP_FIRST_VALID_SERVICE_ID  2
6271 #define NECP_FIRST_VALID_APP_ID  UINT16_MAX
6272 static u_int32_t
necp_get_new_uuid_id(bool service)6273 necp_get_new_uuid_id(bool service)
6274 {
6275 	static u_int32_t necp_last_service_uuid_id = 0;
6276 	static u_int32_t necp_last_app_uuid_id = 0;
6277 
6278 	u_int32_t newid = 0;
6279 
6280 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6281 
6282 	if (service) {
6283 		bool wrapped = FALSE;
6284 		do {
6285 			necp_last_service_uuid_id++;
6286 			if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6287 			    necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6288 				if (wrapped) {
6289 					// Already wrapped, give up
6290 					NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6291 					return NECP_NULL_SERVICE_ID;
6292 				}
6293 				necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6294 				wrapped = TRUE;
6295 			}
6296 			newid = necp_last_service_uuid_id;
6297 		} while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6298 	} else {
6299 		bool wrapped = FALSE;
6300 		do {
6301 			necp_last_app_uuid_id++;
6302 			if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6303 				if (wrapped) {
6304 					// Already wrapped, give up
6305 					NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6306 					return NECP_NULL_SERVICE_ID;
6307 				}
6308 				necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6309 				wrapped = TRUE;
6310 			}
6311 			newid = necp_last_app_uuid_id;
6312 		} while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6313 	}
6314 
6315 	if (newid == NECP_NULL_SERVICE_ID) {
6316 		NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6317 		return NECP_NULL_SERVICE_ID;
6318 	}
6319 
6320 	return newid;
6321 }
6322 
6323 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6324 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6325 {
6326 	struct necp_uuid_id_mapping *searchentry = NULL;
6327 	struct necp_uuid_id_mapping *foundentry = NULL;
6328 
6329 	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6330 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6331 			foundentry = searchentry;
6332 			break;
6333 		}
6334 	}
6335 
6336 	return foundentry;
6337 }
6338 
6339 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6340 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6341 {
6342 	struct necp_uuid_id_mapping *searchentry = NULL;
6343 	struct necp_uuid_id_mapping *foundentry = NULL;
6344 
6345 	struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6346 	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--) {
6347 		LIST_FOREACH(searchentry, uuid_list_head, chain) {
6348 			if (searchentry->id == local_id) {
6349 				foundentry = searchentry;
6350 				break;
6351 			}
6352 		}
6353 	}
6354 
6355 	return foundentry;
6356 }
6357 
6358 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6359 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6360 {
6361 	u_int32_t local_id = 0;
6362 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6363 
6364 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6365 
6366 	if (allocated_mapping) {
6367 		*allocated_mapping = FALSE;
6368 	}
6369 
6370 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6371 	if (existing_mapping != NULL) {
6372 		local_id = existing_mapping->id;
6373 		os_ref_retain_locked(&existing_mapping->refcount);
6374 		if (uuid_policy_table) {
6375 			existing_mapping->table_usecount++;
6376 		}
6377 	} else {
6378 		struct necp_uuid_id_mapping *new_mapping = NULL;
6379 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6380 		    Z_WAITOK | Z_NOFAIL);
6381 		uuid_copy(new_mapping->uuid, uuid);
6382 		new_mapping->id = necp_get_new_uuid_id(false);
6383 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6384 		if (uuid_policy_table) {
6385 			new_mapping->table_usecount = 1;
6386 		} else {
6387 			new_mapping->table_usecount = 0;
6388 		}
6389 
6390 		LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6391 
6392 		if (allocated_mapping) {
6393 			*allocated_mapping = TRUE;
6394 		}
6395 
6396 		local_id = new_mapping->id;
6397 	}
6398 
6399 	return local_id;
6400 }
6401 
6402 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6403 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6404 {
6405 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6406 
6407 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6408 
6409 	if (removed_mapping) {
6410 		*removed_mapping = FALSE;
6411 	}
6412 
6413 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6414 	if (existing_mapping != NULL) {
6415 		if (uuid_policy_table) {
6416 			existing_mapping->table_usecount--;
6417 		}
6418 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6419 			LIST_REMOVE(existing_mapping, chain);
6420 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6421 			if (removed_mapping) {
6422 				*removed_mapping = TRUE;
6423 			}
6424 		}
6425 		return TRUE;
6426 	}
6427 
6428 	return FALSE;
6429 }
6430 
6431 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6432 necp_uuid_get_null_service_id_mapping(void)
6433 {
6434 	static struct necp_uuid_id_mapping null_mapping;
6435 	uuid_clear(null_mapping.uuid);
6436 	null_mapping.id = NECP_NULL_SERVICE_ID;
6437 
6438 	return &null_mapping;
6439 }
6440 
6441 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6442 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6443 {
6444 	struct necp_uuid_id_mapping *searchentry = NULL;
6445 	struct necp_uuid_id_mapping *foundentry = NULL;
6446 
6447 	if (uuid_is_null(uuid)) {
6448 		return necp_uuid_get_null_service_id_mapping();
6449 	}
6450 
6451 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6452 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6453 			foundentry = searchentry;
6454 			break;
6455 		}
6456 	}
6457 
6458 	return foundentry;
6459 }
6460 
6461 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6462 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6463 {
6464 	struct necp_uuid_id_mapping *searchentry = NULL;
6465 	struct necp_uuid_id_mapping *foundentry = NULL;
6466 
6467 	if (local_id == NECP_NULL_SERVICE_ID) {
6468 		return necp_uuid_get_null_service_id_mapping();
6469 	}
6470 
6471 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6472 		if (searchentry->id == local_id) {
6473 			foundentry = searchentry;
6474 			break;
6475 		}
6476 	}
6477 
6478 	return foundentry;
6479 }
6480 
6481 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6482 necp_create_uuid_service_id_mapping(uuid_t uuid)
6483 {
6484 	u_int32_t local_id = 0;
6485 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6486 
6487 	if (uuid_is_null(uuid)) {
6488 		return NECP_NULL_SERVICE_ID;
6489 	}
6490 
6491 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6492 
6493 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6494 	if (existing_mapping != NULL) {
6495 		local_id = existing_mapping->id;
6496 		os_ref_retain_locked(&existing_mapping->refcount);
6497 	} else {
6498 		struct necp_uuid_id_mapping *new_mapping = NULL;
6499 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6500 		    Z_WAITOK | Z_NOFAIL);
6501 		uuid_copy(new_mapping->uuid, uuid);
6502 		new_mapping->id = necp_get_new_uuid_id(true);
6503 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6504 
6505 		LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6506 
6507 		local_id = new_mapping->id;
6508 	}
6509 
6510 	return local_id;
6511 }
6512 
6513 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6514 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6515 {
6516 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6517 
6518 	if (uuid_is_null(uuid)) {
6519 		return TRUE;
6520 	}
6521 
6522 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6523 
6524 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6525 	if (existing_mapping != NULL) {
6526 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6527 			LIST_REMOVE(existing_mapping, chain);
6528 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6529 		}
6530 		return TRUE;
6531 	}
6532 
6533 	return FALSE;
6534 }
6535 
6536 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6537 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6538 {
6539 	struct necp_uuid_id_mapping * __single existing_mapping = NULL;
6540 
6541 	if (service_id == 0) {
6542 		return TRUE;
6543 	}
6544 
6545 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6546 
6547 	existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6548 	if (existing_mapping != NULL) {
6549 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6550 			LIST_REMOVE(existing_mapping, chain);
6551 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6552 		}
6553 		return TRUE;
6554 	}
6555 
6556 	return FALSE;
6557 }
6558 
6559 static bool
necp_kernel_socket_policies_update_uuid_table(void)6560 necp_kernel_socket_policies_update_uuid_table(void)
6561 {
6562 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6563 
6564 	if (necp_uuid_app_id_mappings_dirty) {
6565 		uuid_t dummy_uuid = {};
6566 		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, dummy_uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6567 			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6568 			return FALSE;
6569 		}
6570 
6571 		if (necp_num_uuid_app_id_mappings > 0) {
6572 			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6573 			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--) {
6574 				struct necp_uuid_id_mapping *mapping = NULL;
6575 				LIST_FOREACH(mapping, uuid_list_head, chain) {
6576 					if (mapping->table_usecount > 0 &&
6577 					    proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6578 						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6579 					}
6580 				}
6581 			}
6582 		}
6583 
6584 		necp_uuid_app_id_mappings_dirty = FALSE;
6585 	}
6586 
6587 	return TRUE;
6588 }
6589 
6590 #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)
6591 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)6592 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)
6593 {
6594 	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6595 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6596 
6597 	new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6598 	new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6599 	new_kernel_policy->suborder = suborder;
6600 	new_kernel_policy->order = order;
6601 	new_kernel_policy->session_order = session_order;
6602 	new_kernel_policy->session_pid = session_pid;
6603 
6604 	// Sanitize condition mask
6605 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6606 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6607 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6608 	}
6609 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6610 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6611 	}
6612 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6613 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6614 	}
6615 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6616 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6617 	}
6618 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6619 
6620 	// Set condition values
6621 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6622 		new_kernel_policy->cond_policy_id = cond_policy_id;
6623 	}
6624 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6625 		if (cond_bound_interface) {
6626 			ifnet_reference(cond_bound_interface);
6627 		}
6628 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
6629 	}
6630 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6631 		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6632 	}
6633 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6634 		new_kernel_policy->cond_protocol = cond_protocol;
6635 	}
6636 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6637 		SOCKADDR_COPY(cond_local_start, &new_kernel_policy->cond_local_start, cond_local_start->sa.sa_len);
6638 	}
6639 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6640 		SOCKADDR_COPY(cond_local_end, &new_kernel_policy->cond_local_end, cond_local_end->sa.sa_len);
6641 	}
6642 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6643 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
6644 	}
6645 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6646 		SOCKADDR_COPY(cond_remote_start, &new_kernel_policy->cond_remote_start, cond_remote_start->sa.sa_len);
6647 	}
6648 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6649 		SOCKADDR_COPY(cond_remote_end, &new_kernel_policy->cond_remote_end, cond_remote_end->sa.sa_len);
6650 	}
6651 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6652 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
6653 	}
6654 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
6655 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
6656 	}
6657 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
6658 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
6659 	}
6660 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
6661 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
6662 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
6663 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
6664 	}
6665 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
6666 		new_kernel_policy->cond_local_networks_flags = cond_local_networks_flags;
6667 	}
6668 
6669 	new_kernel_policy->result = result;
6670 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
6671 
6672 	if (necp_debug) {
6673 		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
6674 	}
6675 	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
6676 
6677 	return new_kernel_policy ? new_kernel_policy->id : 0;
6678 }
6679 
6680 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)6681 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
6682 {
6683 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6684 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6685 
6686 	if (policy_id == 0) {
6687 		return NULL;
6688 	}
6689 
6690 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
6691 		if (kernel_policy->id == policy_id) {
6692 			return kernel_policy;
6693 		}
6694 	}
6695 
6696 	return NULL;
6697 }
6698 
6699 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)6700 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
6701 {
6702 	struct necp_kernel_ip_output_policy * __single policy = NULL;
6703 
6704 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6705 
6706 	policy = necp_kernel_ip_output_policy_find(policy_id);
6707 	if (policy) {
6708 		LIST_REMOVE(policy, chain);
6709 
6710 		if (policy->cond_bound_interface) {
6711 			ifnet_release(policy->cond_bound_interface);
6712 			policy->cond_bound_interface = NULL;
6713 		}
6714 
6715 		zfree(necp_ip_policy_zone, policy);
6716 		return TRUE;
6717 	}
6718 
6719 	return FALSE;
6720 }
6721 
6722 static void
necp_kernel_ip_output_policies_dump_all(void)6723 necp_kernel_ip_output_policies_dump_all(void)
6724 {
6725 	if (necp_debug) {
6726 		struct necp_kernel_ip_output_policy *policy = NULL;
6727 		int policy_i;
6728 		int id_i;
6729 		char result_string[MAX_RESULT_STRING_LEN];
6730 		char proc_name_string[MAXCOMLEN + 1];
6731 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
6732 		memset(proc_name_string, 0, MAXCOMLEN + 1);
6733 
6734 		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
6735 		NECPLOG0(LOG_DEBUG, "-----------\n");
6736 		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
6737 			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
6738 			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++) {
6739 				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
6740 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
6741 				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));
6742 			}
6743 			NECPLOG0(LOG_DEBUG, "-----------\n");
6744 		}
6745 	}
6746 }
6747 
6748 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)6749 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
6750 {
6751 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6752 		if (upper_policy->session_order != lower_policy->session_order) {
6753 			// A skip cannot override a policy of a different session
6754 			return FALSE;
6755 		} else {
6756 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
6757 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
6758 				// This policy is beyond the skip
6759 				return FALSE;
6760 			} else {
6761 				// This policy is inside the skip
6762 				return TRUE;
6763 			}
6764 		}
6765 	}
6766 
6767 	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
6768 	return TRUE;
6769 }
6770 
6771 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)6772 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)
6773 {
6774 	bool can_skip = FALSE;
6775 	u_int32_t highest_skip_session_order = 0;
6776 	u_int32_t highest_skip_order = 0;
6777 	int i;
6778 	for (i = 0; i < valid_indices; i++) {
6779 		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
6780 
6781 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
6782 		if (can_skip) {
6783 			if (highest_skip_session_order != compared_policy->session_order ||
6784 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
6785 				// If we've moved on to the next session, or passed the skip window
6786 				highest_skip_session_order = 0;
6787 				highest_skip_order = 0;
6788 				can_skip = FALSE;
6789 			} else {
6790 				// If this policy is also a skip, in can increase the skip window
6791 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6792 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
6793 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6794 					}
6795 				}
6796 				continue;
6797 			}
6798 		}
6799 
6800 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6801 			// This policy is a skip. Set the skip window accordingly
6802 			can_skip = TRUE;
6803 			highest_skip_session_order = compared_policy->session_order;
6804 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6805 		}
6806 
6807 		// The result of the compared policy must be able to block out this policy result
6808 		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
6809 			continue;
6810 		}
6811 
6812 		// If new policy matches All Interfaces, compared policy must also
6813 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
6814 			continue;
6815 		}
6816 
6817 		// If new policy matches Local Networks, compared policy must also
6818 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
6819 			continue;
6820 		}
6821 
6822 		// Default makes lower policies unnecessary always
6823 		if (compared_policy->condition_mask == 0) {
6824 			return TRUE;
6825 		}
6826 
6827 		// Compared must be more general than policy, and include only conditions within policy
6828 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
6829 			continue;
6830 		}
6831 
6832 		// Negative conditions must match for the overlapping conditions
6833 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
6834 			continue;
6835 		}
6836 
6837 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
6838 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
6839 			continue;
6840 		}
6841 
6842 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
6843 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
6844 			continue;
6845 		}
6846 
6847 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
6848 		    compared_policy->cond_protocol != policy->cond_protocol) {
6849 			continue;
6850 		}
6851 
6852 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6853 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6854 				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))) {
6855 					continue;
6856 				}
6857 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6858 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
6859 				    !necp_is_addr_in_subnet(SA(&policy->cond_local_start), SA(&compared_policy->cond_local_start), compared_policy->cond_local_prefix)) {
6860 					continue;
6861 				}
6862 			}
6863 		}
6864 
6865 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6866 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6867 				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))) {
6868 					continue;
6869 				}
6870 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6871 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
6872 				    !necp_is_addr_in_subnet(SA(&policy->cond_remote_start), SA(&compared_policy->cond_remote_start), compared_policy->cond_remote_prefix)) {
6873 					continue;
6874 				}
6875 			}
6876 		}
6877 
6878 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
6879 		    compared_policy->cond_scheme_port != policy->cond_scheme_port) {
6880 			continue;
6881 		}
6882 
6883 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
6884 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
6885 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
6886 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
6887 			continue;
6888 		}
6889 
6890 		return TRUE;
6891 	}
6892 
6893 	return FALSE;
6894 }
6895 
6896 static bool
necp_kernel_ip_output_policies_reprocess(void)6897 necp_kernel_ip_output_policies_reprocess(void)
6898 {
6899 	int i;
6900 	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
6901 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6902 
6903 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6904 
6905 	// Reset mask to 0
6906 	necp_kernel_ip_output_policies_condition_mask = 0;
6907 	necp_kernel_ip_output_policies_count = 0;
6908 	necp_kernel_ip_output_policies_non_id_count = 0;
6909 
6910 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6911 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
6912 			kfree_type(struct necp_kernel_ip_output_policy *,
6913 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
6914 			    necp_kernel_ip_output_policies_map[i]);
6915 			necp_kernel_ip_output_policies_map[i] = NULL;
6916 		}
6917 
6918 		// Init counts
6919 		necp_kernel_ip_output_policies_map_counts[i] = 0;
6920 	}
6921 
6922 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6923 		// Update mask
6924 		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
6925 		necp_kernel_ip_output_policies_count++;
6926 
6927 		/* Update bucket counts:
6928 		 * Non-id and SKIP policies will be added to all buckets
6929 		 * Add local networks policy to all buckets for incoming IP
6930 		 */
6931 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6932 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6933 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6934 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6935 				necp_kernel_ip_output_policies_map_counts[i]++;
6936 			}
6937 		}
6938 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
6939 			necp_kernel_ip_output_policies_non_id_count++;
6940 		} else {
6941 			necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
6942 		}
6943 	}
6944 
6945 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6946 		if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
6947 			// Allocate a NULL-terminated array of policy pointers for each bucket
6948 			necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
6949 			    necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
6950 			if (necp_kernel_ip_output_policies_map[i] == NULL) {
6951 				goto fail;
6952 			}
6953 		}
6954 		bucket_current_free_index[i] = 0;
6955 	}
6956 
6957 	u_int32_t current_session_order = 0;
6958 	u_int32_t current_session_last_non_skip_policy = 0;
6959 
6960 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6961 		// For each new session, find the last non-skip policy. We can
6962 		// avoid adding any skip policies that don't actually skip over
6963 		// any non-skip policies.
6964 		if (current_session_order != kernel_policy->session_order) {
6965 			current_session_order = kernel_policy->session_order;
6966 			current_session_last_non_skip_policy = 0;
6967 
6968 			struct necp_kernel_ip_output_policy *inner_policy = NULL;
6969 			LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
6970 				if (inner_policy->session_order < current_session_order) {
6971 					continue;
6972 				}
6973 				if (inner_policy->session_order > current_session_order) {
6974 					break;
6975 				}
6976 				if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6977 					continue;
6978 				}
6979 
6980 				current_session_last_non_skip_policy = inner_policy->order;
6981 			}
6982 		}
6983 
6984 		if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6985 			if (current_session_last_non_skip_policy == 0) {
6986 				// No useful policies to skip over, don't add
6987 				continue;
6988 			}
6989 			if (kernel_policy->order >= current_session_last_non_skip_policy) {
6990 				// Skip policy is after the last useful policy, don't add
6991 				continue;
6992 			}
6993 		}
6994 
6995 		// Insert pointers into map
6996 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6997 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6998 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6999 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7000 				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])) {
7001 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7002 					bucket_current_free_index[i]++;
7003 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7004 				}
7005 			}
7006 		} else {
7007 			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
7008 			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])) {
7009 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
7010 				bucket_current_free_index[i]++;
7011 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
7012 			}
7013 		}
7014 	}
7015 
7016 	if (bucket_current_free_index[0] == 0) {
7017 		// No non-id policies were actually added
7018 		necp_kernel_ip_output_policies_non_id_count = 0;
7019 
7020 		// Also check if no policies at all were added
7021 		bool policies_added = FALSE;
7022 		for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7023 			if (bucket_current_free_index[i] != 0) {
7024 				policies_added = TRUE;
7025 				break;
7026 			}
7027 		}
7028 		if (!policies_added) {
7029 			necp_kernel_ip_output_policies_condition_mask = 0;
7030 			necp_kernel_ip_output_policies_count = 0;
7031 		}
7032 	}
7033 
7034 	necp_kernel_ip_output_policies_dump_all();
7035 	return TRUE;
7036 
7037 fail:
7038 	// Free memory, reset mask to 0
7039 	necp_kernel_ip_output_policies_condition_mask = 0;
7040 	necp_kernel_ip_output_policies_count = 0;
7041 	necp_kernel_ip_output_policies_non_id_count = 0;
7042 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
7043 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
7044 			kfree_type(struct necp_kernel_ip_output_policy *,
7045 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
7046 			    necp_kernel_ip_output_policies_map[i]);
7047 			necp_kernel_ip_output_policies_map[i] = NULL;
7048 		}
7049 	}
7050 	return FALSE;
7051 }
7052 
7053 // Outbound Policy Matching
7054 // ---------------------
7055 struct substring {
7056 	size_t length;
7057 	char * __sized_by(length) string;
7058 };
7059 
7060 static struct substring
necp_trim_dots_and_stars(char * __sized_by (length)string,size_t length)7061 necp_trim_dots_and_stars(char * __sized_by(length)string, size_t length)
7062 {
7063 	struct substring sub = {};
7064 	char * __indexable ptr = string;
7065 	size_t len = string ? length : 0;
7066 
7067 	while (len && (ptr[0] == '.' || ptr[0] == '*')) {
7068 		ptr++;
7069 		len--;
7070 	}
7071 
7072 	while (len && (ptr[len - 1] == '.' || ptr[len - 1] == '*')) {
7073 		len--;
7074 	}
7075 
7076 	sub.string = ptr;
7077 	sub.length = len;
7078 	return sub;
7079 }
7080 
7081 static char * __null_terminated
necp_create_trimmed_domain(char * __sized_by (length)string,size_t length)7082 necp_create_trimmed_domain(char * __sized_by(length)string, size_t length)
7083 {
7084 	size_t trimmed_domain_length = 0;
7085 	char *trimmed_domain = NULL;
7086 	struct substring sub = necp_trim_dots_and_stars(string, length);
7087 
7088 	trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
7089 	trimmed_domain_length = sub.length + 1;
7090 	if (trimmed_domain == NULL) {
7091 		return NULL;
7092 	}
7093 
7094 	strbufcpy(trimmed_domain, trimmed_domain_length, sub.string, sub.length);
7095 	trimmed_domain[sub.length] = 0;
7096 
7097 	return __unsafe_null_terminated_from_indexable(trimmed_domain, &trimmed_domain[sub.length]);
7098 }
7099 
7100 static inline int
necp_count_dots(char * __sized_by (length)string,size_t length)7101 necp_count_dots(char * __sized_by(length)string, size_t length)
7102 {
7103 	int dot_count = 0;
7104 	size_t i = 0;
7105 
7106 	for (i = 0; i < length; i++) {
7107 		if (string[i] == '.') {
7108 			dot_count++;
7109 		}
7110 	}
7111 
7112 	return dot_count;
7113 }
7114 
7115 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)7116 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
7117 {
7118 	if (parent.length <= suffix.length) {
7119 		return FALSE;
7120 	}
7121 
7122 	size_t length_difference = (parent.length - suffix.length);
7123 
7124 	if (require_dot_before_suffix) {
7125 		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
7126 			return FALSE;
7127 		}
7128 	}
7129 
7130 	// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7131 	return strbufcasecmp(parent.string + length_difference, parent.length - length_difference, suffix.string, suffix.length) == 0;
7132 }
7133 
7134 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)7135 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain __null_terminated, u_int8_t domain_dot_count)
7136 {
7137 	if (hostname_substring.string == NULL || domain == NULL) {
7138 		return hostname_substring.string == domain;
7139 	}
7140 
7141 	struct substring domain_substring;
7142 	domain_substring.string = __unsafe_null_terminated_to_indexable(domain);
7143 	domain_substring.length = strlen(domain);
7144 
7145 	if (hostname_dot_count == domain_dot_count) {
7146 		// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
7147 		if (hostname_substring.length == domain_substring.length &&
7148 		    strbufcasecmp(hostname_substring.string, hostname_substring.length, domain_substring.string, domain_substring.length) == 0) {
7149 			return TRUE;
7150 		}
7151 	} else if (domain_dot_count < hostname_dot_count) {
7152 		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
7153 			return TRUE;
7154 		}
7155 	}
7156 
7157 	return FALSE;
7158 }
7159 
7160 bool
net_domain_contains_hostname(char * hostname_string __null_terminated,char * domain_string __null_terminated)7161 net_domain_contains_hostname(char *hostname_string __null_terminated, char *domain_string __null_terminated)
7162 {
7163 	if (hostname_string == NULL ||
7164 	    domain_string == NULL) {
7165 		return false;
7166 	}
7167 
7168 	struct substring hostname_substring;
7169 	hostname_substring.string = __unsafe_null_terminated_to_indexable(hostname_string);
7170 	hostname_substring.length = strlen(hostname_string);
7171 
7172 	return necp_hostname_matches_domain(hostname_substring,
7173 	           necp_count_dots(hostname_substring.string, hostname_substring.length),
7174 	           domain_string,
7175 	           necp_count_dots(__unsafe_null_terminated_to_indexable(domain_string), strlen(domain_string)));
7176 }
7177 
7178 #define NECP_MAX_STRING_LEN 1024
7179 
7180 static char * __null_terminated
necp_copy_string(char * __sized_by (length)string,size_t length)7181 necp_copy_string(char * __sized_by(length)string, size_t length)
7182 {
7183 	size_t copied_string_length = 0;
7184 	char * __sized_by(copied_string_length) copied_string = NULL;
7185 
7186 	if (length > NECP_MAX_STRING_LEN) {
7187 		return NULL;
7188 	}
7189 
7190 	copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
7191 	copied_string_length = length + 1;
7192 	if (copied_string == NULL) {
7193 		return NULL;
7194 	}
7195 
7196 	memcpy(copied_string, string, length);
7197 	copied_string[length] = 0;
7198 
7199 	return __unsafe_null_terminated_from_indexable(copied_string, &copied_string[length]);
7200 }
7201 
7202 static u_int32_t
necp_get_primary_direct_interface_index(void)7203 necp_get_primary_direct_interface_index(void)
7204 {
7205 	u_int32_t interface_index = IFSCOPE_NONE;
7206 
7207 	ifnet_head_lock_shared();
7208 	struct ifnet *ordered_interface = NULL;
7209 	TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
7210 		const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
7211 		if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
7212 		    functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
7213 			// All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
7214 			interface_index = ordered_interface->if_index;
7215 			break;
7216 		}
7217 	}
7218 	ifnet_head_done();
7219 
7220 	return interface_index;
7221 }
7222 
7223 static inline bool
necp_task_has_match_entitlement(task_t task)7224 necp_task_has_match_entitlement(task_t task)
7225 {
7226 	return task != NULL &&
7227 	       (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
7228 	       IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
7229 }
7230 
7231 // Loopback traffic from certain entitled process will be dropped
7232 static inline bool
necp_task_has_loopback_drop_entitlement(task_t task)7233 necp_task_has_loopback_drop_entitlement(task_t task)
7234 {
7235 	bool drop = (task != NULL && IOTaskHasEntitlement(task, NECP_DDE_ENTITLEMENT));
7236 	if (drop) {
7237 		necp_drop_loopback_count++;
7238 	}
7239 	return drop;
7240 }
7241 
7242 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)7243 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
7244 {
7245 	coalition_t __single coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
7246 
7247 	if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
7248 		// No parent, nothing to do
7249 		return;
7250 	}
7251 
7252 	task_t __single lead_task = coalition_get_leader(coal);
7253 	if (lead_task != NULL) {
7254 		info->is_entitled = necp_task_has_match_entitlement(lead_task);
7255 		task_deallocate(lead_task);
7256 	}
7257 }
7258 
7259 // Some processes, due to particular entitlements, require using an NECP client to
7260 // access networking. Returns true if the result should be a Drop.
7261 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)7262 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7263 {
7264 	if (necp_is_platform_binary(proc)) {
7265 		// This check is currently for the "on-demand-install-capable"
7266 		// entitlement, which by definition cannot be a built-in platform
7267 		// binary.
7268 		return false;
7269 	}
7270 
7271 	task_t __single task = proc_task(proc ? proc : current_proc());
7272 
7273 	if (!info->has_client &&
7274 	    task != NULL &&
7275 	    IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7276 		// Drop connections that don't use NECP clients and have the
7277 		// com.apple.developer.on-demand-install-capable entitlement.
7278 		// This effectively restricts those processes to only using
7279 		// an NECP-aware path for networking.
7280 		return true;
7281 	} else {
7282 		return false;
7283 	}
7284 }
7285 
7286 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7287 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7288 {
7289 	if (!necp_restrict_multicast || proc == NULL) {
7290 		return false;
7291 	}
7292 
7293 	// Check for multicast/broadcast here
7294 	if (info->remote_addr.sa.sa_family == AF_INET) {
7295 		if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7296 		    info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7297 			return false;
7298 		}
7299 	} else if (info->remote_addr.sa.sa_family == AF_INET6) {
7300 		if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7301 			return false;
7302 		}
7303 	} else {
7304 		// Not IPv4/IPv6
7305 		return false;
7306 	}
7307 
7308 	if (necp_is_platform_binary(proc)) {
7309 		return false;
7310 	}
7311 
7312 	const uint32_t platform = proc_platform(proc);
7313 	const uint32_t sdk = proc_sdk(proc);
7314 
7315 	// Enforce for iOS, linked on or after version 14
7316 	// If the caller set `check_minor_version`, only enforce starting at 14.5
7317 	if ((platform != PLATFORM_IOS ||
7318 	    sdk == 0 ||
7319 	    (sdk >> 16) < 14 ||
7320 	    (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7321 		return false;
7322 	}
7323 
7324 	// Allow entitled processes to use multicast
7325 	task_t __single task = proc_task(proc);
7326 	if (task != NULL &&
7327 	    IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7328 		return false;
7329 	}
7330 
7331 	const uint32_t min_sdk = proc_min_sdk(proc);
7332 	NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7333 
7334 	return true;
7335 }
7336 
7337 #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)
7338 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)7339 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)
7340 {
7341 	memset(info, 0, sizeof(struct necp_socket_info));
7342 
7343 	info->pid = pid;
7344 	info->pid_version = pid_version;
7345 	info->uid = uid;
7346 	info->real_uid = real_uid;
7347 	info->protocol = protocol;
7348 	info->bound_interface_index = bound_interface_index;
7349 	info->traffic_class = traffic_class;
7350 	info->has_client = has_client;
7351 	info->has_system_signed_result = has_system_signed_result;
7352 	info->drop_order = drop_order;
7353 	info->client_flags = client_flags;
7354 	info->is_loopback = is_loopback;
7355 	info->is_delegated = is_delegated;
7356 
7357 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7358 	    info->bound_interface_index != IFSCOPE_NONE) {
7359 		ifnet_head_lock_shared();
7360 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7361 		if (interface != NULL) {
7362 			info->bound_interface_flags = interface->if_flags;
7363 			info->bound_interface_eflags = interface->if_eflags;
7364 			info->bound_interface_xflags = interface->if_xflags;
7365 		}
7366 		ifnet_head_done();
7367 	}
7368 
7369 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7370 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7371 		if (existing_mapping) {
7372 			info->application_id = existing_mapping->id;
7373 		}
7374 	}
7375 
7376 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7377 		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7378 			info->real_application_id = info->application_id;
7379 		} else {
7380 			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7381 			if (existing_mapping) {
7382 				info->real_application_id = existing_mapping->id;
7383 			}
7384 		}
7385 	}
7386 
7387 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7388 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7389 		if (existing_mapping != NULL) {
7390 			info->real_application_id = info->application_id;
7391 			info->application_id = existing_mapping->id;
7392 			info->used_responsible_pid = true;
7393 		}
7394 	}
7395 
7396 	if (info->used_responsible_pid) {
7397 		proc = responsible_proc;
7398 	}
7399 
7400 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7401 		info->is_entitled = necp_task_has_match_entitlement(task);
7402 		if (!info->is_entitled) {
7403 			// Task does not have entitlement, check the parent task
7404 			necp_get_parent_is_entitled(task, info);
7405 		}
7406 	}
7407 
7408 	if (((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
7409 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) && proc != NULL) {
7410 		if (necp_is_platform_binary(proc)) {
7411 			info->is_platform_binary = true;
7412 		} else if (responsible_proc != NULL && necp_is_platform_binary(responsible_proc)) {
7413 			info->is_platform_binary = true;
7414 			info->used_responsible_pid = true;
7415 		} else {
7416 			info->is_platform_binary = false;
7417 		}
7418 	}
7419 
7420 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7421 		info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7422 	}
7423 
7424 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7425 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7426 		if (existing_mapping) {
7427 			info->account_id = existing_mapping->id;
7428 		}
7429 	}
7430 
7431 	if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7432 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7433 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7434 		info->domain = domain;
7435 	}
7436 
7437 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7438 		info->url = url;
7439 	}
7440 
7441 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
7442 	    necp_restrict_multicast ||
7443 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7444 		if (local_addr && local_addr->sa.sa_len > 0) {
7445 			SOCKADDR_COPY(local_addr, &info->local_addr, local_addr->sa.sa_len);
7446 			if (local_port != 0) {
7447 				info->local_addr.sin6.sin6_port = local_port;
7448 			}
7449 		} else {
7450 			if (remote_addr && remote_addr->sa.sa_len > 0) {
7451 				info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7452 				info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7453 			} else {
7454 				info->local_addr.sin6.sin6_family = AF_INET6;
7455 				info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7456 			}
7457 			if (local_port != 0) {
7458 				info->local_addr.sin6.sin6_port = local_port;
7459 			}
7460 		}
7461 		if (remote_addr && remote_addr->sa.sa_len > 0) {
7462 			SOCKADDR_COPY(remote_addr, &info->remote_addr, remote_addr->sa.sa_len);
7463 			if (remote_port != 0) {
7464 				info->remote_addr.sin6.sin6_port = remote_port;
7465 			}
7466 		} else if (remote_port != 0) {
7467 			info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7468 			info->remote_addr.sin6.sin6_family = AF_INET6;
7469 			info->remote_addr.sin6.sin6_port = remote_port;
7470 		}
7471 	}
7472 
7473 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7474 		info->scheme_port = scheme_port;
7475 	}
7476 }
7477 
7478 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7479 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7480 {
7481 	struct kev_netpolicy_ifdenied ev_ifdenied;
7482 
7483 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7484 
7485 	ev_ifdenied.ev_data.epid = pid;
7486 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7487 	ev_ifdenied.ev_if_functional_type = if_functional_type;
7488 
7489 	netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7490 }
7491 
7492 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7493 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7494 {
7495 	struct kev_netpolicy_netdenied ev_netdenied = {};
7496 
7497 	bzero(&ev_netdenied, sizeof(ev_netdenied));
7498 
7499 	ev_netdenied.ev_data.epid = pid;
7500 	uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7501 	ev_netdenied.ev_network_type = network_type;
7502 
7503 	netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7504 }
7505 
7506 extern char *proc_name_address(void *p);
7507 
7508 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7509 	if (!has_checked_delegation_entitlement) { \
7510 	        has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7511 	        has_checked_delegation_entitlement = TRUE; \
7512 	} \
7513 	if (!has_delegation_entitlement) { \
7514 	        NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7515 	                                          proc_name_address(_p), proc_pid(_p), _d); \
7516 	        break; \
7517 	}
7518 
7519 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)7520 necp_application_find_policy_match_internal(proc_t proc,
7521     u_int8_t * __sized_by(parameters_size)parameters,
7522     u_int32_t parameters_size,
7523     struct necp_aggregate_result *returned_result,
7524     u_int32_t *flags,
7525     u_int32_t *reason,
7526     u_int required_interface_index,
7527     const union necp_sockaddr_union *override_local_addr,
7528     const union necp_sockaddr_union *override_remote_addr,
7529     struct necp_client_endpoint *returned_v4_gateway,
7530     struct necp_client_endpoint *returned_v6_gateway,
7531     struct rtentry **returned_route, bool ignore_address,
7532     bool has_client,
7533     uuid_t *returned_override_euuid)
7534 {
7535 	int error = 0;
7536 	size_t offset = 0;
7537 
7538 	struct necp_kernel_socket_policy *matched_policy = NULL;
7539 	struct necp_socket_info info = {};
7540 	necp_kernel_policy_filter filter_control_unit = 0;
7541 	necp_kernel_policy_result service_action = 0;
7542 	necp_kernel_policy_service service = { 0, 0 };
7543 
7544 	u_int16_t protocol = 0;
7545 	u_int32_t bound_interface_index = required_interface_index;
7546 	u_int32_t traffic_class = 0;
7547 	u_int32_t client_flags = 0;
7548 	u_int16_t scheme_port = 0;
7549 	union necp_sockaddr_union local_addr;
7550 	union necp_sockaddr_union remote_addr;
7551 	bool no_remote_addr = FALSE;
7552 	u_int8_t remote_family = 0;
7553 	bool no_local_addr = FALSE;
7554 	u_int16_t local_port = 0;
7555 	u_int16_t remote_port = 0;
7556 	u_int32_t remote_endpoint_type = 0;
7557 	bool remote_address_is_empty = false;
7558 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7559 	bool is_delegated = false;
7560 
7561 	if (override_local_addr) {
7562 		memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7563 	} else {
7564 		memset(&local_addr, 0, sizeof(local_addr));
7565 	}
7566 	if (override_remote_addr) {
7567 		memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7568 	} else {
7569 		memset(&remote_addr, 0, sizeof(remote_addr));
7570 	}
7571 
7572 	// Initialize UID, PID, and UUIDs to the current process
7573 	uid_t uid = 0;
7574 	uid_t real_uid = 0;
7575 	kauth_cred_t __single cred = kauth_cred_proc_ref(proc);
7576 	if (cred != NULL) {
7577 		uid = kauth_cred_getuid(cred);
7578 		real_uid = uid;
7579 	}
7580 	task_t __single task = proc_task(proc);
7581 	pid_t pid = proc_pid(proc);
7582 	int32_t pid_version = proc_pidversion(proc);
7583 	uuid_t application_uuid;
7584 	uuid_clear(application_uuid);
7585 	uuid_t real_application_uuid;
7586 	uuid_clear(real_application_uuid);
7587 	proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7588 	uuid_copy(application_uuid, real_application_uuid);
7589 	uuid_t responsible_application_uuid;
7590 	uuid_clear(responsible_application_uuid);
7591 
7592 	char *domain __null_terminated = NULL;
7593 	char *url __null_terminated = NULL;
7594 	char *account __null_terminated = NULL;
7595 
7596 #define NECP_MAX_REQUIRED_AGENTS 16
7597 	u_int32_t num_required_agent_types = 0;
7598 	struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7599 	memset(&required_agent_types, 0, sizeof(required_agent_types));
7600 
7601 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7602 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7603 	memset(&netagent_ids, 0, sizeof(netagent_ids));
7604 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7605 	int netagent_cursor;
7606 
7607 	bool has_checked_delegation_entitlement = false;
7608 	bool has_delegation_entitlement = false;
7609 	bool has_system_signed_result = false;
7610 
7611 	proc_t responsible_proc = PROC_NULL;
7612 	proc_t effective_proc = proc;
7613 	bool release_eproc = false;
7614 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7615 
7616 	u_int32_t flow_divert_aggregate_unit = 0;
7617 
7618 	if (returned_result == NULL) {
7619 		if (cred != NULL) {
7620 			kauth_cred_unref(&cred);
7621 		}
7622 		return EINVAL;
7623 	}
7624 
7625 	if (returned_v4_gateway != NULL) {
7626 		memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7627 	}
7628 
7629 	if (returned_v6_gateway != NULL) {
7630 		memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7631 	}
7632 
7633 	if (returned_override_euuid != NULL) {
7634 		uuid_clear(*returned_override_euuid);
7635 	}
7636 
7637 	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7638 
7639 	u_int32_t drop_order = necp_process_drop_order(cred);
7640 
7641 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7642 
7643 	lck_rw_lock_shared(&necp_kernel_policy_lock);
7644 	if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7645 		if (necp_drop_all_order > 0 || drop_order > 0) {
7646 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7647 			lck_rw_done(&necp_kernel_policy_lock);
7648 			if (cred != NULL) {
7649 				kauth_cred_unref(&cred);
7650 			}
7651 			return 0;
7652 		}
7653 	}
7654 	lck_rw_done(&necp_kernel_policy_lock);
7655 
7656 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
7657 		u_int8_t type = necp_buffer_get_tlv_type(parameters, parameters_size, offset);
7658 		u_int32_t length = necp_buffer_get_tlv_length(parameters, parameters_size, offset);
7659 
7660 		if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
7661 			// If the length is larger than what can fit in the remaining parameters size, bail
7662 			NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
7663 			break;
7664 		}
7665 
7666 		if (length > 0) {
7667 			u_int8_t * __indexable value = necp_buffer_get_tlv_value(parameters, parameters_size, offset, NULL);
7668 			if (value != NULL) {
7669 				switch (type) {
7670 				case NECP_CLIENT_PARAMETER_APPLICATION: {
7671 					if (length >= sizeof(uuid_t)) {
7672 						if (uuid_compare(application_uuid, value) == 0) {
7673 							// No delegation
7674 							break;
7675 						}
7676 
7677 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
7678 
7679 						is_delegated = true;
7680 						uuid_copy(application_uuid, value);
7681 					}
7682 					break;
7683 				}
7684 				case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
7685 					if (length >= sizeof(uuid_t)) {
7686 						if (uuid_compare(real_application_uuid, value) == 0) {
7687 							// No delegation
7688 							break;
7689 						}
7690 
7691 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
7692 
7693 						is_delegated = true;
7694 						uuid_copy(real_application_uuid, value);
7695 					}
7696 					break;
7697 				}
7698 				case NECP_CLIENT_PARAMETER_PID: {
7699 					if (length >= sizeof(pid_t)) {
7700 						if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
7701 							// No delegation
7702 							break;
7703 						}
7704 
7705 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
7706 
7707 						is_delegated = true;
7708 						memcpy(&pid, value, sizeof(pid_t));
7709 					}
7710 					break;
7711 				}
7712 				case NECP_CLIENT_PARAMETER_UID: {
7713 					if (length >= sizeof(uid_t)) {
7714 						if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
7715 							// No delegation
7716 							break;
7717 						}
7718 
7719 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
7720 
7721 						is_delegated = true;
7722 						memcpy(&uid, value, sizeof(uid_t));
7723 					}
7724 					break;
7725 				}
7726 				case NECP_CLIENT_PARAMETER_DOMAIN: {
7727 					char *ptr = (char *)value;
7728 					ptr[length - 1] = 0;
7729 					domain = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
7730 					break;
7731 				}
7732 				case NECP_CLIENT_PARAMETER_URL: {
7733 					char *ptr = (char *)value;
7734 					ptr[length - 1] = 0;
7735 					url = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
7736 					break;
7737 				}
7738 				case NECP_CLIENT_PARAMETER_ACCOUNT: {
7739 					char *ptr = (char *)value;
7740 					ptr[length - 1] = 0;
7741 					account = __unsafe_null_terminated_from_indexable(ptr, &ptr[length - 1]);
7742 					break;
7743 				}
7744 				case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
7745 					if (length >= sizeof(u_int32_t)) {
7746 						memcpy(&traffic_class, value, sizeof(u_int32_t));
7747 					}
7748 					break;
7749 				}
7750 				case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
7751 					if (length >= sizeof(u_int16_t)) {
7752 						memcpy(&protocol, value, sizeof(u_int16_t));
7753 					} else if (length >= sizeof(u_int8_t)) {
7754 						memcpy(&protocol, value, sizeof(u_int8_t));
7755 					}
7756 					break;
7757 				}
7758 				case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
7759 					if (length <= IFXNAMSIZ && length > 0) {
7760 						ifnet_t __single bound_interface = NULL;
7761 						char interface_name[IFXNAMSIZ];
7762 						memcpy(interface_name, value, length);
7763 						interface_name[length - 1] = 0;         // Make sure the string is NULL terminated
7764 						if (ifnet_find_by_name(__unsafe_null_terminated_from_indexable(interface_name, &interface_name[length - 1]), &bound_interface) == 0) {
7765 							bound_interface_index = bound_interface->if_index;
7766 							ifnet_release(bound_interface);
7767 						}
7768 					}
7769 					break;
7770 				}
7771 				case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
7772 					if (ignore_address || override_local_addr) {
7773 						break;
7774 					}
7775 
7776 					if (length >= sizeof(struct necp_policy_condition_addr)) {
7777 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7778 						if (necp_address_is_valid(&address_struct->address.sa)) {
7779 							memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
7780 						}
7781 					}
7782 					break;
7783 				}
7784 				case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
7785 					if (ignore_address || override_remote_addr) {
7786 						break;
7787 					}
7788 
7789 					if (length >= sizeof(struct necp_policy_condition_addr)) {
7790 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7791 						if (necp_address_is_valid(&address_struct->address.sa)) {
7792 							memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
7793 						}
7794 					}
7795 					break;
7796 				}
7797 				case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
7798 					if (ignore_address || override_local_addr) {
7799 						break;
7800 					}
7801 
7802 					if (length >= sizeof(struct necp_client_endpoint)) {
7803 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7804 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
7805 						    endpoint->u.endpoint.endpoint_port != 0) {
7806 							// Save port
7807 							local_port = endpoint->u.endpoint.endpoint_port;
7808 						}
7809 					}
7810 					break;
7811 				}
7812 				case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
7813 					if (ignore_address || override_remote_addr) {
7814 						break;
7815 					}
7816 
7817 					if (length >= sizeof(struct necp_client_endpoint)) {
7818 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7819 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
7820 							remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
7821 							if (endpoint->u.endpoint.endpoint_port != 0) {
7822 								// Save port
7823 								remote_port = endpoint->u.endpoint.endpoint_port;
7824 							}
7825 						} else if (necp_addr_is_empty(&endpoint->u.sa)) {
7826 							remote_address_is_empty = true;
7827 						}
7828 					}
7829 					break;
7830 				}
7831 				case NECP_CLIENT_PARAMETER_FLAGS: {
7832 					if (length >= sizeof(client_flags)) {
7833 						memcpy(&client_flags, value, sizeof(client_flags));
7834 					}
7835 					break;
7836 				}
7837 				case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
7838 				case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
7839 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
7840 						break;
7841 					}
7842 					if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
7843 						memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
7844 						num_required_agent_types++;
7845 					}
7846 					break;
7847 				}
7848 				case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
7849 					if (length >= sizeof(scheme_port)) {
7850 						memcpy(&scheme_port, value, sizeof(scheme_port));
7851 					}
7852 					break;
7853 				}
7854 				case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
7855 					has_system_signed_result = true;
7856 					struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
7857 					if (length >= sizeof(struct necp_client_validatable)) {
7858 						// Check for system-signed sign_type values
7859 						if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
7860 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
7861 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
7862 							has_system_signed_result = true;
7863 						}
7864 					}
7865 					break;
7866 				}
7867 				default: {
7868 					break;
7869 				}
7870 				}
7871 			}
7872 		}
7873 
7874 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
7875 	}
7876 
7877 	// Check for loopback exception
7878 	if (necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
7879 		if (necp_task_has_loopback_drop_entitlement(task)) {
7880 			// Disallow certain entitled processes to send loopback traffic
7881 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7882 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7883 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7884 			if (cred != NULL) {
7885 				kauth_cred_unref(&cred);
7886 			}
7887 			return 0;
7888 		}
7889 		if (necp_pass_loopback > 0) {
7890 			bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
7891 		}
7892 	} else if (bound_interface_index != IFSCOPE_NONE) {
7893 		// Check for inter-process exception
7894 		struct sockaddr *dst = SA(&remote_addr.sa);
7895 		if (dst->sa_family == AF_INET6) {
7896 			struct in6_addr *addrv6 = &SIN6(dst)->sin6_addr;
7897 			if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
7898 				ifnet_head_lock_shared();
7899 				ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
7900 				if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
7901 					bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
7902 				}
7903 				ifnet_head_done();
7904 			}
7905 		}
7906 	}
7907 
7908 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
7909 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7910 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7911 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7912 		if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
7913 			returned_result->routed_interface_index = lo_ifp->if_index;
7914 			*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7915 		} else {
7916 			returned_result->routed_interface_index = bound_interface_index;
7917 		}
7918 		if (cred != NULL) {
7919 			kauth_cred_unref(&cred);
7920 		}
7921 		return 0;
7922 	}
7923 
7924 	if (drop_order != 0) {
7925 		if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
7926 		    client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
7927 		    ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
7928 			// Allow listeners, inbound connections without remote addresses, and
7929 			// application service connections to bypass the unentitled drop order,
7930 			// to allow them to connect to application services (not directly over
7931 			// physical networking interfaces)
7932 			drop_order = 0;
7933 		}
7934 	}
7935 
7936 	if (proc_pid(effective_proc) != pid) {
7937 		proc_t found_proc = proc_find(pid);
7938 		if (found_proc != PROC_NULL) {
7939 			effective_proc = found_proc;
7940 			pid_version = proc_pidversion(effective_proc);
7941 			release_eproc = true;
7942 		}
7943 	}
7944 #if defined(XNU_TARGET_OS_OSX)
7945 	if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
7946 		proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
7947 		responsible_proc = proc_find(effective_proc->p_responsible_pid);
7948 	}
7949 #endif /* defined(XNU_TARGET_OS_OSX) */
7950 
7951 	// Lock
7952 	lck_rw_lock_shared(&necp_kernel_policy_lock);
7953 
7954 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
7955 	size_t route_rule_id_array_count = 0;
7956 	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);
7957 
7958 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
7959 	NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
7960 
7961 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
7962 	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map,
7963 	    &info,
7964 	    &filter_control_unit,
7965 	    route_rule_id_array,
7966 	    &route_rule_id_array_count,
7967 	    MAX_AGGREGATE_ROUTE_RULES,
7968 	    &service_action,
7969 	    &service,
7970 	    netagent_ids,
7971 	    NECP_MAX_NETAGENTS,
7972 	    netagent_use_flags,
7973 	    NECP_MAX_NETAGENTS,
7974 	    required_agent_types,
7975 	    num_required_agent_types,
7976 	    info.used_responsible_pid ? responsible_proc : effective_proc,
7977 	    0,
7978 	    &skip_policy_id,
7979 	    NULL,
7980 	    &drop_dest_policy_result,
7981 	    &drop_all_bypass,
7982 	    &flow_divert_aggregate_unit,
7983 	    NULL,
7984 	    debug);
7985 
7986 	// Check for loopback exception again after the policy match
7987 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
7988 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
7989 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
7990 		if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7991 			returned_result->filter_control_unit = 0;
7992 		} else {
7993 			returned_result->filter_control_unit = filter_control_unit;
7994 		}
7995 
7996 		if (flow_divert_aggregate_unit > 0) {
7997 			returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7998 		}
7999 
8000 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8001 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8002 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
8003 		returned_result->routed_interface_index = lo_ifp->if_index;
8004 		*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8005 		error = 0;
8006 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - Loopback PASS <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8007 		goto done;
8008 	}
8009 
8010 	if (matched_policy) {
8011 		returned_result->policy_id = matched_policy->id;
8012 		returned_result->skip_policy_id = skip_policy_id;
8013 		returned_result->routing_result = matched_policy->result;
8014 		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
8015 		if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
8016 			uuid_copy(*returned_override_euuid, responsible_application_uuid);
8017 		}
8018 	} else {
8019 		bool drop_all = false;
8020 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
8021 			// Mark socket as a drop if drop_all is set
8022 			drop_all = true;
8023 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
8024 				drop_all_bypass = necp_check_drop_all_bypass_result(proc);
8025 			}
8026 		}
8027 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
8028 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8029 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8030 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8031 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", returned_result->policy_id, returned_result->skip_policy_id);
8032 		} else {
8033 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8034 			returned_result->skip_policy_id = skip_policy_id;
8035 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
8036 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - NO MATCH", returned_result->policy_id, returned_result->skip_policy_id);
8037 		}
8038 	}
8039 	if (necp_check_missing_client_drop(proc, &info) ||
8040 	    necp_check_restricted_multicast_drop(proc, &info, false)) {
8041 		// Mark as drop
8042 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8043 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
8044 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8045 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", returned_result->policy_id, returned_result->skip_policy_id);
8046 	}
8047 	if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
8048 		returned_result->filter_control_unit = 0;
8049 	} else {
8050 		returned_result->filter_control_unit = filter_control_unit;
8051 	}
8052 
8053 	if (flow_divert_aggregate_unit > 0) {
8054 		returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8055 	}
8056 
8057 	returned_result->service_action = service_action;
8058 
8059 	// Fetch service registration
8060 	if (service.identifier != 0) {
8061 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
8062 		if (mapping != NULL) {
8063 			struct necp_service_registration *service_registration = NULL;
8064 			uuid_copy(returned_result->service_uuid, mapping->uuid);
8065 			returned_result->service_data = service.data;
8066 			if (service.identifier == NECP_NULL_SERVICE_ID) {
8067 				// NULL service is always 'registered'
8068 				returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8069 			} else {
8070 				LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
8071 					if (service.identifier == service_registration->service_id) {
8072 						returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
8073 						break;
8074 					}
8075 				}
8076 			}
8077 		}
8078 	}
8079 
8080 	// Handle netagents
8081 	size_t netagent_i = 0;
8082 	for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8083 		struct necp_uuid_id_mapping *mapping = NULL;
8084 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
8085 		if (netagent_id == 0) {
8086 			continue;
8087 		}
8088 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8089 		if (mapping != NULL) {
8090 			uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
8091 			returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
8092 			netagent_i++;
8093 		}
8094 
8095 		// If the flags say to remove, clear the local copy
8096 		if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
8097 			netagent_ids[netagent_cursor] = 0;
8098 		}
8099 	}
8100 
8101 	// Do routing evaluation
8102 	u_int output_bound_interface = bound_interface_index;
8103 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
8104 		output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
8105 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
8106 		output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
8107 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
8108 		output_bound_interface = necp_get_primary_direct_interface_index();
8109 		if (output_bound_interface == IFSCOPE_NONE) {
8110 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8111 		} else {
8112 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
8113 			returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
8114 		}
8115 	}
8116 
8117 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
8118 	    returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
8119 		if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
8120 			// Trigger the event that we dropped due to a local network policy
8121 #if defined(XNU_TARGET_OS_OSX)
8122 			bool should_report_responsible_pid = (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid);
8123 			necp_send_network_denied_event(should_report_responsible_pid ? effective_proc->p_responsible_pid : pid,
8124 			    should_report_responsible_pid ? responsible_application_uuid : application_uuid,
8125 			    NETPOLICY_NETWORKTYPE_LOCAL);
8126 #else
8127 			necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
8128 #endif
8129 		}
8130 		if (reason != NULL) {
8131 			*reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
8132 		}
8133 	}
8134 
8135 	if (local_addr.sa.sa_len == 0 ||
8136 	    (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
8137 	    (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
8138 		no_local_addr = TRUE;
8139 	}
8140 
8141 	if (remote_addr.sa.sa_len == 0 ||
8142 	    (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
8143 	    (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
8144 		no_remote_addr = TRUE;
8145 		remote_family = remote_addr.sa.sa_family;
8146 	}
8147 
8148 	returned_result->routed_interface_index = 0;
8149 	struct rtentry *rt = NULL;
8150 	if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
8151 		// Treat the output bound interface as the routed interface for local address
8152 		// validation later.
8153 		returned_result->routed_interface_index = output_bound_interface;
8154 	} else {
8155 		if (no_remote_addr) {
8156 			memset(&remote_addr, 0, sizeof(remote_addr));
8157 			if (remote_family == AF_INET6) {
8158 				// Reset address to ::
8159 				remote_addr.sa.sa_family = AF_INET6;
8160 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8161 			} else {
8162 				// Reset address to 0.0.0.0
8163 				remote_addr.sa.sa_family = AF_INET;
8164 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
8165 			}
8166 		}
8167 
8168 		rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8169 		    output_bound_interface);
8170 
8171 		if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
8172 		    IS_INTF_CLAT46(rt->rt_ifp)) {
8173 			rtfree(rt);
8174 			rt = NULL;
8175 			returned_result->routed_interface_index = 0;
8176 		}
8177 
8178 		if (no_remote_addr && remote_family == AF_UNSPEC &&
8179 		    (rt == NULL || rt->rt_ifp == NULL)) {
8180 			// Route lookup for default IPv4 failed, try IPv6
8181 
8182 			// Cleanup old route if necessary
8183 			if (rt != NULL) {
8184 				rtfree(rt);
8185 				rt = NULL;
8186 			}
8187 
8188 			// Reset address to ::
8189 			memset(&remote_addr, 0, sizeof(remote_addr));
8190 			remote_addr.sa.sa_family = AF_INET6;
8191 			remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
8192 
8193 			// Get route
8194 			rt = rtalloc1_scoped(SA(&remote_addr), 0, 0,
8195 			    output_bound_interface);
8196 		}
8197 
8198 		if (rt != NULL &&
8199 		    rt->rt_ifp != NULL) {
8200 			returned_result->routed_interface_index = rt->rt_ifp->if_index;
8201 			/*
8202 			 * For local addresses, we allow the interface scope to be
8203 			 * either the loopback interface or the interface hosting the
8204 			 * local address.
8205 			 */
8206 			if (bound_interface_index != IFSCOPE_NONE &&
8207 			    rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
8208 			    (output_bound_interface == lo_ifp->if_index ||
8209 			    rt->rt_ifp->if_index == lo_ifp->if_index ||
8210 			    rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
8211 				struct sockaddr_storage dst;
8212 				unsigned int ifscope = bound_interface_index;
8213 
8214 				/*
8215 				 * Transform dst into the internal routing table form
8216 				 */
8217 				(void) sa_copy(SA(&remote_addr),
8218 				    &dst, &ifscope);
8219 
8220 				if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
8221 				    rt_ifa_is_dst(SA(&dst), rt->rt_ifa)) {
8222 					returned_result->routed_interface_index =
8223 					    bound_interface_index;
8224 				}
8225 			}
8226 		}
8227 	}
8228 
8229 	if (returned_result->routed_interface_index != 0 &&
8230 	    returned_result->routed_interface_index != lo_ifp->if_index &&     // Loopback can accept any local address
8231 	    !no_local_addr) {
8232 		// Transform local_addr into the ifaddr form
8233 		// IPv6 Scope IDs are always embedded in the ifaddr list
8234 		struct sockaddr_storage local_address_sanitized;
8235 		u_int ifscope = IFSCOPE_NONE;
8236 		(void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
8237 		SIN(&local_address_sanitized)->sin_port = 0;
8238 		if (local_address_sanitized.ss_family == AF_INET6) {
8239 			if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
8240 				SIN6(&local_address_sanitized)->sin6_scope_id = 0;
8241 			}
8242 		}
8243 
8244 		// Validate local address on routed interface
8245 		struct ifaddr *ifa = ifa_ifwithaddr_scoped(SA(&local_address_sanitized), returned_result->routed_interface_index);
8246 		if (ifa == NULL) {
8247 			// Interface address not found, reject route
8248 			returned_result->routed_interface_index = 0;
8249 			if (rt != NULL) {
8250 				rtfree(rt);
8251 				rt = NULL;
8252 			}
8253 		} else {
8254 			ifaddr_release(ifa);
8255 			ifa = NULL;
8256 		}
8257 	}
8258 
8259 	if (flags != NULL) {
8260 #if SKYWALK
8261 		if (kernel_is_macos_or_server()) {
8262 			enum net_filter_event_subsystems filters = net_filter_event_get_state();
8263 
8264 			if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
8265 				*flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
8266 			}
8267 			if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
8268 				*flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
8269 			}
8270 			if (filters & NET_FILTER_EVENT_ALF) {
8271 				*flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
8272 			}
8273 			if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
8274 				*flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
8275 			}
8276 		}
8277 #endif /* SKYWALK */
8278 		if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
8279 			// Check for local/direct
8280 			bool is_local = FALSE;
8281 			if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
8282 				is_local = TRUE;
8283 			} else if (returned_result->routed_interface_index != 0 &&
8284 			    !no_remote_addr) {
8285 				// Clean up the address before comparison with interface addresses
8286 
8287 				// Transform remote_addr into the ifaddr form
8288 				// IPv6 Scope IDs are always embedded in the ifaddr list
8289 				struct sockaddr_storage remote_address_sanitized;
8290 				u_int ifscope = IFSCOPE_NONE;
8291 				(void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
8292 				SIN(&remote_address_sanitized)->sin_port = 0;
8293 				if (remote_address_sanitized.ss_family == AF_INET6) {
8294 					if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
8295 						SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
8296 					}
8297 				}
8298 
8299 				// Check if remote address is an interface address
8300 				struct ifaddr *ifa = ifa_ifwithaddr(SA(&remote_address_sanitized));
8301 				if (ifa != NULL && ifa->ifa_ifp != NULL) {
8302 					u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
8303 					if (if_index_for_remote_addr == returned_result->routed_interface_index ||
8304 					    if_index_for_remote_addr == lo_ifp->if_index) {
8305 						is_local = TRUE;
8306 					}
8307 				}
8308 				if (ifa != NULL) {
8309 					ifaddr_release(ifa);
8310 					ifa = NULL;
8311 				}
8312 			}
8313 
8314 			if (is_local) {
8315 				*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
8316 			} else if (rt != NULL) {
8317 				if (rt->rt_flags & RTF_GLOBAL) {
8318 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8319 				} else if (!(rt->rt_flags & RTF_GATEWAY) &&
8320 				    (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8321 					// Route is directly accessible
8322 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8323 				}
8324 			}
8325 
8326 			if (rt != NULL &&
8327 			    rt->rt_ifp != NULL) {
8328 				// Check probe status
8329 				if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8330 					*flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8331 				}
8332 
8333 				if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8334 					struct if_cellular_status_v1 *ifsr;
8335 
8336 					ifnet_lock_shared(rt->rt_ifp);
8337 					lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8338 
8339 					if (rt->rt_ifp->if_link_status != NULL) {
8340 						ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8341 
8342 						if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8343 							if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8344 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8345 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8346 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8347 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8348 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8349 							}
8350 						}
8351 					}
8352 					lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8353 					ifnet_lock_done(rt->rt_ifp);
8354 				}
8355 
8356 				// Check link quality
8357 				if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8358 				    (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8359 				    rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8360 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8361 				}
8362 
8363 				// Check QoS marking (fastlane)
8364 				for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8365 					if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8366 						*flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8367 						// If the route can use QoS markings, stop iterating route rules
8368 						break;
8369 					}
8370 				}
8371 
8372 				if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8373 					*flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8374 				}
8375 
8376 				if (traffic_class == SO_TC_BK_SYS) {
8377 					// Block BK_SYS traffic if interface is throttled
8378 					u_int32_t throttle_level = 0;
8379 					if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8380 						if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8381 							returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8382 							memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8383 						}
8384 					}
8385 				}
8386 			}
8387 		}
8388 
8389 		u_int interface_to_check = returned_result->routed_interface_index;
8390 		if (interface_to_check == 0) {
8391 			interface_to_check = output_bound_interface;
8392 		}
8393 		union necp_sockaddr_union default_address;
8394 		struct rtentry *v4Route = NULL;
8395 		struct rtentry *v6Route = NULL;
8396 
8397 		memset(&default_address, 0, sizeof(default_address));
8398 
8399 		// Reset address to 0.0.0.0
8400 		default_address.sa.sa_family = AF_INET;
8401 		default_address.sa.sa_len = sizeof(struct sockaddr_in);
8402 		v4Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8403 		    returned_result->routed_interface_index);
8404 
8405 		// Reset address to ::
8406 		default_address.sa.sa_family = AF_INET6;
8407 		default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8408 		v6Route = rtalloc1_scoped(SA(&default_address), 0, 0,
8409 		    returned_result->routed_interface_index);
8410 
8411 		if (v4Route != NULL) {
8412 			if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8413 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8414 			}
8415 			if (returned_v4_gateway != NULL &&
8416 			    v4Route->rt_gateway != NULL &&
8417 			    v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8418 				memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8419 				memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8420 			}
8421 			rtfree(v4Route);
8422 			v4Route = NULL;
8423 		}
8424 
8425 		if (v6Route != NULL) {
8426 			if (v6Route->rt_ifp != NULL) {
8427 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8428 
8429 				if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8430 					*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8431 				}
8432 			}
8433 			if (returned_v6_gateway != NULL &&
8434 			    v6Route->rt_gateway != NULL &&
8435 			    v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8436 				SOCKADDR_COPY(v6Route->rt_gateway, &returned_v6_gateway->u.sin6, sizeof(returned_v6_gateway->u.sin6));
8437 			}
8438 			rtfree(v6Route);
8439 			v6Route = NULL;
8440 		}
8441 	}
8442 
8443 	// Take two passes through the rule list: first for rules that don't match based on agents,
8444 	// second for rules that match based on agents. Since rules can modify the agent list itself,
8445 	// this makes the logic more deterministic. This allows a non-agent matching rule to remove
8446 	// an agent before it is used for matching later.
8447 	size_t route_rule_index = 0;
8448 	bool second_pass = false;
8449 	while (route_rule_index < route_rule_id_array_count) {
8450 		bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8451 		if (rule_matches_agents != second_pass) {
8452 			// Process rules that match based on agents only in the second pass
8453 			route_rule_index++;
8454 			if (route_rule_index == route_rule_id_array_count && !second_pass) {
8455 				route_rule_index = 0;
8456 				second_pass = true;
8457 			}
8458 			continue;
8459 		}
8460 
8461 		u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8462 		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);
8463 		if (!route_is_allowed) {
8464 			// If the route is blocked, treat the lookup as a drop
8465 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8466 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8467 
8468 			if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8469 				if (reason != NULL) {
8470 					if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8471 						*reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8472 					} else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8473 						*reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8474 					}
8475 				}
8476 				necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8477 			}
8478 			// If the route gets denied, stop matching rules
8479 			break;
8480 		}
8481 
8482 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8483 		if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8484 			u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8485 			    route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8486 			if (flow_divert_control_unit != 0) {
8487 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8488 				returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8489 			}
8490 			if (flow_divert_aggregate_unit != 0) {
8491 				returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8492 			}
8493 		}
8494 
8495 		// Check if there is a route rule that adds or removes an agent
8496 		bool remove = false;
8497 		u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8498 		if (netagent_id != 0) {
8499 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8500 			if (mapping != NULL) {
8501 				bool agent_already_present = false;
8502 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8503 					if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8504 						// Found the agent already present
8505 						agent_already_present = true;
8506 						if (remove) {
8507 							// Mark as remove if necessary
8508 							returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8509 						}
8510 					} else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8511 						// Found open slot
8512 						if (!agent_already_present) {
8513 							uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8514 							if (remove) {
8515 								returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8516 							} else {
8517 								returned_result->netagent_use_flags[netagent_cursor] = 0;
8518 							}
8519 						}
8520 						break;
8521 					}
8522 				}
8523 			}
8524 
8525 			// Update the local netagent_ids array for future evaluations
8526 			if (remove) {
8527 				// Check if the agent ID is in the array, and remove it
8528 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8529 					if (netagent_id == netagent_ids[netagent_cursor]) {
8530 						netagent_ids[netagent_cursor] = 0;
8531 					}
8532 				}
8533 			} else {
8534 				// Check if the agent ID is not yet in the array, and add it
8535 				bool found = false;
8536 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8537 					if (netagent_id == netagent_ids[netagent_cursor]) {
8538 						found = true;
8539 						break;
8540 					}
8541 				}
8542 				if (!found) {
8543 					for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8544 						if (netagent_ids[netagent_cursor] == 0) {
8545 							// Empty slot, add the agent
8546 							netagent_ids[netagent_cursor] = netagent_id;
8547 							break;
8548 						}
8549 					}
8550 				}
8551 			}
8552 		}
8553 
8554 		route_rule_index++;
8555 		if (route_rule_index == route_rule_id_array_count && !second_pass) {
8556 			route_rule_index = 0;
8557 			second_pass = true;
8558 		}
8559 	}
8560 
8561 	if (rt != NULL && rt->rt_ifp != NULL) {
8562 		const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8563 		const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8564 		const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8565 		    IFNET_IS_EXPENSIVE(rt->rt_ifp));
8566 		const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8567 		    IFNET_IS_CONSTRAINED(rt->rt_ifp));
8568 		const bool ultra_constrained_not_allowed = (!(client_flags & NECP_CLIENT_PARAMETER_FLAG_ALLOW_ULTRA_CONSTRAINED) &&
8569 		    IFNET_IS_ULTRA_CONSTRAINED(rt->rt_ifp) && (task == NULL ||
8570 		    !IOTaskHasEntitlement(task, ULTRA_CONSTRAINED_ENTITLEMENT)));
8571 
8572 		const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8573 		if (!is_listener && !is_browser) {
8574 			if (reason != NULL) {
8575 				if (expensive_prohibited) {
8576 					*reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8577 				} else if (constrained_prohibited) {
8578 					*reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8579 				} else if (ultra_constrained_not_allowed) {
8580 					*reason = NECP_CLIENT_RESULT_REASON_ULTRA_CONSTRAINED_NOT_ALLOWED;
8581 				}
8582 			}
8583 			if (expensive_prohibited || constrained_prohibited || ultra_constrained_not_allowed || interface_type_blocked) {
8584 				// If a property of the interface was not allowed, treat it as a drop
8585 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8586 				memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8587 			}
8588 		}
8589 	}
8590 
8591 	if (rt != NULL) {
8592 		if (returned_route != NULL) {
8593 			*returned_route = rt;
8594 		} else {
8595 			rtfree(rt);
8596 		}
8597 		rt = NULL;
8598 	}
8599 
8600 done:
8601 	// Unlock
8602 	lck_rw_done(&necp_kernel_policy_lock);
8603 
8604 	if (release_eproc && effective_proc != PROC_NULL) {
8605 		proc_rele(effective_proc);
8606 	}
8607 #if defined(XNU_TARGET_OS_OSX)
8608 	if (responsible_proc != PROC_NULL) {
8609 		proc_rele(responsible_proc);
8610 	}
8611 #endif
8612 
8613 	if (cred != NULL) {
8614 		kauth_cred_unref(&cred);
8615 	}
8616 
8617 	return error;
8618 }
8619 
8620 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr,Boolean include_local_addresses)8621 necp_is_route_local(union necp_sockaddr_union *remote_addr, Boolean include_local_addresses)
8622 {
8623 	struct rtentry *rt = NULL;
8624 	bool is_local = FALSE;
8625 
8626 	if (remote_addr == NULL) {
8627 		return NULL;
8628 	}
8629 
8630 	if (remote_addr->sa.sa_len == 0 ||
8631 	    (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8632 	    (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8633 		return FALSE;
8634 	}
8635 
8636 	// Lookup route regardless of the scoped interface to check if
8637 	// remote address is in a local network.
8638 	rt = rtalloc1_scoped(SA(remote_addr), 0, 0, 0);
8639 
8640 	if (rt == NULL) {
8641 		goto done;
8642 	}
8643 	if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8644 		goto free_rt;
8645 	}
8646 	is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote_addr, include_local_addresses);
8647 
8648 free_rt:
8649 	rtfree(rt);
8650 
8651 done:
8652 	return is_local;
8653 }
8654 
8655 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)8656 necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy,
8657     necp_app_id app_id,
8658     necp_app_id real_app_id,
8659     uint8_t is_entitled,
8660     u_int32_t account_id,
8661     struct substring domain,
8662     u_int8_t domain_dot_count,
8663     const char *url __null_terminated,
8664     pid_t pid,
8665     int32_t pid_version,
8666     uid_t uid,
8667     uid_t real_uid,
8668     u_int32_t bound_interface_index,
8669     u_int32_t traffic_class,
8670     u_int16_t protocol,
8671     union necp_sockaddr_union *local,
8672     union necp_sockaddr_union *remote,
8673     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
8674     u_int32_t num_required_agent_types,
8675     bool has_client,
8676     uint32_t client_flags,
8677     int is_platform_binary,
8678     bool has_signed_result,
8679     proc_t proc,
8680     u_int16_t pf_tag,
8681     u_int16_t scheme_port,
8682     struct rtentry *rt,
8683     bool is_loopback,
8684     int debug,
8685     bool real_is_platform_binary,
8686     u_int32_t bound_interface_flags,
8687     u_int32_t bound_interface_eflags,
8688     u_int32_t bound_interface_xflags,
8689     struct necp_socket_info *info,
8690     bool is_delegated,
8691     struct socket *socket)
8692 {
8693 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
8694 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8695 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
8696 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
8697 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
8698 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8699 				if (bound_interface_index == cond_bound_interface_index) {
8700 					// No match, matches forbidden interface
8701 					return FALSE;
8702 				}
8703 			} else {
8704 				if (bound_interface_index != cond_bound_interface_index) {
8705 					// No match, does not match required interface
8706 					return FALSE;
8707 				}
8708 			}
8709 		}
8710 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8711 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8712 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
8713 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8714 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
8715 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8716 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
8717 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8718 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8719 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8720 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8721 					// No match, matches some forbidden interface flags
8722 					return FALSE;
8723 				}
8724 			} else {
8725 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8726 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8727 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8728 					// No match, does not match some required interface xflags
8729 					return FALSE;
8730 				}
8731 			}
8732 		}
8733 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
8734 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
8735 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
8736 			if (bound_interface_index != 0) {
8737 				// No match, requires a non-bound packet
8738 				return FALSE;
8739 			}
8740 		}
8741 	}
8742 
8743 	if (kernel_policy->condition_mask == 0) {
8744 		return TRUE;
8745 	}
8746 
8747 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8748 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
8749 		    "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
8750 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
8751 			if (app_id == kernel_policy->cond_app_id) {
8752 				// No match, matches forbidden application
8753 				return FALSE;
8754 			}
8755 		} else {
8756 			if (app_id != kernel_policy->cond_app_id) {
8757 				// No match, does not match required application
8758 				return FALSE;
8759 			}
8760 		}
8761 
8762 		// Check signing identifier only after APP ID matched
8763 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
8764 		    kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8765 			u_int8_t matched = necp_boolean_state_false;
8766 			const char *signing_id __null_terminated = cs_identity_get(proc ? proc : current_proc());
8767 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
8768 			    "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
8769 			    kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
8770 			    signing_id ? signing_id : "<n/a>");
8771 			if (signing_id != NULL) {
8772 				if (strcmp(signing_id, kernel_policy->cond_signing_identifier) == 0) {
8773 					matched = necp_boolean_state_true;
8774 				}
8775 			}
8776 
8777 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8778 				if (matched == necp_boolean_state_true) {
8779 					return FALSE;
8780 				}
8781 			} else {
8782 				if (matched != necp_boolean_state_true) {
8783 					return FALSE;
8784 				}
8785 			}
8786 		}
8787 	}
8788 
8789 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8790 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
8791 		    "NECP_KERNEL_CONDITION_REAL_APP_ID",
8792 		    kernel_policy->cond_real_app_id, real_app_id);
8793 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8794 			if (real_app_id == kernel_policy->cond_real_app_id) {
8795 				// No match, matches forbidden application
8796 				return FALSE;
8797 			}
8798 		} else {
8799 			if (real_app_id != kernel_policy->cond_real_app_id) {
8800 				// No match, does not match required application
8801 				return FALSE;
8802 			}
8803 		}
8804 	}
8805 
8806 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8807 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
8808 		if (!has_client) {
8809 			return FALSE;
8810 		}
8811 	}
8812 
8813 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
8814 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
8815 		if (!is_entitled) {
8816 			// Process is missing entitlement
8817 			return FALSE;
8818 		}
8819 	}
8820 
8821 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8822 		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);
8823 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8824 			if (is_platform_binary) {
8825 				// Process is platform binary
8826 				return FALSE;
8827 			}
8828 		} else {
8829 			if (!is_platform_binary) {
8830 				// Process is not platform binary
8831 				return FALSE;
8832 			}
8833 		}
8834 	}
8835 
8836 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
8837 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
8838 		if (has_signed_result == 0) {
8839 			// Client did not have a system-signed result
8840 			return FALSE;
8841 		}
8842 	}
8843 
8844 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
8845 		if (proc != NULL) {
8846 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
8847 			    kernel_policy->cond_sdk_version.platform,
8848 			    kernel_policy->cond_sdk_version.min_version,
8849 			    kernel_policy->cond_sdk_version.version,
8850 			    proc_platform(proc),
8851 			    proc_min_sdk(proc),
8852 			    proc_sdk(proc));
8853 			if (kernel_policy->cond_sdk_version.platform != 0) {
8854 				if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
8855 					// Process does not match platform
8856 					return FALSE;
8857 				}
8858 			}
8859 
8860 			if (kernel_policy->cond_sdk_version.min_version != 0) {
8861 				if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
8862 					// Process min version is older than required min version
8863 					return FALSE;
8864 				}
8865 			}
8866 
8867 			if (kernel_policy->cond_sdk_version.version != 0) {
8868 				if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
8869 					// Process SDK version is older than required version
8870 					return FALSE;
8871 				}
8872 			}
8873 		}
8874 	}
8875 
8876 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
8877 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
8878 		if (kernel_policy->cond_custom_entitlement != NULL) {
8879 			if (proc == NULL) {
8880 				// No process found, cannot check entitlement
8881 				return FALSE;
8882 			}
8883 			task_t __single task = proc_task(proc);
8884 			if (task == NULL ||
8885 			    !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
8886 				// Process is missing custom entitlement
8887 				return FALSE;
8888 			}
8889 		}
8890 	}
8891 
8892 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8893 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
8894 		    "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
8895 		// Exact match requires the number of dots to match (no suffix matching allowed)
8896 		bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
8897 		    necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
8898 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8899 			if (domain_matches) {
8900 				// No match, matches forbidden domain
8901 				return FALSE;
8902 			}
8903 		} else {
8904 			if (!domain_matches) {
8905 				// No match, does not match required domain
8906 				return FALSE;
8907 			}
8908 		}
8909 	} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8910 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
8911 		    "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
8912 		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
8913 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8914 			if (domain_matches) {
8915 				// No match, matches forbidden domain
8916 				return FALSE;
8917 			}
8918 		} else {
8919 			if (!domain_matches) {
8920 				// No match, does not match required domain
8921 				return FALSE;
8922 			}
8923 		}
8924 	}
8925 
8926 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8927 		struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
8928 		if (filter != NULL && filter->filter != NULL) {
8929 			bool domain_matches = (domain.string != NULL && domain.length > 0) ? net_bloom_filter_contains(filter->filter, domain.string, domain.length) : FALSE;
8930 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8931 				if (domain_matches) {
8932 					// No match, matches forbidden domain
8933 					return FALSE;
8934 				}
8935 			} else {
8936 				if (!domain_matches) {
8937 					// No match, does not match required domain
8938 					return FALSE;
8939 				}
8940 			}
8941 		}
8942 	}
8943 
8944 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
8945 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
8946 		    "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
8947 		bool url_matches = (url ? strcasecmp(kernel_policy->cond_url, url) == 0 : false);
8948 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
8949 			if (url_matches) {
8950 				// No match, matches forbidden url
8951 				return FALSE;
8952 			}
8953 		} else {
8954 			if (!url_matches) {
8955 				// No match, does not match required url
8956 				return FALSE;
8957 			}
8958 		}
8959 	}
8960 
8961 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8962 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
8963 		    "NECP_KERNEL_CONDITION_ACCOUNT_ID",
8964 		    kernel_policy->cond_account_id, account_id);
8965 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8966 			if (account_id == kernel_policy->cond_account_id) {
8967 				// No match, matches forbidden account
8968 				return FALSE;
8969 			}
8970 		} else {
8971 			if (account_id != kernel_policy->cond_account_id) {
8972 				// No match, does not match required account
8973 				return FALSE;
8974 			}
8975 		}
8976 	}
8977 
8978 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
8979 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
8980 		    "NECP_KERNEL_CONDITION_PID",
8981 		    kernel_policy->cond_pid, pid);
8982 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
8983 			if (pid == kernel_policy->cond_pid) {
8984 				// No match, matches forbidden pid
8985 				return FALSE;
8986 			}
8987 			if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
8988 				return FALSE;
8989 			}
8990 		} else {
8991 			if (pid != kernel_policy->cond_pid) {
8992 				// No match, does not match required pid
8993 				return FALSE;
8994 			}
8995 			if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
8996 				return FALSE;
8997 			}
8998 		}
8999 	}
9000 
9001 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
9002 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
9003 		    "NECP_KERNEL_CONDITION_UID",
9004 		    kernel_policy->cond_uid, uid);
9005 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
9006 			if (uid == kernel_policy->cond_uid) {
9007 				// No match, matches forbidden uid
9008 				return FALSE;
9009 			}
9010 		} else {
9011 			if (uid != kernel_policy->cond_uid) {
9012 				// No match, does not match required uid
9013 				return FALSE;
9014 			}
9015 		}
9016 	}
9017 
9018 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9019 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
9020 		    "NECP_KERNEL_CONDITION_REAL_UID",
9021 		    kernel_policy->cond_real_uid, real_uid);
9022 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9023 			if (real_uid == kernel_policy->cond_real_uid) {
9024 				// No match, matches forbidden uid
9025 				return FALSE;
9026 			}
9027 		} else {
9028 			if (real_uid != kernel_policy->cond_real_uid) {
9029 				// No match, does not match required uid
9030 				return FALSE;
9031 			}
9032 		}
9033 	}
9034 
9035 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9036 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
9037 		    kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
9038 		    traffic_class, 0, 0);
9039 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9040 			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
9041 			    traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
9042 				// No match, matches forbidden traffic class
9043 				return FALSE;
9044 			}
9045 		} else {
9046 			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
9047 			    traffic_class > kernel_policy->cond_traffic_class.end_tc) {
9048 				// No match, does not match required traffic class
9049 				return FALSE;
9050 			}
9051 		}
9052 	}
9053 
9054 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9055 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
9056 		    "NECP_KERNEL_CONDITION_PROTOCOL",
9057 		    kernel_policy->cond_protocol, protocol);
9058 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
9059 			if (protocol == kernel_policy->cond_protocol) {
9060 				// No match, matches forbidden protocol
9061 				return FALSE;
9062 			}
9063 		} else {
9064 			if (protocol != kernel_policy->cond_protocol) {
9065 				// No match, does not match required protocol
9066 				return FALSE;
9067 			}
9068 		}
9069 	}
9070 
9071 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
9072 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET_STR3(debug, socket, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
9073 		    kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
9074 		    "n/a", "n/a", "n/a");
9075 		bool matches_agent_type = FALSE;
9076 		for (u_int32_t i = 0; i < num_required_agent_types; i++) {
9077 			struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
9078 			if ((strbuflen(kernel_policy->cond_agent_type.agent_domain, sizeof(kernel_policy->cond_agent_type.agent_domain)) == 0 ||
9079 			    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) &&
9080 			    (strbuflen(kernel_policy->cond_agent_type.agent_type, sizeof(kernel_policy->cond_agent_type.agent_type)) == 0 ||
9081 			    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)) {
9082 				// Found a required agent that matches
9083 				matches_agent_type = TRUE;
9084 				break;
9085 			}
9086 		}
9087 		if (!matches_agent_type) {
9088 			return FALSE;
9089 		}
9090 	}
9091 
9092 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9093 		bool is_local = FALSE;
9094 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
9095 
9096 		if (rt != NULL) {
9097 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
9098 		} else {
9099 			is_local = necp_is_route_local(remote, include_local_addresses);
9100 		}
9101 		if (info != NULL) {
9102 			info->is_local = is_local;
9103 		}
9104 
9105 		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);
9106 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
9107 			if (is_local) {
9108 				// Match local-networks, fail
9109 				return FALSE;
9110 			}
9111 		} else {
9112 			if (!is_local) {
9113 				// Either no route to validate or no match for local networks
9114 				return FALSE;
9115 			}
9116 		}
9117 	}
9118 
9119 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
9120 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9121 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
9122 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
9123 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
9124 				if (inRange) {
9125 					return FALSE;
9126 				}
9127 			} else {
9128 				if (!inRange) {
9129 					return FALSE;
9130 				}
9131 			}
9132 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9133 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
9134 			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);
9135 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
9136 				if (inSubnet) {
9137 					return FALSE;
9138 				}
9139 			} else {
9140 				if (!inSubnet) {
9141 					return FALSE;
9142 				}
9143 			}
9144 		}
9145 	}
9146 
9147 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
9148 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9149 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
9150 			NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
9151 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
9152 				if (inRange) {
9153 					return FALSE;
9154 				}
9155 			} else {
9156 				if (!inRange) {
9157 					return FALSE;
9158 				}
9159 			}
9160 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9161 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
9162 			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);
9163 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
9164 				if (inSubnet) {
9165 					return FALSE;
9166 				}
9167 			} else {
9168 				if (!inSubnet) {
9169 					return FALSE;
9170 				}
9171 			}
9172 		}
9173 	}
9174 
9175 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9176 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
9177 		    "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
9178 		    kernel_policy->cond_client_flags, client_flags);
9179 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9180 			if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
9181 				// Flags do match, and condition is negative, fail.
9182 				return FALSE;
9183 			}
9184 		} else {
9185 			if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
9186 				// Flags do not match, fail.
9187 				return FALSE;
9188 			}
9189 		}
9190 	}
9191 
9192 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9193 		bool isEmpty = necp_addr_is_empty(SA(local));
9194 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
9195 		    "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
9196 		    0, isEmpty);
9197 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
9198 			if (isEmpty) {
9199 				return FALSE;
9200 			}
9201 		} else {
9202 			if (!isEmpty) {
9203 				return FALSE;
9204 			}
9205 		}
9206 	}
9207 
9208 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9209 		bool isEmpty = necp_addr_is_empty(SA(remote));
9210 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
9211 		    "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
9212 		    0, isEmpty);
9213 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
9214 			if (isEmpty) {
9215 				return FALSE;
9216 			}
9217 		} else {
9218 			if (!isEmpty) {
9219 				return FALSE;
9220 			}
9221 		}
9222 	}
9223 
9224 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9225 		u_int16_t remote_port = 0;
9226 		if ((SA(remote))->sa_family == AF_INET || (SA(remote))->sa_family == AF_INET6) {
9227 			remote_port = SIN(remote)->sin_port;
9228 		}
9229 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
9230 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
9231 		    scheme_port, remote_port);
9232 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
9233 			if (kernel_policy->cond_scheme_port == scheme_port ||
9234 			    kernel_policy->cond_scheme_port == remote_port) {
9235 				return FALSE;
9236 			}
9237 		} else {
9238 			if (kernel_policy->cond_scheme_port != scheme_port &&
9239 			    kernel_policy->cond_scheme_port != remote_port) {
9240 				return FALSE;
9241 			}
9242 		}
9243 	}
9244 
9245 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9246 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
9247 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
9248 		    kernel_policy->cond_packet_filter_tags,
9249 		    pf_tag);
9250 		bool tags_matched = false;
9251 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
9252 			if (pf_tag == PF_TAG_ID_STACK_DROP) {
9253 				tags_matched = true;
9254 			}
9255 		}
9256 
9257 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
9258 			if (tags_matched) {
9259 				return FALSE;
9260 			}
9261 		} else {
9262 			if (!tags_matched) {
9263 				return FALSE;
9264 			}
9265 		}
9266 	}
9267 
9268 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9269 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK,
9270 		    "NECP_KERNEL_CONDITION_IS_LOOPBACK", 0, is_loopback);
9271 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
9272 			if (is_loopback) {
9273 				return FALSE;
9274 			}
9275 		} else {
9276 			if (!is_loopback) {
9277 				return FALSE;
9278 			}
9279 		}
9280 	}
9281 
9282 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9283 		NECP_DATA_TRACE_LOG_CONDITION_SOCKET(debug, socket, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY,
9284 		    "NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY", 0, real_is_platform_binary);
9285 		if (is_delegated) {
9286 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9287 				if (real_is_platform_binary) {
9288 					return FALSE;
9289 				}
9290 			} else {
9291 				if (!real_is_platform_binary) {
9292 					return FALSE;
9293 				}
9294 			}
9295 		} else if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) &&
9296 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID)) {
9297 			// If the connection is not delegated, and the policy did not specify a particular effective process UUID
9298 			// or PID, check the process directly
9299 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9300 				if (is_platform_binary) {
9301 					return FALSE;
9302 				}
9303 			} else {
9304 				if (!is_platform_binary) {
9305 					return FALSE;
9306 				}
9307 			}
9308 		}
9309 	}
9310 
9311 	return TRUE;
9312 }
9313 
9314 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)9315 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
9316 {
9317 	return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
9318 }
9319 
9320 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,bool override_is_inbound,u_int32_t drop_order,proc_t * socket_proc,struct necp_socket_info * info,bool is_loopback)9321 necp_socket_fillout_info_locked(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface, bool override_is_inbound, u_int32_t drop_order, proc_t *socket_proc, struct necp_socket_info *info, bool is_loopback)
9322 {
9323 	struct socket *so = NULL;
9324 	proc_t sock_proc = NULL;
9325 	proc_t curr_proc = current_proc();
9326 
9327 	memset(info, 0, sizeof(struct necp_socket_info));
9328 
9329 	so = inp->inp_socket;
9330 
9331 	info->drop_order = drop_order;
9332 	info->is_loopback = is_loopback;
9333 	info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
9334 
9335 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
9336 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
9337 		info->uid = kauth_cred_getuid(so->so_cred);
9338 		info->real_uid = info->uid;
9339 	}
9340 
9341 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
9342 		info->traffic_class = so->so_traffic_class;
9343 	}
9344 
9345 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
9346 		info->has_client = !uuid_is_null(inp->necp_client_uuid);
9347 	}
9348 
9349 	if (inp->inp_ip_p) {
9350 		info->protocol = inp->inp_ip_p;
9351 	} else {
9352 		info->protocol = SOCK_PROTO(so);
9353 	}
9354 
9355 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
9356 		info->client_flags = 0;
9357 		if (INP_NO_CONSTRAINED(inp)) {
9358 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
9359 		}
9360 		if (INP_NO_EXPENSIVE(inp)) {
9361 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
9362 		}
9363 		if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
9364 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
9365 		}
9366 		if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
9367 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
9368 		}
9369 		if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
9370 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
9371 		}
9372 		if (inp->inp_socket->so_flags1 & SOF1_INBOUND || ((info->protocol == IPPROTO_UDP) && override_is_inbound)) {
9373 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
9374 		}
9375 		if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
9376 		    inp->inp_flags2 & INP2_EXTERNAL_PORT) {
9377 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
9378 		}
9379 		if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
9380 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
9381 		}
9382 		if (inp->inp_socket->so_options & SO_REUSEPORT) {
9383 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
9384 		}
9385 	}
9386 
9387 	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
9388 		u_int32_t responsible_application_id = 0;
9389 
9390 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9391 		if (existing_mapping) {
9392 			info->application_id = existing_mapping->id;
9393 		}
9394 
9395 #if defined(XNU_TARGET_OS_OSX)
9396 		if (so->so_rpid > 0) {
9397 			existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9398 			if (existing_mapping != NULL) {
9399 				responsible_application_id = existing_mapping->id;
9400 			}
9401 		}
9402 #endif
9403 
9404 		if (responsible_application_id > 0) {
9405 			info->real_application_id = info->application_id;
9406 			info->application_id = responsible_application_id;
9407 			info->used_responsible_pid = true;
9408 		} else if (!(so->so_flags & SOF_DELEGATED)) {
9409 			info->real_application_id = info->application_id;
9410 		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9411 			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9412 			if (real_existing_mapping) {
9413 				info->real_application_id = real_existing_mapping->id;
9414 			}
9415 		}
9416 	}
9417 
9418 	pid_t socket_pid =
9419 #if defined(XNU_TARGET_OS_OSX)
9420 	    info->used_responsible_pid ? so->so_rpid :
9421 #endif
9422 	    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9423 	if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9424 		sock_proc = proc_find(socket_pid);
9425 		if (socket_proc) {
9426 			*socket_proc = sock_proc;
9427 		}
9428 	}
9429 
9430 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9431 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9432 		info->is_entitled = necp_task_has_match_entitlement(task);
9433 		if (!info->is_entitled) {
9434 			// Task does not have entitlement, check the parent task
9435 			necp_get_parent_is_entitled(task, info);
9436 		}
9437 	}
9438 
9439 	info->pid = socket_pid;
9440 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID) {
9441 		info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9442 	}
9443 
9444 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) ||
9445 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
9446 		if (info->pid == 0 || necp_is_platform_binary(sock_proc ? sock_proc : curr_proc)) {
9447 			info->is_platform_binary = true;
9448 		} else if (so->so_rpid != 0) {
9449 			proc_t responsible_proc = proc_find(so->so_rpid);
9450 			if (responsible_proc != NULL) {
9451 				if (necp_is_platform_binary(responsible_proc)) {
9452 					info->is_platform_binary = true;
9453 					info->used_responsible_pid = true;
9454 				}
9455 				proc_rele(responsible_proc);
9456 			}
9457 		}
9458 	}
9459 
9460 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9461 		proc_t real_proc = curr_proc;
9462 		bool release_real_proc = false;
9463 		if (so->last_pid != proc_pid(real_proc)) {
9464 			if (so->last_pid == socket_pid && sock_proc != NULL) {
9465 				real_proc = sock_proc;
9466 			} else {
9467 				proc_t last_proc = proc_find(so->last_pid);
9468 				if (last_proc != NULL) {
9469 					real_proc = last_proc;
9470 					release_real_proc = true;
9471 				}
9472 			}
9473 		}
9474 		if (real_proc != NULL) {
9475 			if (real_proc == kernproc) {
9476 				info->real_is_platform_binary = true;
9477 			} else {
9478 				info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9479 			}
9480 			if (release_real_proc) {
9481 				proc_rele(real_proc);
9482 			}
9483 		}
9484 	}
9485 
9486 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9487 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9488 		if (existing_mapping) {
9489 			info->account_id = existing_mapping->id;
9490 		}
9491 	}
9492 
9493 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9494 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9495 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9496 		info->domain = inp->inp_necp_attributes.inp_domain;
9497 	}
9498 
9499 	if (override_bound_interface) {
9500 		info->bound_interface_index = override_bound_interface;
9501 	} else {
9502 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9503 			info->bound_interface_index = inp->inp_boundifp->if_index;
9504 		}
9505 	}
9506 
9507 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9508 	    info->bound_interface_index != IFSCOPE_NONE) {
9509 		ifnet_head_lock_shared();
9510 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9511 		if (interface != NULL) {
9512 			info->bound_interface_flags = interface->if_flags;
9513 			info->bound_interface_eflags = interface->if_eflags;
9514 			info->bound_interface_xflags = interface->if_xflags;
9515 		}
9516 		ifnet_head_done();
9517 	}
9518 
9519 	bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9520 	    uuid_is_null(inp->necp_client_uuid) &&
9521 	    necp_socket_has_resolver_signature(inp));
9522 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
9523 	    necp_restrict_multicast ||
9524 	    needs_address_for_signature ||
9525 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
9526 		if (override_local_addr != NULL) {
9527 			if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9528 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9529 				if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9530 					struct sockaddr_in sin;
9531 					in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9532 					memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9533 					memcpy(&info->local_addr, &sin, sin.sin_len);
9534 				}
9535 			} else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9536 				SOCKADDR_COPY(override_local_addr, &info->local_addr, override_local_addr->sa_len);
9537 			}
9538 		} else {
9539 			if (inp->inp_vflag & INP_IPV6) {
9540 				SIN6(&info->local_addr)->sin6_family = AF_INET6;
9541 				SIN6(&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9542 				SIN6(&info->local_addr)->sin6_port = inp->inp_lport;
9543 				memcpy(&SIN6(&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9544 			} else if (inp->inp_vflag & INP_IPV4) {
9545 				SIN(&info->local_addr)->sin_family = AF_INET;
9546 				SIN(&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9547 				SIN(&info->local_addr)->sin_port = inp->inp_lport;
9548 				memcpy(&SIN(&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9549 			}
9550 		}
9551 
9552 		if (override_remote_addr != NULL) {
9553 			if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9554 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9555 				if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9556 					struct sockaddr_in sin;
9557 					in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9558 					memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9559 					memcpy(&info->remote_addr, &sin, sin.sin_len);
9560 				}
9561 			} else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9562 				SOCKADDR_COPY(override_remote_addr, &info->remote_addr, override_remote_addr->sa_len);
9563 			}
9564 		} else {
9565 			if (inp->inp_vflag & INP_IPV6) {
9566 				SIN6(&info->remote_addr)->sin6_family = AF_INET6;
9567 				SIN6(&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9568 				SIN6(&info->remote_addr)->sin6_port = inp->inp_fport;
9569 				memcpy(&SIN6(&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9570 			} else if (inp->inp_vflag & INP_IPV4) {
9571 				SIN(&info->remote_addr)->sin_family = AF_INET;
9572 				SIN(&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9573 				SIN(&info->remote_addr)->sin_port = inp->inp_fport;
9574 				memcpy(&SIN(&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9575 			}
9576 		}
9577 		// Clear the embedded scope id from v6 addresses
9578 		if (info->local_addr.sa.sa_family == AF_INET6) {
9579 			struct sockaddr_in6 *sin6 = SIN6(&info->local_addr);
9580 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9581 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9582 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9583 					sin6->sin6_addr.s6_addr16[1] = 0;
9584 				}
9585 			}
9586 		}
9587 		if (info->remote_addr.sa.sa_family == AF_INET6) {
9588 			struct sockaddr_in6 *sin6 = SIN6(&info->remote_addr);
9589 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9590 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9591 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9592 					sin6->sin6_addr.s6_addr16[1] = 0;
9593 				}
9594 			}
9595 		}
9596 	}
9597 
9598 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9599 		// For checking sockets, only validate that there is an NECP client present. It will have
9600 		// already checked for the signature.
9601 		if (!uuid_is_null(inp->necp_client_uuid)) {
9602 			info->has_system_signed_result = true;
9603 		} else {
9604 			info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9605 		}
9606 	}
9607 }
9608 
9609 #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)
9610 
9611 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)9612 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** __indexable policy_search_array,
9613     struct necp_socket_info *info,
9614     necp_kernel_policy_filter *return_filter,
9615     u_int32_t * __counted_by(route_rule_id_array_count)return_route_rule_id_array,
9616     size_t *return_route_rule_id_array_count,
9617     size_t route_rule_id_array_count,
9618     necp_kernel_policy_result *return_service_action,
9619     necp_kernel_policy_service *return_service,
9620     u_int32_t * __counted_by(netagent_array_count)return_netagent_array,
9621     size_t netagent_array_count,
9622     u_int32_t * __counted_by(netagent_use_flags_array_count)return_netagent_use_flags_array,
9623     size_t netagent_use_flags_array_count,
9624     struct necp_client_parameter_netagent_type * __counted_by(num_required_agent_types)required_agent_types,
9625     u_int32_t num_required_agent_types,
9626     proc_t proc,
9627     u_int16_t pf_tag,
9628     necp_kernel_policy_id *skip_policy_id,
9629     struct rtentry *rt,
9630     necp_kernel_policy_result *return_drop_dest_policy_result,
9631     necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
9632     u_int32_t *return_flow_divert_aggregate_unit,
9633     struct socket *so,
9634     int debug)
9635 {
9636 	struct necp_kernel_socket_policy *matched_policy = NULL;
9637 	u_int32_t skip_order = 0;
9638 	u_int32_t skip_session_order = 0;
9639 	bool skipped_ip_result = false;
9640 	size_t route_rule_id_count = 0;
9641 	int i;
9642 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9643 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
9644 	memset(&netagent_ids, 0, sizeof(netagent_ids));
9645 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
9646 	size_t netagent_cursor = 0;
9647 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9648 	size_t netagent_array_count_adjusted = netagent_array_count;
9649 	if (netagent_use_flags_array_count > 0 && netagent_use_flags_array_count < netagent_array_count_adjusted) {
9650 		netagent_array_count_adjusted = netagent_use_flags_array_count;
9651 	}
9652 
9653 	if (return_drop_all_bypass != NULL) {
9654 		*return_drop_all_bypass = drop_all_bypass;
9655 	}
9656 
9657 	if (netagent_array_count_adjusted > NECP_MAX_NETAGENTS) {
9658 		netagent_array_count_adjusted = NECP_MAX_NETAGENTS;
9659 	}
9660 
9661 	// Pre-process domain for quick matching
9662 	struct substring domain_substring = {};
9663 	u_int8_t domain_dot_count = 0;
9664 	if (info->domain != NULL) {
9665 		domain_substring = necp_trim_dots_and_stars(__unsafe_null_terminated_to_indexable(info->domain), info->domain ? strlen(info->domain) : 0);
9666 		domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
9667 	}
9668 
9669 	if (return_filter != NULL) {
9670 		*return_filter = 0;
9671 	}
9672 
9673 	if (return_route_rule_id_array_count != NULL) {
9674 		*return_route_rule_id_array_count = 0;
9675 	}
9676 
9677 	if (return_service_action != NULL) {
9678 		*return_service_action = 0;
9679 	}
9680 
9681 	if (return_service != NULL) {
9682 		return_service->identifier = 0;
9683 		return_service->data = 0;
9684 	}
9685 
9686 	// Do not subject layer-2 filter to NECP policies, return a PASS policy
9687 	if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
9688 		return &pass_policy;
9689 	}
9690 
9691 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9692 
9693 	if (policy_search_array != NULL) {
9694 		for (i = 0; policy_search_array[i] != NULL; i++) {
9695 			NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "EXAMINING");
9696 
9697 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
9698 				// We've hit a drop all rule
9699 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9700 					drop_all_bypass = necp_check_drop_all_bypass_result(proc);
9701 					if (return_drop_all_bypass != NULL) {
9702 						*return_drop_all_bypass = drop_all_bypass;
9703 					}
9704 				}
9705 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9706 					NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
9707 					break;
9708 				}
9709 			}
9710 			if (necp_drop_dest_policy.entry_count != 0 &&
9711 			    necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
9712 				// We've hit a drop by destination address rule
9713 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
9714 				break;
9715 			}
9716 			if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
9717 				// We've hit a drop order for this socket
9718 				break;
9719 			}
9720 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
9721 				// Done skipping
9722 				skip_order = 0;
9723 				skip_session_order = 0;
9724 				// If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
9725 				if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
9726 					*skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9727 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (cleared saved skip)");
9728 				}
9729 			}
9730 			if (skip_order) {
9731 				if (policy_search_array[i]->order < skip_order) {
9732 					// Skip this policy
9733 					// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9734 					// didn't, clear out the return value for skip ID when we are done with each session.'
9735 					if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9736 						skipped_ip_result = true;
9737 						NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
9738 					}
9739 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (session order < skip-order)");
9740 					continue;
9741 				} else {
9742 					// Done skipping
9743 					skip_order = 0;
9744 					skip_session_order = 0;
9745 				}
9746 			} else if (skip_session_order) {
9747 				// Skip this policy
9748 				// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9749 				// didn't, clear out the return value for skip ID when we are done with each session.'
9750 				if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9751 					skipped_ip_result = true;
9752 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIPPING POLICY");
9753 				}
9754 				NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "SKIP (skip-session-order)");
9755 				continue;
9756 			}
9757 
9758 			if (necp_socket_check_policy(policy_search_array[i],
9759 			    info->application_id,
9760 			    info->real_application_id,
9761 			    info->is_entitled,
9762 			    info->account_id,
9763 			    domain_substring,
9764 			    domain_dot_count,
9765 			    info->url,
9766 			    info->pid,
9767 			    info->pid_version,
9768 			    info->uid,
9769 			    info->real_uid,
9770 			    info->bound_interface_index,
9771 			    info->traffic_class,
9772 			    info->protocol,
9773 			    &info->local_addr,
9774 			    &info->remote_addr,
9775 			    required_agent_types,
9776 			    num_required_agent_types,
9777 			    info->has_client,
9778 			    info->client_flags,
9779 			    info->is_platform_binary,
9780 			    info->has_system_signed_result,
9781 			    proc,
9782 			    pf_tag,
9783 			    info->scheme_port,
9784 			    rt,
9785 			    info->is_loopback,
9786 			    debug,
9787 			    info->real_is_platform_binary,
9788 			    info->bound_interface_flags,
9789 			    info->bound_interface_eflags,
9790 			    info->bound_interface_xflags,
9791 			    info,
9792 			    info->is_delegated,
9793 			    so)) {
9794 				if (!debug && necp_data_tracing_session_order) {
9795 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
9796 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
9797 						NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
9798 					}
9799 				}
9800 
9801 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
9802 					if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
9803 						necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
9804 						if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
9805 							*return_filter = control_unit;
9806 						} else {
9807 							// Preserve pre-existing connections only if all filters preserve.
9808 							bool preserve_bit_off = false;
9809 							if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
9810 							    (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
9811 								preserve_bit_off = true;
9812 							}
9813 							*return_filter |= control_unit;
9814 							if (preserve_bit_off == true) {
9815 								*return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
9816 							}
9817 						}
9818 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9819 							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);
9820 						}
9821 					}
9822 					continue;
9823 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
9824 					if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
9825 						return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
9826 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9827 							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);
9828 						}
9829 					}
9830 					continue;
9831 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
9832 				    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9833 					if (netagent_cursor < netagent_array_count_adjusted) {
9834 						bool agent_already_present = false;
9835 						for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9836 							if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9837 								// Already present. Mark the "SCOPED" flag if flags are necessary.
9838 								agent_already_present = true;
9839 								if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
9840 								    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9841 									netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
9842 								}
9843 							}
9844 						}
9845 
9846 						if (!agent_already_present) {
9847 							netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9848 							if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9849 								netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
9850 							}
9851 							netagent_cursor++;
9852 						}
9853 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9854 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
9855 							    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9856 							    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
9857 							    policy_search_array[i]->result_parameter.netagent_id);
9858 						}
9859 					}
9860 					continue;
9861 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
9862 					bool agent_already_present = false;
9863 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9864 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9865 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
9866 							agent_already_present = true;
9867 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
9868 						}
9869 					}
9870 					if (!agent_already_present && netagent_cursor < netagent_array_count_adjusted) {
9871 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
9872 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9873 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
9874 						netagent_cursor++;
9875 					}
9876 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9877 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy <so %llx>: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
9878 						    (uint64_t)VM_KERNEL_ADDRPERM(so), info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9879 						    policy_search_array[i]->result_parameter.netagent_id);
9880 					}
9881 					continue;
9882 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
9883 					u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
9884 					if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
9885 						/* For transparent proxies, accumulate the control unit and continue to the next policy */
9886 						if (return_flow_divert_aggregate_unit != NULL) {
9887 							*return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
9888 							if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9889 								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);
9890 							}
9891 						}
9892 						continue;
9893 					}
9894 				}
9895 
9896 				// Matched policy is a skip. Do skip and continue.
9897 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
9898 					NECP_DATA_TRACE_LOG_POLICY_SOCKET(debug, so, "SOCKET", "MATCHED SKIP POLICY");
9899 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
9900 					skip_session_order = policy_search_array[i]->session_order + 1;
9901 					if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
9902 						*skip_policy_id = policy_search_array[i]->id;
9903 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9904 							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);
9905 						}
9906 					}
9907 					continue;
9908 				}
9909 
9910 				// Matched an allow unentitled, which clears any drop order
9911 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
9912 					info->drop_order = 0;
9913 					continue;
9914 				}
9915 
9916 				// Passed all tests, found a match
9917 				matched_policy = policy_search_array[i];
9918 				NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
9919 				break;
9920 			}
9921 		}
9922 	}
9923 
9924 	if (return_netagent_array != NULL) {
9925 		if (return_netagent_use_flags_array != NULL) {
9926 			memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count_adjusted);
9927 			memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count_adjusted);
9928 		} else {
9929 			for (size_t netagent_i = 0; netagent_i < netagent_array_count_adjusted; netagent_i++) {
9930 				if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
9931 					return_netagent_array[netagent_i] = netagent_ids[netagent_i];
9932 				} else {
9933 					return_netagent_array[netagent_i] = 0;
9934 				}
9935 			}
9936 		}
9937 	}
9938 
9939 	if (return_route_rule_id_array_count != NULL) {
9940 		*return_route_rule_id_array_count = route_rule_id_count;
9941 	}
9942 	return matched_policy;
9943 }
9944 
9945 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)9946 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
9947 {
9948 	bool found_match = FALSE;
9949 	ifaddr_t ifa;
9950 	union necp_sockaddr_union address_storage;
9951 	int family = AF_INET;
9952 
9953 	ifnet_head_lock_shared();
9954 	ifnet_t interface = ifindex2ifnet[interface_index];
9955 	ifnet_head_done();
9956 
9957 	if (inp == NULL || interface == NULL) {
9958 		return FALSE;
9959 	}
9960 
9961 	if (inp->inp_vflag & INP_IPV4) {
9962 		family = AF_INET;
9963 	} else if (inp->inp_vflag & INP_IPV6) {
9964 		family = AF_INET6;
9965 	} else {
9966 		return FALSE;
9967 	}
9968 
9969 	// Match socket address against interface addresses
9970 	ifnet_lock_shared(interface);
9971 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
9972 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
9973 			if (address_storage.sa.sa_family != family) {
9974 				continue;
9975 			}
9976 
9977 			if (family == AF_INET) {
9978 				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
9979 					found_match = TRUE;
9980 					break;
9981 				}
9982 			} else if (family == AF_INET6) {
9983 				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
9984 					found_match = TRUE;
9985 					break;
9986 				}
9987 			}
9988 		}
9989 	}
9990 	ifnet_lock_done(interface);
9991 
9992 	return found_match;
9993 }
9994 
9995 static inline bool
necp_socket_is_connected(struct inpcb * inp)9996 necp_socket_is_connected(struct inpcb *inp)
9997 {
9998 	return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
9999 }
10000 
10001 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)10002 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
10003 {
10004 	if (necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
10005 		proc_t curr_proc = current_proc();
10006 		proc_t sock_proc = NULL;
10007 		struct socket *so = inp ? inp->inp_socket : NULL;
10008 		pid_t socket_pid = (so == NULL) ? 0 :
10009 #if defined(XNU_TARGET_OS_OSX)
10010 		    so->so_rpid ? so->so_rpid :
10011 #endif
10012 		    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
10013 		if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
10014 			sock_proc = proc_find(socket_pid);
10015 		}
10016 		const task_t __single task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
10017 		if (task != NULL && necp_task_has_loopback_drop_entitlement(task)) {
10018 			if (sock_proc) {
10019 				proc_rele(sock_proc);
10020 			}
10021 			return NECP_BYPASS_TYPE_DROP;
10022 		}
10023 		if (sock_proc) {
10024 			proc_rele(sock_proc);
10025 		}
10026 
10027 		if (necp_pass_loopback > 0) {
10028 			return NECP_BYPASS_TYPE_LOOPBACK;
10029 		}
10030 	} else if (necp_is_intcoproc(inp, NULL)) {
10031 		return NECP_BYPASS_TYPE_INTCOPROC;
10032 	}
10033 
10034 	return NECP_BYPASS_TYPE_NONE;
10035 }
10036 
10037 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)10038 necp_socket_ip_tunnel_tso(struct inpcb *inp)
10039 {
10040 	u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
10041 	ifnet_t tunnel_interface = NULL;
10042 
10043 	ifnet_head_lock_shared();
10044 	tunnel_interface = ifindex2ifnet[tunnel_interface_index];
10045 	ifnet_head_done();
10046 
10047 	if (tunnel_interface != NULL) {
10048 		tcp_set_tso(intotcpcb(inp), tunnel_interface);
10049 	}
10050 }
10051 
10052 static inline void
necp_unscope(struct inpcb * inp)10053 necp_unscope(struct inpcb *inp)
10054 {
10055 	// If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
10056 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
10057 		inp->inp_flags &= ~INP_BOUND_IF;
10058 		inp->inp_boundifp = NULL;
10059 	}
10060 }
10061 
10062 static inline void
necp_clear_tunnel(struct inpcb * inp)10063 necp_clear_tunnel(struct inpcb *inp)
10064 {
10065 	if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
10066 		inp->inp_flags &= ~INP_BOUND_IF;
10067 		inp->inp_boundifp = NULL;
10068 	}
10069 }
10070 
10071 static inline bool
necp_socket_verify_netagents(u_int32_t * __counted_by (NECP_MAX_NETAGENTS)netagent_ids,int debug,struct socket * so)10072 necp_socket_verify_netagents(u_int32_t * __counted_by(NECP_MAX_NETAGENTS)netagent_ids, int debug, struct socket *so)
10073 {
10074 	// Verify netagents
10075 	for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
10076 		struct necp_uuid_id_mapping *mapping = NULL;
10077 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
10078 		if (netagent_id == 0) {
10079 			continue;
10080 		}
10081 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
10082 		if (mapping != NULL) {
10083 			u_int32_t agent_flags = 0;
10084 			agent_flags = netagent_get_flags(mapping->uuid);
10085 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
10086 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
10087 					continue;
10088 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
10089 					if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
10090 						int trigger_error = 0;
10091 						trigger_error = netagent_kernel_trigger(mapping->uuid);
10092 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10093 							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);
10094 						}
10095 					}
10096 					return false;
10097 				}
10098 			}
10099 		}
10100 	}
10101 	return true;
10102 }
10103 
10104 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)10105 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
10106 {
10107 	struct socket *so = NULL;
10108 	necp_kernel_policy_filter filter_control_unit = 0;
10109 	struct necp_kernel_socket_policy *matched_policy = NULL;
10110 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10111 	necp_kernel_policy_result service_action = 0;
10112 	necp_kernel_policy_service service = { 0, 0 };
10113 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10114 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10115 	proc_t __single socket_proc = NULL;
10116 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
10117 
10118 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
10119 	memset(&netagent_ids, 0, sizeof(netagent_ids));
10120 
10121 	struct necp_socket_info info = {};
10122 
10123 	u_int32_t flow_divert_aggregate_unit = 0;
10124 
10125 	if (inp == NULL) {
10126 		return NECP_KERNEL_POLICY_ID_NONE;
10127 	}
10128 
10129 	// Ignore invalid addresses
10130 	if (override_local_addr != NULL &&
10131 	    !necp_address_is_valid(override_local_addr)) {
10132 		override_local_addr = NULL;
10133 	}
10134 	if (override_remote_addr != NULL &&
10135 	    !necp_address_is_valid(override_remote_addr)) {
10136 		override_remote_addr = NULL;
10137 	}
10138 
10139 	so = inp->inp_socket;
10140 
10141 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
10142 
10143 	// Don't lock. Possible race condition, but we don't want the performance hit.
10144 	if (necp_drop_management_order == 0 &&
10145 	    (necp_kernel_socket_policies_count == 0 ||
10146 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
10147 		if (necp_drop_all_order > 0 || drop_order > 0) {
10148 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10149 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10150 			inp->inp_policyresult.policy_gencount = 0;
10151 			inp->inp_policyresult.app_id = 0;
10152 			inp->inp_policyresult.flowhash = 0;
10153 			inp->inp_policyresult.results.filter_control_unit = 0;
10154 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10155 			inp->inp_policyresult.results.route_rule_id = 0;
10156 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10157 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
10158 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10159 			} else {
10160 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10161 			}
10162 		}
10163 		return NECP_KERNEL_POLICY_ID_NONE;
10164 	}
10165 
10166 	// Check for loopback exception
10167 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
10168 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
10169 		// Mark socket as a drop
10170 		necp_unscope(inp);
10171 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10172 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10173 		inp->inp_policyresult.policy_gencount = 0;
10174 		inp->inp_policyresult.app_id = 0;
10175 		inp->inp_policyresult.flowhash = 0;
10176 		inp->inp_policyresult.results.filter_control_unit = 0;
10177 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10178 		inp->inp_policyresult.results.route_rule_id = 0;
10179 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10180 		return NECP_KERNEL_POLICY_ID_NONE;
10181 	}
10182 
10183 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
10184 		// Mark socket as a pass
10185 		necp_unscope(inp);
10186 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10187 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10188 		inp->inp_policyresult.policy_gencount = 0;
10189 		inp->inp_policyresult.app_id = 0;
10190 		inp->inp_policyresult.flowhash = 0;
10191 		inp->inp_policyresult.results.filter_control_unit = 0;
10192 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10193 		inp->inp_policyresult.results.route_rule_id = 0;
10194 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10195 		return NECP_KERNEL_POLICY_ID_NONE;
10196 	}
10197 
10198 	// Lock
10199 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10200 	necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
10201 
10202 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
10203 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
10204 
10205 	// Check info
10206 	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
10207 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
10208 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
10209 	    inp->inp_policyresult.flowhash == flowhash) {
10210 		// If already matched this socket on this generation of table, skip
10211 
10212 		// Unlock
10213 		lck_rw_done(&necp_kernel_policy_lock);
10214 
10215 		if (socket_proc) {
10216 			proc_rele(socket_proc);
10217 		}
10218 
10219 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10220 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
10221 			    inp->inp_socket, info.bound_interface_index, info.protocol,
10222 			    inp->inp_policyresult.policy_id,
10223 			    inp->inp_policyresult.results.result,
10224 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
10225 		}
10226 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10227 		return inp->inp_policyresult.policy_id;
10228 	}
10229 
10230 	inp->inp_policyresult.app_id = info.application_id;
10231 
10232 	// Match socket to policy
10233 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10234 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
10235 	size_t route_rule_id_array_count = 0;
10236 
10237 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
10238 	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)],
10239 	    &info,
10240 	    &filter_control_unit,
10241 	    route_rule_id_array,
10242 	    &route_rule_id_array_count,
10243 	    MAX_AGGREGATE_ROUTE_RULES,
10244 	    &service_action,
10245 	    &service,
10246 	    netagent_ids,
10247 	    NECP_MAX_NETAGENTS,
10248 	    NULL,
10249 	    0,
10250 	    NULL,
10251 	    0,
10252 	    effective_proc,
10253 	    0,
10254 	    &skip_policy_id,
10255 	    inp->inp_route.ro_rt,
10256 	    &drop_dest_policy_result,
10257 	    &drop_all_bypass,
10258 	    &flow_divert_aggregate_unit,
10259 	    so,
10260 	    debug);
10261 
10262 	// Check for loopback exception again after the policy match
10263 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
10264 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
10265 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
10266 		// Mark socket as a pass
10267 		necp_unscope(inp);
10268 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10269 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10270 		inp->inp_policyresult.policy_gencount = 0;
10271 		inp->inp_policyresult.app_id = 0;
10272 		inp->inp_policyresult.flowhash = 0;
10273 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10274 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10275 		inp->inp_policyresult.results.route_rule_id = 0;
10276 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
10277 
10278 		// Unlock
10279 		lck_rw_done(&necp_kernel_policy_lock);
10280 
10281 		if (socket_proc) {
10282 			proc_rele(socket_proc);
10283 		}
10284 
10285 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - Loopback PASS", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10286 		return NECP_KERNEL_POLICY_ID_NONE;
10287 	}
10288 
10289 	// Verify netagents
10290 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
10291 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10292 			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);
10293 		}
10294 
10295 		// Mark socket as a drop if required agent is not active
10296 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10297 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10298 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10299 		inp->inp_policyresult.flowhash = flowhash;
10300 		inp->inp_policyresult.results.filter_control_unit = 0;
10301 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10302 		inp->inp_policyresult.results.route_rule_id = 0;
10303 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10304 
10305 		// Unlock
10306 		lck_rw_done(&necp_kernel_policy_lock);
10307 
10308 		if (socket_proc) {
10309 			proc_rele(socket_proc);
10310 		}
10311 
10312 		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);
10313 		return NECP_KERNEL_POLICY_ID_NONE;
10314 	}
10315 
10316 	u_int32_t route_rule_id = 0;
10317 	if (route_rule_id_array_count == 1) {
10318 		route_rule_id = route_rule_id_array[0];
10319 	} else if (route_rule_id_array_count > 1) {
10320 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10321 	}
10322 
10323 	bool reset_tcp_tunnel_interface = false;
10324 	bool send_local_network_denied_event = false;
10325 	if (matched_policy) {
10326 		// For PASS policy result, clear previous rescope / tunnel inteface
10327 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
10328 		    (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
10329 			necp_unscope(inp);
10330 			necp_clear_tunnel(inp);
10331 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10332 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, skip_policy_id);
10333 			}
10334 		}
10335 		matched_policy_id = matched_policy->id;
10336 		inp->inp_policyresult.policy_id = matched_policy->id;
10337 		inp->inp_policyresult.skip_policy_id = skip_policy_id;
10338 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10339 		inp->inp_policyresult.flowhash = flowhash;
10340 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10341 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10342 		inp->inp_policyresult.results.route_rule_id = route_rule_id;
10343 		inp->inp_policyresult.results.result = matched_policy->result;
10344 		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10345 
10346 		if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
10347 			inp->inp_policyresult.app_id = info.real_application_id;
10348 		}
10349 
10350 		if (necp_socket_is_connected(inp) &&
10351 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
10352 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
10353 			NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
10354 			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
10355 		} else if (necp_socket_is_connected(inp) &&
10356 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
10357 		    info.protocol == IPPROTO_TCP) {
10358 			// Reset TCP socket interface based parameters if tunnel policy changes
10359 			reset_tcp_tunnel_interface = true;
10360 		}
10361 
10362 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10363 			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);
10364 		}
10365 
10366 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
10367 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
10368 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
10369 			// Trigger the event that we dropped due to a local network policy
10370 			send_local_network_denied_event = true;
10371 		}
10372 	} else {
10373 		bool drop_all = false;
10374 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
10375 			// Mark socket as a drop if set
10376 			drop_all = true;
10377 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10378 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
10379 			}
10380 		}
10381 
10382 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
10383 		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);
10384 		if (flow_divert_control_unit != 0) {
10385 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10386 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10387 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10388 			inp->inp_policyresult.flowhash = flowhash;
10389 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
10390 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10391 			inp->inp_policyresult.results.route_rule_id = route_rule_id;
10392 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
10393 			inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
10394 			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);
10395 		} else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10396 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10397 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10398 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10399 			inp->inp_policyresult.flowhash = flowhash;
10400 			inp->inp_policyresult.results.filter_control_unit = 0;
10401 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10402 			inp->inp_policyresult.results.route_rule_id = 0;
10403 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10404 			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);
10405 		} else {
10406 			// Mark non-matching socket so we don't re-check it
10407 			necp_unscope(inp);
10408 			if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
10409 				necp_clear_tunnel(inp);
10410 			}
10411 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10412 				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);
10413 			}
10414 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10415 			inp->inp_policyresult.skip_policy_id = skip_policy_id;
10416 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10417 			inp->inp_policyresult.flowhash = flowhash;
10418 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
10419 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
10420 			inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
10421 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
10422 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - NO MATCH", inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
10423 		}
10424 	}
10425 
10426 	if (necp_check_missing_client_drop(effective_proc, &info) ||
10427 	    necp_check_restricted_multicast_drop(effective_proc, &info, false)) {
10428 		// Mark as drop
10429 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10430 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10431 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
10432 		inp->inp_policyresult.flowhash = flowhash;
10433 		inp->inp_policyresult.results.filter_control_unit = 0;
10434 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
10435 		inp->inp_policyresult.results.route_rule_id = 0;
10436 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
10437 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10438 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <MISSING CLIENT>", 0, 0);
10439 		}
10440 	}
10441 
10442 	// Unlock
10443 	lck_rw_done(&necp_kernel_policy_lock);
10444 
10445 	if (reset_tcp_tunnel_interface) {
10446 		// Update MSS when not holding the policy lock to avoid recursive locking
10447 		tcp_mtudisc(inp, 0);
10448 
10449 		// Update TSO flag based on the tunnel interface
10450 		necp_socket_ip_tunnel_tso(inp);
10451 	}
10452 
10453 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
10454 		inp->inp_policyresult.network_denied_notifies++;
10455 #if defined(XNU_TARGET_OS_OSX)
10456 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
10457 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10458 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10459 		    NETPOLICY_NETWORKTYPE_LOCAL);
10460 #else
10461 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
10462 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
10463 		    NETPOLICY_NETWORKTYPE_LOCAL);
10464 #endif
10465 	}
10466 
10467 	if (socket_proc) {
10468 		proc_rele(socket_proc);
10469 	}
10470 
10471 	return matched_policy_id;
10472 }
10473 
10474 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)10475 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)
10476 {
10477 	u_int32_t bound_interface_flags = 0;
10478 	u_int32_t bound_interface_eflags = 0;
10479 	u_int32_t bound_interface_xflags = 0;
10480 
10481 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
10482 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10483 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
10484 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
10485 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
10486 			    cond_bound_interface_index, bound_interface_index);
10487 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
10488 				if (bound_interface_index == cond_bound_interface_index) {
10489 					// No match, matches forbidden interface
10490 					return FALSE;
10491 				}
10492 			} else {
10493 				if (bound_interface_index != cond_bound_interface_index) {
10494 					// No match, does not match required interface
10495 					return FALSE;
10496 				}
10497 			}
10498 		}
10499 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10500 			if (bound_interface_index != IFSCOPE_NONE) {
10501 				ifnet_head_lock_shared();
10502 				ifnet_t interface = ifindex2ifnet[bound_interface_index];
10503 				if (interface != NULL) {
10504 					bound_interface_flags = interface->if_flags;
10505 					bound_interface_eflags = interface->if_eflags;
10506 					bound_interface_xflags = interface->if_xflags;
10507 				}
10508 				ifnet_head_done();
10509 			}
10510 
10511 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10512 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
10513 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10514 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
10515 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
10516 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
10517 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
10518 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10519 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10520 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10521 					// No match, matches some forbidden interface flags
10522 					return FALSE;
10523 				}
10524 			} else {
10525 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
10526 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
10527 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
10528 					// No match, does not match some required interface xflags
10529 					return FALSE;
10530 				}
10531 			}
10532 		}
10533 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
10534 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
10535 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
10536 			if (bound_interface_index != 0) {
10537 				// No match, requires a non-bound packet
10538 				return FALSE;
10539 			}
10540 		}
10541 	}
10542 
10543 	if (kernel_policy->condition_mask == 0) {
10544 		return TRUE;
10545 	}
10546 
10547 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10548 		necp_kernel_policy_id matched_policy_id =
10549 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10550 		NECP_DATA_TRACE_LOG_CONDITION_IP3(debug, "IP", false,
10551 		    "NECP_KERNEL_CONDITION_POLICY_ID",
10552 		    kernel_policy->cond_policy_id, 0, 0,
10553 		    matched_policy_id, socket_policy_id, socket_skip_policy_id);
10554 		if (matched_policy_id != kernel_policy->cond_policy_id) {
10555 			// No match, does not match required id
10556 			return FALSE;
10557 		}
10558 	}
10559 
10560 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10561 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", false,
10562 		    "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10563 		    kernel_policy->cond_last_interface_index, last_interface_index);
10564 		if (last_interface_index != kernel_policy->cond_last_interface_index) {
10565 			return FALSE;
10566 		}
10567 	}
10568 
10569 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10570 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10571 		    "NECP_KERNEL_CONDITION_PROTOCOL",
10572 		    kernel_policy->cond_protocol, protocol);
10573 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10574 			if (protocol == kernel_policy->cond_protocol) {
10575 				// No match, matches forbidden protocol
10576 				return FALSE;
10577 			}
10578 		} else {
10579 			if (protocol != kernel_policy->cond_protocol) {
10580 				// No match, does not match required protocol
10581 				return FALSE;
10582 			}
10583 		}
10584 	}
10585 
10586 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10587 		bool is_local = FALSE;
10588 		bool include_local_addresses = (kernel_policy->cond_local_networks_flags & NECP_POLICY_LOCAL_NETWORKS_FLAG_INCLUDE_LOCAL_ADDRESSES);
10589 
10590 		if (rt != NULL) {
10591 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt, remote, include_local_addresses);
10592 		} else {
10593 			is_local = necp_is_route_local(remote, include_local_addresses);
10594 		}
10595 		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);
10596 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10597 			if (is_local) {
10598 				// Match local-networks, fail
10599 				return FALSE;
10600 			}
10601 		} else {
10602 			if (!is_local) {
10603 				// Either no route to validate or no match for local networks
10604 				return FALSE;
10605 			}
10606 		}
10607 	}
10608 
10609 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
10610 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10611 			bool inRange = necp_is_addr_in_range(SA(local), SA(&kernel_policy->cond_local_start), SA(&kernel_policy->cond_local_end));
10612 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
10613 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10614 				if (inRange) {
10615 					return FALSE;
10616 				}
10617 			} else {
10618 				if (!inRange) {
10619 					return FALSE;
10620 				}
10621 			}
10622 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10623 			bool inSubnet = necp_is_addr_in_subnet(SA(local), SA(&kernel_policy->cond_local_start), kernel_policy->cond_local_prefix);
10624 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
10625 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10626 				if (inSubnet) {
10627 					return FALSE;
10628 				}
10629 			} else {
10630 				if (!inSubnet) {
10631 					return FALSE;
10632 				}
10633 			}
10634 		}
10635 	}
10636 
10637 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
10638 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10639 			bool inRange = necp_is_addr_in_range(SA(remote), SA(&kernel_policy->cond_remote_start), SA(&kernel_policy->cond_remote_end));
10640 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
10641 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10642 				if (inRange) {
10643 					return FALSE;
10644 				}
10645 			} else {
10646 				if (!inRange) {
10647 					return FALSE;
10648 				}
10649 			}
10650 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10651 			bool inSubnet = necp_is_addr_in_subnet(SA(remote), SA(&kernel_policy->cond_remote_start), kernel_policy->cond_remote_prefix);
10652 			NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
10653 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10654 				if (inSubnet) {
10655 					return FALSE;
10656 				}
10657 			} else {
10658 				if (!inSubnet) {
10659 					return FALSE;
10660 				}
10661 			}
10662 		}
10663 	}
10664 
10665 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10666 		u_int16_t remote_port = 0;
10667 		if ((SA(remote))->sa_family == AF_INET || SA(remote)->sa_family == AF_INET6) {
10668 			remote_port = SIN(remote)->sin_port;
10669 		}
10670 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
10671 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
10672 		    0, remote_port);
10673 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10674 			if (kernel_policy->cond_scheme_port == remote_port) {
10675 				return FALSE;
10676 			}
10677 		} else {
10678 			if (kernel_policy->cond_scheme_port != remote_port) {
10679 				return FALSE;
10680 			}
10681 		}
10682 	}
10683 
10684 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10685 		bool tags_matched = false;
10686 		NECP_DATA_TRACE_LOG_CONDITION_IP(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
10687 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
10688 		    kernel_policy->cond_packet_filter_tags, pf_tag);
10689 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
10690 			if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
10691 				tags_matched = true;
10692 			}
10693 
10694 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10695 				if (tags_matched) {
10696 					return FALSE;
10697 				}
10698 			} else {
10699 				if (!tags_matched) {
10700 					return FALSE;
10701 				}
10702 			}
10703 		}
10704 	}
10705 
10706 	return TRUE;
10707 }
10708 
10709 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)10710 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)
10711 {
10712 	u_int32_t skip_order = 0;
10713 	u_int32_t skip_session_order = 0;
10714 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
10715 	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)];
10716 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
10717 	size_t route_rule_id_count = 0;
10718 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10719 	if (return_drop_all_bypass != NULL) {
10720 		*return_drop_all_bypass = drop_all_bypass;
10721 	}
10722 
10723 	if (return_route_rule_id != NULL) {
10724 		*return_route_rule_id = 0;
10725 	}
10726 
10727 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10728 
10729 	if (policy_search_array != NULL) {
10730 		for (int i = 0; policy_search_array[i] != NULL; i++) {
10731 			NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "EXAMINING");
10732 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10733 				// We've hit a drop all rule
10734 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10735 					drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10736 					if (return_drop_all_bypass != NULL) {
10737 						*return_drop_all_bypass = drop_all_bypass;
10738 					}
10739 				}
10740 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10741 					NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
10742 					break;
10743 				}
10744 			}
10745 			if (necp_drop_dest_policy.entry_count > 0 &&
10746 			    necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
10747 				// We've hit a drop by destination address rule
10748 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10749 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
10750 				break;
10751 			}
10752 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10753 				// Done skipping
10754 				skip_order = 0;
10755 				skip_session_order = 0;
10756 			}
10757 			if (skip_order) {
10758 				if (policy_search_array[i]->order < skip_order) {
10759 					// Skip this policy
10760 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (session order < skip-order)");
10761 					continue;
10762 				} else {
10763 					// Done skipping
10764 					skip_order = 0;
10765 					skip_session_order = 0;
10766 				}
10767 			} else if (skip_session_order) {
10768 				// Skip this policy
10769 				NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "SKIP (skip-session-order)");
10770 				continue;
10771 			}
10772 
10773 			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)) {
10774 				if (!debug && necp_data_tracing_session_order) {
10775 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10776 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10777 						NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
10778 					}
10779 				}
10780 
10781 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10782 					if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
10783 						route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10784 					}
10785 					continue;
10786 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10787 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10788 					skip_session_order = policy_search_array[i]->session_order + 1;
10789 					NECP_DATA_TRACE_LOG_POLICY_IP(debug, "IP", "MATCHED SKIP POLICY");
10790 					continue;
10791 				}
10792 
10793 				// Passed all tests, found a match
10794 				matched_policy = policy_search_array[i];
10795 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
10796 				break;
10797 			}
10798 		}
10799 	}
10800 
10801 	if (route_rule_id_count == 1) {
10802 		*return_route_rule_id = route_rule_id_array[0];
10803 	} else if (route_rule_id_count > 1) {
10804 		*return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10805 	}
10806 
10807 	return matched_policy;
10808 }
10809 
10810 static inline bool
necp_output_bypass(struct mbuf * packet)10811 necp_output_bypass(struct mbuf *packet)
10812 {
10813 	if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
10814 		return true;
10815 	}
10816 	if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
10817 		return true;
10818 	}
10819 	if (necp_is_intcoproc(NULL, packet)) {
10820 		return true;
10821 	}
10822 	return false;
10823 }
10824 
10825 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)10826 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
10827     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
10828 {
10829 	struct ip *ip = NULL;
10830 	int hlen = sizeof(struct ip);
10831 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10832 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10833 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10834 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
10835 	u_int16_t protocol = 0;
10836 	u_int32_t bound_interface_index = 0;
10837 	u_int32_t last_interface_index = 0;
10838 	union necp_sockaddr_union local_addr = { };
10839 	union necp_sockaddr_union remote_addr = { };
10840 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10841 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10842 	u_int16_t pf_tag = 0;
10843 
10844 	if (result) {
10845 		*result = 0;
10846 	}
10847 
10848 	if (result_parameter) {
10849 		memset(result_parameter, 0, sizeof(*result_parameter));
10850 	}
10851 
10852 	if (packet == NULL) {
10853 		return NECP_KERNEL_POLICY_ID_NONE;
10854 	}
10855 
10856 	socket_policy_id = necp_get_policy_id_from_packet(packet);
10857 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
10858 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
10859 
10860 	// Exit early for an empty list
10861 	// Don't lock. Possible race condition, but we don't want the performance hit.
10862 	if (necp_kernel_ip_output_policies_count == 0 ||
10863 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
10864 		if (necp_drop_all_order > 0) {
10865 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10866 			if (result) {
10867 				if (necp_output_bypass(packet)) {
10868 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
10869 				} else {
10870 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
10871 				}
10872 			}
10873 		}
10874 
10875 		return matched_policy_id;
10876 	}
10877 
10878 	// Check for loopback exception
10879 	if (necp_output_bypass(packet)) {
10880 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10881 		if (result) {
10882 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
10883 		}
10884 		return matched_policy_id;
10885 	}
10886 
10887 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
10888 
10889 	// Process packet to get relevant fields
10890 	ip = mtod(packet, struct ip *);
10891 #ifdef _IP_VHL
10892 	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
10893 #else
10894 	hlen = ip->ip_hl << 2;
10895 #endif
10896 
10897 	protocol = ip->ip_p;
10898 
10899 	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
10900 	    (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
10901 	    ipoa->ipoa_boundif != IFSCOPE_NONE) {
10902 		bound_interface_index = ipoa->ipoa_boundif;
10903 	}
10904 
10905 	local_addr.sin.sin_family = AF_INET;
10906 	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
10907 	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
10908 
10909 	remote_addr.sin.sin_family = AF_INET;
10910 	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
10911 	memcpy(&SIN(&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
10912 
10913 	switch (protocol) {
10914 	case IPPROTO_TCP: {
10915 		struct tcphdr th;
10916 		if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
10917 			m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
10918 			SIN(&local_addr)->sin_port = th.th_sport;
10919 			SIN(&remote_addr)->sin_port = th.th_dport;
10920 		}
10921 		break;
10922 	}
10923 	case IPPROTO_UDP: {
10924 		struct udphdr uh;
10925 		if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
10926 			m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
10927 			SIN(&local_addr)->sin_port = uh.uh_sport;
10928 			SIN(&remote_addr)->sin_port = uh.uh_dport;
10929 		}
10930 		break;
10931 	}
10932 	default: {
10933 		SIN(&local_addr)->sin_port = 0;
10934 		SIN(&remote_addr)->sin_port = 0;
10935 		break;
10936 	}
10937 	}
10938 
10939 	// Match packet to policy
10940 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10941 	u_int32_t route_rule_id = 0;
10942 
10943 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
10944 	NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
10945 
10946 	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);
10947 	if (matched_policy) {
10948 		matched_policy_id = matched_policy->id;
10949 		if (result) {
10950 			*result = matched_policy->result;
10951 		}
10952 
10953 		if (result_parameter) {
10954 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10955 		}
10956 
10957 		if (route_rule_id != 0 &&
10958 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10959 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10960 		}
10961 
10962 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10963 			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);
10964 		}
10965 	} else {
10966 		bool drop_all = false;
10967 		/*
10968 		 * Apply drop-all only to packets which have never matched a primary policy (check
10969 		 * if the packet saved policy id is none or falls within the socket policy id range).
10970 		 */
10971 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10972 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10973 			drop_all = true;
10974 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10975 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10976 			}
10977 		}
10978 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10979 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10980 			if (result) {
10981 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
10982 				NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
10983 			}
10984 		} else if (route_rule_id != 0 &&
10985 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10986 			// If we matched a route rule, mark it
10987 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10988 		}
10989 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10990 			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);
10991 		}
10992 	}
10993 
10994 	lck_rw_done(&necp_kernel_policy_lock);
10995 
10996 	return matched_policy_id;
10997 }
10998 
10999 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)11000 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
11001     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
11002 {
11003 	struct ip6_hdr *ip6 = NULL;
11004 	int next = -1;
11005 	int offset = 0;
11006 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11007 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11008 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11009 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
11010 	u_int16_t protocol = 0;
11011 	u_int32_t bound_interface_index = 0;
11012 	u_int32_t last_interface_index = 0;
11013 	union necp_sockaddr_union local_addr = { };
11014 	union necp_sockaddr_union remote_addr = { };
11015 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11016 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11017 	u_int16_t pf_tag = 0;
11018 
11019 	if (result) {
11020 		*result = 0;
11021 	}
11022 
11023 	if (result_parameter) {
11024 		memset(result_parameter, 0, sizeof(*result_parameter));
11025 	}
11026 
11027 	if (packet == NULL) {
11028 		return NECP_KERNEL_POLICY_ID_NONE;
11029 	}
11030 
11031 	socket_policy_id = necp_get_policy_id_from_packet(packet);
11032 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
11033 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
11034 
11035 	// Exit early for an empty list
11036 	// Don't lock. Possible race condition, but we don't want the performance hit.
11037 	if (necp_drop_management_order == 0 &&
11038 	    (necp_kernel_ip_output_policies_count == 0 ||
11039 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
11040 		if (necp_drop_all_order > 0) {
11041 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11042 			if (result) {
11043 				if (necp_output_bypass(packet)) {
11044 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
11045 				} else {
11046 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
11047 				}
11048 			}
11049 		}
11050 
11051 		return matched_policy_id;
11052 	}
11053 
11054 	// Check for loopback exception
11055 	if (necp_output_bypass(packet)) {
11056 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11057 		if (result) {
11058 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
11059 		}
11060 		return matched_policy_id;
11061 	}
11062 
11063 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
11064 
11065 	// Process packet to get relevant fields
11066 	ip6 = mtod(packet, struct ip6_hdr *);
11067 
11068 	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
11069 	    (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
11070 	    ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
11071 		bound_interface_index = ip6oa->ip6oa_boundif;
11072 	}
11073 
11074 	SIN6(&local_addr)->sin6_family = AF_INET6;
11075 	SIN6(&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
11076 	memcpy(&SIN6(&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
11077 
11078 	SIN6(&remote_addr)->sin6_family = AF_INET6;
11079 	SIN6(&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
11080 	memcpy(&SIN6(&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
11081 
11082 	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
11083 	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
11084 		protocol = next;
11085 		switch (protocol) {
11086 		case IPPROTO_TCP: {
11087 			struct tcphdr th;
11088 			if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
11089 				m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
11090 				SIN6(&local_addr)->sin6_port = th.th_sport;
11091 				SIN6(&remote_addr)->sin6_port = th.th_dport;
11092 			}
11093 			break;
11094 		}
11095 		case IPPROTO_UDP: {
11096 			struct udphdr uh;
11097 			if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
11098 				m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
11099 				SIN6(&local_addr)->sin6_port = uh.uh_sport;
11100 				SIN6(&remote_addr)->sin6_port = uh.uh_dport;
11101 			}
11102 			break;
11103 		}
11104 		default: {
11105 			SIN6(&local_addr)->sin6_port = 0;
11106 			SIN6(&remote_addr)->sin6_port = 0;
11107 			break;
11108 		}
11109 		}
11110 	}
11111 
11112 	// Match packet to policy
11113 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11114 	u_int32_t route_rule_id = 0;
11115 
11116 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
11117 	NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
11118 
11119 	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);
11120 	if (matched_policy) {
11121 		matched_policy_id = matched_policy->id;
11122 		if (result) {
11123 			*result = matched_policy->result;
11124 		}
11125 
11126 		if (result_parameter) {
11127 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
11128 		}
11129 
11130 		if (route_rule_id != 0 &&
11131 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11132 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11133 		}
11134 
11135 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11136 			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);
11137 		}
11138 	} else {
11139 		bool drop_all = false;
11140 		/*
11141 		 * Apply drop-all only to packets which have never matched a primary policy (check
11142 		 * if the packet saved policy id is none or falls within the socket policy id range).
11143 		 */
11144 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
11145 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
11146 			drop_all = true;
11147 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11148 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
11149 			}
11150 		}
11151 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11152 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11153 			if (result) {
11154 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
11155 				NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
11156 			}
11157 		} else if (route_rule_id != 0 &&
11158 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
11159 			// If we matched a route rule, mark it
11160 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
11161 		}
11162 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11163 			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);
11164 		}
11165 	}
11166 
11167 	lck_rw_done(&necp_kernel_policy_lock);
11168 
11169 	return matched_policy_id;
11170 }
11171 
11172 // Utilities
11173 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)11174 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
11175 {
11176 	int cmp = 0;
11177 
11178 	if (addr == NULL || range_start == NULL || range_end == NULL) {
11179 		return FALSE;
11180 	}
11181 
11182 	/* Must be greater than or equal to start */
11183 	cmp = necp_addr_compare(addr, range_start, 1);
11184 	if (cmp != 0 && cmp != 1) {
11185 		return FALSE;
11186 	}
11187 
11188 	/* Must be less than or equal to end */
11189 	cmp = necp_addr_compare(addr, range_end, 1);
11190 	if (cmp != 0 && cmp != -1) {
11191 		return FALSE;
11192 	}
11193 
11194 	return TRUE;
11195 }
11196 
11197 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)11198 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
11199 {
11200 	int cmp = 0;
11201 
11202 	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
11203 		return FALSE;
11204 	}
11205 
11206 	/* Must be greater than or equal to start */
11207 	cmp = necp_addr_compare(inner_range_start, range_start, 1);
11208 	if (cmp != 0 && cmp != 1) {
11209 		return FALSE;
11210 	}
11211 
11212 	/* Must be less than or equal to end */
11213 	cmp = necp_addr_compare(inner_range_end, range_end, 1);
11214 	if (cmp != 0 && cmp != -1) {
11215 		return FALSE;
11216 	}
11217 
11218 	return TRUE;
11219 }
11220 
11221 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)11222 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
11223 {
11224 	if (addr == NULL || subnet_addr == NULL) {
11225 		return FALSE;
11226 	}
11227 
11228 	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
11229 		return FALSE;
11230 	}
11231 
11232 	switch (addr->sa_family) {
11233 	case AF_INET: {
11234 		if (satosin(subnet_addr)->sin_port != 0 &&
11235 		    satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
11236 			return FALSE;
11237 		}
11238 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
11239 	}
11240 	case AF_INET6: {
11241 		if (satosin6(subnet_addr)->sin6_port != 0 &&
11242 		    satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
11243 			return FALSE;
11244 		}
11245 		if (satosin6(addr)->sin6_scope_id &&
11246 		    satosin6(subnet_addr)->sin6_scope_id &&
11247 		    satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
11248 			return FALSE;
11249 		}
11250 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
11251 	}
11252 	default: {
11253 		return FALSE;
11254 	}
11255 	}
11256 
11257 	return FALSE;
11258 }
11259 
11260 /*
11261  * Return values:
11262  * -1: sa1 < sa2
11263  * 0: sa1 == sa2
11264  * 1: sa1 > sa2
11265  * 2: Not comparable or error
11266  */
11267 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)11268 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
11269 {
11270 	int result = 0;
11271 	int port_result = 0;
11272 
11273 	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
11274 		return 2;
11275 	}
11276 
11277 	if (sa1->sa_len == 0) {
11278 		return 0;
11279 	}
11280 
11281 	switch (sa1->sa_family) {
11282 	case AF_INET: {
11283 		if (sa1->sa_len != sizeof(struct sockaddr_in)) {
11284 			return 2;
11285 		}
11286 
11287 		result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
11288 
11289 		if (check_port) {
11290 			if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
11291 				port_result = -1;
11292 			} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
11293 				port_result = 1;
11294 			}
11295 
11296 			if (result == 0) {
11297 				result = port_result;
11298 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11299 				return 2;
11300 			}
11301 		}
11302 
11303 		break;
11304 	}
11305 	case AF_INET6: {
11306 		if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
11307 			return 2;
11308 		}
11309 
11310 		if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
11311 			return 2;
11312 		}
11313 
11314 		result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
11315 
11316 		if (check_port) {
11317 			if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
11318 				port_result = -1;
11319 			} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
11320 				port_result = 1;
11321 			}
11322 
11323 			if (result == 0) {
11324 				result = port_result;
11325 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
11326 				return 2;
11327 			}
11328 		}
11329 
11330 		break;
11331 	}
11332 	default: {
11333 		result = SOCKADDR_CMP(sa1, sa2, sa1->sa_len);
11334 		break;
11335 	}
11336 	}
11337 
11338 	if (result < 0) {
11339 		result = (-1);
11340 	} else if (result > 0) {
11341 		result = (1);
11342 	}
11343 
11344 	return result;
11345 }
11346 
11347 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1,u_int8_t * __indexable p2,u_int32_t bits)11348 necp_buffer_compare_with_bit_prefix(u_int8_t * __indexable p1, u_int8_t * __indexable p2, u_int32_t bits)
11349 {
11350 	u_int8_t mask;
11351 
11352 	/* Handle null pointers */
11353 	if (p1 == NULL || p2 == NULL) {
11354 		return p1 == p2;
11355 	}
11356 
11357 	while (bits >= 8) {
11358 		if (*p1++ != *p2++) {
11359 			return FALSE;
11360 		}
11361 		bits -= 8;
11362 	}
11363 
11364 	if (bits > 0) {
11365 		mask = ~((1 << (8 - bits)) - 1);
11366 		if ((*p1 & mask) != (*p2 & mask)) {
11367 			return FALSE;
11368 		}
11369 	}
11370 	return TRUE;
11371 }
11372 
11373 static bool
necp_addr_is_empty(struct sockaddr * addr)11374 necp_addr_is_empty(struct sockaddr *addr)
11375 {
11376 	if (addr == NULL) {
11377 		return TRUE;
11378 	}
11379 
11380 	if (addr->sa_len == 0) {
11381 		return TRUE;
11382 	}
11383 
11384 	switch (addr->sa_family) {
11385 	case AF_INET: {
11386 		static struct sockaddr_in ipv4_empty_address = {
11387 			.sin_len = sizeof(struct sockaddr_in),
11388 			.sin_family = AF_INET,
11389 			.sin_port = 0,
11390 			.sin_addr = { .s_addr = 0 }, // 0.0.0.0
11391 			.sin_zero = {0},
11392 		};
11393 		if (necp_addr_compare(addr, SA(&ipv4_empty_address), 0) == 0) {
11394 			return TRUE;
11395 		} else {
11396 			return FALSE;
11397 		}
11398 	}
11399 	case AF_INET6: {
11400 		static struct sockaddr_in6 ipv6_empty_address = {
11401 			.sin6_len = sizeof(struct sockaddr_in6),
11402 			.sin6_family = AF_INET6,
11403 			.sin6_port = 0,
11404 			.sin6_flowinfo = 0,
11405 			.sin6_addr = IN6ADDR_ANY_INIT, // ::
11406 			.sin6_scope_id = 0,
11407 		};
11408 		if (necp_addr_compare(addr, SA(&ipv6_empty_address), 0) == 0) {
11409 			return TRUE;
11410 		} else {
11411 			return FALSE;
11412 		}
11413 	}
11414 	default:
11415 		return FALSE;
11416 	}
11417 
11418 	return FALSE;
11419 }
11420 
11421 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)11422 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)
11423 {
11424 	bool qos_marking = FALSE;
11425 	int exception_index = 0;
11426 	struct necp_route_rule *route_rule = NULL;
11427 
11428 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11429 	if (route_rule == NULL) {
11430 		qos_marking = FALSE;
11431 		goto done;
11432 	}
11433 
11434 	if (route_rule->match_netagent_id != 0) {
11435 		if (netagent_array == NULL || netagent_array_count == 0) {
11436 			// No agents, ignore rule
11437 			goto done;
11438 		}
11439 		bool found_match = FALSE;
11440 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11441 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11442 				found_match = TRUE;
11443 				break;
11444 			}
11445 		}
11446 		if (!found_match) {
11447 			// Agents don't match, ignore rule
11448 			goto done;
11449 		}
11450 	}
11451 
11452 	qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
11453 
11454 	if (ifp == NULL) {
11455 		goto done;
11456 	}
11457 
11458 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11459 		if (route_rule->exception_if_indices[exception_index] == 0) {
11460 			break;
11461 		}
11462 		if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
11463 			continue;
11464 		}
11465 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
11466 			qos_marking = TRUE;
11467 			if (necp_debug > 2) {
11468 				NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
11469 				    route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
11470 			}
11471 			goto done;
11472 		}
11473 	}
11474 
11475 	if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
11476 	    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
11477 	    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
11478 	    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
11479 	    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
11480 	    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp)) ||
11481 	    (route_rule->vpn_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_VPN(ifp))) {
11482 		qos_marking = TRUE;
11483 		if (necp_debug > 2) {
11484 			NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d VPN:%d for Rule %d Allowed %d",
11485 			    route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
11486 			    route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule->vpn_action, route_rule_id, qos_marking);
11487 		}
11488 		goto done;
11489 	}
11490 done:
11491 	if (necp_debug > 1) {
11492 		NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
11493 		    route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
11494 	}
11495 	return qos_marking;
11496 }
11497 
11498 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)11499 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)
11500 {
11501 	bool new_qos_marking = old_qos_marking;
11502 	struct ifnet *ifp = interface;
11503 
11504 	if (net_qos_policy_restricted == 0) {
11505 		return new_qos_marking;
11506 	}
11507 
11508 	/*
11509 	 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
11510 	 */
11511 	if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
11512 		return new_qos_marking;
11513 	}
11514 
11515 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11516 
11517 	if (ifp == NULL && route != NULL) {
11518 		ifp = route->rt_ifp;
11519 	}
11520 	/*
11521 	 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
11522 	 */
11523 	if (ifp == NULL || route_rule_id == 0) {
11524 		new_qos_marking = FALSE;
11525 		goto done;
11526 	}
11527 
11528 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11529 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11530 		if (aggregate_route_rule != NULL) {
11531 			int index = 0;
11532 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11533 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11534 				if (sub_route_rule_id == 0) {
11535 					break;
11536 				}
11537 				new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
11538 				if (new_qos_marking == TRUE) {
11539 					break;
11540 				}
11541 			}
11542 		}
11543 	} else {
11544 		new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
11545 	}
11546 	/*
11547 	 * Now that we have an interface we remember the gencount
11548 	 */
11549 	*qos_marking_gencount = necp_kernel_socket_policies_gencount;
11550 
11551 done:
11552 	lck_rw_done(&necp_kernel_policy_lock);
11553 	return new_qos_marking;
11554 }
11555 
11556 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11557 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11558 {
11559 	bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11560 
11561 	if (net_qos_policy_restricted == 0) {
11562 		return;
11563 	}
11564 	if (inp->inp_socket == NULL) {
11565 		return;
11566 	}
11567 	if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11568 		return;
11569 	}
11570 
11571 	qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11572 
11573 	if (qos_marking == TRUE) {
11574 		inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11575 	} else {
11576 		inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11577 	}
11578 }
11579 
11580 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)11581 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11582 {
11583 	if (ifp != NULL &&
11584 	    (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11585 	    ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11586 		return true;
11587 	}
11588 	if (delegated_ifp != NULL &&
11589 	    (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11590 	    delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11591 		return true;
11592 	}
11593 	return false;
11594 }
11595 
11596 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)11597 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,
11598     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11599 {
11600 	bool default_is_allowed = TRUE;
11601 	u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
11602 	int exception_index = 0;
11603 	struct ifnet *delegated_ifp = NULL;
11604 	struct necp_route_rule *route_rule = NULL;
11605 
11606 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11607 	if (route_rule == NULL) {
11608 		return TRUE;
11609 	}
11610 
11611 	if (route_rule->match_netagent_id != 0) {
11612 		if (netagent_array == NULL || netagent_array_count == 0) {
11613 			// No agents, ignore rule
11614 			return TRUE;
11615 		}
11616 		bool found_match = FALSE;
11617 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11618 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11619 				found_match = TRUE;
11620 				break;
11621 			}
11622 		}
11623 		if (!found_match) {
11624 			// Agents don't match, ignore rule
11625 			return TRUE;
11626 		}
11627 	}
11628 
11629 	default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
11630 	if (ifp == NULL && route != NULL) {
11631 		ifp = route->rt_ifp;
11632 	}
11633 	if (ifp == NULL) {
11634 		if (necp_debug > 1 && !default_is_allowed) {
11635 			NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11636 		}
11637 		return default_is_allowed;
11638 	}
11639 
11640 	delegated_ifp = ifp->if_delegated.ifp;
11641 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11642 		if (route_rule->exception_if_indices[exception_index] == 0) {
11643 			break;
11644 		}
11645 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
11646 		    (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
11647 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11648 				const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
11649 				if (necp_debug > 1 && lqm_abort) {
11650 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
11651 					    route_rule->exception_if_indices[exception_index], route_rule_id);
11652 				}
11653 				return false;
11654 			} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
11655 				if (necp_debug > 1) {
11656 					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));
11657 				}
11658 				if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
11659 					*interface_type_denied = route_rule->effective_type;
11660 				}
11661 				return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
11662 			}
11663 		}
11664 	}
11665 
11666 	if (IFNET_IS_CELLULAR(ifp)) {
11667 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11668 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11669 				if (interface_type_denied != NULL) {
11670 					*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11671 					if (route_rule->effective_type != 0) {
11672 						*interface_type_denied = route_rule->effective_type;
11673 					}
11674 				}
11675 				// Mark aggregate action as deny
11676 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11677 			}
11678 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
11679 			if (interface_type_denied != NULL) {
11680 				*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11681 				if (route_rule->effective_type != 0) {
11682 					*interface_type_denied = route_rule->effective_type;
11683 				}
11684 			}
11685 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11686 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11687 			    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
11688 				// Deny wins if there is a conflict
11689 				type_aggregate_action = route_rule->cellular_action;
11690 			}
11691 		}
11692 	}
11693 
11694 	if (IFNET_IS_WIFI(ifp)) {
11695 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11696 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11697 				if (interface_type_denied != NULL) {
11698 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11699 					if (route_rule->effective_type != 0) {
11700 						*interface_type_denied = route_rule->effective_type;
11701 					}
11702 				}
11703 				// Mark aggregate action as deny
11704 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11705 			}
11706 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
11707 			if (interface_type_denied != NULL) {
11708 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11709 				if (route_rule->effective_type != 0) {
11710 					*interface_type_denied = route_rule->effective_type;
11711 				}
11712 			}
11713 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11714 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11715 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
11716 				// Deny wins if there is a conflict
11717 				type_aggregate_action = route_rule->wifi_action;
11718 			}
11719 		}
11720 	}
11721 
11722 	if (IFNET_IS_COMPANION_LINK(ifp) ||
11723 	    (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
11724 		if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11725 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11726 				if (interface_type_denied != NULL) {
11727 					*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11728 					if (route_rule->effective_type != 0) {
11729 						*interface_type_denied = route_rule->effective_type;
11730 					}
11731 				}
11732 				// Mark aggregate action as deny
11733 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11734 			}
11735 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
11736 			if (interface_type_denied != NULL) {
11737 				*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11738 				if (route_rule->effective_type != 0) {
11739 					*interface_type_denied = route_rule->effective_type;
11740 				}
11741 			}
11742 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11743 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11744 			    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
11745 				// Deny wins if there is a conflict
11746 				type_aggregate_action = route_rule->companion_action;
11747 			}
11748 		}
11749 	}
11750 
11751 	if (IFNET_IS_WIRED(ifp)) {
11752 		if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11753 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11754 				if (interface_type_denied != NULL) {
11755 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11756 					if (route_rule->effective_type != 0) {
11757 						*interface_type_denied = route_rule->effective_type;
11758 					}
11759 				}
11760 				// Mark aggregate action as deny
11761 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11762 			}
11763 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
11764 			if (interface_type_denied != NULL) {
11765 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11766 				if (route_rule->effective_type != 0) {
11767 					*interface_type_denied = route_rule->effective_type;
11768 				}
11769 			}
11770 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11771 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11772 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
11773 				// Deny wins if there is a conflict
11774 				type_aggregate_action = route_rule->wired_action;
11775 			}
11776 		}
11777 	}
11778 
11779 	if (IFNET_IS_EXPENSIVE(ifp)) {
11780 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11781 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11782 				// Mark aggregate action as deny
11783 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11784 			}
11785 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
11786 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11787 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11788 			    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
11789 				// Deny wins if there is a conflict
11790 				type_aggregate_action = route_rule->expensive_action;
11791 			}
11792 		}
11793 	}
11794 
11795 	if (IFNET_IS_CONSTRAINED(ifp)) {
11796 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11797 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11798 				// Mark aggregate action as deny
11799 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11800 			}
11801 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
11802 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11803 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11804 			    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
11805 				// Deny wins if there is a conflict
11806 				type_aggregate_action = route_rule->constrained_action;
11807 			}
11808 		}
11809 	}
11810 
11811 	if (IFNET_IS_VPN(ifp)) {
11812 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11813 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11814 				// Mark aggregate action as deny
11815 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11816 			}
11817 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->vpn_action)) {
11818 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11819 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11820 			    IS_NECP_ROUTE_RULE_DENY(route_rule->vpn_action))) {
11821 				// Deny wins if there is a conflict
11822 				type_aggregate_action = route_rule->vpn_action;
11823 			}
11824 		}
11825 	}
11826 
11827 	if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
11828 		if (necp_debug > 1) {
11829 			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));
11830 		}
11831 		return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
11832 	}
11833 
11834 	if (necp_debug > 1 && !default_is_allowed) {
11835 		NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11836 	}
11837 	return default_is_allowed;
11838 }
11839 
11840 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)11841 necp_proc_is_allowed_on_management_interface(proc_t proc)
11842 {
11843 	bool allowed = false;
11844 	const task_t __single task = proc_task(proc);
11845 
11846 	if (task != NULL) {
11847 		if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
11848 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
11849 #if DEBUG || DEVELOPMENT
11850 		    || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
11851 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
11852 #endif /* DEBUG || DEVELOPMENT */
11853 		    ) {
11854 			allowed = true;
11855 		}
11856 	}
11857 	return allowed;
11858 }
11859 
11860 __attribute__((noinline))
11861 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)11862 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11863 {
11864 	char buf[128];
11865 
11866 	if (inp != NULL) {
11867 		inp_snprintf_tuple(inp, buf, sizeof(buf));
11868 	} else {
11869 		*buf = 0;
11870 	}
11871 	os_log(OS_LOG_DEFAULT,
11872 	    "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
11873 	    proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
11874 	    proc != NULL ? proc_getpid(proc) : proc_selfpid(),
11875 	    inp != NULL ? buf : "",
11876 	    ifp->if_xname);
11877 }
11878 
11879 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)11880 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11881 {
11882 	if (if_management_interface_check_needed == false) {
11883 		return true;
11884 	}
11885 	if (necp_drop_management_order == 0) {
11886 		return true;
11887 	}
11888 	if (ifp == NULL && route != NULL) {
11889 		ifp = route->rt_ifp;
11890 	}
11891 	if (ifp == NULL) {
11892 		return true;
11893 	}
11894 
11895 	if (IFNET_IS_MANAGEMENT(ifp)) {
11896 		bool allowed = true;
11897 
11898 		if (inp != NULL) {
11899 			/*
11900 			 * The entitlement check is already performed for socket flows
11901 			 */
11902 			allowed = INP_MANAGEMENT_ALLOWED(inp);
11903 		} else if (proc != NULL) {
11904 			allowed = necp_proc_is_allowed_on_management_interface(proc);
11905 		}
11906 		if (__improbable(if_management_verbose > 1 && allowed == false)) {
11907 			necp_log_interface_not_allowed(ifp, proc, inp);
11908 		}
11909 		return allowed;
11910 	}
11911 	return true;
11912 }
11913 
11914 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)11915 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,
11916     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11917 {
11918 	if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
11919 		if (necp_debug > 1) {
11920 			NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
11921 		}
11922 		return TRUE;
11923 	}
11924 
11925 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11926 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11927 		if (aggregate_route_rule != NULL) {
11928 			int index = 0;
11929 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11930 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11931 				if (sub_route_rule_id == 0) {
11932 					break;
11933 				}
11934 				if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
11935 					return FALSE;
11936 				}
11937 			}
11938 		}
11939 	} else {
11940 		return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
11941 	}
11942 
11943 	return TRUE;
11944 }
11945 
11946 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)11947 necp_route_rule_matches_agents(u_int32_t route_rule_id)
11948 {
11949 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11950 	if (route_rule == NULL) {
11951 		return false;
11952 	}
11953 
11954 	return route_rule->match_netagent_id != 0;
11955 }
11956 
11957 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)11958 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)
11959 {
11960 	if (remove == NULL) {
11961 		return 0;
11962 	}
11963 
11964 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11965 	if (route_rule == NULL) {
11966 		return 0;
11967 	}
11968 
11969 	// No netagent, skip
11970 	if (route_rule->netagent_id == 0) {
11971 		return 0;
11972 	}
11973 
11974 	if (route_rule->match_netagent_id != 0) {
11975 		if (netagent_array == NULL || netagent_array_count == 0) {
11976 			// No agents, ignore rule
11977 			return 0;
11978 		}
11979 		bool found_match = FALSE;
11980 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11981 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11982 				found_match = TRUE;
11983 				break;
11984 			}
11985 		}
11986 		if (!found_match) {
11987 			// Agents don't match, ignore rule
11988 			return 0;
11989 		}
11990 	}
11991 
11992 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
11993 	if (ifp == NULL) {
11994 		// No interface, apply the default action
11995 		if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11996 		    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11997 			*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11998 			return route_rule->netagent_id;
11999 		}
12000 		return 0;
12001 	}
12002 
12003 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12004 		if (route_rule->exception_if_indices[exception_index] == 0) {
12005 			break;
12006 		}
12007 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12008 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12009 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
12010 			    route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12011 				*remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12012 				return route_rule->netagent_id;
12013 			}
12014 			return 0;
12015 		}
12016 	}
12017 
12018 	if (ifp->if_type == IFT_CELLULAR &&
12019 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12020 		if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12021 		    route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12022 			*remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12023 			return route_rule->netagent_id;
12024 		}
12025 		return 0;
12026 	}
12027 
12028 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12029 	    route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
12030 		if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12031 		    route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12032 			*remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12033 			return route_rule->netagent_id;
12034 		}
12035 		return 0;
12036 	}
12037 
12038 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12039 	    route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
12040 		if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12041 		    route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12042 			*remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12043 			return route_rule->netagent_id;
12044 		}
12045 		return 0;
12046 	}
12047 
12048 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12049 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12050 		if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12051 		    route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
12052 			*remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12053 			return route_rule->netagent_id;
12054 		}
12055 		return 0;
12056 	}
12057 
12058 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12059 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12060 		if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12061 		    route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12062 			*remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12063 			return route_rule->netagent_id;
12064 		}
12065 		return 0;
12066 	}
12067 
12068 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12069 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12070 		if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12071 		    route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12072 			*remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12073 			return route_rule->netagent_id;
12074 		}
12075 		return 0;
12076 	}
12077 
12078 	if (ifp->if_xflags & IFXF_IS_VPN &&
12079 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12080 		if (route_rule->vpn_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12081 		    route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12082 			*remove = (route_rule->vpn_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12083 			return route_rule->netagent_id;
12084 		}
12085 		return 0;
12086 	}
12087 
12088 	// No more specific case matched, apply the default action
12089 	if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
12090 	    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
12091 		*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
12092 		return route_rule->netagent_id;
12093 	}
12094 
12095 	return 0;
12096 }
12097 
12098 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)12099 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)
12100 {
12101 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
12102 	if (route_rule == NULL) {
12103 		return 0;
12104 	}
12105 
12106 	// No control unit, skip
12107 	if (route_rule->control_unit == 0) {
12108 		return 0;
12109 	}
12110 
12111 	if (route_rule->match_netagent_id != 0) {
12112 		if (netagent_array == NULL || netagent_array_count == 0) {
12113 			// No agents, ignore rule
12114 			return 0;
12115 		}
12116 		bool found_match = FALSE;
12117 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
12118 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
12119 				found_match = TRUE;
12120 				break;
12121 			}
12122 		}
12123 		if (!found_match) {
12124 			// Agents don't match, ignore rule
12125 			return 0;
12126 		}
12127 	}
12128 
12129 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
12130 	if (ifp == NULL) {
12131 		// No interface, apply the default action
12132 		if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12133 			return route_rule->control_unit;
12134 		}
12135 		return 0;
12136 	}
12137 
12138 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
12139 		if (route_rule->exception_if_indices[exception_index] == 0) {
12140 			break;
12141 		}
12142 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
12143 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
12144 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12145 				return route_rule->control_unit;
12146 			}
12147 			return 0;
12148 		}
12149 	}
12150 
12151 	if (ifp->if_type == IFT_CELLULAR &&
12152 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
12153 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12154 			return route_rule->control_unit;
12155 		}
12156 		return 0;
12157 	}
12158 
12159 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
12160 	    route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12161 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12162 			return route_rule->control_unit;
12163 		}
12164 		return 0;
12165 	}
12166 
12167 	if (IFNET_IS_COMPANION_LINK(ifp) &&
12168 	    route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12169 		if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12170 			return route_rule->control_unit;
12171 		}
12172 		return 0;
12173 	}
12174 
12175 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
12176 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
12177 		if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12178 			return route_rule->control_unit;
12179 		}
12180 		return 0;
12181 	}
12182 
12183 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
12184 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
12185 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12186 			return route_rule->control_unit;
12187 		}
12188 		return 0;
12189 	}
12190 
12191 	if ((ifp->if_xflags & IFXF_CONSTRAINED || ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) &&
12192 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
12193 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12194 			return route_rule->control_unit;
12195 		}
12196 		return 0;
12197 	}
12198 
12199 	if (ifp->if_xflags & IFXF_IS_VPN &&
12200 	    route_rule->vpn_action != NECP_ROUTE_RULE_NONE) {
12201 		if (route_rule->vpn_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12202 			return route_rule->control_unit;
12203 		}
12204 		return 0;
12205 	}
12206 
12207 	// No more specific case matched, apply the default action
12208 	if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
12209 		return route_rule->control_unit;
12210 	}
12211 	return 0;
12212 }
12213 
12214 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)12215 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,
12216     u_int32_t *flow_divert_aggregate_unit)
12217 {
12218 	if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
12219 		return 0;
12220 	}
12221 
12222 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
12223 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
12224 		if (aggregate_route_rule != NULL) {
12225 			int index = 0;
12226 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
12227 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
12228 				if (sub_route_rule_id == 0) {
12229 					break;
12230 				}
12231 				uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
12232 				if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12233 					// For transparent proxies, accumulate the control unit and continue to the next route rule
12234 					*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12235 					continue;
12236 				}
12237 
12238 				if (control_unit != 0) {
12239 					return control_unit;
12240 				}
12241 			}
12242 		}
12243 	} else {
12244 		uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
12245 		if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
12246 			// For transparent proxies, accumulate the control unit and let the caller continue
12247 			*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
12248 			return 0;
12249 		}
12250 		return control_unit;
12251 	}
12252 
12253 	return 0;
12254 }
12255 
12256 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)12257 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
12258 {
12259 	bool is_allowed = true;
12260 	u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
12261 	if (route_rule_id != 0 &&
12262 	    interface != NULL) {
12263 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12264 		is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
12265 		lck_rw_done(&necp_kernel_policy_lock);
12266 	}
12267 	return is_allowed;
12268 }
12269 
12270 static bool
necp_netagents_allow_traffic(u_int32_t * __counted_by (netagent_id_count)netagent_ids,size_t netagent_id_count)12271 necp_netagents_allow_traffic(u_int32_t * __counted_by(netagent_id_count)netagent_ids, size_t netagent_id_count)
12272 {
12273 	size_t netagent_cursor;
12274 	for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
12275 		struct necp_uuid_id_mapping *mapping = NULL;
12276 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
12277 		if (netagent_id == 0) {
12278 			continue;
12279 		}
12280 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
12281 		if (mapping != NULL) {
12282 			u_int32_t agent_flags = 0;
12283 			agent_flags = netagent_get_flags(mapping->uuid);
12284 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
12285 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
12286 					continue;
12287 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
12288 					return FALSE;
12289 				}
12290 			}
12291 		}
12292 	}
12293 	return TRUE;
12294 }
12295 
12296 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)12297 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
12298 {
12299 	bool allowed_to_receive = TRUE;
12300 
12301 	if (pf_tag == PF_TAG_ID_STACK_DROP &&
12302 	    (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
12303 		allowed_to_receive = FALSE;
12304 	}
12305 
12306 	return allowed_to_receive;
12307 }
12308 
12309 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)12310 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)
12311 {
12312 	u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
12313 	bool allowed_to_receive = TRUE;
12314 	struct necp_socket_info info = {};
12315 	u_int32_t flowhash = 0;
12316 	necp_kernel_policy_result service_action = 0;
12317 	necp_kernel_policy_service service = { 0, 0 };
12318 	u_int32_t route_rule_id = 0;
12319 	struct rtentry *route = NULL;
12320 	u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
12321 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
12322 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
12323 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
12324 	proc_t __single socket_proc = NULL;
12325 	necp_kernel_policy_filter filter_control_unit = 0;
12326 	u_int32_t pass_flags = 0;
12327 	u_int32_t flow_divert_aggregate_unit = 0;
12328 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
12329 	int debug = NECP_DATA_TRACE_ON(necp_data_tracing_level);
12330 
12331 	memset(&netagent_ids, 0, sizeof(netagent_ids));
12332 
12333 	if (return_policy_id) {
12334 		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12335 	}
12336 	if (return_skip_policy_id) {
12337 		*return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12338 	}
12339 	if (return_route_rule_id) {
12340 		*return_route_rule_id = 0;
12341 	}
12342 	if (return_pass_flags) {
12343 		*return_pass_flags = 0;
12344 	}
12345 
12346 	if (inp == NULL) {
12347 		goto done;
12348 	}
12349 
12350 	route = inp->inp_route.ro_rt;
12351 
12352 	struct socket *so = inp->inp_socket;
12353 
12354 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
12355 
12356 	// Don't lock. Possible race condition, but we don't want the performance hit.
12357 	if (necp_drop_management_order == 0 &&
12358 	    (necp_kernel_socket_policies_count == 0 ||
12359 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
12360 		if (necp_drop_all_order > 0 || drop_order > 0) {
12361 			bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12362 			if (bypass_type != NECP_BYPASS_TYPE_NONE && bypass_type != NECP_BYPASS_TYPE_DROP) {
12363 				allowed_to_receive = TRUE;
12364 			} else {
12365 				allowed_to_receive = FALSE;
12366 			}
12367 		}
12368 		goto done;
12369 	}
12370 
12371 	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
12372 	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12373 		bool policies_have_changed = FALSE;
12374 		bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
12375 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
12376 			policies_have_changed = TRUE;
12377 		} else {
12378 			if (inp->inp_policyresult.results.route_rule_id != 0) {
12379 				lck_rw_lock_shared(&necp_kernel_policy_lock);
12380 				if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
12381 					route_allowed = FALSE;
12382 				}
12383 				lck_rw_done(&necp_kernel_policy_lock);
12384 			}
12385 		}
12386 
12387 		if (!policies_have_changed) {
12388 			if (debug) {
12389 				necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? true : false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
12390 				debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12391 			}
12392 
12393 			if (!route_allowed ||
12394 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12395 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12396 			    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12397 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
12398 				allowed_to_receive = FALSE;
12399 				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);
12400 			} else {
12401 				if (return_policy_id) {
12402 					*return_policy_id = inp->inp_policyresult.policy_id;
12403 				}
12404 				if (return_skip_policy_id) {
12405 					*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12406 				}
12407 				if (return_route_rule_id) {
12408 					*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12409 				}
12410 				if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12411 					pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12412 				}
12413 				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);
12414 			}
12415 			goto done;
12416 		}
12417 	}
12418 
12419 	// Check for loopback exception
12420 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
12421 	if (bypass_type == NECP_BYPASS_TYPE_DROP) {
12422 		allowed_to_receive = FALSE;
12423 		goto done;
12424 	}
12425 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
12426 		allowed_to_receive = TRUE;
12427 		goto done;
12428 	}
12429 
12430 	// Actually calculate policy result
12431 	lck_rw_lock_shared(&necp_kernel_policy_lock);
12432 	necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, 0, input_interface != NULL ? true : false, drop_order, &socket_proc, &info, (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
12433 
12434 	debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
12435 	NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
12436 
12437 	flowhash = necp_socket_calc_flowhash_locked(&info);
12438 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12439 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
12440 	    inp->inp_policyresult.flowhash == flowhash) {
12441 		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
12442 		    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12443 		    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12444 		    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
12445 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12446 		    (inp->inp_policyresult.results.route_rule_id != 0 &&
12447 		    !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
12448 			allowed_to_receive = FALSE;
12449 			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);
12450 		} else {
12451 			if (return_policy_id) {
12452 				*return_policy_id = inp->inp_policyresult.policy_id;
12453 			}
12454 			if (return_route_rule_id) {
12455 				*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12456 			}
12457 			if (return_skip_policy_id) {
12458 				*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12459 			}
12460 			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
12461 				pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
12462 			}
12463 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12464 				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",
12465 				    inp->inp_socket, info.bound_interface_index, info.protocol,
12466 				    inp->inp_policyresult.policy_id,
12467 				    inp->inp_policyresult.skip_policy_id,
12468 				    inp->inp_policyresult.results.result,
12469 				    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
12470 			}
12471 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
12472 			    return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
12473 		}
12474 		lck_rw_done(&necp_kernel_policy_lock);
12475 		goto done;
12476 	}
12477 
12478 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
12479 	size_t route_rule_id_array_count = 0;
12480 	proc_t __single effective_proc = socket_proc ? socket_proc : current_proc();
12481 	struct necp_kernel_socket_policy *matched_policy =
12482 	    necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)],
12483 	    &info,
12484 	    &filter_control_unit,
12485 	    route_rule_id_array,
12486 	    &route_rule_id_array_count,
12487 	    MAX_AGGREGATE_ROUTE_RULES,
12488 	    &service_action,
12489 	    &service,
12490 	    netagent_ids,
12491 	    NECP_MAX_NETAGENTS,
12492 	    NULL,
12493 	    0,
12494 	    NULL,
12495 	    0,
12496 	    effective_proc,
12497 	    pf_tag,
12498 	    return_skip_policy_id,
12499 	    inp->inp_route.ro_rt,
12500 	    &drop_dest_policy_result,
12501 	    &drop_all_bypass,
12502 	    &flow_divert_aggregate_unit,
12503 	    so,
12504 	    debug);
12505 
12506 	// Check for loopback exception again after the policy match
12507 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
12508 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
12509 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
12510 		// If policies haven't changed since last evaluation, do not update filter result in order to
12511 		// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12512 		// allow content filter to detect and drop pre-existing flows.
12513 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12514 		    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12515 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12516 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12517 		}
12518 		if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12519 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12520 		}
12521 		allowed_to_receive = TRUE;
12522 		lck_rw_done(&necp_kernel_policy_lock);
12523 
12524 		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);
12525 		goto done;
12526 	}
12527 
12528 	if (info.protocol != IPPROTO_UDP) {
12529 		goto skip_agent_check;
12530 	}
12531 
12532 	// Verify netagents
12533 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
12534 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
12535 			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);
12536 		}
12537 
12538 		// Mark socket as a drop if required agent is not active
12539 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12540 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12541 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12542 		inp->inp_policyresult.flowhash = flowhash;
12543 		inp->inp_policyresult.results.filter_control_unit = 0;
12544 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
12545 		inp->inp_policyresult.results.route_rule_id = 0;
12546 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
12547 
12548 		// Unlock
12549 		allowed_to_receive = FALSE;
12550 		lck_rw_done(&necp_kernel_policy_lock);
12551 
12552 		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);
12553 
12554 		goto done;
12555 	}
12556 
12557 skip_agent_check:
12558 
12559 	if (route_rule_id_array_count == 1) {
12560 		route_rule_id = route_rule_id_array[0];
12561 	} else if (route_rule_id_array_count > 1) {
12562 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
12563 	}
12564 
12565 	bool send_local_network_denied_event = false;
12566 	if (matched_policy != NULL) {
12567 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
12568 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
12569 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
12570 			// Trigger the event that we dropped due to a local network policy
12571 			send_local_network_denied_event = true;
12572 		}
12573 
12574 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
12575 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12576 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
12577 		    matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
12578 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
12579 		    (route_rule_id != 0 &&
12580 		    !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
12581 		    !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
12582 			allowed_to_receive = FALSE;
12583 		} else {
12584 			if (return_policy_id) {
12585 				*return_policy_id = matched_policy->id;
12586 			}
12587 			if (return_route_rule_id) {
12588 				*return_route_rule_id = route_rule_id;
12589 			}
12590 			if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
12591 				pass_flags = matched_policy->result_parameter.pass_flags;
12592 			}
12593 			// If policies haven't changed since last evaluation, do not update filter result in order to
12594 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12595 			// allow content filter to detect and drop pre-existing flows.
12596 			if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12597 			    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12598 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12599 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12600 			}
12601 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12602 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12603 			}
12604 		}
12605 
12606 		if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
12607 			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>",
12608 			    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);
12609 		}
12610 	} else {
12611 		bool drop_all = false;
12612 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
12613 			drop_all = true;
12614 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
12615 				drop_all_bypass = necp_check_drop_all_bypass_result(effective_proc);
12616 			}
12617 		}
12618 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
12619 			allowed_to_receive = FALSE;
12620 			NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
12621 		} else {
12622 			if (return_policy_id) {
12623 				*return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12624 			}
12625 			if (return_route_rule_id) {
12626 				*return_route_rule_id = route_rule_id;
12627 			}
12628 
12629 			// If policies haven't changed since last evaluation, do not update filter result in order to
12630 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12631 			// allow content filter to detect and drop pre-existing flows.
12632 			if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12633 			    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12634 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12635 				inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
12636 			}
12637 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12638 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12639 			}
12640 			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);
12641 		}
12642 	}
12643 
12644 	if (necp_check_restricted_multicast_drop(effective_proc, &info, true)) {
12645 		allowed_to_receive = FALSE;
12646 		NECP_DATA_TRACE_LOG_SOCKET_DP(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
12647 	}
12648 
12649 	lck_rw_done(&necp_kernel_policy_lock);
12650 
12651 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
12652 		inp->inp_policyresult.network_denied_notifies++;
12653 #if defined(XNU_TARGET_OS_OSX)
12654 		bool should_report_responsible_pid = (so->so_rpid > 0 && so->so_rpid != ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid));
12655 		necp_send_network_denied_event(should_report_responsible_pid ? so->so_rpid : ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
12656 		    should_report_responsible_pid ? so->so_ruuid : ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
12657 		    NETPOLICY_NETWORKTYPE_LOCAL);
12658 #else
12659 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
12660 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
12661 		    NETPOLICY_NETWORKTYPE_LOCAL);
12662 #endif
12663 	}
12664 
12665 done:
12666 	if (return_pass_flags != NULL) {
12667 		*return_pass_flags = pass_flags;
12668 	}
12669 
12670 	if (pf_tag != 0 && allowed_to_receive) {
12671 		allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
12672 	}
12673 
12674 	if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
12675 		soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
12676 	}
12677 
12678 	if (socket_proc) {
12679 		proc_rele(socket_proc);
12680 	}
12681 
12682 	return allowed_to_receive;
12683 }
12684 
12685 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)12686 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)
12687 {
12688 	struct sockaddr_in local = {};
12689 	struct sockaddr_in remote = {};
12690 	local.sin_family = remote.sin_family = AF_INET;
12691 	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
12692 	local.sin_port = local_port;
12693 	remote.sin_port = remote_port;
12694 	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
12695 	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
12696 
12697 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
12698 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12699 }
12700 
12701 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)12702 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)
12703 {
12704 	struct sockaddr_in6 local = {};
12705 	struct sockaddr_in6 remote = {};
12706 	local.sin6_family = remote.sin6_family = AF_INET6;
12707 	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
12708 	local.sin6_port = local_port;
12709 	remote.sin6_port = remote_port;
12710 	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
12711 	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
12712 
12713 	return necp_socket_is_allowed_to_send_recv_internal(inp, SA(&local), SA(&remote), input_interface,
12714 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12715 }
12716 
12717 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)12718 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,
12719     u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
12720 {
12721 	return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
12722 	           return_policy_id, return_route_rule_id,
12723 	           return_skip_policy_id, return_pass_flags);
12724 }
12725 
12726 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)12727 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
12728     necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
12729 {
12730 	if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
12731 		return EINVAL;
12732 	}
12733 
12734 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
12735 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "START - MARK PACKET",
12736 		    policy_id, skip_policy_id, inp->inp_policyresult.policy_id, inp->inp_policyresult.skip_policy_id);
12737 	}
12738 
12739 	// Mark ID for Pass and IP Tunnel
12740 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12741 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12742 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
12743 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
12744 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
12745 	} else if (inp->inp_policyresult.policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH &&
12746 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_NONE) {
12747 		// This case is same as a PASS
12748 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
12749 	} else {
12750 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12751 	}
12752 	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
12753 	if (route_rule_id != 0) {
12754 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
12755 	} else {
12756 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12757 	}
12758 	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);
12759 
12760 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12761 	    skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
12762 		// Only mark the skip policy if it is a valid policy ID
12763 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12764 	} else if (inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12765 	    inp->inp_policyresult.skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
12766 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = inp->inp_policyresult.skip_policy_id;
12767 	} else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
12768 		// Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
12769 		// to indicate that NECP_FILTER_UNIT_NO_FILTER was set
12770 		// See necp_get_skip_policy_id_from_packet() and
12771 		// necp_packet_should_skip_filters().
12772 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12773 	} else {
12774 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12775 	}
12776 
12777 	if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
12778 	    ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
12779 		m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
12780 	}
12781 
12782 	if (NECP_DATA_TRACE_DP_ON(necp_data_tracing_level)) {
12783 		NECP_DATA_TRACE_LOG_SOCKET_BRIEF(TRUE, inp->inp_socket, "SOCKET", "RESULT - MARK PACKET",
12784 		    packet->m_pkthdr.necp_mtag.necp_policy_id, packet->m_pkthdr.necp_mtag.necp_skip_policy_id, 0, 0);
12785 	}
12786 
12787 	return 0;
12788 }
12789 
12790 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)12791 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
12792 {
12793 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12794 		return EINVAL;
12795 	}
12796 
12797 	// Mark ID for Pass and IP Tunnel
12798 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12799 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12800 	} else {
12801 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12802 	}
12803 
12804 	return 0;
12805 }
12806 
12807 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)12808 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
12809 {
12810 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12811 		return EINVAL;
12812 	}
12813 
12814 	// Mark ID for Pass and IP Tunnel
12815 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12816 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12817 	} else {
12818 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12819 	}
12820 
12821 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12822 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12823 	} else {
12824 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12825 	}
12826 	return 0;
12827 }
12828 
12829 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)12830 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
12831 {
12832 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12833 		return EINVAL;
12834 	}
12835 
12836 	// Mark ID for Pass and IP Tunnel
12837 	if (interface != NULL) {
12838 		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
12839 	}
12840 
12841 	return 0;
12842 }
12843 
12844 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)12845 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
12846 {
12847 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12848 		return EINVAL;
12849 	}
12850 
12851 	if (is_keepalive) {
12852 		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
12853 	} else {
12854 		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
12855 	}
12856 
12857 	return 0;
12858 }
12859 
12860 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)12861 necp_get_policy_id_from_packet(struct mbuf *packet)
12862 {
12863 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12864 		return NECP_KERNEL_POLICY_ID_NONE;
12865 	}
12866 
12867 	return packet->m_pkthdr.necp_mtag.necp_policy_id;
12868 }
12869 
12870 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)12871 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
12872 {
12873 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12874 		return NECP_KERNEL_POLICY_ID_NONE;
12875 	}
12876 
12877 	// Check for overloaded value. See necp_mark_packet_from_socket().
12878 	if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
12879 		return NECP_KERNEL_POLICY_ID_NONE;
12880 	}
12881 
12882 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
12883 }
12884 
12885 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)12886 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
12887 {
12888 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12889 		return 0;
12890 	}
12891 
12892 	return m_pftag(packet)->pftag_tag;
12893 }
12894 
12895 bool
necp_packet_should_skip_filters(struct mbuf * packet)12896 necp_packet_should_skip_filters(struct mbuf *packet)
12897 {
12898 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12899 		return false;
12900 	}
12901 
12902 	// Check for overloaded value. See necp_mark_packet_from_socket().
12903 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
12904 }
12905 
12906 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)12907 necp_get_last_interface_index_from_packet(struct mbuf *packet)
12908 {
12909 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12910 		return 0;
12911 	}
12912 
12913 	return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
12914 }
12915 
12916 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)12917 necp_get_route_rule_id_from_packet(struct mbuf *packet)
12918 {
12919 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12920 		return 0;
12921 	}
12922 
12923 	return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
12924 }
12925 
12926 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)12927 necp_get_app_uuid_from_packet(struct mbuf *packet,
12928     uuid_t app_uuid)
12929 {
12930 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12931 		return EINVAL;
12932 	}
12933 
12934 	bool found_mapping = FALSE;
12935 	if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
12936 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12937 		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);
12938 		struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
12939 		if (entry != NULL) {
12940 			uuid_copy(app_uuid, entry->uuid);
12941 			found_mapping = true;
12942 		}
12943 		lck_rw_done(&necp_kernel_policy_lock);
12944 	}
12945 	if (!found_mapping) {
12946 		uuid_clear(app_uuid);
12947 	}
12948 	return 0;
12949 }
12950 
12951 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)12952 necp_get_is_keepalive_from_packet(struct mbuf *packet)
12953 {
12954 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12955 		return FALSE;
12956 	}
12957 
12958 	return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
12959 }
12960 
12961 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)12962 necp_socket_get_content_filter_control_unit(struct socket *so)
12963 {
12964 	struct inpcb *inp = sotoinpcb(so);
12965 
12966 	if (inp == NULL) {
12967 		return 0;
12968 	}
12969 	return inp->inp_policyresult.results.filter_control_unit;
12970 }
12971 
12972 u_int32_t
necp_socket_get_policy_gencount(struct socket * so)12973 necp_socket_get_policy_gencount(struct socket *so)
12974 {
12975 	struct inpcb *inp = so ? sotoinpcb(so) : NULL;
12976 
12977 	if (inp == NULL) {
12978 		return 0;
12979 	}
12980 	return inp->inp_policyresult.policy_gencount;
12981 }
12982 
12983 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)12984 necp_socket_should_use_flow_divert(struct inpcb *inp)
12985 {
12986 	if (inp == NULL) {
12987 		return FALSE;
12988 	}
12989 
12990 	return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
12991 	       (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12992 	       (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
12993 }
12994 
12995 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)12996 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
12997 {
12998 	if (inp == NULL) {
12999 		return 0;
13000 	}
13001 
13002 	if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
13003 		return 0;
13004 	}
13005 
13006 	if (aggregate_unit != NULL &&
13007 	    inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
13008 		*aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
13009 	}
13010 
13011 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
13012 		return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
13013 	}
13014 
13015 	return 0;
13016 }
13017 
13018 bool
necp_socket_should_rescope(struct inpcb * inp)13019 necp_socket_should_rescope(struct inpcb *inp)
13020 {
13021 	if (inp == NULL) {
13022 		return FALSE;
13023 	}
13024 
13025 	return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
13026 	       inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
13027 }
13028 
13029 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)13030 necp_socket_get_rescope_if_index(struct inpcb *inp)
13031 {
13032 	if (inp == NULL) {
13033 		return 0;
13034 	}
13035 
13036 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
13037 		return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
13038 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
13039 		return necp_get_primary_direct_interface_index();
13040 	}
13041 
13042 	return 0;
13043 }
13044 
13045 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)13046 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
13047 {
13048 	if (inp == NULL) {
13049 		return current_mtu;
13050 	}
13051 
13052 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
13053 	    (inp->inp_flags & INP_BOUND_IF) &&
13054 	    inp->inp_boundifp) {
13055 		u_int bound_interface_index = inp->inp_boundifp->if_index;
13056 		u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
13057 
13058 		// The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
13059 		if (bound_interface_index != tunnel_interface_index) {
13060 			ifnet_t tunnel_interface = NULL;
13061 
13062 			ifnet_head_lock_shared();
13063 			tunnel_interface = ifindex2ifnet[tunnel_interface_index];
13064 			ifnet_head_done();
13065 
13066 			if (tunnel_interface != NULL) {
13067 				u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
13068 				u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
13069 				const char ipsec_prefix[] = "ipsec";
13070 				if (delegate_tunnel_mtu != 0 &&
13071 				    strlcmp(ipsec_prefix, tunnel_interface->if_name, sizeof(ipsec_prefix)) == 0) {
13072 					// For ipsec interfaces, calculate the overhead from the delegate interface
13073 					u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
13074 					if (delegate_tunnel_mtu > tunnel_overhead) {
13075 						delegate_tunnel_mtu -= tunnel_overhead;
13076 					}
13077 
13078 					if (delegate_tunnel_mtu < direct_tunnel_mtu) {
13079 						// If the (delegate - overhead) < direct, return (delegate - overhead)
13080 						return delegate_tunnel_mtu;
13081 					} else {
13082 						// Otherwise return direct
13083 						return direct_tunnel_mtu;
13084 					}
13085 				} else {
13086 					// For non-ipsec interfaces, just return the tunnel MTU
13087 					return direct_tunnel_mtu;
13088 				}
13089 			}
13090 		}
13091 	}
13092 
13093 	// By default, just return the MTU passed in
13094 	return current_mtu;
13095 }
13096 
13097 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)13098 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
13099 {
13100 	if (result_parameter == NULL) {
13101 		return NULL;
13102 	}
13103 
13104 	return ifindex2ifnet[result_parameter->tunnel_interface_index];
13105 }
13106 
13107 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)13108 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
13109 {
13110 	bool found_match = FALSE;
13111 	bool can_rebind = FALSE;
13112 	ifaddr_t ifa;
13113 	union necp_sockaddr_union address_storage;
13114 
13115 	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
13116 		return FALSE;
13117 	}
13118 
13119 	// Match source address against interface addresses
13120 	ifnet_lock_shared(interface);
13121 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
13122 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
13123 			if (address_storage.sa.sa_family != family) {
13124 				continue;
13125 			}
13126 
13127 			if (family == AF_INET) {
13128 				struct ip *ip = mtod(packet, struct ip *);
13129 				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
13130 					found_match = TRUE;
13131 					break;
13132 				}
13133 			} else if (family == AF_INET6) {
13134 				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13135 				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
13136 					found_match = TRUE;
13137 					break;
13138 				}
13139 			}
13140 		}
13141 	}
13142 	const uint32_t if_idx = interface->if_index;
13143 	ifnet_lock_done(interface);
13144 
13145 	// If source address matched, attempt to construct a route to the destination address
13146 	if (found_match) {
13147 		ROUTE_RELEASE(new_route);
13148 
13149 		if (family == AF_INET) {
13150 			struct ip *ip = mtod(packet, struct ip *);
13151 			struct sockaddr_in *dst4 = SIN(&new_route->ro_dst);
13152 			dst4->sin_family = AF_INET;
13153 			dst4->sin_len = sizeof(struct sockaddr_in);
13154 			dst4->sin_addr = ip->ip_dst;
13155 			rtalloc_scoped(new_route, if_idx);
13156 			if (!ROUTE_UNUSABLE(new_route)) {
13157 				can_rebind = TRUE;
13158 			}
13159 		} else if (family == AF_INET6) {
13160 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13161 			struct sockaddr_in6 *dst6 = SIN6(SA(&new_route->ro_dst));
13162 			dst6->sin6_family = AF_INET6;
13163 			dst6->sin6_len = sizeof(struct sockaddr_in6);
13164 			dst6->sin6_addr = ip6->ip6_dst;
13165 			rtalloc_scoped(new_route, if_idx);
13166 			if (!ROUTE_UNUSABLE(new_route)) {
13167 				can_rebind = TRUE;
13168 			}
13169 		}
13170 	}
13171 
13172 	return can_rebind;
13173 }
13174 
13175 static bool
necp_addr_is_loopback(struct sockaddr * address)13176 necp_addr_is_loopback(struct sockaddr *address)
13177 {
13178 	if (address == NULL) {
13179 		return FALSE;
13180 	}
13181 
13182 	if (address->sa_family == AF_INET) {
13183 		return ntohl(SIN(address)->sin_addr.s_addr) == INADDR_LOOPBACK;
13184 	} else if (address->sa_family == AF_INET6) {
13185 		if (!IN6_IS_ADDR_V4MAPPED(&SIN6(address)->sin6_addr)) {
13186 			return IN6_IS_ADDR_LOOPBACK(&SIN6(address)->sin6_addr);
13187 		} else {
13188 			// Match ::ffff:127.0.0.1 loopback address
13189 			in6_addr_t *in6_addr_ptr = &(SIN6(address)->sin6_addr);
13190 			return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
13191 		}
13192 	}
13193 
13194 	return FALSE;
13195 }
13196 
13197 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)13198 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
13199 {
13200 	// Note: This function only checks for the loopback addresses.
13201 	// In the future, we may want to expand to also allow any traffic
13202 	// going through the loopback interface, but until then, this
13203 	// check is cheaper.
13204 
13205 	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
13206 		return TRUE;
13207 	}
13208 
13209 	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
13210 		return TRUE;
13211 	}
13212 
13213 	if (inp != NULL) {
13214 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
13215 			return TRUE;
13216 		}
13217 		if (inp->inp_vflag & INP_IPV4) {
13218 			if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
13219 			    ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
13220 				return TRUE;
13221 			}
13222 		} else if (inp->inp_vflag & INP_IPV6) {
13223 			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
13224 			    IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
13225 				return TRUE;
13226 			}
13227 		}
13228 	} else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
13229 		return TRUE;
13230 	}
13231 
13232 	if (packet != NULL) {
13233 		struct ip *ip = mtod(packet, struct ip *);
13234 		if (ip->ip_v == 4) {
13235 			if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
13236 				return TRUE;
13237 			}
13238 			if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
13239 				return TRUE;
13240 			}
13241 		} else if (ip->ip_v == 6) {
13242 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
13243 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
13244 				return TRUE;
13245 			}
13246 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
13247 				return TRUE;
13248 			}
13249 		}
13250 	}
13251 
13252 	return FALSE;
13253 }
13254 
13255 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)13256 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
13257 {
13258 	if (inp != NULL) {
13259 		if (!(inp->inp_vflag & INP_IPV6)) {
13260 			return false;
13261 		}
13262 		if (INP_INTCOPROC_ALLOWED(inp)) {
13263 			return true;
13264 		}
13265 		if ((inp->inp_flags & INP_BOUND_IF) &&
13266 		    IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
13267 			return true;
13268 		}
13269 		return false;
13270 	}
13271 	if (packet != NULL) {
13272 		struct ip6_hdr * __single ip6 = mtod(packet, struct ip6_hdr *);
13273 		struct in6_addr * __single addrv6 = &ip6->ip6_dst;
13274 		if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
13275 		    NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
13276 			return true;
13277 		}
13278 	}
13279 
13280 	return false;
13281 }
13282 
13283 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)13284 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
13285 {
13286 	char dest_str[MAX_IPv6_STR_LEN];
13287 
13288 	if (necp_drop_dest_debug > 0) {
13289 		if (sau->sa.sa_family == AF_INET) {
13290 			(void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
13291 		} else if (sau->sa.sa_family == AF_INET6) {
13292 			(void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
13293 		} else {
13294 			dest_str[0] = 0;
13295 		}
13296 	}
13297 	for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
13298 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13299 		struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
13300 
13301 		if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
13302 			if (necp_drop_dest_debug > 0) {
13303 				char subnet_str[MAX_IPv6_STR_LEN];
13304 				struct proc *p = current_proc();
13305 				pid_t pid = proc_pid(p);
13306 
13307 				if (sau->sa.sa_family == AF_INET) {
13308 					(void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
13309 					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);
13310 				} else if (sau->sa.sa_family == AF_INET6) {
13311 					(void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
13312 					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);
13313 				}
13314 			}
13315 			return true;
13316 		}
13317 	}
13318 	if (necp_drop_dest_debug > 1) {
13319 		struct proc *p = current_proc();
13320 		pid_t pid = proc_pid(p);
13321 
13322 		os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
13323 	}
13324 	return false;
13325 }
13326 
13327 static int
13328 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
13329 {
13330 #pragma unused(arg1, arg2, oidp)
13331 	int changed = 0;
13332 	int error = 0;
13333 	struct necp_drop_dest_policy tmp_drop_dest_policy;
13334 	struct proc *p = current_proc();
13335 	pid_t pid = proc_pid(p);
13336 
13337 	if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
13338 	    priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
13339 		NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
13340 		return EPERM;
13341 	}
13342 	if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
13343 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
13344 		return EINVAL;
13345 	}
13346 
13347 	memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
13348 	error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
13349 	if (error != 0) {
13350 		NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
13351 		return error;
13352 	}
13353 	if (changed == 0 || req->newptr == USER_ADDR_NULL) {
13354 		return error;
13355 	}
13356 
13357 	//
13358 	// Validate the passed parameters
13359 	//
13360 	if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
13361 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
13362 		return EINVAL;
13363 	}
13364 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13365 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13366 		struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
13367 
13368 		switch (tmp_drop_dest_entry->level) {
13369 		case NECP_SESSION_PRIORITY_UNKNOWN:
13370 			if (tmp_drop_dest_policy.entry_count != 0) {
13371 				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);
13372 				return EINVAL;
13373 			}
13374 			break;
13375 		case NECP_SESSION_PRIORITY_CONTROL:
13376 		case NECP_SESSION_PRIORITY_CONTROL_1:
13377 		case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
13378 		case NECP_SESSION_PRIORITY_HIGH:
13379 		case NECP_SESSION_PRIORITY_HIGH_1:
13380 		case NECP_SESSION_PRIORITY_HIGH_2:
13381 		case NECP_SESSION_PRIORITY_HIGH_3:
13382 		case NECP_SESSION_PRIORITY_HIGH_4:
13383 		case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
13384 		case NECP_SESSION_PRIORITY_DEFAULT:
13385 		case NECP_SESSION_PRIORITY_LOW:
13386 			if (tmp_drop_dest_policy.entry_count == 0) {
13387 				NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13388 				return EINVAL;
13389 			}
13390 			break;
13391 		default: {
13392 			NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
13393 			return EINVAL;
13394 		}
13395 		}
13396 
13397 		switch (npca->address.sa.sa_family) {
13398 		case AF_INET: {
13399 			if (npca->prefix > 32) {
13400 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13401 				return EINVAL;
13402 			}
13403 			if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
13404 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
13405 				return EINVAL;
13406 			}
13407 			if (npca->address.sin.sin_port != 0) {
13408 				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);
13409 				return EINVAL;
13410 			}
13411 			break;
13412 		}
13413 		case AF_INET6: {
13414 			if (npca->prefix > 128) {
13415 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
13416 				return EINVAL;
13417 			}
13418 			if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
13419 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
13420 				return EINVAL;
13421 			}
13422 			if (npca->address.sin6.sin6_port != 0) {
13423 				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);
13424 				return EINVAL;
13425 			}
13426 			if (npca->address.sin6.sin6_flowinfo != 0) {
13427 				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);
13428 				return EINVAL;
13429 			}
13430 			if (npca->address.sin6.sin6_scope_id != 0) {
13431 				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);
13432 				return EINVAL;
13433 			}
13434 			break;
13435 		}
13436 		default: {
13437 			return EINVAL;
13438 		}
13439 		}
13440 	}
13441 
13442 	//
13443 	// Commit the changed policy
13444 	//
13445 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
13446 	memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
13447 
13448 	necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
13449 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
13450 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
13451 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
13452 
13453 		memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
13454 
13455 		necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
13456 	}
13457 	lck_rw_done(&necp_kernel_policy_lock);
13458 
13459 	return 0;
13460 }
13461 
13462 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])13463 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
13464 {
13465 	uint16_t fam = address->sa.sa_family;
13466 	memset(addr_str, 0, MAX_IPv6_STR_LEN);
13467 	if (fam == AF_INET) {
13468 		(void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
13469 	} else if (fam == AF_INET6) {
13470 		(void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
13471 	}
13472 	return __unsafe_null_terminated_from_indexable(addr_str);
13473 }
13474