xref: /xnu-10063.121.3/bsd/net/necp.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1 /*
2  * Copyright (c) 2013-2022 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 && defined(XNU_TARGET_OS_OSX)
62 #include <skywalk/lib/net_filter_event.h>
63 #endif /* defined(SKYWALK) && defined(XNU_TARGET_OS_OSX) */
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 /*
81  * NECP - Network Extension Control Policy database
82  * ------------------------------------------------
83  * The goal of this module is to allow clients connecting via a
84  * policy file descriptor to create high-level policy sessions, which
85  * are ingested into low-level kernel policies that control and tag
86  * traffic at the application, socket, and IP layers.
87  *
88  * ------------------------------------------------
89  * Sessions
90  * ------------------------------------------------
91  * Each session owns a list of session policies, each of which can
92  * specify any combination of conditions and a single result. Each
93  * session also has a priority level (such as High, Default, or Low)
94  * which is requested by the client. Based on the requested level,
95  * a session order value is assigned to the session, which will be used
96  * to sort kernel policies generated by the session. The session client
97  * can specify the sub-order for each policy it creates which will be
98  * used to further sort the kernel policies.
99  *
100  *  Policy fd --> 1 necp_session --> list of necp_session_policy structs
101  *
102  * ------------------------------------------------
103  * Kernel Policies
104  * ------------------------------------------------
105  * Whenever a session send the Apply command, its policies are ingested
106  * and generate kernel policies. There are two phases of kernel policy
107  * ingestion.
108  *
109  * 1. The session policy is parsed to create kernel policies at the socket
110  *	  and IP layers, when applicable. For example, a policy that requires
111  *    all traffic from App1 to Pass will generate a socket kernel policy to
112  *    match App1 and mark packets with ID1, and also an IP policy to match
113  *    ID1 and let the packet pass. This is handled in necp_apply_policy. The
114  *    resulting kernel policies are added to the global socket and IP layer
115  *    policy lists.
116  *  necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
117  *                                      ||                             ||
118  *                                      \/                             \/
119  *                          necp_kernel_socket_policies   necp_kernel_ip_output_policies
120  *
121  * 2. Once the global lists of kernel policies have been filled out, each
122  *    list is traversed to create optimized sub-lists ("Maps") which are used during
123  *    data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
124  *    which hashes incoming packets based on marked socket-layer policies, and removes
125  *    duplicate or overlapping policies. Socket policies are sent into two maps,
126  *    necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
127  *    The app layer map is used for policy checks coming in from user space, and is one
128  *    list with duplicate and overlapping policies removed. The socket map hashes based
129  *    on app UUID, and removes duplicate and overlapping policies.
130  *  necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
131  *                            |-> necp_kernel_socket_policies_map
132  *
133  *  necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
134  *
135  * ------------------------------------------------
136  * Drop All Level
137  * ------------------------------------------------
138  * The Drop All Level is a sysctl that controls the level at which policies are allowed
139  * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
140  * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
141  * by a session with a priority level better than (numerically less than) the
142  * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
143  * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
144  * session orders to be dropped.
145  */
146 
147 u_int32_t necp_drop_all_order = 0;
148 u_int32_t necp_drop_all_level = 0;
149 
150 u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
151 u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
152 u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
153 u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
154 u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
155 
156 u_int32_t necp_drop_unentitled_order = 0;
157 #ifdef XNU_TARGET_OS_WATCH
158 u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
159 #else // XNU_TARGET_OS_WATCH
160 u_int32_t necp_drop_unentitled_level = 0;
161 #endif // XNU_TARGET_OS_WATCH
162 
163 u_int32_t necp_drop_management_order = 0;
164 u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
165 
166 u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
167 
168 os_log_t necp_log_handle = NULL;
169 os_log_t necp_data_trace_log_handle = NULL;
170 
171 u_int32_t necp_session_count = 0;
172 
173 static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
174     struct necp_session_policy, NET_KT_DEFAULT);
175 static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
176     struct necp_kernel_socket_policy, NET_KT_DEFAULT);
177 static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
178     struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
179 
180 #define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do {          \
181 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) {  \
182 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
183 	} else {                                                                                                                                                \
184 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
185 	                if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) {      \
186 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
187 	                        break;                                                                                                                          \
188 	                }                                                                                                                                               \
189 	        }                                                                                                                                                       \
190 	}                                                                                                                                                               \
191 } while (0)
192 
193 #define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do {      \
194 	if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) {                                                                                                               \
195 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
196 	} else {                                                                                                                                                \
197 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
198 	                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))) {         \
199 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
200 	                        break;                                                                                                                          \
201 	                }                                                                                                                                               \
202 	        }                                                                                                                                                       \
203 	}                                                                                                                                                               \
204 } while (0)
205 
206 #define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
207 	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))) {                                                                                                                      \
208 	        LIST_INSERT_HEAD((head), elm, field);                                                                           \
209 	} else {                                                                                                                                                \
210 	        LIST_FOREACH(tmpelm, head, field) {                                                                                     \
211 	                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)))	{ \
212 	                        LIST_INSERT_AFTER(tmpelm, elm, field);                                                          \
213 	                        break;                                                                                                                          \
214 	                }                                                                                                                                               \
215 	        }                                                                                                                                                       \
216 	}                                                                                                                                                               \
217 } while (0)
218 
219 #define IS_NECP_ROUTE_RULE_DENY(x)     ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
220 
221 #define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x)     (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
222 
223 #define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt) \
224     ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT)))
225 
226 #define NECP_KERNEL_CONDITION_ALL_INTERFACES            0x000001
227 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE           0x000002
228 #define NECP_KERNEL_CONDITION_PROTOCOL                          0x000004
229 #define NECP_KERNEL_CONDITION_LOCAL_START                       0x000008
230 #define NECP_KERNEL_CONDITION_LOCAL_END                         0x000010
231 #define NECP_KERNEL_CONDITION_LOCAL_PREFIX                      0x000020
232 #define NECP_KERNEL_CONDITION_REMOTE_START                      0x000040
233 #define NECP_KERNEL_CONDITION_REMOTE_END                        0x000080
234 #define NECP_KERNEL_CONDITION_REMOTE_PREFIX                     0x000100
235 #define NECP_KERNEL_CONDITION_APP_ID                            0x000200
236 #define NECP_KERNEL_CONDITION_REAL_APP_ID                       0x000400
237 #define NECP_KERNEL_CONDITION_DOMAIN                            0x000800
238 #define NECP_KERNEL_CONDITION_ACCOUNT_ID                        0x001000
239 #define NECP_KERNEL_CONDITION_POLICY_ID                         0x002000
240 #define NECP_KERNEL_CONDITION_PID                                       0x004000
241 #define NECP_KERNEL_CONDITION_UID                                       0x008000
242 #define NECP_KERNEL_CONDITION_LAST_INTERFACE            0x010000                        // Only set from packets looping between interfaces
243 #define NECP_KERNEL_CONDITION_TRAFFIC_CLASS                     0x020000
244 #define NECP_KERNEL_CONDITION_ENTITLEMENT                       0x040000
245 #define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT        0x080000
246 #define NECP_KERNEL_CONDITION_AGENT_TYPE                        0x100000
247 #define NECP_KERNEL_CONDITION_HAS_CLIENT                        0x200000
248 #define NECP_KERNEL_CONDITION_LOCAL_NETWORKS                    0x400000
249 #define NECP_KERNEL_CONDITION_CLIENT_FLAGS                      0x800000
250 #define NECP_KERNEL_CONDITION_LOCAL_EMPTY                       0x1000000
251 #define NECP_KERNEL_CONDITION_REMOTE_EMPTY                      0x2000000
252 #define NECP_KERNEL_CONDITION_PLATFORM_BINARY                   0x4000000
253 #define NECP_KERNEL_CONDITION_SDK_VERSION                       0x8000000
254 #define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER                0x10000000
255 #define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS                0x20000000
256 #define NECP_KERNEL_CONDITION_IS_LOOPBACK                       0x40000000
257 #define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY       0x80000000
258 #define NECP_KERNEL_CONDITION_SCHEME_PORT                       0x100000000
259 #define NECP_KERNEL_CONDITION_DOMAIN_FILTER                     0x200000000
260 #define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT              0x400000000
261 #define NECP_KERNEL_CONDITION_EXACT_DOMAIN                      0x800000000
262 #define NECP_KERNEL_CONDITION_REAL_UID                          0x1000000000
263 #define NECP_KERNEL_CONDITION_URL                               0x2000000000
264 #define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS             0x4000000000
265 
266 #define NECP_MAX_POLICY_RESULT_SIZE                                     512
267 #define NECP_MAX_ROUTE_RULES_ARRAY_SIZE                         1024
268 #define NECP_MAX_CONDITIONS_ARRAY_SIZE                          4096
269 #define NECP_MAX_POLICY_LIST_COUNT                                      1024
270 
271 #define NECP_MAX_DOMAIN_FILTER_SIZE                             65536 // Allows room for 100K domains
272 
273 typedef enum {
274 	NECP_BYPASS_TYPE_NONE = 0,
275 	NECP_BYPASS_TYPE_INTCOPROC = 1,
276 	NECP_BYPASS_TYPE_LOOPBACK = 2,
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;
345 	char *url;
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 **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 **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 **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 *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 * necp_get_result_description(char *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 *conditions_array, u_int32_t conditions_array_size, u_int8_t *route_rules_array, u_int32_t route_rules_array_size, u_int8_t *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, u_int32_t cond_account_id, char *cond_domain, u_int32_t cond_domain_filter, char *cond_url, pid_t cond_pid, int32_t cond_pidversion, 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 *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, 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, 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 **policy_search_array, struct necp_socket_info *info, necp_kernel_policy_filter *return_filter, u_int32_t *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 *return_netagent_array, u_int32_t *return_netagent_use_flags_array, size_t netagent_array_count, struct necp_client_parameter_netagent_type *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 *, int debug);
452 
453 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
454 static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
455 static bool necp_kernel_ip_output_policies_reprocess(void);
456 
457 static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
458 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);
459 static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
460 static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
461 static bool necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits);
462 static bool necp_addr_is_empty(struct sockaddr *addr);
463 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);
464 static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
465 
466 struct necp_uuid_id_mapping {
467 	LIST_ENTRY(necp_uuid_id_mapping) chain;
468 	uuid_t          uuid;
469 	u_int32_t       id;
470 	os_refcnt_t     refcount;
471 	u_int32_t       table_usecount; // Add to UUID policy table count
472 };
473 static size_t necp_num_uuid_app_id_mappings;
474 static bool necp_uuid_app_id_mappings_dirty;
475 #define NECP_UUID_APP_ID_HASH_SIZE 64
476 static u_long necp_uuid_app_id_hash_mask;
477 static u_long necp_uuid_app_id_hash_num_buckets;
478 static LIST_HEAD(necp_uuid_id_mapping_head, necp_uuid_id_mapping) * necp_uuid_app_id_hashtbl, necp_uuid_service_id_list; // App map is real hash table, service map is just mapping
479 #define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
480 static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
481 static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
482 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
483 
484 static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
485 static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
486 static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
487 static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
488 static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
489 
490 struct necp_string_id_mapping {
491 	LIST_ENTRY(necp_string_id_mapping) chain;
492 	char            *string;
493 	necp_app_id     id;
494 	os_refcnt_t     refcount;
495 };
496 static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
497 static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
498 static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
499 static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
500 
501 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);
502 static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
503 static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
504 
505 static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
506 static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
507 
508 static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
509 
510 static char *necp_create_trimmed_domain(char *string, size_t length);
511 static inline int necp_count_dots(char *string, size_t length);
512 
513 static char *necp_copy_string(char *string, size_t length);
514 static bool necp_update_qos_marking(struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
515 
516 #define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
517 
518 #define MAX_ROUTE_RULE_INTERFACES 10
519 struct necp_route_rule {
520 	LIST_ENTRY(necp_route_rule) chain;
521 	u_int32_t       id;
522 	u_int32_t       netagent_id;
523 	u_int32_t       control_unit;
524 	u_int32_t       match_netagent_id;
525 	u_int32_t       effective_type;
526 	u_int8_t        default_action;
527 	u_int8_t        cellular_action;
528 	u_int8_t        wifi_action;
529 	u_int8_t        wired_action;
530 	u_int8_t        expensive_action;
531 	u_int8_t        constrained_action;
532 	u_int8_t        companion_action;
533 	u_int           exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
534 	u_int8_t        exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
535 	os_refcnt_t     refcount;
536 };
537 static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
538 static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size, bool *has_socket_only_actions);
539 static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
540 static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
541 static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t *netagent_array, size_t netagent_array_count,
542     u_int32_t route_rule_id, u_int32_t *interface_type_denied);
543 static uint32_t necp_route_get_netagent(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove);
544 static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
545 static uint32_t necp_route_get_flow_divert(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, u_int32_t *flow_divert_aggregate_unit);
546 static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
547 static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
548 
549 #define MAX_AGGREGATE_ROUTE_RULES 16
550 struct necp_aggregate_route_rule {
551 	LIST_ENTRY(necp_aggregate_route_rule) chain;
552 	u_int32_t       id;
553 	u_int32_t       rule_ids[MAX_AGGREGATE_ROUTE_RULES];
554 };
555 static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
556 static u_int32_t necp_create_aggregate_route_rule(u_int32_t *rule_ids);
557 
558 // Sysctl definitions
559 static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
560 static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
561 static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
562 
563 SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
564 SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
565 SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
566 SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
567 SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
568 SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
569 SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
570 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", "");
571 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", "");
572 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", "");
573 SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
574 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, "");
575 SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
576 SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
577 
578 static struct necp_drop_dest_policy necp_drop_dest_policy;
579 static int necp_drop_dest_debug = 0;    // 0: off, 1: match, >1: every evaluation
580 SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
581 
582 static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
583 SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
584     0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
585 
586 static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
587 
588 /*
589  * data tracing control -
590  *
591  * necp_data_tracing_level    : 1 for brief trace, 2 for policy details, 3 for condition details
592  * necp_data_tracing_port     : match traffic with specified port
593  * necp_data_tracing_proto    : match traffic with specified protocol
594  * necp_data_tracing_pid      : match traffic with specified pid (only applied at socket level)
595  * necp_data_tracing_ifindex  : match traffic on specified ifindex
596  * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched.  Default is 0 to trace traffic if any specified attributes matched.
597  * data_tracing_session_order     : match policies in the specified session - log traffic that hit these policies
598  * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
599  */
600 static int necp_data_tracing_level = 0;
601 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
602 
603 static int necp_data_tracing_port = 0;
604 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
605 
606 static int necp_data_tracing_proto = 0;
607 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
608 
609 static int necp_data_tracing_pid = 0;
610 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
611 
612 static int necp_data_tracing_ifindex = 0;
613 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
614 
615 static int necp_data_tracing_match_all = 0;
616 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
617 
618 static int necp_data_tracing_session_order = 0;
619 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
620 
621 static int necp_data_tracing_policy_order = 0;
622 SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
623 
624 #define NECP_DATA_TRACE_LEVEL_BRIEF     1
625 #define NECP_DATA_TRACE_LEVEL_POLICY    2
626 #define NECP_DATA_TRACE_LEVEL_CONDITION 3
627 
628 #define NECP_DATA_TRACE_PID_MATCHED(pid) \
629     (pid == necp_data_tracing_pid)
630 #define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
631     (protocol == necp_data_tracing_proto)
632 #define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
633     (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
634 #define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
635     (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
636 #define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
637 	(ifindex == necp_data_tracing_ifindex)
638 
639 #define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
640     ((necp_data_tracing_level && \
641 	((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
642 	(necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
643 	(necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
644 	(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)
645 
646 #define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
647     ((necp_data_tracing_level && \
648 	((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
649 	(!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
650 	(!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
651 	(!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)
652 
653 #define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
654     (necp_data_tracing_match_all ? \
655 	NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
656 	NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
657 
658 #define NECP_DATA_TRACE_ON(debug) (debug)
659 #define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
660 #define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
661 
662 const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
663 
664 #define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
665     if (NECP_DATA_TRACE_ON(debug)) { \
666     char laddr_str[MAX_IPv6_STR_LEN]; \
667     char raddr_str[MAX_IPv6_STR_LEN]; \
668     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>", \
669 	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); \
670     }
671 
672 #define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
673     if (NECP_DATA_TRACE_ON(debug)) { \
674     char laddr_str[MAX_IPv6_STR_LEN]; \
675     char raddr_str[MAX_IPv6_STR_LEN]; \
676     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>", \
677 	    caller, (unsigned long long)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); \
678     }
679 
680 #define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
681     if (NECP_DATA_TRACE_ON(debug)) { \
682     char laddr_str[MAX_IPv6_STR_LEN]; \
683     char raddr_str[MAX_IPv6_STR_LEN]; \
684     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)", \
685 	caller, (unsigned long long)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]); \
686     }
687 
688 #define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
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> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d>", \
693 	        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)); \
694     }
695 
696 #define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
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>: %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>", \
701 	        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)); \
702     }
703 
704 #define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
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>: %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)", \
709 	    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]); \
710     }
711 
712 #define NECP_DATA_TRACE_LOG_POLICY(debug, caller, log_msg) \
713     if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
714     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)", \
715 	        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); \
716     }
717 
718 #define NECP_DATA_TRACE_LOG_CONDITION3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
719     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
720     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)>", \
721 	        caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
722     }
723 
724 #define NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
725     if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
726     NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
727 	    caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
728 	    input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
729     }
730 
731 #define NECP_DATA_TRACE_LOG_CONDITION(debug, caller, negate, name, val, input) \
732     NECP_DATA_TRACE_LOG_CONDITION3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
733 
734 #define NECP_DATA_TRACE_LOG_CONDITION_STR(debug, caller, negate, name, val, input) \
735     NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
736 
737 #define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
738     (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
739      addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
740 
741 const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
742 	"INVALID",
743 	"PASS",
744 	"SKIP",
745 	"DROP",
746 	"SOCKET_DIVERT",
747 	"SOCKET_FILTER",
748 	"IP_TUNNEL",
749 	"IP_FILTER",
750 	"TRIGGER",
751 	"TRIGGER_IF_NEEDED",
752 	"TRIGGER_SCOPED",
753 	"NO_TRIGGER_SCOPED",
754 	"SOCKET_SCOPED",
755 	"ROUTE_RULES",
756 	"USE_NETAGENT",
757 	"NETAGENT_SCOPED",
758 	"SCOPED_DIRECT",
759 	"ALLOW_UNENTITLED",
760 	"REMOVE_NETAGENT"
761 };
762 
763 // Session order allocation
764 static u_int32_t
necp_allocate_new_session_order(u_int32_t priority,u_int32_t control_unit)765 necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
766 {
767 	u_int32_t new_order = 0;
768 
769 	// For now, just allocate 1000 orders for each priority
770 	if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
771 		priority = NECP_SESSION_PRIORITY_DEFAULT;
772 	}
773 
774 	// Use the control unit to decide the offset into the priority list
775 	new_order = (control_unit) + ((priority - 1) * 1000);
776 
777 	return new_order;
778 }
779 
780 static inline u_int32_t
necp_get_first_order_for_priority(u_int32_t priority)781 necp_get_first_order_for_priority(u_int32_t priority)
782 {
783 	if (priority == 0) {
784 		return 0;
785 	}
786 	return ((priority - 1) * 1000) + 1;
787 }
788 
789 // Sysctl handler
790 static int
791 sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
792 {
793 #pragma unused(arg1, arg2)
794 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
795 	necp_drop_all_order = necp_get_first_order_for_priority(necp_drop_all_level);
796 	return error;
797 }
798 
799 static int
800 sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
801 {
802 #pragma unused(arg1, arg2)
803 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
804 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
805 	return error;
806 }
807 
808 // Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
809 static inline u_int32_t
_necp_process_drop_order_inner(kauth_cred_t cred)810 _necp_process_drop_order_inner(kauth_cred_t cred)
811 {
812 	if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, 0) != 0 &&
813 	    priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, 0) != 0) {
814 		return necp_drop_unentitled_order;
815 	} else {
816 		return 0;
817 	}
818 }
819 
820 #define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
821 #pragma GCC poison _necp_process_drop_order_inner
822 
823 static int
824 sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
825 {
826 #pragma unused(arg1, arg2)
827 	int error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
828 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
829 	return error;
830 }
831 
832 // Session fd
833 
834 static int necp_session_op_close(struct fileglob *, vfs_context_t);
835 
836 static const struct fileops necp_session_fd_ops = {
837 	.fo_type     = DTYPE_NETPOLICY,
838 	.fo_read     = fo_no_read,
839 	.fo_write    = fo_no_write,
840 	.fo_ioctl    = fo_no_ioctl,
841 	.fo_select   = fo_no_select,
842 	.fo_close    = necp_session_op_close,
843 	.fo_drain    = fo_no_drain,
844 	.fo_kqfilter = fo_no_kqfilter,
845 };
846 
847 static inline int
necp_is_platform_binary(proc_t proc)848 necp_is_platform_binary(proc_t proc)
849 {
850 	return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
851 }
852 
853 static inline necp_drop_all_bypass_check_result_t
necp_check_drop_all_bypass_result(proc_t proc)854 necp_check_drop_all_bypass_result(proc_t proc)
855 {
856 	if (proc == NULL) {
857 		proc = current_proc();
858 		if (proc == NULL) {
859 			return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
860 		}
861 	}
862 
863 #if defined(XNU_TARGET_OS_OSX)
864 	const char *signing_id = NULL;
865 	const bool isConfigd = (necp_is_platform_binary(proc) &&
866 	    (signing_id = cs_identity_get(proc)) &&
867 	    (strlen(signing_id) == SIGNING_ID_CONFIGD_LEN) &&
868 	    (memcmp(signing_id, SIGNING_ID_CONFIGD, SIGNING_ID_CONFIGD_LEN) == 0));
869 	if (isConfigd) {
870 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
871 	}
872 #endif
873 
874 	const task_t task = proc_task(proc);
875 	if (task == NULL || !IOTaskHasEntitlement(task, "com.apple.private.necp.drop_all_bypass")) {
876 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
877 	} else {
878 		return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
879 	}
880 }
881 
882 int
necp_session_open(struct proc * p,struct necp_session_open_args * uap,int * retval)883 necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
884 {
885 #pragma unused(uap)
886 	int error = 0;
887 	struct necp_session *session = NULL;
888 	struct fileproc *fp = NULL;
889 	int fd = -1;
890 	uid_t uid = kauth_cred_getuid(kauth_cred_get());
891 
892 	if (!necp_is_platform_binary(p)) {
893 		NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
894 		error = EACCES;
895 		goto done;
896 	}
897 
898 	if (uid != 0 && priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
899 		NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
900 		error = EACCES;
901 		goto done;
902 	}
903 
904 	error = falloc(p, &fp, &fd);
905 	if (error != 0) {
906 		goto done;
907 	}
908 
909 	session = necp_create_session();
910 	if (session == NULL) {
911 		error = ENOMEM;
912 		goto done;
913 	}
914 
915 	fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
916 	fp->fp_glob->fg_flag = 0;
917 	fp->fp_glob->fg_ops = &necp_session_fd_ops;
918 	fp_set_data(fp, session);
919 
920 	proc_fdlock(p);
921 	procfdtbl_releasefd(p, fd, NULL);
922 	fp_drop(p, fd, fp, 1);
923 	proc_fdunlock(p);
924 
925 	*retval = fd;
926 done:
927 	if (error != 0) {
928 		if (fp != NULL) {
929 			fp_free(p, fd, fp);
930 			fp = NULL;
931 		}
932 	}
933 
934 	return error;
935 }
936 
937 static int
necp_session_op_close(struct fileglob * fg,vfs_context_t ctx)938 necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
939 {
940 #pragma unused(ctx)
941 	struct necp_session *session = (struct necp_session *)fg_get_data(fg);
942 	fg_set_data(fg, NULL);
943 
944 	if (session != NULL) {
945 		necp_policy_mark_all_for_deletion(session);
946 		necp_policy_apply_all(session);
947 		necp_delete_session(session);
948 		return 0;
949 	} else {
950 		return ENOENT;
951 	}
952 }
953 
954 static int
necp_session_find_from_fd(struct proc * p,int fd,struct fileproc ** fpp,struct necp_session ** session)955 necp_session_find_from_fd(struct proc *p, int fd,
956     struct fileproc **fpp, struct necp_session **session)
957 {
958 	struct fileproc *fp = NULL;
959 	int error = fp_get_ftype(p, fd, DTYPE_NETPOLICY, ENODEV, &fp);
960 
961 	if (error == 0) {
962 		*fpp = fp;
963 		*session = (struct necp_session *)fp_get_data(fp);
964 		if ((*session)->necp_fd_type != necp_fd_type_session) {
965 			// Not a client fd, ignore
966 			fp_drop(p, fd, fp, 0);
967 			error = EINVAL;
968 		}
969 	}
970 
971 	return error;
972 }
973 
974 static int
necp_session_add_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)975 necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
976 {
977 	int error = 0;
978 	u_int8_t *tlv_buffer = NULL;
979 
980 	if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
981 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
982 		error = EINVAL;
983 		goto done;
984 	}
985 
986 	if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
987 		NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
988 		error = EINVAL;
989 		goto done;
990 	}
991 
992 	if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
993 		error = ENOMEM;
994 		goto done;
995 	}
996 
997 	error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
998 	if (error != 0) {
999 		NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1000 		goto done;
1001 	}
1002 
1003 	necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, uap->in_buffer_length, 0, &error);
1004 	if (error != 0) {
1005 		NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1006 		goto done;
1007 	}
1008 
1009 	error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1010 	if (error != 0) {
1011 		NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1012 		goto done;
1013 	}
1014 
1015 done:
1016 	if (tlv_buffer != NULL) {
1017 		kfree_data(tlv_buffer, uap->in_buffer_length);
1018 		tlv_buffer = NULL;
1019 	}
1020 	*retval = error;
1021 
1022 	return error;
1023 }
1024 
1025 static int
necp_session_get_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1026 necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1027 {
1028 	int error = 0;
1029 	u_int8_t *response = NULL;
1030 
1031 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1032 		NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1033 		error = EINVAL;
1034 		goto done;
1035 	}
1036 
1037 	necp_policy_id policy_id = 0;
1038 	error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1039 	if (error != 0) {
1040 		NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1041 		goto done;
1042 	}
1043 
1044 	struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1045 	if (policy == NULL || policy->pending_deletion) {
1046 		NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1047 		error = ENOENT;
1048 		goto done;
1049 	}
1050 
1051 	u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1052 	u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1053 	u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1054 
1055 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1056 		NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1057 		error = EINVAL;
1058 		goto done;
1059 	}
1060 
1061 	if (response_size > NECP_MAX_POLICY_SIZE) {
1062 		NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1063 		error = EINVAL;
1064 		goto done;
1065 	}
1066 
1067 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1068 	if (response == NULL) {
1069 		error = ENOMEM;
1070 		goto done;
1071 	}
1072 
1073 	u_int8_t *cursor = response;
1074 	cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, response, response_size);
1075 	if (result_tlv_size) {
1076 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, policy->result_size, &policy->result, response, response_size);
1077 	}
1078 	if (policy->conditions_size) {
1079 		memcpy(((u_int8_t *)(void *)(cursor)), policy->conditions, policy->conditions_size);
1080 	}
1081 
1082 	error = copyout(response, uap->out_buffer, response_size);
1083 	if (error != 0) {
1084 		NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1085 		goto done;
1086 	}
1087 
1088 done:
1089 	if (response != NULL) {
1090 		kfree_data(response, response_size);
1091 		response = NULL;
1092 	}
1093 	*retval = error;
1094 
1095 	return error;
1096 }
1097 
1098 static int
necp_session_delete_policy(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1099 necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1100 {
1101 	int error = 0;
1102 
1103 	if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1104 		NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1105 		error = EINVAL;
1106 		goto done;
1107 	}
1108 
1109 	necp_policy_id delete_policy_id = 0;
1110 	error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1111 	if (error != 0) {
1112 		NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1113 		goto done;
1114 	}
1115 
1116 	struct necp_session_policy *policy = necp_policy_find(session, delete_policy_id);
1117 	if (policy == NULL || policy->pending_deletion) {
1118 		NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1119 		error = ENOENT;
1120 		goto done;
1121 	}
1122 
1123 	necp_policy_mark_for_deletion(session, policy);
1124 done:
1125 	*retval = error;
1126 	return error;
1127 }
1128 
1129 static int
necp_session_apply_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1130 necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1131 {
1132 #pragma unused(uap)
1133 	necp_policy_apply_all(session);
1134 	*retval = 0;
1135 	return 0;
1136 }
1137 
1138 static int
necp_session_list_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1139 necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1140 {
1141 	u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1142 	u_int32_t response_size = 0;
1143 	u_int8_t *response = NULL;
1144 	int num_policies = 0;
1145 	int cur_policy_index = 0;
1146 	int error = 0;
1147 	struct necp_session_policy *policy;
1148 
1149 	LIST_FOREACH(policy, &session->policies, chain) {
1150 		if (!policy->pending_deletion) {
1151 			num_policies++;
1152 		}
1153 	}
1154 
1155 	if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1156 		NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1157 		error = EINVAL;
1158 		goto done;
1159 	}
1160 
1161 	response_size = num_policies * tlv_size;
1162 	if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1163 		NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1164 		error = EINVAL;
1165 		goto done;
1166 	}
1167 
1168 	// Create a response with one Policy ID TLV for each policy
1169 	response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1170 	if (response == NULL) {
1171 		error = ENOMEM;
1172 		goto done;
1173 	}
1174 
1175 	u_int8_t *cursor = response;
1176 	LIST_FOREACH(policy, &session->policies, chain) {
1177 		if (!policy->pending_deletion && cur_policy_index < num_policies) {
1178 			cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(u_int32_t), &policy->local_id, response, response_size);
1179 			cur_policy_index++;
1180 		}
1181 	}
1182 
1183 	error = copyout(response, uap->out_buffer, response_size);
1184 	if (error != 0) {
1185 		NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1186 		goto done;
1187 	}
1188 
1189 done:
1190 	if (response != NULL) {
1191 		kfree_data(response, response_size);
1192 		response = NULL;
1193 	}
1194 	*retval = error;
1195 
1196 	return error;
1197 }
1198 
1199 
1200 static int
necp_session_delete_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1201 necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1202 {
1203 #pragma unused(uap)
1204 	necp_policy_mark_all_for_deletion(session);
1205 	*retval = 0;
1206 	return 0;
1207 }
1208 
1209 static int
necp_session_set_session_priority(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1210 necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1211 {
1212 	int error = 0;
1213 	struct necp_session_policy *policy = NULL;
1214 	struct necp_session_policy *temp_policy = NULL;
1215 
1216 	if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1217 		NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1218 		error = EINVAL;
1219 		goto done;
1220 	}
1221 
1222 	necp_session_priority requested_session_priority = 0;
1223 	error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1224 	if (error != 0) {
1225 		NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1226 		goto done;
1227 	}
1228 
1229 	// Enforce special session priorities with entitlements
1230 	if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1231 	    requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1232 	    requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1233 	    requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1234 		errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
1235 		if (cred_result != 0) {
1236 			NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1237 			error = EPERM;
1238 			goto done;
1239 		}
1240 	}
1241 
1242 	if (session->session_priority != requested_session_priority) {
1243 		session->session_priority = requested_session_priority;
1244 		session->session_order = necp_allocate_new_session_order(session->session_priority, session->control_unit);
1245 		session->dirty = TRUE;
1246 
1247 		// Mark all policies as needing updates
1248 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1249 			policy->pending_update = TRUE;
1250 		}
1251 	}
1252 
1253 done:
1254 	*retval = error;
1255 	return error;
1256 }
1257 
1258 static int
necp_session_lock_to_process(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1259 necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1260 {
1261 #pragma unused(uap)
1262 	session->proc_locked = TRUE;
1263 	*retval = 0;
1264 	return 0;
1265 }
1266 
1267 static int
necp_session_register_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1268 necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1269 {
1270 	int error = 0;
1271 	struct necp_service_registration *new_service = NULL;
1272 
1273 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1274 		NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1275 		error = EINVAL;
1276 		goto done;
1277 	}
1278 
1279 	uuid_t service_uuid;
1280 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1281 	if (error != 0) {
1282 		NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1283 		goto done;
1284 	}
1285 
1286 	new_service = kalloc_type(struct necp_service_registration,
1287 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
1288 
1289 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1290 	new_service->service_id = necp_create_uuid_service_id_mapping(service_uuid);
1291 	LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1292 	LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1293 	lck_rw_done(&necp_kernel_policy_lock);
1294 
1295 done:
1296 	*retval = error;
1297 	return error;
1298 }
1299 
1300 static int
necp_session_unregister_service(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1301 necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1302 {
1303 	int error = 0;
1304 	struct necp_service_registration *service = NULL;
1305 	struct necp_service_registration *temp_service = NULL;
1306 	struct necp_uuid_id_mapping *mapping = NULL;
1307 
1308 	if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1309 		NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1310 		error = EINVAL;
1311 		goto done;
1312 	}
1313 
1314 	uuid_t service_uuid;
1315 	error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1316 	if (error != 0) {
1317 		NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1318 		goto done;
1319 	}
1320 
1321 	// Remove all matching services for this session
1322 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1323 	mapping = necp_uuid_lookup_service_id_locked(service_uuid);
1324 	if (mapping != NULL) {
1325 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1326 			if (service->service_id == mapping->id) {
1327 				LIST_REMOVE(service, session_chain);
1328 				LIST_REMOVE(service, kernel_chain);
1329 				kfree_type(struct necp_service_registration, service);
1330 			}
1331 		}
1332 		necp_remove_uuid_service_id_mapping(service_uuid);
1333 	}
1334 	lck_rw_done(&necp_kernel_policy_lock);
1335 
1336 done:
1337 	*retval = error;
1338 	return error;
1339 }
1340 
1341 static int
necp_session_dump_all(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1342 necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1343 {
1344 #pragma unused(session)
1345 	int error = 0;
1346 
1347 	if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1348 		NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1349 		error = EINVAL;
1350 		goto done;
1351 	}
1352 
1353 	error = necp_handle_policy_dump_all(uap->out_buffer, uap->out_buffer_length);
1354 done:
1355 	*retval = error;
1356 	return error;
1357 }
1358 
1359 static int
necp_session_add_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1360 necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1361 {
1362 	int error = 0;
1363 	struct net_bloom_filter *bloom_filter = NULL;
1364 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1365 	const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1366 
1367 	if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1368 	    in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1369 	    uap->in_buffer == 0) {
1370 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1371 		error = EINVAL;
1372 		goto done;
1373 	}
1374 
1375 	if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1376 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1377 		error = EINVAL;
1378 		goto done;
1379 	}
1380 
1381 	bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1382 	if (bloom_filter == NULL) {
1383 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1384 		error = ENOMEM;
1385 		goto done;
1386 	}
1387 
1388 	error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1389 	if (error != 0) {
1390 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1391 		goto done;
1392 	}
1393 
1394 	size_t expected_filter_size = net_bloom_filter_get_size(bloom_filter->b_table_num_bits);
1395 	if (expected_filter_size != in_buffer_length) {
1396 		NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1397 		error = EINVAL;
1398 		goto done;
1399 	}
1400 
1401 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1402 	u_int32_t filter_id = necp_create_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, bloom_filter);
1403 	lck_rw_done(&necp_kernel_policy_lock);
1404 
1405 	if (filter_id == 0) {
1406 		error = ENOMEM;
1407 	} else {
1408 		// Bloom filter is taken over by the new filter entry, clear the local pointer
1409 		bloom_filter = NULL;
1410 
1411 		error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1412 		if (error != 0) {
1413 			NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1414 			goto done;
1415 		}
1416 	}
1417 
1418 done:
1419 	*retval = error;
1420 	if (error != 0 && bloom_filter != NULL) {
1421 		uint8_t *filter_buffer = (uint8_t *)bloom_filter;
1422 		kfree_data(filter_buffer, in_buffer_length);
1423 		bloom_filter = NULL;
1424 	}
1425 	return error;
1426 }
1427 
1428 static int
necp_session_remove_domain_filter(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1429 necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1430 {
1431 	int error = 0;
1432 
1433 	const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1434 	if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1435 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1436 		error = EINVAL;
1437 		goto done;
1438 	}
1439 
1440 	u_int32_t filter_id;
1441 	error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1442 	if (error != 0) {
1443 		NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1444 		goto done;
1445 	}
1446 
1447 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1448 	bool removed = necp_remove_domain_filter(&necp_global_domain_filter_list, &session->domain_filters, filter_id);
1449 	if (!removed) {
1450 		error = ENOENT;
1451 	}
1452 	lck_rw_done(&necp_kernel_policy_lock);
1453 
1454 done:
1455 	*retval = error;
1456 	return error;
1457 }
1458 
1459 static int
necp_session_remove_all_domain_filters(struct necp_session * session,struct necp_session_action_args * uap,int * retval)1460 necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1461 {
1462 #pragma unused(uap)
1463 
1464 	struct necp_domain_filter *filter = NULL;
1465 	struct necp_domain_filter *temp_filter = NULL;
1466 	LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1467 		if (os_ref_release_locked(&filter->refcount) == 0) {
1468 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
1469 			LIST_REMOVE(filter, chain);
1470 			lck_rw_done(&necp_kernel_policy_lock);
1471 			LIST_REMOVE(filter, owner_chain);
1472 			net_bloom_filter_destroy(filter->filter);
1473 			kfree_type(struct necp_domain_filter, filter);
1474 		}
1475 	}
1476 
1477 	*retval = 0;
1478 	return 0;
1479 }
1480 
1481 int
necp_session_action(struct proc * p,struct necp_session_action_args * uap,int * retval)1482 necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1483 {
1484 	struct fileproc *fp;
1485 	int error = 0;
1486 	int return_value = 0;
1487 	struct necp_session *session = NULL;
1488 
1489 	error = necp_session_find_from_fd(p, uap->necp_fd, &fp, &session);
1490 	if (error != 0) {
1491 		NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1492 		return error;
1493 	}
1494 
1495 	NECP_SESSION_LOCK(session);
1496 
1497 	if (session->proc_locked) {
1498 		// Verify that the calling process is allowed to do actions
1499 		uuid_t proc_uuid;
1500 		proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1501 		if (uuid_compare(proc_uuid, session->proc_uuid) != 0) {
1502 			error = EPERM;
1503 			goto done;
1504 		}
1505 	} else {
1506 		// If not locked, update the proc_uuid and proc_pid of the session
1507 		proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1508 		session->proc_pid = proc_pid(current_proc());
1509 	}
1510 
1511 	u_int32_t action = uap->action;
1512 	switch (action) {
1513 	case NECP_SESSION_ACTION_POLICY_ADD: {
1514 		return_value = necp_session_add_policy(session, uap, retval);
1515 		break;
1516 	}
1517 	case NECP_SESSION_ACTION_POLICY_GET: {
1518 		return_value = necp_session_get_policy(session, uap, retval);
1519 		break;
1520 	}
1521 	case NECP_SESSION_ACTION_POLICY_DELETE:  {
1522 		return_value = necp_session_delete_policy(session, uap, retval);
1523 		break;
1524 	}
1525 	case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1526 		return_value = necp_session_apply_all(session, uap, retval);
1527 		break;
1528 	}
1529 	case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1530 		return_value = necp_session_list_all(session, uap, retval);
1531 		break;
1532 	}
1533 	case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1534 		return_value = necp_session_delete_all(session, uap, retval);
1535 		break;
1536 	}
1537 	case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1538 		return_value = necp_session_set_session_priority(session, uap, retval);
1539 		break;
1540 	}
1541 	case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1542 		return_value = necp_session_lock_to_process(session, uap, retval);
1543 		break;
1544 	}
1545 	case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1546 		return_value = necp_session_register_service(session, uap, retval);
1547 		break;
1548 	}
1549 	case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1550 		return_value = necp_session_unregister_service(session, uap, retval);
1551 		break;
1552 	}
1553 	case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1554 		return_value = necp_session_dump_all(session, uap, retval);
1555 		break;
1556 	}
1557 	case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1558 		return_value = necp_session_add_domain_filter(session, uap, retval);
1559 		break;
1560 	}
1561 	case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1562 		return_value = necp_session_remove_domain_filter(session, uap, retval);
1563 		break;
1564 	}
1565 	case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1566 		return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1567 		break;
1568 	}
1569 	default: {
1570 		NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1571 		return_value = EINVAL;
1572 		break;
1573 	}
1574 	}
1575 
1576 done:
1577 	NECP_SESSION_UNLOCK(session);
1578 	fp_drop(p, uap->necp_fd, fp, 0);
1579 	return return_value;
1580 }
1581 
1582 struct necp_resolver_key_state {
1583 	const struct ccdigest_info *digest_info;
1584 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1585 };
1586 static struct necp_resolver_key_state s_necp_resolver_key_state;
1587 
1588 static void
necp_generate_resolver_key(void)1589 necp_generate_resolver_key(void)
1590 {
1591 	s_necp_resolver_key_state.digest_info = ccsha256_di();
1592 	cc_rand_generate(s_necp_resolver_key_state.key, sizeof(s_necp_resolver_key_state.key));
1593 }
1594 
1595 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)1596 necp_sign_update_context(const struct ccdigest_info *di,
1597     cchmac_ctx_t ctx,
1598     uuid_t client_id,
1599     u_int32_t sign_type,
1600     u_int8_t *data,
1601     size_t data_length)
1602 {
1603 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1604 	const char *context_string = "NECP Resolver Binder";
1605 	uint8_t separator = 0;
1606 	cchmac_update(di, ctx, sizeof(context), context);
1607 	cchmac_update(di, ctx, strlen(context_string), context_string);
1608 	cchmac_update(di, ctx, sizeof(separator), &separator);
1609 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1610 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1611 	cchmac_update(di, ctx, data_length, data);
1612 }
1613 
1614 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)1615 necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1616     u_int8_t *data, size_t data_length,
1617     u_int8_t *tag, size_t *out_tag_length)
1618 {
1619 	if (s_necp_resolver_key_state.digest_info == NULL) {
1620 		return EINVAL;
1621 	}
1622 
1623 	if (data == NULL ||
1624 	    data_length == 0 ||
1625 	    tag == NULL ||
1626 	    out_tag_length == NULL) {
1627 		return EINVAL;
1628 	}
1629 
1630 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1631 	if (*out_tag_length < required_tag_length) {
1632 		return ERANGE;
1633 	}
1634 
1635 	*out_tag_length = required_tag_length;
1636 
1637 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1638 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1639 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1640 	    sizeof(s_necp_resolver_key_state.key),
1641 	    s_necp_resolver_key_state.key);
1642 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1643 	    ctx, client_id, sign_type, data, data_length);
1644 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, tag);
1645 
1646 	return 0;
1647 }
1648 
1649 bool
necp_validate_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 tag_length)1650 necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1651     u_int8_t *data, size_t data_length,
1652     u_int8_t *tag, size_t tag_length)
1653 {
1654 	if (s_necp_resolver_key_state.digest_info == NULL) {
1655 		return false;
1656 	}
1657 
1658 	if (data == NULL ||
1659 	    data_length == 0 ||
1660 	    tag == NULL ||
1661 	    tag_length == 0) {
1662 		return false;
1663 	}
1664 
1665 	size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1666 	if (tag_length != required_tag_length) {
1667 		return false;
1668 	}
1669 
1670 	uint8_t actual_tag[required_tag_length];
1671 
1672 	cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1673 	    s_necp_resolver_key_state.digest_info->block_size, ctx);
1674 	cchmac_init(s_necp_resolver_key_state.digest_info, ctx,
1675 	    sizeof(s_necp_resolver_key_state.key),
1676 	    s_necp_resolver_key_state.key);
1677 	necp_sign_update_context(s_necp_resolver_key_state.digest_info,
1678 	    ctx, client_id, sign_type, data, data_length);
1679 	cchmac_final(s_necp_resolver_key_state.digest_info, ctx, actual_tag);
1680 
1681 	return cc_cmp_safe(s_necp_resolver_key_state.digest_info->output_size, tag, actual_tag) == 0;
1682 }
1683 
1684 struct necp_application_id_key_state {
1685 	const struct ccdigest_info *digest_info;
1686 	uint8_t key[CCSHA256_OUTPUT_SIZE];
1687 };
1688 static struct necp_application_id_key_state s_necp_application_id_key_state;
1689 
1690 static void
necp_generate_application_id_key(void)1691 necp_generate_application_id_key(void)
1692 {
1693 	s_necp_application_id_key_state.digest_info = ccsha256_di();
1694 	cc_rand_generate(s_necp_application_id_key_state.key, sizeof(s_necp_application_id_key_state.key));
1695 }
1696 
1697 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)1698 necp_sign_application_id_update_context(const struct ccdigest_info *di,
1699     cchmac_ctx_t ctx,
1700     uuid_t client_id,
1701     u_int32_t sign_type)
1702 {
1703 	const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1704 	const char *context_string = "NECP Application ID";
1705 	uint8_t separator = 0;
1706 	cchmac_update(di, ctx, sizeof(context), context);
1707 	cchmac_update(di, ctx, strlen(context_string), context_string);
1708 	cchmac_update(di, ctx, sizeof(separator), &separator);
1709 	cchmac_update(di, ctx, sizeof(uuid_t), client_id);
1710 	cchmac_update(di, ctx, sizeof(sign_type), &sign_type);
1711 }
1712 
1713 int
necp_sign_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * tag,size_t * out_tag_length)1714 necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
1715     u_int8_t *tag, size_t *out_tag_length)
1716 {
1717 	if (s_necp_application_id_key_state.digest_info == NULL) {
1718 		return EINVAL;
1719 	}
1720 
1721 	if (tag == NULL ||
1722 	    out_tag_length == NULL) {
1723 		return EINVAL;
1724 	}
1725 
1726 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1727 	if (*out_tag_length < required_tag_length) {
1728 		return ERANGE;
1729 	}
1730 
1731 	*out_tag_length = required_tag_length;
1732 
1733 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1734 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
1735 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1736 	    sizeof(s_necp_application_id_key_state.key),
1737 	    s_necp_application_id_key_state.key);
1738 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1739 	    ctx, client_id, sign_type);
1740 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, tag);
1741 
1742 	return 0;
1743 }
1744 
1745 bool
necp_validate_application_id(uuid_t client_id,u_int32_t sign_type,u_int8_t * tag,size_t tag_length)1746 necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
1747     u_int8_t *tag, size_t tag_length)
1748 {
1749 	if (s_necp_application_id_key_state.digest_info == NULL) {
1750 		return false;
1751 	}
1752 
1753 	if (tag == NULL ||
1754 	    tag_length == 0) {
1755 		return false;
1756 	}
1757 
1758 	size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1759 	if (tag_length != required_tag_length) {
1760 		return false;
1761 	}
1762 
1763 	uint8_t actual_tag[required_tag_length];
1764 
1765 	cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1766 	    s_necp_application_id_key_state.digest_info->block_size, ctx);
1767 	cchmac_init(s_necp_application_id_key_state.digest_info, ctx,
1768 	    sizeof(s_necp_application_id_key_state.key),
1769 	    s_necp_application_id_key_state.key);
1770 	necp_sign_application_id_update_context(s_necp_application_id_key_state.digest_info,
1771 	    ctx, client_id, sign_type);
1772 	cchmac_final(s_necp_application_id_key_state.digest_info, ctx, actual_tag);
1773 
1774 	return cc_cmp_safe(s_necp_application_id_key_state.digest_info->output_size, tag, actual_tag) == 0;
1775 }
1776 
1777 void
necp_init(void)1778 necp_init(void)
1779 {
1780 	necp_log_handle = os_log_create("com.apple.xnu.net.necp", "necp");
1781 	necp_data_trace_log_handle = os_log_create("com.apple.xnu.net.necp", "necp-data-trace");
1782 
1783 	necp_client_init();
1784 
1785 	TAILQ_INIT(&necp_session_list);
1786 
1787 	LIST_INIT(&necp_kernel_socket_policies);
1788 	LIST_INIT(&necp_kernel_ip_output_policies);
1789 
1790 	LIST_INIT(&necp_account_id_list);
1791 
1792 	LIST_INIT(&necp_uuid_service_id_list);
1793 
1794 	LIST_INIT(&necp_registered_service_list);
1795 
1796 	LIST_INIT(&necp_route_rules);
1797 	LIST_INIT(&necp_aggregate_route_rules);
1798 
1799 	LIST_INIT(&necp_global_domain_filter_list);
1800 
1801 	necp_generate_resolver_key();
1802 	necp_generate_application_id_key();
1803 
1804 	necp_uuid_app_id_hashtbl = hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, &necp_uuid_app_id_hash_mask);
1805 	necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
1806 	necp_num_uuid_app_id_mappings = 0;
1807 	necp_uuid_app_id_mappings_dirty = FALSE;
1808 
1809 	necp_kernel_application_policies_condition_mask = 0;
1810 	necp_kernel_socket_policies_condition_mask = 0;
1811 	necp_kernel_ip_output_policies_condition_mask = 0;
1812 
1813 	necp_kernel_application_policies_count = 0;
1814 	necp_kernel_socket_policies_count = 0;
1815 	necp_kernel_socket_policies_non_app_count = 0;
1816 	necp_kernel_ip_output_policies_count = 0;
1817 	necp_kernel_ip_output_policies_non_id_count = 0;
1818 
1819 	necp_kernel_socket_policies_gencount = 1;
1820 
1821 	memset(&necp_kernel_socket_policies_map, 0, sizeof(necp_kernel_socket_policies_map));
1822 	memset(&necp_kernel_ip_output_policies_map, 0, sizeof(necp_kernel_ip_output_policies_map));
1823 	necp_kernel_socket_policies_app_layer_map = NULL;
1824 
1825 	necp_drop_unentitled_order = necp_get_first_order_for_priority(necp_drop_unentitled_level);
1826 	necp_drop_management_order = necp_get_first_order_for_priority(necp_drop_management_level);
1827 }
1828 
1829 static void
necp_post_change_event(struct kev_necp_policies_changed_data * necp_event_data)1830 necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
1831 {
1832 	struct kev_msg ev_msg;
1833 	memset(&ev_msg, 0, sizeof(ev_msg));
1834 
1835 	ev_msg.vendor_code      = KEV_VENDOR_APPLE;
1836 	ev_msg.kev_class        = KEV_NETWORK_CLASS;
1837 	ev_msg.kev_subclass     = KEV_NECP_SUBCLASS;
1838 	ev_msg.event_code       = KEV_NECP_POLICIES_CHANGED;
1839 
1840 	ev_msg.dv[0].data_ptr    = necp_event_data;
1841 	ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
1842 	ev_msg.dv[1].data_length = 0;
1843 
1844 	kev_post_msg(&ev_msg);
1845 }
1846 
1847 static inline bool
necp_buffer_write_tlv_validate(u_int8_t * cursor,u_int8_t type,u_int32_t length,u_int8_t * buffer,u_int32_t buffer_length)1848 necp_buffer_write_tlv_validate(u_int8_t *cursor, u_int8_t type, u_int32_t length,
1849     u_int8_t *buffer, u_int32_t buffer_length)
1850 {
1851 	if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
1852 		NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
1853 		return false;
1854 	}
1855 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1856 	if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
1857 	    (uintptr_t)(next_tlv - buffer) > buffer_length) {     // make sure the next TLV has enough room in buffer
1858 		NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1859 		    length, buffer_length);
1860 		return false;
1861 	}
1862 	return true;
1863 }
1864 
1865 u_int8_t *
necp_buffer_write_tlv_if_different(u_int8_t * cursor,u_int8_t type,u_int32_t length,const void * value,bool * updated,u_int8_t * buffer,u_int32_t buffer_length)1866 necp_buffer_write_tlv_if_different(u_int8_t *cursor, u_int8_t type,
1867     u_int32_t length, const void *value, bool *updated,
1868     u_int8_t *buffer, u_int32_t buffer_length)
1869 {
1870 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1871 		// If we can't fit this TLV, return the current cursor
1872 		return cursor;
1873 	}
1874 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1875 	if (*updated || *(u_int8_t *)(cursor) != type) {
1876 		*(u_int8_t *)(cursor) = type;
1877 		*updated = TRUE;
1878 	}
1879 	if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
1880 		*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1881 		*updated = TRUE;
1882 	}
1883 	if (length > 0) {
1884 		if (*updated || memcmp((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length) != 0) {
1885 			memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
1886 			*updated = TRUE;
1887 		}
1888 	}
1889 	return next_tlv;
1890 }
1891 
1892 u_int8_t *
necp_buffer_write_tlv(u_int8_t * cursor,u_int8_t type,u_int32_t length,const void * value,u_int8_t * buffer,u_int32_t buffer_length)1893 necp_buffer_write_tlv(u_int8_t *cursor, u_int8_t type,
1894     u_int32_t length, const void *value,
1895     u_int8_t *buffer, u_int32_t buffer_length)
1896 {
1897 	if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1898 		return NULL;
1899 	}
1900 	u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1901 	*(u_int8_t *)(cursor) = type;
1902 	*(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1903 	if (length > 0) {
1904 		memcpy((u_int8_t *)(cursor + sizeof(type) + sizeof(length)), value, length);
1905 	}
1906 
1907 	return next_tlv;
1908 }
1909 
1910 u_int8_t
necp_buffer_get_tlv_type(u_int8_t * buffer,int tlv_offset)1911 necp_buffer_get_tlv_type(u_int8_t *buffer, int tlv_offset)
1912 {
1913 	u_int8_t *type = NULL;
1914 
1915 	if (buffer == NULL) {
1916 		return 0;
1917 	}
1918 
1919 	type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
1920 	return type ? *type : 0;
1921 }
1922 
1923 u_int32_t
necp_buffer_get_tlv_length(u_int8_t * buffer,int tlv_offset)1924 necp_buffer_get_tlv_length(u_int8_t *buffer, int tlv_offset)
1925 {
1926 	u_int32_t *length = NULL;
1927 
1928 	if (buffer == NULL) {
1929 		return 0;
1930 	}
1931 
1932 	length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
1933 	return length ? *length : 0;
1934 }
1935 
1936 u_int8_t *
necp_buffer_get_tlv_value(u_int8_t * buffer,int tlv_offset,u_int32_t * value_size)1937 necp_buffer_get_tlv_value(u_int8_t *buffer, int tlv_offset, u_int32_t *value_size)
1938 {
1939 	u_int8_t *value = NULL;
1940 	u_int32_t length = necp_buffer_get_tlv_length(buffer, tlv_offset);
1941 	if (length == 0) {
1942 		return value;
1943 	}
1944 
1945 	if (value_size) {
1946 		*value_size = length;
1947 	}
1948 
1949 	value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
1950 	return value;
1951 }
1952 
1953 int
necp_buffer_find_tlv(u_int8_t * buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)1954 necp_buffer_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
1955 {
1956 	if (err != NULL) {
1957 		*err = ENOENT;
1958 	}
1959 	if (offset < 0) {
1960 		if (err != NULL) {
1961 			*err = EINVAL;
1962 		}
1963 		return -1;
1964 	}
1965 	int cursor = offset;
1966 	int next_cursor;
1967 	u_int32_t curr_length;
1968 	u_int8_t curr_type;
1969 
1970 	while (TRUE) {
1971 		if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
1972 			return -1;
1973 		}
1974 		if (!next) {
1975 			curr_type = necp_buffer_get_tlv_type(buffer, cursor);
1976 		} else {
1977 			next = 0;
1978 			curr_type = NECP_TLV_NIL;
1979 		}
1980 		curr_length = necp_buffer_get_tlv_length(buffer, cursor);
1981 		if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
1982 			return -1;
1983 		}
1984 
1985 		next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
1986 		if (curr_type == type) {
1987 			// check if entire TLV fits inside buffer
1988 			if (((u_int32_t)next_cursor) <= buffer_length) {
1989 				if (err != NULL) {
1990 					*err = 0;
1991 				}
1992 				return cursor;
1993 			} else {
1994 				return -1;
1995 			}
1996 		}
1997 		cursor = next_cursor;
1998 	}
1999 }
2000 
2001 static int
necp_find_tlv(u_int8_t * buffer,u_int32_t buffer_length,int offset,u_int8_t type,int * err,int next)2002 necp_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2003 {
2004 	int cursor = -1;
2005 	if (buffer != NULL) {
2006 		cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2007 	}
2008 	return cursor;
2009 }
2010 
2011 static int
necp_get_tlv_at_offset(u_int8_t * buffer,u_int32_t buffer_length,int tlv_offset,u_int32_t out_buffer_length,void * out_buffer,u_int32_t * value_size)2012 necp_get_tlv_at_offset(u_int8_t *buffer, u_int32_t buffer_length,
2013     int tlv_offset, u_int32_t out_buffer_length, void *out_buffer, u_int32_t *value_size)
2014 {
2015 	if (buffer == NULL) {
2016 		NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2017 		return EINVAL;
2018 	}
2019 
2020 	// Handle buffer parsing
2021 
2022 	// Validate that buffer has enough room for any TLV
2023 	if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2024 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2025 		    buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2026 		return EINVAL;
2027 	}
2028 
2029 	// Validate that buffer has enough room for this TLV
2030 	u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, tlv_offset);
2031 	if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2032 		NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2033 		    tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2034 		return EINVAL;
2035 	}
2036 
2037 	if (out_buffer != NULL && out_buffer_length > 0) {
2038 		// Validate that out buffer is large enough for  value
2039 		if (out_buffer_length < tlv_length) {
2040 			NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2041 			    out_buffer_length, tlv_length);
2042 			return EINVAL;
2043 		}
2044 
2045 		// Get value pointer
2046 		u_int8_t *tlv_value = necp_buffer_get_tlv_value(buffer, tlv_offset, NULL);
2047 		if (tlv_value == NULL) {
2048 			NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2049 			return ENOENT;
2050 		}
2051 
2052 		// Copy value
2053 		memcpy(out_buffer, tlv_value, tlv_length);
2054 	}
2055 
2056 	// Copy out length
2057 	if (value_size != NULL) {
2058 		*value_size = tlv_length;
2059 	}
2060 
2061 	return 0;
2062 }
2063 
2064 static int
necp_get_tlv(u_int8_t * buffer,u_int32_t buffer_length,int offset,u_int8_t type,u_int32_t buff_len,void * buff,u_int32_t * value_size)2065 necp_get_tlv(u_int8_t *buffer, u_int32_t buffer_length,
2066     int offset, u_int8_t type, u_int32_t buff_len, void *buff, u_int32_t *value_size)
2067 {
2068 	int error = 0;
2069 
2070 	int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, &error, 0);
2071 	if (tlv_offset < 0) {
2072 		return error;
2073 	}
2074 
2075 	return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, buff_len, buff, value_size);
2076 }
2077 
2078 // Session Management
2079 
2080 static struct necp_session *
necp_create_session(void)2081 necp_create_session(void)
2082 {
2083 	struct necp_session *new_session = NULL;
2084 
2085 	new_session = kalloc_type(struct necp_session,
2086 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
2087 
2088 	new_session->necp_fd_type = necp_fd_type_session;
2089 	new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2090 	new_session->dirty = FALSE;
2091 	LIST_INIT(&new_session->policies);
2092 	LIST_INIT(&new_session->services);
2093 	LIST_INIT(&new_session->domain_filters);
2094 	lck_mtx_init(&new_session->lock, &necp_kernel_policy_mtx_grp, &necp_kernel_policy_mtx_attr);
2095 
2096 	// Take the lock
2097 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2098 
2099 	// Find the next available control unit
2100 	u_int32_t control_unit = 1;
2101 	struct necp_session *next_session = NULL;
2102 	TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2103 		if (next_session->control_unit > control_unit) {
2104 			// Found a gap, grab this control unit
2105 			break;
2106 		}
2107 
2108 		// Try the next control unit, loop around
2109 		control_unit = next_session->control_unit + 1;
2110 	}
2111 
2112 	new_session->control_unit = control_unit;
2113 	new_session->session_order = necp_allocate_new_session_order(new_session->session_priority, control_unit);
2114 
2115 	if (next_session != NULL) {
2116 		TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2117 	} else {
2118 		TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2119 	}
2120 
2121 	necp_session_count++;
2122 	lck_rw_done(&necp_kernel_policy_lock);
2123 
2124 	if (necp_debug) {
2125 		NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2126 	}
2127 
2128 	return new_session;
2129 }
2130 
2131 static void
necp_delete_session(struct necp_session * session)2132 necp_delete_session(struct necp_session *session)
2133 {
2134 	if (session != NULL) {
2135 		struct necp_service_registration *service = NULL;
2136 		struct necp_service_registration *temp_service = NULL;
2137 		LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2138 			LIST_REMOVE(service, session_chain);
2139 			lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2140 			LIST_REMOVE(service, kernel_chain);
2141 			lck_rw_done(&necp_kernel_policy_lock);
2142 			kfree_type(struct necp_service_registration, service);
2143 		}
2144 		struct necp_domain_filter *filter = NULL;
2145 		struct necp_domain_filter *temp_filter = NULL;
2146 		LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2147 			if (os_ref_release_locked(&filter->refcount) == 0) {
2148 				lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2149 				LIST_REMOVE(filter, chain);
2150 				lck_rw_done(&necp_kernel_policy_lock);
2151 				LIST_REMOVE(filter, owner_chain);
2152 				net_bloom_filter_destroy(filter->filter);
2153 				kfree_type(struct necp_domain_filter, filter);
2154 			}
2155 		}
2156 		if (necp_debug) {
2157 			NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2158 		}
2159 
2160 		lck_rw_lock_exclusive(&necp_kernel_policy_lock);
2161 		TAILQ_REMOVE(&necp_session_list, session, chain);
2162 		necp_session_count--;
2163 		lck_rw_done(&necp_kernel_policy_lock);
2164 
2165 		lck_mtx_destroy(&session->lock, &necp_kernel_policy_mtx_grp);
2166 		kfree_type(struct necp_session, session);
2167 	}
2168 }
2169 
2170 // Session Policy Management
2171 
2172 static inline u_int8_t
necp_policy_result_get_type_from_buffer(u_int8_t * buffer,u_int32_t length)2173 necp_policy_result_get_type_from_buffer(u_int8_t *buffer, u_int32_t length)
2174 {
2175 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2176 }
2177 
2178 static inline u_int32_t
necp_policy_result_get_parameter_length_from_buffer(u_int8_t * buffer,u_int32_t length)2179 necp_policy_result_get_parameter_length_from_buffer(u_int8_t *buffer, u_int32_t length)
2180 {
2181 	return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2182 }
2183 
2184 static inline u_int8_t *
necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t * buffer,u_int32_t length)2185 necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t *buffer, u_int32_t length)
2186 {
2187 	return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2188 }
2189 
2190 static bool
necp_policy_result_requires_route_rules(u_int8_t * buffer,u_int32_t length)2191 necp_policy_result_requires_route_rules(u_int8_t *buffer, u_int32_t length)
2192 {
2193 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2194 	if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2195 		return TRUE;
2196 	}
2197 	return FALSE;
2198 }
2199 
2200 static inline bool
_necp_address_is_valid(struct sockaddr * address)2201 _necp_address_is_valid(struct sockaddr *address)
2202 {
2203 	if (address->sa_family == AF_INET) {
2204 		return address->sa_len == sizeof(struct sockaddr_in);
2205 	} else if (address->sa_family == AF_INET6) {
2206 		return address->sa_len == sizeof(struct sockaddr_in6);
2207 	} else {
2208 		return FALSE;
2209 	}
2210 }
2211 
2212 #define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2213 
2214 static bool
necp_policy_result_is_valid(u_int8_t * buffer,u_int32_t length,bool * is_pass_skip)2215 necp_policy_result_is_valid(u_int8_t *buffer, u_int32_t length, bool *is_pass_skip)
2216 {
2217 	bool validated = FALSE;
2218 	u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2219 	u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2220 	*is_pass_skip = FALSE;
2221 	switch (type) {
2222 	case NECP_POLICY_RESULT_PASS: {
2223 		*is_pass_skip = TRUE;
2224 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2225 			validated = TRUE;
2226 		}
2227 		break;
2228 	}
2229 	case NECP_POLICY_RESULT_DROP: {
2230 		if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2231 			validated = TRUE;
2232 		}
2233 		break;
2234 	}
2235 	case NECP_POLICY_RESULT_ROUTE_RULES:
2236 	case NECP_POLICY_RESULT_SCOPED_DIRECT:
2237 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2238 		validated = TRUE;
2239 		break;
2240 	}
2241 	case NECP_POLICY_RESULT_SKIP:
2242 		*is_pass_skip = TRUE;
2243 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
2244 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
2245 		if (parameter_length >= sizeof(u_int32_t)) {
2246 			validated = TRUE;
2247 		}
2248 		break;
2249 	}
2250 	case NECP_POLICY_RESULT_IP_TUNNEL: {
2251 		if (parameter_length > sizeof(u_int32_t)) {
2252 			validated = TRUE;
2253 		}
2254 		break;
2255 	}
2256 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2257 		if (parameter_length > 0) {
2258 			validated = TRUE;
2259 		}
2260 		break;
2261 	}
2262 	case NECP_POLICY_RESULT_USE_NETAGENT:
2263 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2264 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2265 		if (parameter_length >= sizeof(uuid_t)) {
2266 			validated = TRUE;
2267 		}
2268 		break;
2269 	}
2270 	default: {
2271 		validated = FALSE;
2272 		break;
2273 	}
2274 	}
2275 
2276 	if (necp_debug) {
2277 		NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2278 	}
2279 
2280 	return validated;
2281 }
2282 
2283 static inline u_int8_t
necp_policy_condition_get_type_from_buffer(u_int8_t * buffer,u_int32_t length)2284 necp_policy_condition_get_type_from_buffer(u_int8_t *buffer, u_int32_t length)
2285 {
2286 	return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2287 }
2288 
2289 static inline u_int8_t
necp_policy_condition_get_flags_from_buffer(u_int8_t * buffer,u_int32_t length)2290 necp_policy_condition_get_flags_from_buffer(u_int8_t *buffer, u_int32_t length)
2291 {
2292 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2293 }
2294 
2295 static inline u_int32_t
necp_policy_condition_get_value_length_from_buffer(u_int8_t * buffer,u_int32_t length)2296 necp_policy_condition_get_value_length_from_buffer(u_int8_t *buffer, u_int32_t length)
2297 {
2298 	return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2299 }
2300 
2301 static inline u_int8_t *
necp_policy_condition_get_value_pointer_from_buffer(u_int8_t * buffer,u_int32_t length)2302 necp_policy_condition_get_value_pointer_from_buffer(u_int8_t *buffer, u_int32_t length)
2303 {
2304 	return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2305 }
2306 
2307 static inline bool
necp_policy_condition_is_default(u_int8_t * buffer,u_int32_t length)2308 necp_policy_condition_is_default(u_int8_t *buffer, u_int32_t length)
2309 {
2310 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2311 }
2312 
2313 static inline bool
necp_policy_condition_is_application(u_int8_t * buffer,u_int32_t length)2314 necp_policy_condition_is_application(u_int8_t *buffer, u_int32_t length)
2315 {
2316 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2317 }
2318 
2319 static inline bool
necp_policy_condition_is_real_application(u_int8_t * buffer,u_int32_t length)2320 necp_policy_condition_is_real_application(u_int8_t *buffer, u_int32_t length)
2321 {
2322 	return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2323 }
2324 
2325 static inline bool
necp_policy_condition_requires_application(u_int8_t * buffer,u_int32_t length)2326 necp_policy_condition_requires_application(u_int8_t *buffer, u_int32_t length)
2327 {
2328 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2329 	return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2330 }
2331 
2332 static inline bool
necp_policy_condition_is_kernel_pid(u_int8_t * buffer,u_int32_t length)2333 necp_policy_condition_is_kernel_pid(u_int8_t *buffer, u_int32_t length)
2334 {
2335 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2336 	u_int32_t condition_length = 0;
2337 	pid_t *condition_value = NULL;
2338 
2339 	if (type == NECP_POLICY_CONDITION_PID) {
2340 		condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2341 		if (condition_length >= sizeof(pid_t)) {
2342 			condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2343 			return *condition_value == 0;
2344 		}
2345 	}
2346 	return false;
2347 }
2348 
2349 static bool
necp_policy_condition_is_valid(u_int8_t * buffer,u_int32_t length,u_int8_t policy_result_type)2350 necp_policy_condition_is_valid(u_int8_t *buffer, u_int32_t length, u_int8_t policy_result_type)
2351 {
2352 	bool validated = FALSE;
2353 	bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2354 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2355 	    policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2356 	    policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2357 	    policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2358 	    policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2359 	    policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2360 	    policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2361 	    policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2362 	u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2363 	u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2364 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2365 	u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2366 	switch (type) {
2367 	case NECP_POLICY_CONDITION_APPLICATION:
2368 	case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2369 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2370 		    condition_length >= sizeof(uuid_t) &&
2371 		    condition_value != NULL &&
2372 		    !uuid_is_null(condition_value)) {
2373 			validated = TRUE;
2374 		}
2375 		break;
2376 	}
2377 	case NECP_POLICY_CONDITION_DOMAIN:
2378 	case NECP_POLICY_CONDITION_ACCOUNT:
2379 	case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2380 	case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2381 	case NECP_POLICY_CONDITION_URL: {
2382 		if (condition_length > 0) {
2383 			validated = TRUE;
2384 		}
2385 		break;
2386 	}
2387 	case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2388 		if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2389 			validated = TRUE;
2390 		}
2391 		break;
2392 	}
2393 	case NECP_POLICY_CONDITION_DEFAULT:
2394 	case NECP_POLICY_CONDITION_ALL_INTERFACES:
2395 	case NECP_POLICY_CONDITION_ENTITLEMENT:
2396 	case NECP_POLICY_CONDITION_PLATFORM_BINARY:
2397 	case NECP_POLICY_CONDITION_HAS_CLIENT:
2398 	case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT:
2399 	case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2400 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2401 			validated = TRUE;
2402 		}
2403 		break;
2404 	}
2405 	case NECP_POLICY_CONDITION_SDK_VERSION: {
2406 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2407 		    condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2408 			validated = TRUE;
2409 		}
2410 		break;
2411 	}
2412 	case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2413 		if (condition_length >= sizeof(u_int16_t)) {
2414 			validated = TRUE;
2415 		}
2416 		break;
2417 	}
2418 	case NECP_POLICY_CONDITION_PID: {
2419 		if (condition_length >= sizeof(pid_t) &&
2420 		    condition_value != NULL) {
2421 			validated = TRUE;
2422 		}
2423 		break;
2424 	}
2425 	case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2426 		if (condition_length >= sizeof(u_int32_t)) {
2427 			validated = TRUE;
2428 		}
2429 		break;
2430 	}
2431 	case NECP_POLICY_CONDITION_UID:
2432 	case NECP_POLICY_CONDITION_REAL_UID: {
2433 		if (condition_length >= sizeof(uid_t)) {
2434 			validated = TRUE;
2435 		}
2436 		break;
2437 	}
2438 	case NECP_POLICY_CONDITION_LOCAL_ADDR:
2439 	case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2440 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2441 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2442 			validated = TRUE;
2443 		}
2444 		break;
2445 	}
2446 	case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2447 	case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2448 		if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2449 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2450 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2451 			validated = TRUE;
2452 		}
2453 		break;
2454 	}
2455 	case NECP_POLICY_CONDITION_AGENT_TYPE: {
2456 		if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2457 		    condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2458 			validated = TRUE;
2459 		}
2460 		break;
2461 	}
2462 	case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2463 		if (condition_length >= sizeof(u_int16_t)) {
2464 			validated = TRUE;
2465 		}
2466 		break;
2467 	}
2468 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2469 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2470 		if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2471 		    necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2472 			validated = TRUE;
2473 		}
2474 		break;
2475 	}
2476 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2477 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2478 		if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2479 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2480 		    necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2481 			validated = TRUE;
2482 		}
2483 		break;
2484 	}
2485 	case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2486 		if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2487 			validated = TRUE;
2488 		}
2489 		break;
2490 	}
2491 	case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2492 		validated = TRUE;
2493 		break;
2494 	}
2495 	case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2496 		validated = TRUE;
2497 		break;
2498 	}
2499 	case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2500 		if (condition_length >= sizeof(u_int16_t)) {
2501 			u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2502 			if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2503 				validated = TRUE;
2504 			}
2505 		}
2506 		break;
2507 	}
2508 	case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2509 		validated = TRUE;
2510 		break;
2511 	}
2512 	case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2513 		validated = TRUE;
2514 		break;
2515 	}
2516 	case NECP_POLICY_CONDITION_SCHEME_PORT: {
2517 		if (condition_length >= sizeof(u_int16_t)) {
2518 			validated = TRUE;
2519 		}
2520 		break;
2521 	}
2522 	case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2523 		if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2524 			validated = TRUE;
2525 		}
2526 		break;
2527 	}
2528 	default: {
2529 		validated = FALSE;
2530 		break;
2531 	}
2532 	}
2533 
2534 	if (necp_debug) {
2535 		NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2536 	}
2537 
2538 	return validated;
2539 }
2540 
2541 static bool
necp_policy_route_rule_is_default(u_int8_t * buffer,u_int32_t length)2542 necp_policy_route_rule_is_default(u_int8_t *buffer, u_int32_t length)
2543 {
2544 	return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2545 	       necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2546 }
2547 
2548 static bool
necp_policy_route_rule_is_valid(u_int8_t * buffer,u_int32_t length)2549 necp_policy_route_rule_is_valid(u_int8_t *buffer, u_int32_t length)
2550 {
2551 	bool validated = FALSE;
2552 	u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2553 	switch (type) {
2554 	case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2555 		validated = TRUE;
2556 		break;
2557 	}
2558 	case NECP_ROUTE_RULE_DENY_INTERFACE: {
2559 		validated = TRUE;
2560 		break;
2561 	}
2562 	case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2563 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2564 		validated = (rule_length >= sizeof(u_int32_t));
2565 		break;
2566 	}
2567 	case NECP_ROUTE_RULE_QOS_MARKING: {
2568 		validated = TRUE;
2569 		break;
2570 	}
2571 	case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2572 		validated = TRUE;
2573 		break;
2574 	}
2575 	case NECP_ROUTE_RULE_USE_NETAGENT:
2576 	case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2577 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2578 		validated = (rule_length >= sizeof(uuid_t));
2579 		break;
2580 	}
2581 	case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2582 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2583 		validated = (rule_length >= sizeof(uint32_t));
2584 		break;
2585 	}
2586 	default: {
2587 		validated = FALSE;
2588 		break;
2589 	}
2590 	}
2591 
2592 	if (necp_debug) {
2593 		NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2594 	}
2595 
2596 	return validated;
2597 }
2598 
2599 static int
necp_get_posix_error_for_necp_error(int response_error)2600 necp_get_posix_error_for_necp_error(int response_error)
2601 {
2602 	switch (response_error) {
2603 	case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2604 	case NECP_ERROR_INVALID_TLV:
2605 	case NECP_ERROR_POLICY_RESULT_INVALID:
2606 	case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2607 	case NECP_ERROR_ROUTE_RULES_INVALID: {
2608 		return EINVAL;
2609 	}
2610 	case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2611 		return ENOENT;
2612 	}
2613 	case NECP_ERROR_INVALID_PROCESS: {
2614 		return EPERM;
2615 	}
2616 	case NECP_ERROR_INTERNAL:
2617 	default: {
2618 		return ENOMEM;
2619 	}
2620 	}
2621 }
2622 
2623 static necp_policy_id
necp_handle_policy_add(struct necp_session * session,u_int8_t * tlv_buffer,size_t tlv_buffer_length,int offset,int * return_error)2624 necp_handle_policy_add(struct necp_session *session,
2625     u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2626 {
2627 	bool has_default_condition = FALSE;
2628 	bool has_non_default_condition = FALSE;
2629 	bool has_application_condition = FALSE;
2630 	bool has_real_application_condition = FALSE;
2631 	bool requires_application_condition = FALSE;
2632 	bool has_kernel_pid = FALSE;
2633 	bool is_pass_skip = FALSE;
2634 	u_int8_t *conditions_array = NULL;
2635 	u_int32_t conditions_array_size = 0;
2636 	int conditions_array_cursor;
2637 
2638 	bool has_default_route_rule = FALSE;
2639 	u_int8_t *route_rules_array = NULL;
2640 	u_int32_t route_rules_array_size = 0;
2641 	int route_rules_array_cursor;
2642 
2643 	int cursor;
2644 	int error = 0;
2645 	u_int32_t response_error = NECP_ERROR_INTERNAL;
2646 
2647 	necp_policy_order order = 0;
2648 	struct necp_session_policy *policy = NULL;
2649 	u_int8_t *policy_result = NULL;
2650 	u_int32_t policy_result_size = 0;
2651 
2652 	// Read policy order
2653 	error = necp_get_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, sizeof(order), &order, NULL);
2654 	if (error) {
2655 		NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2656 		response_error = NECP_ERROR_INVALID_TLV;
2657 		goto fail;
2658 	}
2659 
2660 	// Read policy result
2661 	cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, &error, 0);
2662 	if (error || cursor < 0) {
2663 		NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2664 		response_error = NECP_ERROR_INVALID_TLV;
2665 		goto fail;
2666 	}
2667 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &policy_result_size);
2668 	if (error || policy_result_size == 0) {
2669 		NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2670 		response_error = NECP_ERROR_INVALID_TLV;
2671 		goto fail;
2672 	}
2673 	if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2674 		NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2675 		response_error = NECP_ERROR_INVALID_TLV;
2676 		goto fail;
2677 	}
2678 	policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2679 	if (policy_result == NULL) {
2680 		NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2681 		response_error = NECP_ERROR_INTERNAL;
2682 		goto fail;
2683 	}
2684 	error = necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, policy_result_size, policy_result, NULL);
2685 	if (error) {
2686 		NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2687 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2688 		goto fail;
2689 	}
2690 	if (!necp_policy_result_is_valid(policy_result, policy_result_size, &is_pass_skip)) {
2691 		NECPLOG0(LOG_ERR, "Failed to validate policy result");
2692 		response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2693 		goto fail;
2694 	}
2695 
2696 	if (necp_policy_result_requires_route_rules(policy_result, policy_result_size)) {
2697 		// Read route rules conditions
2698 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2699 		    cursor >= 0;
2700 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2701 			u_int32_t route_rule_size = 0;
2702 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2703 			if (os_add_overflow(route_rules_array_size,
2704 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
2705 			    &route_rules_array_size)) {
2706 				NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
2707 				response_error = NECP_ERROR_INVALID_TLV;
2708 				goto fail;
2709 			}
2710 		}
2711 
2712 		if (route_rules_array_size == 0) {
2713 			NECPLOG0(LOG_ERR, "Failed to get policy route rules");
2714 			response_error = NECP_ERROR_INVALID_TLV;
2715 			goto fail;
2716 		}
2717 		if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
2718 			NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
2719 			response_error = NECP_ERROR_INVALID_TLV;
2720 			goto fail;
2721 		}
2722 		route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
2723 		if (route_rules_array == NULL) {
2724 			NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
2725 			response_error = NECP_ERROR_INTERNAL;
2726 			goto fail;
2727 		}
2728 
2729 		route_rules_array_cursor = 0;
2730 		for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, &error, 0);
2731 		    cursor >= 0;
2732 		    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_ROUTE_RULE, &error, 1)) {
2733 			u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
2734 			u_int32_t route_rule_size = 0;
2735 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &route_rule_size);
2736 			if (route_rule_size > 0 &&
2737 			    (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
2738 				// Add type
2739 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_type, sizeof(route_rule_type));
2740 				route_rules_array_cursor += sizeof(route_rule_type);
2741 
2742 				// Add length
2743 				memcpy((route_rules_array + route_rules_array_cursor), &route_rule_size, sizeof(route_rule_size));
2744 				route_rules_array_cursor += sizeof(route_rule_size);
2745 
2746 				// Add value
2747 				necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, route_rule_size, (route_rules_array + route_rules_array_cursor), NULL);
2748 
2749 				if (!necp_policy_route_rule_is_valid((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2750 					NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
2751 					response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2752 					goto fail;
2753 				}
2754 
2755 				if (necp_policy_route_rule_is_default((route_rules_array + route_rules_array_cursor), route_rule_size)) {
2756 					if (has_default_route_rule) {
2757 						NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
2758 						response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2759 						goto fail;
2760 					}
2761 					has_default_route_rule = TRUE;
2762 				}
2763 
2764 				route_rules_array_cursor += route_rule_size;
2765 			}
2766 		}
2767 	}
2768 
2769 	// Read policy conditions
2770 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2771 	    cursor >= 0;
2772 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2773 		u_int32_t condition_size = 0;
2774 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2775 
2776 		if (condition_size > 0) {
2777 			if (os_add_overflow(conditions_array_size,
2778 			    (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
2779 			    &conditions_array_size)) {
2780 				NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
2781 				response_error = NECP_ERROR_INVALID_TLV;
2782 				goto fail;
2783 			}
2784 		}
2785 	}
2786 
2787 	if (conditions_array_size == 0) {
2788 		NECPLOG0(LOG_ERR, "Failed to get policy conditions");
2789 		response_error = NECP_ERROR_INVALID_TLV;
2790 		goto fail;
2791 	}
2792 	if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
2793 		NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
2794 		response_error = NECP_ERROR_INVALID_TLV;
2795 		goto fail;
2796 	}
2797 	conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
2798 	if (conditions_array == NULL) {
2799 		NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
2800 		response_error = NECP_ERROR_INTERNAL;
2801 		goto fail;
2802 	}
2803 
2804 	conditions_array_cursor = 0;
2805 	for (cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, &error, 0);
2806 	    cursor >= 0;
2807 	    cursor = necp_find_tlv(tlv_buffer, tlv_buffer_length, cursor, NECP_TLV_POLICY_CONDITION, &error, 1)) {
2808 		u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
2809 		u_int32_t condition_size = 0;
2810 		necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, 0, NULL, &condition_size);
2811 		if (condition_size > 0 &&
2812 		    (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
2813 			// Add type
2814 			memcpy((conditions_array + conditions_array_cursor), &condition_type, sizeof(condition_type));
2815 			conditions_array_cursor += sizeof(condition_type);
2816 
2817 			// Add length
2818 			memcpy((conditions_array + conditions_array_cursor), &condition_size, sizeof(condition_size));
2819 			conditions_array_cursor += sizeof(condition_size);
2820 
2821 			// Add value
2822 			necp_get_tlv_at_offset(tlv_buffer, tlv_buffer_length, cursor, condition_size, (conditions_array + conditions_array_cursor), NULL);
2823 			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))) {
2824 				NECPLOG0(LOG_ERR, "Failed to validate policy condition");
2825 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2826 				goto fail;
2827 			}
2828 
2829 			if (necp_policy_condition_is_default((conditions_array + conditions_array_cursor), condition_size)) {
2830 				has_default_condition = TRUE;
2831 			} else {
2832 				has_non_default_condition = TRUE;
2833 			}
2834 			if (has_default_condition && has_non_default_condition) {
2835 				NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
2836 				response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2837 				goto fail;
2838 			}
2839 
2840 			if (necp_policy_condition_is_application((conditions_array + conditions_array_cursor), condition_size)) {
2841 				has_application_condition = TRUE;
2842 			}
2843 
2844 			if (necp_policy_condition_is_real_application((conditions_array + conditions_array_cursor), condition_size)) {
2845 				has_real_application_condition = TRUE;
2846 			}
2847 
2848 			if (necp_policy_condition_requires_application((conditions_array + conditions_array_cursor), condition_size)) {
2849 				requires_application_condition = TRUE;
2850 			}
2851 
2852 			if (necp_policy_condition_is_kernel_pid((conditions_array + conditions_array_cursor), condition_size)) {
2853 				has_kernel_pid = TRUE;
2854 			}
2855 
2856 			conditions_array_cursor += condition_size;
2857 		}
2858 	}
2859 
2860 	if (requires_application_condition && !has_application_condition) {
2861 		NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
2862 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2863 		goto fail;
2864 	}
2865 
2866 	if (has_kernel_pid && !is_pass_skip) {
2867 		NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
2868 		response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2869 		goto fail;
2870 	}
2871 
2872 	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) {
2873 		response_error = NECP_ERROR_INTERNAL;
2874 		goto fail;
2875 	}
2876 
2877 	return policy->local_id;
2878 
2879 fail:
2880 	if (policy_result != NULL) {
2881 		kfree_data(policy_result, policy_result_size);
2882 	}
2883 	if (conditions_array != NULL) {
2884 		kfree_data(conditions_array, conditions_array_size);
2885 	}
2886 	if (route_rules_array != NULL) {
2887 		kfree_data(route_rules_array, route_rules_array_size);
2888 	}
2889 
2890 	if (return_error != NULL) {
2891 		*return_error = necp_get_posix_error_for_necp_error(response_error);
2892 	}
2893 	return 0;
2894 }
2895 
2896 static necp_policy_id
necp_policy_get_new_id(struct necp_session * session)2897 necp_policy_get_new_id(struct necp_session *session)
2898 {
2899 	session->last_policy_id++;
2900 	if (session->last_policy_id < 1) {
2901 		session->last_policy_id = 1;
2902 	}
2903 
2904 	necp_policy_id newid = session->last_policy_id;
2905 
2906 	if (newid == 0) {
2907 		NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
2908 		return 0;
2909 	}
2910 
2911 	return newid;
2912 }
2913 
2914 /*
2915  *	For the policy dump response this is the structure:
2916  *
2917  *	<NECP_PACKET_HEADER>
2918  *	{
2919  *		type	:	NECP_TLV_POLICY_DUMP
2920  *		length	:	...
2921  *		value	:
2922  *		{
2923  *			{
2924  *				type	:	NECP_TLV_POLICY_ID
2925  *				len		:	...
2926  *				value	:	...
2927  *			}
2928  *			{
2929  *				type	:	NECP_TLV_POLICY_ORDER
2930  *				len		:	...
2931  *				value	:	...
2932  *			}
2933  *			{
2934  *				type	:	NECP_TLV_POLICY_RESULT_STRING
2935  *				len		:	...
2936  *				value	:	...
2937  *			}
2938  *			{
2939  *				type	:	NECP_TLV_POLICY_OWNER
2940  *				len		:	...
2941  *				value	:	...
2942  *			}
2943  *			{
2944  *				type	:	NECP_TLV_POLICY_CONDITION
2945  *				len		:	...
2946  *				value	:
2947  *				{
2948  *					{
2949  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
2950  *						len		:	...
2951  *						value	:	...
2952  *					}
2953  *					{
2954  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
2955  *						len		:	...
2956  *						value	:	...
2957  *					}
2958  *					...
2959  *				}
2960  *			}
2961  *		}
2962  *	}
2963  *	{
2964  *		type	:	NECP_TLV_POLICY_DUMP
2965  *		length	:	...
2966  *		value	:
2967  *		{
2968  *			{
2969  *				type	:	NECP_TLV_POLICY_ID
2970  *				len		:	...
2971  *				value	:	...
2972  *			}
2973  *			{
2974  *				type	:	NECP_TLV_POLICY_ORDER
2975  *				len		:	...
2976  *				value	:	...
2977  *			}
2978  *			{
2979  *				type	:	NECP_TLV_POLICY_RESULT_STRING
2980  *				len		:	...
2981  *				value	:	...
2982  *			}
2983  *			{
2984  *				type	:	NECP_TLV_POLICY_OWNER
2985  *				len		:	...
2986  *				value	:	...
2987  *			}
2988  *			{
2989  *				type	:	NECP_TLV_POLICY_CONDITION
2990  *				len		:	...
2991  *				value	:
2992  *				{
2993  *					{
2994  *						type	:	NECP_POLICY_CONDITION_ALL_INTERFACES
2995  *						len		:	...
2996  *						value	:	...
2997  *					}
2998  *					{
2999  *						type	:	NECP_POLICY_CONDITION_BOUND_INTERFACES
3000  *						len		:	...
3001  *						value	:	...
3002  *					}
3003  *					...
3004  *				}
3005  *			}
3006  *		}
3007  *	}
3008  *	...
3009  */
3010 static int
necp_handle_policy_dump_all(user_addr_t out_buffer,size_t out_buffer_length)3011 necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3012 {
3013 	struct necp_kernel_socket_policy *policy = NULL;
3014 	int policy_i;
3015 	int policy_count = 0;
3016 	u_int8_t **tlv_buffer_pointers = NULL;
3017 	u_int32_t *tlv_buffer_lengths = NULL;
3018 	u_int32_t total_tlv_len = 0;
3019 	u_int8_t *result_buf = NULL;
3020 	u_int8_t *result_buf_cursor = result_buf;
3021 	char result_string[MAX_RESULT_STRING_LEN];
3022 	char proc_name_string[MAXCOMLEN + 1];
3023 
3024 	int error_code = 0;
3025 	bool error_occured = false;
3026 	u_int32_t response_error = NECP_ERROR_INTERNAL;
3027 
3028 #define REPORT_ERROR(error) error_occured = true;               \
3029 	                                                response_error = error;         \
3030 	                                                goto done
3031 
3032 #define UNLOCK_AND_REPORT_ERROR(lock, error)    lck_rw_done(lock);      \
3033 	                                                                                        REPORT_ERROR(error)
3034 
3035 	errno_t cred_result = priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0);
3036 	if (cred_result != 0) {
3037 		NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3038 		REPORT_ERROR(NECP_ERROR_INTERNAL);
3039 	}
3040 
3041 	// LOCK
3042 	lck_rw_lock_shared(&necp_kernel_policy_lock);
3043 
3044 	if (necp_debug) {
3045 		NECPLOG0(LOG_DEBUG, "Gathering policies");
3046 	}
3047 
3048 	policy_count = necp_kernel_application_policies_count;
3049 
3050 	tlv_buffer_pointers = kalloc_type(u_int8_t *, policy_count, M_WAITOK | Z_ZERO);
3051 	if (tlv_buffer_pointers == NULL) {
3052 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3053 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3054 	}
3055 
3056 	tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3057 	if (tlv_buffer_lengths == NULL) {
3058 		NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3059 		UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3060 	}
3061 
3062 	for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3063 		policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3064 
3065 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
3066 		memset(proc_name_string, 0, MAXCOMLEN + 1);
3067 
3068 		necp_get_result_description(result_string, policy->result, policy->result_parameter);
3069 		proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
3070 
3071 		u_int16_t proc_name_len = strlen(proc_name_string) + 1;
3072 		u_int16_t result_string_len = strlen(result_string) + 1;
3073 
3074 		if (necp_debug) {
3075 			NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3076 		}
3077 
3078 		u_int32_t total_allocated_bytes =       sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) +                                     // NECP_TLV_POLICY_ID
3079 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) +                                                                                              // NECP_TLV_POLICY_ORDER
3080 		    sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) +                                                                              // NECP_TLV_POLICY_SESSION_ORDER
3081 		    sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len +                                                                                                          // NECP_TLV_POLICY_RESULT_STRING
3082 		    sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len +                                                                                                              // NECP_TLV_POLICY_OWNER
3083 		    sizeof(u_int8_t) + sizeof(u_int32_t);                                                                                                                                               // NECP_TLV_POLICY_CONDITION
3084 
3085 		// We now traverse the condition_mask to see how much space we need to allocate
3086 		u_int64_t condition_mask = policy->condition_mask;
3087 		u_int8_t num_conditions = 0;
3088 		struct necp_string_id_mapping *account_id_entry = NULL;
3089 		char if_name[IFXNAMSIZ];
3090 		u_int32_t condition_tlv_length = 0;
3091 		memset(if_name, 0, sizeof(if_name));
3092 
3093 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3094 			num_conditions++;
3095 		} else {
3096 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3097 				num_conditions++;
3098 			}
3099 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3100 				num_conditions++;
3101 			}
3102 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3103 				snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(policy->cond_bound_interface), ifnet_unit(policy->cond_bound_interface));
3104 				condition_tlv_length += strlen(if_name) + 1;
3105 				num_conditions++;
3106 			}
3107 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3108 				condition_tlv_length += sizeof(policy->cond_protocol);
3109 				num_conditions++;
3110 			}
3111 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3112 				condition_tlv_length += sizeof(uuid_t);
3113 				num_conditions++;
3114 			}
3115 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3116 				condition_tlv_length += sizeof(uuid_t);
3117 				num_conditions++;
3118 			}
3119 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3120 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3121 				u_int32_t domain_len = strlen(policy->cond_domain) + 1;
3122 				condition_tlv_length += domain_len;
3123 				num_conditions++;
3124 			}
3125 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3126 				condition_tlv_length += sizeof(u_int32_t);
3127 				num_conditions++;
3128 			}
3129 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3130 				u_int32_t url_len = strlen(policy->cond_url) + 1;
3131 				condition_tlv_length += url_len;
3132 				num_conditions++;
3133 			}
3134 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3135 				account_id_entry = necp_lookup_string_with_id_locked(&necp_account_id_list, policy->cond_account_id);
3136 				u_int32_t account_id_len = 0;
3137 				if (account_id_entry) {
3138 					account_id_len = account_id_entry->string ? strlen(account_id_entry->string) + 1 : 0;
3139 				}
3140 				condition_tlv_length += account_id_len;
3141 				num_conditions++;
3142 			}
3143 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3144 				condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3145 				num_conditions++;
3146 			}
3147 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3148 				condition_tlv_length += sizeof(uid_t);
3149 				num_conditions++;
3150 			}
3151 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3152 				condition_tlv_length += sizeof(uid_t);
3153 				num_conditions++;
3154 			}
3155 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3156 				condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3157 				num_conditions++;
3158 			}
3159 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3160 				num_conditions++;
3161 			}
3162 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3163 				u_int32_t entitlement_len = strlen(policy->cond_custom_entitlement) + 1;
3164 				condition_tlv_length += entitlement_len;
3165 				num_conditions++;
3166 			}
3167 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3168 				num_conditions++;
3169 			}
3170 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3171 				num_conditions++;
3172 			}
3173 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3174 				condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3175 				num_conditions++;
3176 			}
3177 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3178 				num_conditions++;
3179 			}
3180 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3181 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3182 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3183 				} else {
3184 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3185 				}
3186 				num_conditions++;
3187 			}
3188 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3189 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3190 					condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3191 				} else {
3192 					condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3193 				}
3194 				num_conditions++;
3195 			}
3196 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3197 				condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3198 				num_conditions++;
3199 			}
3200 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3201 				condition_tlv_length += sizeof(u_int32_t);
3202 				num_conditions++;
3203 			}
3204 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3205 				num_conditions++;
3206 			}
3207 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3208 				num_conditions++;
3209 			}
3210 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3211 				u_int32_t identifier_len = strlen(policy->cond_signing_identifier) + 1;
3212 				condition_tlv_length += identifier_len;
3213 				num_conditions++;
3214 			}
3215 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3216 				condition_tlv_length += sizeof(u_int16_t);
3217 				num_conditions++;
3218 			}
3219 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3220 				num_conditions++;
3221 			}
3222 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3223 				num_conditions++;
3224 			}
3225 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3226 				condition_tlv_length += sizeof(u_int16_t);
3227 				num_conditions++;
3228 			}
3229 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3230 				condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3231 				num_conditions++;
3232 			}
3233 		}
3234 
3235 		condition_tlv_length += num_conditions * (sizeof(u_int8_t) + sizeof(u_int32_t)); // These are for the condition TLVs. The space for "value" is already accounted for above.
3236 		total_allocated_bytes += condition_tlv_length;
3237 
3238 		u_int8_t *tlv_buffer;
3239 		tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3240 		if (tlv_buffer == NULL) {
3241 			NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3242 			continue;
3243 		}
3244 
3245 		u_int8_t *cursor = tlv_buffer;
3246 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, sizeof(policy->id), &policy->id, tlv_buffer, total_allocated_bytes);
3247 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, sizeof(necp_policy_order), &policy->order, tlv_buffer, total_allocated_bytes);
3248 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, sizeof(policy->session_order), &policy->session_order, tlv_buffer, total_allocated_bytes);
3249 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, result_string_len, result_string, tlv_buffer, total_allocated_bytes);
3250 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, proc_name_len, proc_name_string, tlv_buffer, total_allocated_bytes);
3251 
3252 #define N_QUICK 256
3253 		u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3254 
3255 		u_int8_t *cond_buf; // To be used for condition TLVs
3256 		if (condition_tlv_length <= N_QUICK) {
3257 			cond_buf = q_cond_buf;
3258 		} else {
3259 			cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3260 			if (cond_buf == NULL) {
3261 				NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3262 				kfree_data(tlv_buffer, total_allocated_bytes);
3263 				continue;
3264 			}
3265 		}
3266 
3267 		memset(cond_buf, 0, condition_tlv_length);
3268 		u_int8_t *cond_buf_cursor = cond_buf;
3269 		if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3270 			cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, 0, "", cond_buf, condition_tlv_length);
3271 		} else {
3272 			if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3273 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ALL_INTERFACES, 0, "", cond_buf, condition_tlv_length);
3274 			}
3275 			if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3276 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_HAS_CLIENT, 0, "", cond_buf, condition_tlv_length);
3277 			}
3278 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3279 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_NETWORKS, 0, "", cond_buf, condition_tlv_length);
3280 			}
3281 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3282 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE, strlen(if_name) + 1,
3283 				    if_name, cond_buf, condition_tlv_length);
3284 			}
3285 			if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3286 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_IP_PROTOCOL, sizeof(policy->cond_protocol), &policy->cond_protocol,
3287 				    cond_buf, condition_tlv_length);
3288 			}
3289 			if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3290 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_app_id);
3291 				if (entry != NULL) {
3292 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, sizeof(entry->uuid), entry->uuid,
3293 					    cond_buf, condition_tlv_length);
3294 				}
3295 			}
3296 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3297 				struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(policy->cond_real_app_id);
3298 				if (entry != NULL) {
3299 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, sizeof(entry->uuid), entry->uuid,
3300 					    cond_buf, condition_tlv_length);
3301 				}
3302 			}
3303 			if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3304 			    (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3305 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN, strlen(policy->cond_domain) + 1, policy->cond_domain,
3306 				    cond_buf, condition_tlv_length);
3307 			}
3308 			if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3309 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN_FILTER, sizeof(policy->cond_domain_filter), &policy->cond_domain_filter,
3310 				    cond_buf, condition_tlv_length);
3311 			}
3312 			if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3313 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_URL, strlen(policy->cond_url) + 1, policy->cond_url,
3314 				    cond_buf, condition_tlv_length);
3315 			}
3316 			if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3317 				if (account_id_entry != NULL) {
3318 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ACCOUNT, strlen(account_id_entry->string) + 1, account_id_entry->string,
3319 					    cond_buf, condition_tlv_length);
3320 				}
3321 			}
3322 			if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3323 				uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3324 				memcpy(pid_buffer, &policy->cond_pid, sizeof(policy->cond_pid));
3325 				memcpy(pid_buffer + sizeof(policy->cond_pid), &policy->cond_pid_version, sizeof(policy->cond_pid_version));
3326 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PID, sizeof(pid_buffer), &pid_buffer,
3327 				    cond_buf, condition_tlv_length);
3328 			}
3329 			if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3330 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_UID, sizeof(policy->cond_uid), &policy->cond_uid,
3331 				    cond_buf, condition_tlv_length);
3332 			}
3333 			if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3334 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REAL_UID, sizeof(policy->cond_real_uid), &policy->cond_real_uid,
3335 				    cond_buf, condition_tlv_length);
3336 			}
3337 			if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3338 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_TRAFFIC_CLASS, sizeof(policy->cond_traffic_class), &policy->cond_traffic_class,
3339 				    cond_buf, condition_tlv_length);
3340 			}
3341 			if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3342 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, 0, "",
3343 				    cond_buf, condition_tlv_length);
3344 			}
3345 			if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3346 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, strlen(policy->cond_custom_entitlement) + 1, policy->cond_custom_entitlement,
3347 				    cond_buf, condition_tlv_length);
3348 			}
3349 			if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3350 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PLATFORM_BINARY, 0, "", cond_buf, condition_tlv_length);
3351 			}
3352 			if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3353 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT, 0, "", cond_buf, condition_tlv_length);
3354 			}
3355 			if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3356 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION,
3357 				    sizeof(policy->cond_sdk_version), &policy->cond_sdk_version,
3358 				    cond_buf, condition_tlv_length);
3359 			}
3360 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3361 				if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3362 					struct necp_policy_condition_addr_range range;
3363 					memcpy(&range.start_address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3364 					memcpy(&range.end_address, &policy->cond_local_end, sizeof(policy->cond_local_end));
3365 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, sizeof(range), &range,
3366 					    cond_buf, condition_tlv_length);
3367 				} else {
3368 					struct necp_policy_condition_addr addr;
3369 					addr.prefix = policy->cond_local_prefix;
3370 					memcpy(&addr.address, &policy->cond_local_start, sizeof(policy->cond_local_start));
3371 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, sizeof(addr), &addr,
3372 					    cond_buf, condition_tlv_length);
3373 				}
3374 			}
3375 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3376 				if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3377 					struct necp_policy_condition_addr_range range;
3378 					memcpy(&range.start_address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3379 					memcpy(&range.end_address, &policy->cond_remote_end, sizeof(policy->cond_remote_end));
3380 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, sizeof(range), &range,
3381 					    cond_buf, condition_tlv_length);
3382 				} else {
3383 					struct necp_policy_condition_addr addr;
3384 					addr.prefix = policy->cond_remote_prefix;
3385 					memcpy(&addr.address, &policy->cond_remote_start, sizeof(policy->cond_remote_start));
3386 					cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, sizeof(addr), &addr,
3387 					    cond_buf, condition_tlv_length);
3388 				}
3389 			}
3390 			if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3391 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE,
3392 				    sizeof(policy->cond_agent_type), &policy->cond_agent_type,
3393 				    cond_buf, condition_tlv_length);
3394 			}
3395 			if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3396 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_CLIENT_FLAGS, sizeof(policy->cond_client_flags), &policy->cond_client_flags, cond_buf, condition_tlv_length);
3397 			}
3398 			if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3399 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY, 0, "", cond_buf, condition_tlv_length);
3400 			}
3401 			if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3402 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, 0, "", cond_buf, condition_tlv_length);
3403 			}
3404 			if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3405 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, strlen(policy->cond_signing_identifier) + 1, policy->cond_signing_identifier,
3406 				    cond_buf, condition_tlv_length);
3407 			}
3408 			if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3409 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS, sizeof(policy->cond_packet_filter_tags), &policy->cond_packet_filter_tags, cond_buf, condition_tlv_length);
3410 			}
3411 			if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3412 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, 0, "", cond_buf, condition_tlv_length);
3413 			}
3414 			if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3415 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, 0, "", cond_buf, condition_tlv_length);
3416 			}
3417 			if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3418 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_SCHEME_PORT, sizeof(policy->cond_scheme_port), &policy->cond_scheme_port, cond_buf, condition_tlv_length);
3419 			}
3420 			if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3421 				uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3422 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3423 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3424 				flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3425 				cond_buf_cursor = necp_buffer_write_tlv(cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, sizeof(flags), &flags,
3426 				    cond_buf, condition_tlv_length);
3427 			}
3428 		}
3429 
3430 		cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, cond_buf_cursor - cond_buf, cond_buf, tlv_buffer, total_allocated_bytes);
3431 		if (cond_buf != q_cond_buf) {
3432 			kfree_data(cond_buf, condition_tlv_length);
3433 		}
3434 
3435 		tlv_buffer_pointers[policy_i] = tlv_buffer;
3436 		tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3437 
3438 		// This is the length of the TLV for NECP_TLV_POLICY_DUMP
3439 		total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3440 	}
3441 
3442 	// UNLOCK
3443 	lck_rw_done(&necp_kernel_policy_lock);
3444 
3445 	// Copy out
3446 	if (out_buffer != 0) {
3447 		if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3448 			NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3449 			REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3450 		}
3451 
3452 		// Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3453 		result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3454 		if (result_buf == NULL) {
3455 			NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3456 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3457 		}
3458 
3459 		// Add four bytes for total length at the start
3460 		memcpy(result_buf, &total_tlv_len, sizeof(u_int32_t));
3461 
3462 		// Copy the TLVs
3463 		result_buf_cursor = result_buf + sizeof(u_int32_t);
3464 		for (int i = 0; i < policy_count; i++) {
3465 			if (tlv_buffer_pointers[i] != NULL) {
3466 				result_buf_cursor = necp_buffer_write_tlv(result_buf_cursor, NECP_TLV_POLICY_DUMP, tlv_buffer_lengths[i], tlv_buffer_pointers[i],
3467 				    result_buf, total_tlv_len + sizeof(u_int32_t));
3468 			}
3469 		}
3470 
3471 		int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3472 		if (copy_error) {
3473 			NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3474 			REPORT_ERROR(NECP_ERROR_INTERNAL);
3475 		}
3476 	}
3477 
3478 done:
3479 
3480 	if (error_occured) {
3481 		error_code = necp_get_posix_error_for_necp_error(response_error);
3482 	}
3483 
3484 	if (result_buf != NULL) {
3485 		kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3486 	}
3487 
3488 	if (tlv_buffer_pointers != NULL) {
3489 		for (int i = 0; i < policy_count; i++) {
3490 			if (tlv_buffer_pointers[i] != NULL) {
3491 				kfree_data_addr(tlv_buffer_pointers[i]);
3492 				tlv_buffer_pointers[i] = NULL;
3493 			}
3494 		}
3495 		kfree_type(u_int8_t *, policy_count, tlv_buffer_pointers);
3496 	}
3497 
3498 	if (tlv_buffer_lengths != NULL) {
3499 		kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3500 	}
3501 #undef N_QUICK
3502 #undef RESET_COND_BUF
3503 #undef REPORT_ERROR
3504 #undef UNLOCK_AND_REPORT_ERROR
3505 
3506 	return error_code;
3507 }
3508 
3509 static struct necp_session_policy *
necp_policy_create(struct necp_session * session,necp_policy_order order,u_int8_t * conditions_array,u_int32_t conditions_array_size,u_int8_t * route_rules_array,u_int32_t route_rules_array_size,u_int8_t * result,u_int32_t result_size)3510 necp_policy_create(struct necp_session *session, necp_policy_order order, u_int8_t *conditions_array, u_int32_t conditions_array_size, u_int8_t *route_rules_array, u_int32_t route_rules_array_size, u_int8_t *result, u_int32_t result_size)
3511 {
3512 	struct necp_session_policy *new_policy = NULL;
3513 	struct necp_session_policy *tmp_policy = NULL;
3514 
3515 	if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3516 		goto done;
3517 	}
3518 
3519 	new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3520 	new_policy->applied = FALSE;
3521 	new_policy->pending_deletion = FALSE;
3522 	new_policy->pending_update = FALSE;
3523 	new_policy->order = order;
3524 	new_policy->conditions = conditions_array;
3525 	new_policy->conditions_size = conditions_array_size;
3526 	new_policy->route_rules = route_rules_array;
3527 	new_policy->route_rules_size = route_rules_array_size;
3528 	new_policy->result = result;
3529 	new_policy->result_size = result_size;
3530 	new_policy->local_id = necp_policy_get_new_id(session);
3531 
3532 	LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3533 
3534 	session->dirty = TRUE;
3535 
3536 	if (necp_debug) {
3537 		NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3538 	}
3539 done:
3540 	return new_policy;
3541 }
3542 
3543 static struct necp_session_policy *
necp_policy_find(struct necp_session * session,necp_policy_id policy_id)3544 necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3545 {
3546 	struct necp_session_policy *policy = NULL;
3547 	if (policy_id == 0) {
3548 		return NULL;
3549 	}
3550 
3551 	LIST_FOREACH(policy, &session->policies, chain) {
3552 		if (policy->local_id == policy_id) {
3553 			return policy;
3554 		}
3555 	}
3556 
3557 	return NULL;
3558 }
3559 
3560 static inline u_int8_t
necp_policy_get_result_type(struct necp_session_policy * policy)3561 necp_policy_get_result_type(struct necp_session_policy *policy)
3562 {
3563 	return policy ? necp_policy_result_get_type_from_buffer(policy->result, policy->result_size) : 0;
3564 }
3565 
3566 static inline u_int32_t
necp_policy_get_result_parameter_length(struct necp_session_policy * policy)3567 necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3568 {
3569 	return policy ? necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) : 0;
3570 }
3571 
3572 static bool
necp_policy_get_result_parameter(struct necp_session_policy * policy,u_int8_t * parameter_buffer,u_int32_t parameter_buffer_length)3573 necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t *parameter_buffer, u_int32_t parameter_buffer_length)
3574 {
3575 	if (policy) {
3576 		u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size);
3577 		if (parameter_buffer_length >= parameter_length) {
3578 			u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(policy->result, policy->result_size);
3579 			if (parameter && parameter_buffer) {
3580 				memcpy(parameter_buffer, parameter, parameter_length);
3581 				return TRUE;
3582 			}
3583 		}
3584 	}
3585 
3586 	return FALSE;
3587 }
3588 
3589 static bool
necp_policy_mark_for_deletion(struct necp_session * session,struct necp_session_policy * policy)3590 necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3591 {
3592 	if (session == NULL || policy == NULL) {
3593 		return FALSE;
3594 	}
3595 
3596 	policy->pending_deletion = TRUE;
3597 	session->dirty = TRUE;
3598 
3599 	if (necp_debug) {
3600 		NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3601 	}
3602 	return TRUE;
3603 }
3604 
3605 static bool
necp_policy_mark_all_for_deletion(struct necp_session * session)3606 necp_policy_mark_all_for_deletion(struct necp_session *session)
3607 {
3608 	struct necp_session_policy *policy = NULL;
3609 	struct necp_session_policy *temp_policy = NULL;
3610 
3611 	LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3612 		necp_policy_mark_for_deletion(session, policy);
3613 	}
3614 
3615 	return TRUE;
3616 }
3617 
3618 static bool
necp_policy_delete(struct necp_session * session,struct necp_session_policy * policy)3619 necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3620 {
3621 	if (session == NULL || policy == NULL) {
3622 		return FALSE;
3623 	}
3624 
3625 	LIST_REMOVE(policy, chain);
3626 
3627 	if (policy->result) {
3628 		kfree_data(policy->result, policy->result_size);
3629 		policy->result = NULL;
3630 	}
3631 
3632 	if (policy->conditions) {
3633 		kfree_data(policy->conditions, policy->conditions_size);
3634 		policy->conditions = NULL;
3635 	}
3636 
3637 	if (policy->route_rules) {
3638 		kfree_data(policy->route_rules, policy->route_rules_size);
3639 		policy->route_rules = NULL;
3640 	}
3641 
3642 	zfree(necp_session_policy_zone, policy);
3643 
3644 	if (necp_debug) {
3645 		NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3646 	}
3647 	return TRUE;
3648 }
3649 
3650 static bool
necp_policy_unapply(struct necp_session_policy * policy)3651 necp_policy_unapply(struct necp_session_policy *policy)
3652 {
3653 	int i = 0;
3654 	if (policy == NULL) {
3655 		return FALSE;
3656 	}
3657 
3658 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3659 
3660 	// Release local uuid mappings
3661 	if (!uuid_is_null(policy->applied_app_uuid)) {
3662 		bool removed_mapping = FALSE;
3663 		if (necp_remove_uuid_app_id_mapping(policy->applied_app_uuid, &removed_mapping, TRUE) && removed_mapping) {
3664 			necp_uuid_app_id_mappings_dirty = TRUE;
3665 			necp_num_uuid_app_id_mappings--;
3666 		}
3667 		uuid_clear(policy->applied_app_uuid);
3668 	}
3669 	if (!uuid_is_null(policy->applied_real_app_uuid)) {
3670 		necp_remove_uuid_app_id_mapping(policy->applied_real_app_uuid, NULL, FALSE);
3671 		uuid_clear(policy->applied_real_app_uuid);
3672 	}
3673 	if (!uuid_is_null(policy->applied_result_uuid)) {
3674 		necp_remove_uuid_service_id_mapping(policy->applied_result_uuid);
3675 		uuid_clear(policy->applied_result_uuid);
3676 	}
3677 
3678 	// Release string mappings
3679 	if (policy->applied_account != NULL) {
3680 		necp_remove_string_to_id_mapping(&necp_account_id_list, policy->applied_account);
3681 		kfree_data(policy->applied_account, policy->applied_account_size);
3682 		policy->applied_account = NULL;
3683 	}
3684 
3685 	// Release route rule
3686 	if (policy->applied_route_rules_id != 0) {
3687 		necp_remove_route_rule(&necp_route_rules, policy->applied_route_rules_id);
3688 		policy->applied_route_rules_id = 0;
3689 	}
3690 
3691 	// Remove socket policies
3692 	for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
3693 		if (policy->kernel_socket_policies[i] != 0) {
3694 			necp_kernel_socket_policy_delete(policy->kernel_socket_policies[i]);
3695 			policy->kernel_socket_policies[i] = 0;
3696 		}
3697 	}
3698 
3699 	// Remove IP output policies
3700 	for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
3701 		if (policy->kernel_ip_output_policies[i] != 0) {
3702 			necp_kernel_ip_output_policy_delete(policy->kernel_ip_output_policies[i]);
3703 			policy->kernel_ip_output_policies[i] = 0;
3704 		}
3705 	}
3706 
3707 	policy->applied = FALSE;
3708 
3709 	return TRUE;
3710 }
3711 
3712 #define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION                 0
3713 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION             1
3714 #define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION                                2
3715 #define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS                   3
3716 struct necp_policy_result_ip_tunnel {
3717 	u_int32_t secondary_result;
3718 	char interface_name[IFXNAMSIZ];
3719 } __attribute__((__packed__));
3720 
3721 struct necp_policy_result_service {
3722 	uuid_t identifier;
3723 	u_int32_t data;
3724 } __attribute__((__packed__));
3725 
3726 static bool
necp_policy_apply(struct necp_session * session,struct necp_session_policy * policy)3727 necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
3728 {
3729 	bool socket_only_conditions = FALSE;
3730 	bool socket_ip_conditions = FALSE;
3731 
3732 	bool socket_layer_non_id_conditions = FALSE;
3733 	bool ip_output_layer_non_id_conditions = FALSE;
3734 	bool ip_output_layer_non_id_only = FALSE;
3735 	bool ip_output_layer_id_condition = FALSE;
3736 	bool ip_output_layer_tunnel_condition_from_id = FALSE;
3737 	bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
3738 	necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
3739 
3740 	u_int64_t master_condition_mask = 0;
3741 	u_int64_t master_condition_negated_mask = 0;
3742 	ifnet_t cond_bound_interface = NULL;
3743 	u_int32_t cond_account_id = 0;
3744 	char *cond_domain = NULL;
3745 	u_int32_t cond_domain_filter = 0;
3746 	char *cond_url = NULL;
3747 	char *cond_custom_entitlement = NULL;
3748 	char *cond_signing_identifier = NULL;
3749 	pid_t cond_pid = 0;
3750 	int32_t cond_pid_version = 0;
3751 	uid_t cond_uid = 0;
3752 	uid_t cond_real_uid = 0;
3753 	necp_app_id cond_app_id = 0;
3754 	necp_app_id cond_real_app_id = 0;
3755 	struct necp_policy_condition_tc_range cond_traffic_class;
3756 	cond_traffic_class.start_tc = 0;
3757 	cond_traffic_class.end_tc = 0;
3758 	u_int16_t cond_protocol = 0;
3759 	union necp_sockaddr_union cond_local_start;
3760 	union necp_sockaddr_union cond_local_end;
3761 	u_int8_t cond_local_prefix = 0;
3762 	union necp_sockaddr_union cond_remote_start;
3763 	union necp_sockaddr_union cond_remote_end;
3764 	u_int8_t cond_remote_prefix = 0;
3765 	u_int32_t cond_client_flags = 0;
3766 	u_int32_t offset = 0;
3767 	u_int8_t ultimate_result = 0;
3768 	u_int32_t secondary_result = 0;
3769 	struct necp_policy_condition_agent_type cond_agent_type = {};
3770 	struct necp_policy_condition_sdk_version cond_sdk_version = {};
3771 	u_int16_t cond_packet_filter_tags = 0;
3772 	u_int16_t cond_scheme_port = 0;
3773 	u_int32_t cond_bound_interface_flags = 0;
3774 	u_int32_t cond_bound_interface_eflags = 0;
3775 	u_int32_t cond_bound_interface_xflags = 0;
3776 	necp_kernel_policy_result_parameter secondary_result_parameter;
3777 	memset(&secondary_result_parameter, 0, sizeof(secondary_result_parameter));
3778 	u_int32_t cond_last_interface_index = 0;
3779 	necp_kernel_policy_result_parameter ultimate_result_parameter;
3780 	memset(&ultimate_result_parameter, 0, sizeof(ultimate_result_parameter));
3781 
3782 	if (policy == NULL) {
3783 		return FALSE;
3784 	}
3785 
3786 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3787 
3788 	// Process conditions
3789 	while (offset < policy->conditions_size) {
3790 		u_int32_t length = 0;
3791 		u_int8_t *value = necp_buffer_get_tlv_value(policy->conditions, offset, &length);
3792 
3793 		u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(value, length);
3794 		u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(value, length);
3795 		bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
3796 		u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(value, length);
3797 		u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
3798 		switch (condition_type) {
3799 		case NECP_POLICY_CONDITION_DEFAULT: {
3800 			socket_ip_conditions = TRUE;
3801 			break;
3802 		}
3803 		case NECP_POLICY_CONDITION_ALL_INTERFACES: {
3804 			master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
3805 			socket_ip_conditions = TRUE;
3806 			break;
3807 		}
3808 		case NECP_POLICY_CONDITION_HAS_CLIENT: {
3809 			master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
3810 			socket_only_conditions = TRUE;
3811 			break;
3812 		}
3813 		case NECP_POLICY_CONDITION_ENTITLEMENT: {
3814 			if (condition_length > 0) {
3815 				if (cond_custom_entitlement == NULL) {
3816 					cond_custom_entitlement = necp_copy_string((char *)condition_value, condition_length);
3817 					if (cond_custom_entitlement != NULL) {
3818 						master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
3819 						socket_only_conditions = TRUE;
3820 					}
3821 				}
3822 			} else {
3823 				master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
3824 				socket_only_conditions = TRUE;
3825 			}
3826 			break;
3827 		}
3828 		case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
3829 			master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
3830 			socket_only_conditions = TRUE;
3831 			break;
3832 		}
3833 		case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
3834 			master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
3835 			socket_only_conditions = TRUE;
3836 			break;
3837 		}
3838 		case NECP_POLICY_CONDITION_SDK_VERSION: {
3839 			if (condition_length >= sizeof(cond_sdk_version)) {
3840 				master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
3841 				memcpy(&cond_sdk_version, condition_value, sizeof(cond_sdk_version));
3842 				socket_only_conditions = TRUE;
3843 			}
3844 			break;
3845 		}
3846 		case NECP_POLICY_CONDITION_DOMAIN: {
3847 			// Make sure there is only one such rule
3848 			if (condition_length > 0 && cond_domain == NULL) {
3849 				const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
3850 
3851 				u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
3852 				cond_domain = necp_create_trimmed_domain((char *)condition_value, condition_length);
3853 				if (cond_domain != NULL) {
3854 					master_condition_mask |= mask_value;
3855 					if (condition_is_negative) {
3856 						master_condition_negated_mask |= mask_value;
3857 					}
3858 					socket_only_conditions = TRUE;
3859 				}
3860 			}
3861 			break;
3862 		}
3863 		case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
3864 			// Make sure there is only one such rule
3865 			if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
3866 				memcpy(&cond_domain_filter, condition_value, sizeof(cond_domain_filter));
3867 				if (cond_domain_filter != 0) {
3868 					master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
3869 					if (condition_is_negative) {
3870 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
3871 					}
3872 					socket_only_conditions = TRUE;
3873 				}
3874 			}
3875 			break;
3876 		}
3877 		case NECP_POLICY_CONDITION_URL: {
3878 			// Make sure there is only one such rule
3879 			if (condition_length > 0 && cond_url == NULL) {
3880 				u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
3881 				cond_url = necp_create_trimmed_domain((char *)condition_value, condition_length);
3882 				if (cond_url != NULL) {
3883 					master_condition_mask |= mask_value;
3884 					if (condition_is_negative) {
3885 						master_condition_negated_mask |= mask_value;
3886 					}
3887 					socket_only_conditions = TRUE;
3888 				}
3889 			}
3890 			break;
3891 		}
3892 		case NECP_POLICY_CONDITION_ACCOUNT: {
3893 			// Make sure there is only one such rule
3894 			if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
3895 				char *string = NULL;
3896 				string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
3897 				if (string != NULL) {
3898 					memcpy(string, condition_value, condition_length);
3899 					string[condition_length] = 0;
3900 					cond_account_id = necp_create_string_to_id_mapping(&necp_account_id_list, string);
3901 					if (cond_account_id != 0) {
3902 						policy->applied_account = string;         // Save the string in parent policy
3903 						policy->applied_account_size = condition_length + 1;
3904 						master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
3905 						if (condition_is_negative) {
3906 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
3907 						}
3908 						socket_only_conditions = TRUE;
3909 					} else {
3910 						kfree_data(string, condition_length + 1);
3911 					}
3912 				}
3913 			}
3914 			break;
3915 		}
3916 		case NECP_POLICY_CONDITION_APPLICATION: {
3917 			// Make sure there is only one such rule, because we save the uuid in the policy
3918 			if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
3919 				bool allocated_mapping = FALSE;
3920 				uuid_t application_uuid;
3921 				memcpy(application_uuid, condition_value, sizeof(uuid_t));
3922 				cond_app_id = necp_create_uuid_app_id_mapping(application_uuid, &allocated_mapping, TRUE);
3923 				if (cond_app_id != 0) {
3924 					if (allocated_mapping) {
3925 						necp_uuid_app_id_mappings_dirty = TRUE;
3926 						necp_num_uuid_app_id_mappings++;
3927 					}
3928 					uuid_copy(policy->applied_app_uuid, application_uuid);
3929 					master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
3930 					if (condition_is_negative) {
3931 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
3932 					}
3933 					socket_only_conditions = TRUE;
3934 				}
3935 			}
3936 			break;
3937 		}
3938 		case NECP_POLICY_CONDITION_REAL_APPLICATION: {
3939 			// Make sure there is only one such rule, because we save the uuid in the policy
3940 			if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
3941 				uuid_t real_application_uuid;
3942 				memcpy(real_application_uuid, condition_value, sizeof(uuid_t));
3943 				cond_real_app_id = necp_create_uuid_app_id_mapping(real_application_uuid, NULL, FALSE);
3944 				if (cond_real_app_id != 0) {
3945 					uuid_copy(policy->applied_real_app_uuid, real_application_uuid);
3946 					master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
3947 					if (condition_is_negative) {
3948 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
3949 					}
3950 					socket_only_conditions = TRUE;
3951 				}
3952 			}
3953 			break;
3954 		}
3955 		case NECP_POLICY_CONDITION_PID: {
3956 			if (condition_length >= sizeof(pid_t)) {
3957 				master_condition_mask |= NECP_KERNEL_CONDITION_PID;
3958 				if (condition_is_negative) {
3959 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
3960 				}
3961 				memcpy(&cond_pid, condition_value, sizeof(cond_pid));
3962 				if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
3963 					memcpy(&cond_pid_version, (condition_value + sizeof(pid_t)), sizeof(cond_pid_version));
3964 				}
3965 				socket_only_conditions = TRUE;
3966 			}
3967 			break;
3968 		}
3969 		case NECP_POLICY_CONDITION_UID: {
3970 			if (condition_length >= sizeof(uid_t)) {
3971 				master_condition_mask |= NECP_KERNEL_CONDITION_UID;
3972 				if (condition_is_negative) {
3973 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
3974 				}
3975 				memcpy(&cond_uid, condition_value, sizeof(cond_uid));
3976 				socket_only_conditions = TRUE;
3977 			}
3978 			break;
3979 		}
3980 		case NECP_POLICY_CONDITION_REAL_UID: {
3981 			if (condition_length >= sizeof(uid_t)) {
3982 				master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
3983 				if (condition_is_negative) {
3984 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
3985 				}
3986 				memcpy(&cond_real_uid, condition_value, sizeof(cond_real_uid));
3987 				socket_only_conditions = TRUE;
3988 			}
3989 			break;
3990 		}
3991 		case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
3992 			if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
3993 				master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
3994 				if (condition_is_negative) {
3995 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
3996 				}
3997 				memcpy(&cond_traffic_class, condition_value, sizeof(cond_traffic_class));
3998 				socket_only_conditions = TRUE;
3999 			}
4000 			break;
4001 		}
4002 		case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4003 			if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4004 				char interface_name[IFXNAMSIZ];
4005 				memcpy(interface_name, condition_value, condition_length);
4006 				interface_name[condition_length - 1] = 0;         // Make sure the string is NULL terminated
4007 				if (ifnet_find_by_name(interface_name, &cond_bound_interface) == 0) {
4008 					master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4009 					if (condition_is_negative) {
4010 						master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4011 					}
4012 				}
4013 				socket_ip_conditions = TRUE;
4014 			}
4015 			break;
4016 		}
4017 		case NECP_POLICY_CONDITION_IP_PROTOCOL:
4018 		case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4019 			if (condition_length >= sizeof(u_int16_t)) {
4020 				master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4021 				if (condition_is_negative) {
4022 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4023 				}
4024 				memcpy(&cond_protocol, condition_value, sizeof(cond_protocol));
4025 				if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4026 					socket_only_conditions = TRUE;
4027 				} else {
4028 					socket_ip_conditions = TRUE;
4029 				}
4030 			}
4031 			break;
4032 		}
4033 		case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4034 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4035 			socket_ip_conditions = TRUE;
4036 			break;
4037 		}
4038 		case NECP_POLICY_CONDITION_LOCAL_ADDR:
4039 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4040 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4041 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4042 				break;
4043 			}
4044 
4045 			cond_local_prefix = address_struct->prefix;
4046 			memcpy(&cond_local_start, &address_struct->address, sizeof(address_struct->address));
4047 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4048 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4049 			if (condition_is_negative) {
4050 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4051 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4052 			}
4053 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4054 				socket_only_conditions = TRUE;
4055 			} else {
4056 				socket_ip_conditions = TRUE;
4057 			}
4058 			break;
4059 		}
4060 		case NECP_POLICY_CONDITION_REMOTE_ADDR:
4061 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4062 			struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4063 			if (!necp_address_is_valid(&address_struct->address.sa)) {
4064 				break;
4065 			}
4066 
4067 			cond_remote_prefix = address_struct->prefix;
4068 			memcpy(&cond_remote_start, &address_struct->address, sizeof(address_struct->address));
4069 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4070 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4071 			if (condition_is_negative) {
4072 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4073 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4074 			}
4075 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4076 				socket_only_conditions = TRUE;
4077 			} else {
4078 				socket_ip_conditions = TRUE;
4079 			}
4080 			break;
4081 		}
4082 		case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4083 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4084 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4085 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4086 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4087 				break;
4088 			}
4089 
4090 			memcpy(&cond_local_start, &address_struct->start_address, sizeof(address_struct->start_address));
4091 			memcpy(&cond_local_end, &address_struct->end_address, sizeof(address_struct->end_address));
4092 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4093 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4094 			if (condition_is_negative) {
4095 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4096 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4097 			}
4098 			if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4099 				socket_only_conditions = TRUE;
4100 			} else {
4101 				socket_ip_conditions = TRUE;
4102 			}
4103 			break;
4104 		}
4105 		case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4106 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4107 			struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4108 			if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4109 			    !necp_address_is_valid(&address_struct->end_address.sa)) {
4110 				break;
4111 			}
4112 
4113 			memcpy(&cond_remote_start, &address_struct->start_address, sizeof(address_struct->start_address));
4114 			memcpy(&cond_remote_end, &address_struct->end_address, sizeof(address_struct->end_address));
4115 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4116 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4117 			if (condition_is_negative) {
4118 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4119 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4120 			}
4121 			if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4122 				socket_only_conditions = TRUE;
4123 			} else {
4124 				socket_ip_conditions = TRUE;
4125 			}
4126 			break;
4127 		}
4128 		case NECP_POLICY_CONDITION_AGENT_TYPE: {
4129 			if (condition_length >= sizeof(cond_agent_type)) {
4130 				master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4131 				memcpy(&cond_agent_type, condition_value, sizeof(cond_agent_type));
4132 				socket_only_conditions = TRUE;
4133 			}
4134 			break;
4135 		}
4136 		case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4137 			if (condition_is_negative) {
4138 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4139 			}
4140 			master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4141 			socket_only_conditions = TRUE;
4142 			if (condition_length >= sizeof(u_int32_t)) {
4143 				memcpy(&cond_client_flags, condition_value, sizeof(cond_client_flags));
4144 			} else {
4145 				// Empty means match on fallback traffic
4146 				cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4147 			}
4148 			break;
4149 		}
4150 		case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4151 			master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4152 			if (condition_is_negative) {
4153 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4154 			}
4155 			socket_only_conditions = TRUE;
4156 			break;
4157 		}
4158 		case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4159 			master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4160 			if (condition_is_negative) {
4161 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4162 			}
4163 			socket_only_conditions = TRUE;
4164 			break;
4165 		}
4166 		case NECP_POLICY_CONDITION_SCHEME_PORT: {
4167 			master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4168 			if (condition_is_negative) {
4169 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4170 			}
4171 			memcpy(&cond_scheme_port, condition_value, sizeof(cond_scheme_port));
4172 			socket_ip_conditions = TRUE;
4173 			break;
4174 		}
4175 		case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4176 			if (condition_length > 0) {
4177 				if (cond_signing_identifier == NULL) {
4178 					cond_signing_identifier = necp_copy_string((char *)condition_value, condition_length);
4179 					if (cond_signing_identifier != NULL) {
4180 						master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4181 						socket_only_conditions = TRUE;
4182 						if (condition_is_negative) {
4183 							master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4184 						}
4185 					}
4186 				}
4187 			}
4188 			break;
4189 		}
4190 		case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4191 			if (condition_length >= sizeof(u_int16_t)) {
4192 				master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4193 				if (condition_is_negative) {
4194 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4195 				}
4196 				memcpy(&cond_packet_filter_tags, condition_value, sizeof(cond_packet_filter_tags));
4197 				socket_ip_conditions = TRUE;
4198 			}
4199 			break;
4200 		}
4201 		case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4202 			master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4203 			if (condition_is_negative) {
4204 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4205 			}
4206 			socket_only_conditions = TRUE;
4207 			break;
4208 		}
4209 		case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4210 			master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4211 			if (condition_is_negative) {
4212 				master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4213 			}
4214 			socket_only_conditions = TRUE;
4215 			break;
4216 		}
4217 		case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4218 			if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4219 				u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4220 				memcpy(&flags, condition_value, sizeof(flags));
4221 				cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4222 				cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4223 				cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4224 				master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4225 				if (condition_is_negative) {
4226 					master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4227 				}
4228 				socket_ip_conditions = TRUE;
4229 			}
4230 			break;
4231 		}
4232 		default: {
4233 			break;
4234 		}
4235 		}
4236 
4237 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4238 	}
4239 
4240 	// Process result
4241 	ultimate_result = necp_policy_get_result_type(policy);
4242 	switch (ultimate_result) {
4243 	case NECP_POLICY_RESULT_PASS: {
4244 		u_int32_t pass_flags = 0;
4245 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4246 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&pass_flags, sizeof(pass_flags))) {
4247 				ultimate_result_parameter.pass_flags = pass_flags;
4248 			}
4249 		}
4250 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4251 			socket_layer_non_id_conditions = TRUE;
4252 			ip_output_layer_id_condition = TRUE;
4253 		} else if (socket_ip_conditions) {
4254 			socket_layer_non_id_conditions = TRUE;
4255 			ip_output_layer_id_condition = TRUE;
4256 			ip_output_layer_non_id_conditions = TRUE;
4257 		}
4258 		break;
4259 	}
4260 	case NECP_POLICY_RESULT_DROP: {
4261 		u_int32_t drop_flags = 0;
4262 		if (necp_policy_result_get_parameter_length_from_buffer(policy->result, policy->result_size) > 0) {
4263 			if (necp_policy_get_result_parameter(policy, (u_int8_t *)&drop_flags, sizeof(drop_flags))) {
4264 				ultimate_result_parameter.drop_flags = drop_flags;
4265 			}
4266 		}
4267 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4268 			socket_layer_non_id_conditions = TRUE;
4269 		} else if (socket_ip_conditions) {
4270 			socket_layer_non_id_conditions = TRUE;
4271 			ip_output_layer_non_id_conditions = TRUE;
4272 			ip_output_layer_non_id_only = TRUE;         // Only apply drop to packets that didn't go through socket layer
4273 		}
4274 		break;
4275 	}
4276 	case NECP_POLICY_RESULT_SKIP: {
4277 		u_int32_t skip_policy_order = 0;
4278 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&skip_policy_order, sizeof(skip_policy_order))) {
4279 			ultimate_result_parameter.skip_policy_order = skip_policy_order;
4280 		}
4281 
4282 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4283 			socket_layer_non_id_conditions = TRUE;
4284 			ip_output_layer_id_condition = TRUE;
4285 		} else if (socket_ip_conditions) {
4286 			socket_layer_non_id_conditions = TRUE;
4287 			ip_output_layer_non_id_conditions = TRUE;
4288 		}
4289 		break;
4290 	}
4291 	case NECP_POLICY_RESULT_SOCKET_DIVERT:
4292 	case NECP_POLICY_RESULT_SOCKET_FILTER: {
4293 		u_int32_t control_unit = 0;
4294 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&control_unit, sizeof(control_unit))) {
4295 			ultimate_result_parameter.flow_divert_control_unit = control_unit;
4296 		}
4297 		socket_layer_non_id_conditions = TRUE;
4298 		break;
4299 	}
4300 	case NECP_POLICY_RESULT_IP_TUNNEL: {
4301 		struct necp_policy_result_ip_tunnel tunnel_parameters;
4302 		u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4303 		if (tunnel_parameters_length > sizeof(u_int32_t) &&
4304 		    tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4305 		    necp_policy_get_result_parameter(policy, (u_int8_t *)&tunnel_parameters, sizeof(tunnel_parameters))) {
4306 			ifnet_t tunnel_interface = NULL;
4307 			tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0;         // Make sure the string is NULL terminated
4308 			if (ifnet_find_by_name(tunnel_parameters.interface_name, &tunnel_interface) == 0) {
4309 				ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4310 				ifnet_release(tunnel_interface);
4311 			}
4312 
4313 			secondary_result = tunnel_parameters.secondary_result;
4314 			if (secondary_result) {
4315 				cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4316 			}
4317 		}
4318 
4319 		if (socket_only_conditions) {         // socket_ip_conditions can be TRUE or FALSE
4320 			socket_layer_non_id_conditions = TRUE;
4321 			ip_output_layer_id_condition = TRUE;
4322 			if (secondary_result) {
4323 				ip_output_layer_tunnel_condition_from_id = TRUE;
4324 			}
4325 		} else if (socket_ip_conditions) {
4326 			socket_layer_non_id_conditions = TRUE;
4327 			ip_output_layer_id_condition = TRUE;
4328 			ip_output_layer_non_id_conditions = TRUE;
4329 			if (secondary_result) {
4330 				ip_output_layer_tunnel_condition_from_id = TRUE;
4331 				ip_output_layer_tunnel_condition_from_non_id = TRUE;
4332 			}
4333 		}
4334 		break;
4335 	}
4336 	case NECP_POLICY_RESULT_USE_NETAGENT:
4337 	case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4338 	case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4339 		uuid_t netagent_uuid;
4340 		if (necp_policy_get_result_parameter(policy, (u_int8_t *)&netagent_uuid, sizeof(netagent_uuid))) {
4341 			ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
4342 			if (ultimate_result_parameter.netagent_id != 0) {
4343 				uuid_copy(policy->applied_result_uuid, netagent_uuid);
4344 				socket_layer_non_id_conditions = TRUE;
4345 			}
4346 		}
4347 		break;
4348 	}
4349 	case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4350 		u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4351 		if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4352 			char interface_name[IFXNAMSIZ];
4353 			ifnet_t scope_interface = NULL;
4354 			necp_policy_get_result_parameter(policy, (u_int8_t *)interface_name, interface_name_length);
4355 			interface_name[interface_name_length - 1] = 0;         // Make sure the string is NULL terminated
4356 			if (ifnet_find_by_name(interface_name, &scope_interface) == 0) {
4357 				ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4358 				socket_layer_non_id_conditions = TRUE;
4359 				ifnet_release(scope_interface);
4360 			}
4361 		}
4362 		break;
4363 	}
4364 	case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4365 		socket_layer_non_id_conditions = TRUE;
4366 		break;
4367 	}
4368 	case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4369 		socket_layer_non_id_conditions = TRUE;
4370 		break;
4371 	}
4372 	case NECP_POLICY_RESULT_ROUTE_RULES: {
4373 		if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4374 			bool has_socket_only_actions = FALSE;
4375 			u_int32_t route_rule_id = necp_create_route_rule(&necp_route_rules, policy->route_rules, policy->route_rules_size, &has_socket_only_actions);
4376 			if (route_rule_id > 0) {
4377 				policy->applied_route_rules_id = route_rule_id;
4378 				ultimate_result_parameter.route_rule_id = route_rule_id;
4379 				if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4380 					socket_layer_non_id_conditions = TRUE;
4381 				} else if (socket_ip_conditions) {
4382 					socket_layer_non_id_conditions = TRUE;
4383 					ip_output_layer_non_id_conditions = TRUE;
4384 					ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4385 				}
4386 			}
4387 		}
4388 		break;
4389 	}
4390 	default: {
4391 		break;
4392 	}
4393 	}
4394 
4395 	if (socket_layer_non_id_conditions) {
4396 		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, ultimate_result, ultimate_result_parameter);
4397 
4398 		if (policy_id == 0) {
4399 			NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4400 			goto fail;
4401 		}
4402 
4403 		cond_ip_output_layer_id = policy_id;
4404 		policy->kernel_socket_policies[0] = policy_id;
4405 	}
4406 
4407 	if (ip_output_layer_non_id_conditions) {
4408 		u_int64_t condition_mask = master_condition_mask;
4409 		if (ip_output_layer_non_id_only) {
4410 			condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4411 		}
4412 
4413 		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, ultimate_result, ultimate_result_parameter);
4414 
4415 		if (policy_id == 0) {
4416 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4417 			goto fail;
4418 		}
4419 
4420 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4421 	}
4422 
4423 	if (ip_output_layer_id_condition) {
4424 		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, ultimate_result, ultimate_result_parameter);
4425 
4426 		if (policy_id == 0) {
4427 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4428 			goto fail;
4429 		}
4430 
4431 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4432 	}
4433 
4434 	// Extra policies for IP Output tunnels for when packets loop back
4435 	if (ip_output_layer_tunnel_condition_from_id) {
4436 		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, secondary_result, secondary_result_parameter);
4437 
4438 		if (policy_id == 0) {
4439 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4440 			goto fail;
4441 		}
4442 
4443 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4444 	}
4445 
4446 	if (ip_output_layer_tunnel_condition_from_id) {
4447 		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, secondary_result, secondary_result_parameter);
4448 
4449 		if (policy_id == 0) {
4450 			NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4451 			goto fail;
4452 		}
4453 
4454 		policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4455 	}
4456 
4457 	policy->applied = TRUE;
4458 	policy->pending_update = FALSE;
4459 	return TRUE;
4460 
4461 fail:
4462 	return FALSE;
4463 }
4464 
4465 static void
necp_policy_apply_all(struct necp_session * session)4466 necp_policy_apply_all(struct necp_session *session)
4467 {
4468 	struct necp_session_policy *policy = NULL;
4469 	struct necp_session_policy *temp_policy = NULL;
4470 	struct kev_necp_policies_changed_data kev_data;
4471 	kev_data.changed_count = 0;
4472 
4473 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
4474 
4475 	// Remove exisiting applied policies
4476 	if (session->dirty) {
4477 		LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4478 			if (policy->pending_deletion) {
4479 				if (policy->applied) {
4480 					necp_policy_unapply(policy);
4481 				}
4482 				// Delete the policy
4483 				necp_policy_delete(session, policy);
4484 			} else if (!policy->applied) {
4485 				necp_policy_apply(session, policy);
4486 			} else if (policy->pending_update) {
4487 				// Must have been applied, but needs an update. Remove and re-add.
4488 				necp_policy_unapply(policy);
4489 				necp_policy_apply(session, policy);
4490 			}
4491 		}
4492 
4493 		necp_kernel_socket_policies_update_uuid_table();
4494 		necp_kernel_socket_policies_reprocess();
4495 		necp_kernel_ip_output_policies_reprocess();
4496 
4497 		// Clear dirty bit flags
4498 		session->dirty = FALSE;
4499 	}
4500 
4501 	lck_rw_done(&necp_kernel_policy_lock);
4502 
4503 	necp_update_all_clients();
4504 	necp_post_change_event(&kev_data);
4505 
4506 	if (necp_debug) {
4507 		NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4508 	}
4509 }
4510 
4511 // Kernel Policy Management
4512 // ---------------------
4513 // Kernel policies are derived from session policies
4514 static necp_kernel_policy_id
necp_kernel_policy_get_new_id(bool socket_level)4515 necp_kernel_policy_get_new_id(bool socket_level)
4516 {
4517 	static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4518 	static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4519 
4520 	necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4521 
4522 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4523 
4524 	if (socket_level) {
4525 		bool wrapped = FALSE;
4526 		do {
4527 			necp_last_kernel_socket_policy_id++;
4528 			if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4529 			    necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4530 				if (wrapped) {
4531 					// Already wrapped, give up
4532 					NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4533 					return NECP_KERNEL_POLICY_ID_NONE;
4534 				}
4535 				necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4536 				wrapped = TRUE;
4537 			}
4538 			newid = necp_last_kernel_socket_policy_id;
4539 		} while (necp_kernel_socket_policy_find(newid) != NULL); // If already used, keep trying
4540 	} else {
4541 		bool wrapped = FALSE;
4542 		do {
4543 			necp_last_kernel_ip_policy_id++;
4544 			if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4545 				if (wrapped) {
4546 					// Already wrapped, give up
4547 					NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4548 					return NECP_KERNEL_POLICY_ID_NONE;
4549 				}
4550 				necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4551 				wrapped = TRUE;
4552 			}
4553 			newid = necp_last_kernel_ip_policy_id;
4554 		} while (necp_kernel_ip_output_policy_find(newid) != NULL); // If already used, keep trying
4555 	}
4556 
4557 	if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4558 		NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4559 		return NECP_KERNEL_POLICY_ID_NONE;
4560 	}
4561 
4562 	return newid;
4563 }
4564 
4565 #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)
4566 
4567 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,u_int32_t cond_account_id,char * cond_domain,u_int32_t cond_domain_filter,char * cond_url,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 * 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,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,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)4568 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, u_int32_t cond_account_id, char *cond_domain, u_int32_t cond_domain_filter, char *cond_url, 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 *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, 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
4569 {
4570 	struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4571 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4572 
4573 	new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4574 
4575 	new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4576 	new_kernel_policy->order = order;
4577 	new_kernel_policy->session_order = session_order;
4578 	new_kernel_policy->session_pid = session_pid;
4579 
4580 	// Sanitize condition mask
4581 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4582 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4583 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4584 	}
4585 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4586 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4587 	}
4588 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4589 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4590 	}
4591 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4592 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4593 	}
4594 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4595 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4596 	}
4597 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4598 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4599 	}
4600 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4601 		new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4602 	}
4603 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4604 
4605 	// Set condition values
4606 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4607 		new_kernel_policy->cond_app_id = cond_app_id;
4608 	}
4609 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4610 		new_kernel_policy->cond_real_app_id = cond_real_app_id;
4611 	}
4612 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4613 		new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4614 	}
4615 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4616 		new_kernel_policy->cond_account_id = cond_account_id;
4617 	}
4618 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
4619 	    (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
4620 		new_kernel_policy->cond_domain = cond_domain;
4621 		new_kernel_policy->cond_domain_dot_count = necp_count_dots(cond_domain, strlen(cond_domain));
4622 	}
4623 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
4624 		new_kernel_policy->cond_domain_filter = cond_domain_filter;
4625 	}
4626 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
4627 		new_kernel_policy->cond_url = cond_url;
4628 	}
4629 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4630 		new_kernel_policy->cond_pid = cond_pid;
4631 		new_kernel_policy->cond_pid_version = cond_pid_version;
4632 	}
4633 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4634 		new_kernel_policy->cond_uid = cond_uid;
4635 	}
4636 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
4637 		new_kernel_policy->cond_real_uid = cond_real_uid;
4638 	}
4639 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4640 		if (cond_bound_interface) {
4641 			ifnet_reference(cond_bound_interface);
4642 		}
4643 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
4644 	}
4645 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4646 		new_kernel_policy->cond_traffic_class = cond_traffic_class;
4647 	}
4648 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4649 		new_kernel_policy->cond_protocol = cond_protocol;
4650 	}
4651 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4652 		memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
4653 	}
4654 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4655 		memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
4656 	}
4657 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4658 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
4659 	}
4660 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4661 		memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
4662 	}
4663 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4664 		memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
4665 	}
4666 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4667 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
4668 	}
4669 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
4670 		memcpy(&new_kernel_policy->cond_agent_type, cond_agent_type, sizeof(*cond_agent_type));
4671 	}
4672 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
4673 		memcpy(&new_kernel_policy->cond_sdk_version, cond_sdk_version, sizeof(*cond_sdk_version));
4674 	}
4675 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
4676 		new_kernel_policy->cond_client_flags = cond_client_flags;
4677 	}
4678 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
4679 		new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
4680 	}
4681 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
4682 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
4683 	}
4684 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
4685 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
4686 	}
4687 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
4688 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
4689 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
4690 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
4691 	}
4692 
4693 	new_kernel_policy->result = result;
4694 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
4695 
4696 	if (necp_debug) {
4697 		NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
4698 	}
4699 	LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
4700 
4701 	return new_kernel_policy ? new_kernel_policy->id : 0;
4702 }
4703 
4704 static struct necp_kernel_socket_policy *
necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)4705 necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
4706 {
4707 	struct necp_kernel_socket_policy *kernel_policy = NULL;
4708 	struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4709 
4710 	if (policy_id == 0) {
4711 		return NULL;
4712 	}
4713 
4714 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
4715 		if (kernel_policy->id == policy_id) {
4716 			return kernel_policy;
4717 		}
4718 	}
4719 
4720 	return NULL;
4721 }
4722 
4723 static bool
necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)4724 necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
4725 {
4726 	struct necp_kernel_socket_policy *policy = NULL;
4727 
4728 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4729 
4730 	policy = necp_kernel_socket_policy_find(policy_id);
4731 	if (policy) {
4732 		LIST_REMOVE(policy, chain);
4733 
4734 		if (policy->cond_bound_interface) {
4735 			ifnet_release(policy->cond_bound_interface);
4736 			policy->cond_bound_interface = NULL;
4737 		}
4738 
4739 		if (policy->cond_domain) {
4740 			kfree_data_addr(policy->cond_domain);
4741 			policy->cond_domain = NULL;
4742 		}
4743 
4744 		if (policy->cond_url) {
4745 			kfree_data_addr(policy->cond_url);
4746 			policy->cond_url = NULL;
4747 		}
4748 
4749 		if (policy->cond_custom_entitlement) {
4750 			kfree_data_addr(policy->cond_custom_entitlement);
4751 			policy->cond_custom_entitlement = NULL;
4752 		}
4753 
4754 		if (policy->cond_signing_identifier) {
4755 			kfree_data_addr(policy->cond_signing_identifier);
4756 			policy->cond_signing_identifier = NULL;
4757 		}
4758 
4759 		zfree(necp_socket_policy_zone, policy);
4760 		return TRUE;
4761 	}
4762 
4763 	return FALSE;
4764 }
4765 
4766 static inline const char *
necp_get_result_description(char * result_string,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)4767 necp_get_result_description(char *result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
4768 {
4769 	uuid_string_t uuid_string;
4770 	switch (result) {
4771 	case NECP_KERNEL_POLICY_RESULT_NONE: {
4772 		snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
4773 		break;
4774 	}
4775 	case NECP_KERNEL_POLICY_RESULT_PASS: {
4776 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
4777 		break;
4778 	}
4779 	case NECP_KERNEL_POLICY_RESULT_SKIP: {
4780 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
4781 		break;
4782 	}
4783 	case NECP_KERNEL_POLICY_RESULT_DROP: {
4784 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
4785 		break;
4786 	}
4787 	case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
4788 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
4789 		break;
4790 	}
4791 	case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
4792 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
4793 		break;
4794 	}
4795 	case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
4796 		ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
4797 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
4798 		break;
4799 	}
4800 	case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
4801 		snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
4802 		break;
4803 	}
4804 	case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
4805 		ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
4806 		snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
4807 		break;
4808 	}
4809 	case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
4810 		snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
4811 		break;
4812 	}
4813 	case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
4814 		snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
4815 		break;
4816 	}
4817 	case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
4818 		int index = 0;
4819 		char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
4820 		struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, result_parameter.route_rule_id);
4821 		if (route_rule != NULL) {
4822 			for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
4823 				if (route_rule->exception_if_indices[index] != 0) {
4824 					ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
4825 					snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
4826 				} else {
4827 					memset(interface_names[index], 0, IFXNAMSIZ);
4828 				}
4829 			}
4830 			switch (route_rule->default_action) {
4831 			case NECP_ROUTE_RULE_DENY_INTERFACE:
4832 			case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
4833 				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)",
4834 				    (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
4835 				    (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
4836 				    (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
4837 				    (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
4838 				    (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
4839 				    (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
4840 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
4841 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4842 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
4843 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4844 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
4845 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4846 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
4847 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4848 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
4849 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4850 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
4851 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4852 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
4853 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4854 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
4855 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4856 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
4857 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4858 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
4859 				break;
4860 			case NECP_ROUTE_RULE_ALLOW_INTERFACE:
4861 				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)",
4862 				    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
4863 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
4864 				    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
4865 				    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
4866 				    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
4867 				    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
4868 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
4869 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
4870 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
4871 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
4872 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
4873 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
4874 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
4875 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
4876 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
4877 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
4878 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
4879 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
4880 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
4881 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
4882 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
4883 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
4884 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
4885 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
4886 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
4887 				    IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
4888 				break;
4889 			case NECP_ROUTE_RULE_QOS_MARKING:
4890 				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)",
4891 				    (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
4892 				    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
4893 				    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
4894 				    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
4895 				    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
4896 				    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
4897 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
4898 				    (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4899 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
4900 				    (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4901 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
4902 				    (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4903 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
4904 				    (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4905 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
4906 				    (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4907 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
4908 				    (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4909 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
4910 				    (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4911 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
4912 				    (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4913 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
4914 				    (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4915 				    (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
4916 				break;
4917 			default:
4918 				snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
4919 				break;
4920 			}
4921 		}
4922 		break;
4923 	}
4924 	case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
4925 		bool found_mapping = FALSE;
4926 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
4927 		if (mapping != NULL) {
4928 			uuid_unparse(mapping->uuid, uuid_string);
4929 			found_mapping = TRUE;
4930 		}
4931 		snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
4932 		break;
4933 	}
4934 	case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
4935 		bool found_mapping = FALSE;
4936 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
4937 		if (mapping != NULL) {
4938 			uuid_unparse(mapping->uuid, uuid_string);
4939 			found_mapping = TRUE;
4940 		}
4941 		snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
4942 		break;
4943 	}
4944 	case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
4945 		bool found_mapping = FALSE;
4946 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(result_parameter.netagent_id);
4947 		if (mapping != NULL) {
4948 			uuid_unparse(mapping->uuid, uuid_string);
4949 			found_mapping = TRUE;
4950 		}
4951 		snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
4952 		break;
4953 	}
4954 	default: {
4955 		snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
4956 		break;
4957 	}
4958 	}
4959 	return result_string;
4960 }
4961 
4962 static void
necp_kernel_socket_policies_dump_all(void)4963 necp_kernel_socket_policies_dump_all(void)
4964 {
4965 	if (necp_debug) {
4966 		struct necp_kernel_socket_policy *policy = NULL;
4967 		int policy_i;
4968 		int app_i;
4969 		char result_string[MAX_RESULT_STRING_LEN];
4970 		char proc_name_string[MAXCOMLEN + 1];
4971 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
4972 		memset(proc_name_string, 0, MAXCOMLEN + 1);
4973 
4974 		NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
4975 		NECPLOG0(LOG_DEBUG, "-----------\n");
4976 		for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
4977 			policy = necp_kernel_socket_policies_app_layer_map[policy_i];
4978 			proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
4979 			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));
4980 		}
4981 		if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
4982 			NECPLOG0(LOG_DEBUG, "-----------\n");
4983 		}
4984 
4985 		NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
4986 		NECPLOG0(LOG_DEBUG, "-----------\n");
4987 		for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
4988 			NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
4989 			for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
4990 				policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
4991 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
4992 				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));
4993 			}
4994 			NECPLOG0(LOG_DEBUG, "-----------\n");
4995 		}
4996 	}
4997 }
4998 
4999 static inline bool
necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy * upper_policy,struct necp_kernel_socket_policy * lower_policy)5000 necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5001 {
5002 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5003 		// Drop always cancels out lower policies
5004 		return TRUE;
5005 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5006 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5007 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5008 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5009 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5010 	    upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5011 		// Filters and route rules never cancel out lower policies
5012 		return FALSE;
5013 	} else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5014 		if (upper_policy->session_order != lower_policy->session_order) {
5015 			// A skip cannot override a policy of a different session
5016 			return FALSE;
5017 		} else {
5018 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
5019 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5020 				// This policy is beyond the skip
5021 				return FALSE;
5022 			} else {
5023 				// This policy is inside the skip
5024 				return TRUE;
5025 			}
5026 		}
5027 	}
5028 
5029 	// A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5030 	return TRUE;
5031 }
5032 
5033 static bool
necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy * policy,struct necp_kernel_socket_policy ** policy_array,int valid_indices)5034 necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy **policy_array, int valid_indices)
5035 {
5036 	bool can_skip = FALSE;
5037 	u_int32_t highest_skip_session_order = 0;
5038 	u_int32_t highest_skip_order = 0;
5039 	int i;
5040 	for (i = 0; i < valid_indices; i++) {
5041 		struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5042 
5043 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
5044 		if (can_skip) {
5045 			if (highest_skip_session_order != compared_policy->session_order ||
5046 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5047 				// If we've moved on to the next session, or passed the skip window
5048 				highest_skip_session_order = 0;
5049 				highest_skip_order = 0;
5050 				can_skip = FALSE;
5051 			} else {
5052 				// If this policy is also a skip, in can increase the skip window
5053 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5054 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5055 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5056 					}
5057 				}
5058 				continue;
5059 			}
5060 		}
5061 
5062 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5063 			// This policy is a skip. Set the skip window accordingly
5064 			can_skip = TRUE;
5065 			highest_skip_session_order = compared_policy->session_order;
5066 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5067 		}
5068 
5069 		// The result of the compared policy must be able to block out this policy result
5070 		if (!necp_kernel_socket_policy_results_overlap(compared_policy, policy)) {
5071 			continue;
5072 		}
5073 
5074 		// If new policy matches All Interfaces, compared policy must also
5075 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5076 			continue;
5077 		}
5078 
5079 		// If new policy matches Local Networks, compared policy must also
5080 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
5081 			continue;
5082 		}
5083 
5084 		// Default makes lower policies unecessary always
5085 		if (compared_policy->condition_mask == 0) {
5086 			return TRUE;
5087 		}
5088 
5089 		// Compared must be more general than policy, and include only conditions within policy
5090 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5091 			continue;
5092 		}
5093 
5094 		// Negative conditions must match for the overlapping conditions
5095 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5096 			continue;
5097 		}
5098 
5099 		if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5100 		    compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5101 		    strcmp(compared_policy->cond_domain, policy->cond_domain) != 0) {
5102 			continue;
5103 		}
5104 
5105 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5106 		    compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5107 			continue;
5108 		}
5109 
5110 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5111 		    strcmp(compared_policy->cond_url, policy->cond_url) != 0) {
5112 			continue;
5113 		}
5114 
5115 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5116 		    strcmp(compared_policy->cond_custom_entitlement, policy->cond_custom_entitlement) != 0) {
5117 			continue;
5118 		}
5119 
5120 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5121 		    compared_policy->cond_account_id != policy->cond_account_id) {
5122 			continue;
5123 		}
5124 
5125 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5126 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
5127 			continue;
5128 		}
5129 
5130 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5131 		    compared_policy->cond_app_id != policy->cond_app_id) {
5132 			continue;
5133 		}
5134 
5135 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5136 		    compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5137 			continue;
5138 		}
5139 
5140 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5141 		    (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5142 			continue;
5143 		}
5144 
5145 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5146 		    compared_policy->cond_uid != policy->cond_uid) {
5147 			continue;
5148 		}
5149 
5150 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5151 		    compared_policy->cond_real_uid != policy->cond_real_uid) {
5152 			continue;
5153 		}
5154 
5155 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5156 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5157 			continue;
5158 		}
5159 
5160 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5161 		    compared_policy->cond_protocol != policy->cond_protocol) {
5162 			continue;
5163 		}
5164 
5165 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5166 		    compared_policy->cond_client_flags != policy->cond_client_flags) {
5167 			continue;
5168 		}
5169 
5170 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5171 		    !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5172 		    compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5173 			continue;
5174 		}
5175 
5176 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5177 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5178 				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&policy->cond_local_end, (struct sockaddr *)&compared_policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_end)) {
5179 					continue;
5180 				}
5181 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5182 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5183 				    !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
5184 					continue;
5185 				}
5186 			}
5187 		}
5188 
5189 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5190 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5191 				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&policy->cond_remote_end, (struct sockaddr *)&compared_policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_end)) {
5192 					continue;
5193 				}
5194 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5195 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5196 				    !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
5197 					continue;
5198 				}
5199 			}
5200 		}
5201 
5202 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5203 		    memcmp(&compared_policy->cond_agent_type, &policy->cond_agent_type, sizeof(policy->cond_agent_type)) == 0) {
5204 			continue;
5205 		}
5206 
5207 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5208 		    memcmp(&compared_policy->cond_sdk_version, &policy->cond_sdk_version, sizeof(policy->cond_sdk_version)) == 0) {
5209 			continue;
5210 		}
5211 
5212 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5213 		    memcmp(&compared_policy->cond_packet_filter_tags, &policy->cond_packet_filter_tags, sizeof(policy->cond_packet_filter_tags)) == 0) {
5214 			continue;
5215 		}
5216 
5217 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5218 		    memcmp(&compared_policy->cond_scheme_port, &policy->cond_scheme_port, sizeof(policy->cond_scheme_port)) == 0) {
5219 			continue;
5220 		}
5221 
5222 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5223 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5224 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5225 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5226 			continue;
5227 		}
5228 
5229 		return TRUE;
5230 	}
5231 
5232 	return FALSE;
5233 }
5234 
5235 static bool
necp_kernel_socket_policies_reprocess(void)5236 necp_kernel_socket_policies_reprocess(void)
5237 {
5238 	int app_i;
5239 	int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5240 	int app_layer_current_free_index = 0;
5241 	struct necp_kernel_socket_policy *kernel_policy = NULL;
5242 
5243 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5244 
5245 	// Reset mask to 0
5246 	necp_kernel_application_policies_condition_mask = 0;
5247 	necp_kernel_socket_policies_condition_mask = 0;
5248 	necp_kernel_application_policies_count = 0;
5249 	necp_kernel_socket_policies_count = 0;
5250 	necp_kernel_socket_policies_non_app_count = 0;
5251 
5252 	// Reset all maps to NULL
5253 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5254 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5255 			kfree_type(struct necp_kernel_socket_policy *,
5256 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5257 			    necp_kernel_socket_policies_map[app_i]);
5258 			necp_kernel_socket_policies_map[app_i] = NULL;
5259 		}
5260 
5261 		// Init counts
5262 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5263 	}
5264 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5265 		kfree_type(struct necp_kernel_socket_policy *,
5266 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5267 		    necp_kernel_socket_policies_app_layer_map);
5268 	}
5269 	necp_kernel_socket_policies_app_layer_map = NULL;
5270 	necp_kernel_socket_policies_app_layer_map_count = 0;
5271 
5272 	// Create masks and counts
5273 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5274 		// App layer mask/count
5275 		necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5276 		necp_kernel_application_policies_count++;
5277 		necp_kernel_socket_policies_app_layer_map_count++;
5278 
5279 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5280 			// Agent type conditions only apply to app layer
5281 			continue;
5282 		}
5283 
5284 		// Update socket layer bucket mask/counts
5285 		necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5286 		necp_kernel_socket_policies_count++;
5287 
5288 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5289 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5290 			necp_kernel_socket_policies_non_app_count++;
5291 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5292 				necp_kernel_socket_policies_map_counts[app_i]++;
5293 			}
5294 		} else {
5295 			necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5296 		}
5297 	}
5298 
5299 	// Allocate maps
5300 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5301 		if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5302 			// Allocate a NULL-terminated array of policy pointers for each bucket
5303 			necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5304 			    necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5305 			if (necp_kernel_socket_policies_map[app_i] == NULL) {
5306 				goto fail;
5307 			}
5308 		}
5309 		bucket_current_free_index[app_i] = 0;
5310 	}
5311 	necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5312 	    necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5313 	if (necp_kernel_socket_policies_app_layer_map == NULL) {
5314 		goto fail;
5315 	}
5316 
5317 	// Fill out maps
5318 	LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5319 		// Add app layer policies
5320 		if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(kernel_policy, necp_kernel_socket_policies_app_layer_map, app_layer_current_free_index)) {
5321 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5322 			app_layer_current_free_index++;
5323 			necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5324 		}
5325 
5326 		if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5327 			// Agent type conditions only apply to app layer
5328 			continue;
5329 		}
5330 
5331 		// Add socket policies
5332 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5333 		    kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5334 			for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5335 				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])) {
5336 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5337 					bucket_current_free_index[app_i]++;
5338 					(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5339 				}
5340 			}
5341 		} else {
5342 			app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5343 			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])) {
5344 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5345 				bucket_current_free_index[app_i]++;
5346 				(necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5347 			}
5348 		}
5349 	}
5350 	necp_kernel_socket_policies_dump_all();
5351 	BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5352 	return TRUE;
5353 
5354 fail:
5355 	// Free memory, reset masks to 0
5356 	necp_kernel_application_policies_condition_mask = 0;
5357 	necp_kernel_socket_policies_condition_mask = 0;
5358 	necp_kernel_application_policies_count = 0;
5359 	necp_kernel_socket_policies_count = 0;
5360 	necp_kernel_socket_policies_non_app_count = 0;
5361 	for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5362 		if (necp_kernel_socket_policies_map[app_i] != NULL) {
5363 			kfree_type(struct necp_kernel_socket_policy *,
5364 			    necp_kernel_socket_policies_map_counts[app_i] + 1,
5365 			    necp_kernel_socket_policies_map[app_i]);
5366 			necp_kernel_socket_policies_map[app_i] = NULL;
5367 		}
5368 		necp_kernel_socket_policies_map_counts[app_i] = 0;
5369 	}
5370 	if (necp_kernel_socket_policies_app_layer_map != NULL) {
5371 		kfree_type(struct necp_kernel_socket_policy *,
5372 		    necp_kernel_socket_policies_app_layer_map_count + 1,
5373 		    necp_kernel_socket_policies_app_layer_map);
5374 		necp_kernel_socket_policies_app_layer_map = NULL;
5375 	}
5376 	necp_kernel_socket_policies_app_layer_map_count = 0;
5377 	return FALSE;
5378 }
5379 
5380 static u_int32_t
necp_get_new_string_id(void)5381 necp_get_new_string_id(void)
5382 {
5383 	static u_int32_t necp_last_string_id = 0;
5384 
5385 	u_int32_t newid = 0;
5386 
5387 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5388 
5389 	bool wrapped = FALSE;
5390 	do {
5391 		necp_last_string_id++;
5392 		if (necp_last_string_id < 1) {
5393 			if (wrapped) {
5394 				// Already wrapped, give up
5395 				NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5396 				return 0;
5397 			}
5398 			necp_last_string_id = 1;
5399 			wrapped = TRUE;
5400 		}
5401 		newid = necp_last_string_id;
5402 	} while (necp_lookup_string_with_id_locked(&necp_account_id_list, newid) != NULL); // If already used, keep trying
5403 
5404 	if (newid == 0) {
5405 		NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5406 		return 0;
5407 	}
5408 
5409 	return newid;
5410 }
5411 
5412 static struct necp_string_id_mapping *
necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list * list,char * string)5413 necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string)
5414 {
5415 	struct necp_string_id_mapping *searchentry = NULL;
5416 	struct necp_string_id_mapping *foundentry = NULL;
5417 
5418 	LIST_FOREACH(searchentry, list, chain) {
5419 		if (strcmp(searchentry->string, string) == 0) {
5420 			foundentry = searchentry;
5421 			break;
5422 		}
5423 	}
5424 
5425 	return foundentry;
5426 }
5427 
5428 static struct necp_string_id_mapping *
necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list * list,u_int32_t local_id)5429 necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5430 {
5431 	struct necp_string_id_mapping *searchentry = NULL;
5432 	struct necp_string_id_mapping *foundentry = NULL;
5433 
5434 	LIST_FOREACH(searchentry, list, chain) {
5435 		if (searchentry->id == local_id) {
5436 			foundentry = searchentry;
5437 			break;
5438 		}
5439 	}
5440 
5441 	return foundentry;
5442 }
5443 
5444 static u_int32_t
necp_create_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string)5445 necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
5446 {
5447 	u_int32_t string_id = 0;
5448 	struct necp_string_id_mapping *existing_mapping = NULL;
5449 
5450 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5451 
5452 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5453 	if (existing_mapping != NULL) {
5454 		string_id = existing_mapping->id;
5455 		os_ref_retain_locked(&existing_mapping->refcount);
5456 	} else {
5457 		struct necp_string_id_mapping *new_mapping = NULL;
5458 		new_mapping = kalloc_type(struct necp_string_id_mapping,
5459 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5460 
5461 		size_t length = strlen(string) + 1;
5462 		new_mapping->string = (char *)kalloc_data(length, Z_WAITOK);
5463 		if (new_mapping->string != NULL) {
5464 			memcpy(new_mapping->string, string, length);
5465 			new_mapping->id = necp_get_new_string_id();
5466 			os_ref_init(&new_mapping->refcount, &necp_refgrp);
5467 			LIST_INSERT_HEAD(list, new_mapping, chain);
5468 			string_id = new_mapping->id;
5469 		} else {
5470 			kfree_type(struct necp_string_id_mapping, new_mapping);
5471 			new_mapping = NULL;
5472 		}
5473 	}
5474 	return string_id;
5475 }
5476 
5477 static bool
necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list * list,char * string)5478 necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
5479 {
5480 	struct necp_string_id_mapping *existing_mapping = NULL;
5481 
5482 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5483 
5484 	existing_mapping = necp_lookup_string_to_id_locked(list, string);
5485 	if (existing_mapping != NULL) {
5486 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
5487 			LIST_REMOVE(existing_mapping, chain);
5488 			kfree_data_addr(existing_mapping->string);
5489 			kfree_type(struct necp_string_id_mapping, existing_mapping);
5490 		}
5491 		return TRUE;
5492 	}
5493 
5494 	return FALSE;
5495 }
5496 
5497 static struct necp_domain_filter *
necp_lookup_domain_filter(struct necp_domain_filter_list * list,u_int32_t filter_id)5498 necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5499 {
5500 	struct necp_domain_filter *searchfilter = NULL;
5501 	struct necp_domain_filter *foundfilter = NULL;
5502 
5503 	LIST_FOREACH(searchfilter, list, chain) {
5504 		if (searchfilter->id == filter_id) {
5505 			foundfilter = searchfilter;
5506 			break;
5507 		}
5508 	}
5509 
5510 	return foundfilter;
5511 }
5512 
5513 static u_int32_t
necp_get_new_domain_filter_id(void)5514 necp_get_new_domain_filter_id(void)
5515 {
5516 	static u_int32_t necp_last_filter_id = 0;
5517 
5518 	u_int32_t newid = 0;
5519 
5520 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5521 
5522 	bool wrapped = FALSE;
5523 	do {
5524 		necp_last_filter_id++;
5525 		if (necp_last_filter_id < 1) {
5526 			if (wrapped) {
5527 				// Already wrapped, give up
5528 				NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5529 				return 0;
5530 			}
5531 			necp_last_filter_id = 1;
5532 			wrapped = TRUE;
5533 		}
5534 		newid = necp_last_filter_id;
5535 	} while (necp_lookup_domain_filter(&necp_global_domain_filter_list, newid) != NULL); // If already used, keep trying
5536 
5537 	if (newid == 0) {
5538 		NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5539 		return 0;
5540 	}
5541 
5542 	return newid;
5543 }
5544 
5545 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)5546 necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5547 {
5548 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5549 
5550 	struct necp_domain_filter *new_filter = NULL;
5551 	new_filter = kalloc_type(struct necp_domain_filter,
5552 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5553 
5554 	new_filter->filter = filter;
5555 	new_filter->id = necp_get_new_domain_filter_id();
5556 	LIST_INSERT_HEAD(list, new_filter, chain);
5557 	LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5558 	os_ref_init(&new_filter->refcount, &necp_refgrp);
5559 
5560 	return new_filter->id;
5561 }
5562 
5563 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)5564 necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5565 {
5566 	struct necp_domain_filter *existing_filter = NULL;
5567 
5568 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5569 
5570 	existing_filter = necp_lookup_domain_filter(list, filter_id);
5571 	if (existing_filter != NULL) {
5572 		if (os_ref_release_locked(&existing_filter->refcount) == 0) {
5573 			LIST_REMOVE(existing_filter, chain);
5574 			LIST_REMOVE(existing_filter, owner_chain);
5575 			net_bloom_filter_destroy(existing_filter->filter);
5576 			kfree_type(struct necp_domain_filter, existing_filter);
5577 		}
5578 		return true;
5579 	}
5580 
5581 	return false;
5582 }
5583 
5584 #define NECP_FIRST_VALID_ROUTE_RULE_ID 1
5585 #define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
5586 static u_int32_t
necp_get_new_route_rule_id(bool aggregate)5587 necp_get_new_route_rule_id(bool aggregate)
5588 {
5589 	static u_int32_t necp_last_route_rule_id = 0;
5590 	static u_int32_t necp_last_aggregate_route_rule_id = 0;
5591 
5592 	u_int32_t newid = 0;
5593 
5594 	if (!aggregate) {
5595 		// Main necp_kernel_policy_lock protects non-aggregate rule IDs
5596 		LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5597 
5598 		bool wrapped = FALSE;
5599 		do {
5600 			necp_last_route_rule_id++;
5601 			if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
5602 			    necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5603 				if (wrapped) {
5604 					// Already wrapped, give up
5605 					NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
5606 					return 0;
5607 				}
5608 				necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
5609 				wrapped = TRUE;
5610 			}
5611 			newid = necp_last_route_rule_id;
5612 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5613 	} else {
5614 		// necp_route_rule_lock protects aggregate rule IDs
5615 		LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
5616 
5617 		bool wrapped = FALSE;
5618 		do {
5619 			necp_last_aggregate_route_rule_id++;
5620 			if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5621 				if (wrapped) {
5622 					// Already wrapped, give up
5623 					NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
5624 					return 0;
5625 				}
5626 				necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
5627 				wrapped = TRUE;
5628 			}
5629 			newid = necp_last_aggregate_route_rule_id;
5630 		} while (necp_lookup_route_rule_locked(&necp_route_rules, newid) != NULL); // If already used, keep trying
5631 	}
5632 
5633 	if (newid == 0) {
5634 		NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
5635 		return 0;
5636 	}
5637 
5638 	return newid;
5639 }
5640 
5641 static struct necp_route_rule *
necp_lookup_route_rule_locked(struct necp_route_rule_list * list,u_int32_t route_rule_id)5642 necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5643 {
5644 	struct necp_route_rule *searchentry = NULL;
5645 	struct necp_route_rule *foundentry = NULL;
5646 
5647 	LIST_FOREACH(searchentry, list, chain) {
5648 		if (searchentry->id == route_rule_id) {
5649 			foundentry = searchentry;
5650 			break;
5651 		}
5652 	}
5653 
5654 	return foundentry;
5655 }
5656 
5657 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_int32_t * if_indices,u_int8_t * if_actions,uuid_t netagent_uuid,uuid_t match_netagent_uuid,u_int32_t control_unit,u_int32_t effective_type)5658 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_int32_t *if_indices, u_int8_t *if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
5659 {
5660 	struct necp_route_rule *searchentry = NULL;
5661 	struct necp_route_rule *foundentry = NULL;
5662 
5663 	LIST_FOREACH(searchentry, list, chain) {
5664 		if (searchentry->default_action == default_action &&
5665 		    searchentry->cellular_action == cellular_action &&
5666 		    searchentry->wifi_action == wifi_action &&
5667 		    searchentry->wired_action == wired_action &&
5668 		    searchentry->expensive_action == expensive_action &&
5669 		    searchentry->constrained_action == constrained_action &&
5670 		    searchentry->companion_action == companion_action &&
5671 		    searchentry->control_unit == control_unit &&
5672 		    searchentry->effective_type == effective_type) {
5673 			bool match_failed = FALSE;
5674 			size_t index_a = 0;
5675 			size_t index_b = 0;
5676 			size_t count_a = 0;
5677 			size_t count_b = 0;
5678 			for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
5679 				bool found_index = FALSE;
5680 				if (searchentry->exception_if_indices[index_a] == 0) {
5681 					break;
5682 				}
5683 				count_a++;
5684 				for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
5685 					if (if_indices[index_b] == 0) {
5686 						break;
5687 					}
5688 					if (index_b >= count_b) {
5689 						count_b = index_b + 1;
5690 					}
5691 					if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
5692 					    searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
5693 						found_index = TRUE;
5694 						break;
5695 					}
5696 				}
5697 				if (!found_index) {
5698 					match_failed = TRUE;
5699 					break;
5700 				}
5701 			}
5702 
5703 			if (match_failed || count_a != count_b) {
5704 				continue;
5705 			}
5706 
5707 			bool has_agent_a = !uuid_is_null(netagent_uuid);
5708 			bool has_agent_b = (searchentry->netagent_id != 0);
5709 			if (has_agent_a != has_agent_b) {
5710 				continue;
5711 			}
5712 
5713 			if (has_agent_a) {
5714 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->netagent_id);
5715 				if (mapping == NULL) {
5716 					// Bad mapping, doesn't match
5717 					continue;
5718 				}
5719 				if (uuid_compare(mapping->uuid, netagent_uuid) != 0) {
5720 					// UUIDs don't match
5721 					continue;
5722 				}
5723 			}
5724 
5725 			bool has_match_agent_a = !uuid_is_null(match_netagent_uuid);
5726 			bool has_match_agent_b = (searchentry->match_netagent_id != 0);
5727 			if (has_match_agent_a != has_match_agent_b) {
5728 				continue;
5729 			}
5730 
5731 			if (has_match_agent_a) {
5732 				struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(searchentry->match_netagent_id);
5733 				if (mapping == NULL) {
5734 					// Bad mapping, doesn't match
5735 					continue;
5736 				}
5737 				if (uuid_compare(mapping->uuid, match_netagent_uuid) != 0) {
5738 					// UUIDs don't match
5739 					continue;
5740 				}
5741 			}
5742 
5743 			// Rules match!
5744 			foundentry = searchentry;
5745 			break;
5746 		}
5747 	}
5748 
5749 	return foundentry;
5750 }
5751 
5752 static u_int32_t
necp_create_route_rule(struct necp_route_rule_list * list,u_int8_t * route_rules_array,u_int32_t route_rules_array_size,bool * has_socket_only_actions)5753 necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size,
5754     bool *has_socket_only_actions)
5755 {
5756 	size_t offset = 0;
5757 	u_int32_t route_rule_id = 0;
5758 	struct necp_route_rule *existing_rule = NULL;
5759 	u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
5760 	u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
5761 	u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
5762 	u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
5763 	u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
5764 	u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
5765 	u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
5766 	u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
5767 	size_t num_valid_indices = 0;
5768 	memset(&if_indices, 0, sizeof(if_indices));
5769 	u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
5770 	memset(&if_actions, 0, sizeof(if_actions));
5771 
5772 	uuid_t netagent_uuid = {};
5773 
5774 	uuid_t match_netagent_uuid = {};
5775 	uint32_t control_unit = 0;
5776 	uint32_t effective_type = 0;
5777 
5778 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5779 
5780 	if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
5781 		return 0;
5782 	}
5783 
5784 	// Process rules
5785 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
5786 		ifnet_t rule_interface = NULL;
5787 		char interface_name[IFXNAMSIZ];
5788 		u_int32_t length = 0;
5789 		u_int8_t *value = necp_buffer_get_tlv_value(route_rules_array, offset, &length);
5790 
5791 		if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
5792 			// Invalid TLV goes beyond end of the rules array
5793 			break;
5794 		}
5795 
5796 		// Increment offset for the next time through the loop
5797 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
5798 
5799 		u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(value, length);
5800 		u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(value, length);
5801 		u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(value, length);
5802 		u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(value, length);
5803 
5804 		if (rule_action == NECP_ROUTE_RULE_NONE) {
5805 			// Don't allow an explicit rule to be None action
5806 			continue;
5807 		}
5808 
5809 		if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
5810 		    rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
5811 			if (rule_length < sizeof(uuid_t)) {
5812 				// Too short, skip
5813 				continue;
5814 			}
5815 
5816 			if (!uuid_is_null(netagent_uuid)) {
5817 				if (uuid_compare(netagent_uuid, rule_value) != 0) {
5818 					// UUIDs don't match, skip
5819 					continue;
5820 				}
5821 			} else {
5822 				// Copy out agent UUID
5823 				memcpy(netagent_uuid, rule_value, sizeof(netagent_uuid));
5824 			}
5825 
5826 			// Adjust remaining length
5827 			rule_value += sizeof(netagent_uuid);
5828 			rule_length -= sizeof(netagent_uuid);
5829 			*has_socket_only_actions = true;
5830 		} else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
5831 			if (rule_length < sizeof(control_unit)) {
5832 				// Too short, skip
5833 				continue;
5834 			}
5835 
5836 			memcpy(&control_unit, rule_value, sizeof(control_unit));
5837 
5838 			// Adjust remaining length
5839 			rule_value += sizeof(control_unit);
5840 			rule_length -= sizeof(control_unit);
5841 			*has_socket_only_actions = true;
5842 		} else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
5843 			if (rule_length < sizeof(effective_type)) {
5844 				// Too short, skip
5845 				continue;
5846 			}
5847 
5848 			memcpy(&effective_type, rule_value, sizeof(effective_type));
5849 
5850 			// Adjust remaining length
5851 			rule_value += sizeof(effective_type);
5852 			rule_length -= sizeof(effective_type);
5853 		}
5854 
5855 		if (rule_length == 0) {
5856 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
5857 				cellular_action = rule_action;
5858 			}
5859 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
5860 				wifi_action = rule_action;
5861 			}
5862 			if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
5863 				wired_action = rule_action;
5864 			}
5865 			if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
5866 				expensive_action = rule_action;
5867 			}
5868 			if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
5869 				constrained_action = rule_action;
5870 			}
5871 			if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
5872 				companion_action = rule_action;
5873 			}
5874 			if (rule_flags == 0) {
5875 				default_action = rule_action;
5876 			}
5877 			continue;
5878 		} else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
5879 			if (rule_length == sizeof(uuid_t)) {
5880 				memcpy(match_netagent_uuid, rule_value, sizeof(match_netagent_uuid));
5881 				default_action = rule_action;
5882 			}
5883 			continue;
5884 		}
5885 
5886 		if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
5887 			continue;
5888 		}
5889 
5890 		if (rule_length <= IFXNAMSIZ) {
5891 			memcpy(interface_name, rule_value, rule_length);
5892 			interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
5893 			if (ifnet_find_by_name(interface_name, &rule_interface) == 0) {
5894 				if_actions[num_valid_indices] = rule_action;
5895 				if_indices[num_valid_indices++] = rule_interface->if_index;
5896 				ifnet_release(rule_interface);
5897 			}
5898 		}
5899 	}
5900 
5901 	existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
5902 	if (existing_rule != NULL) {
5903 		route_rule_id = existing_rule->id;
5904 		os_ref_retain_locked(&existing_rule->refcount);
5905 	} else {
5906 		struct necp_route_rule *new_rule = NULL;
5907 		new_rule = kalloc_type(struct necp_route_rule,
5908 		    Z_WAITOK | Z_ZERO | Z_NOFAIL);
5909 		route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
5910 		if (!uuid_is_null(netagent_uuid)) {
5911 			new_rule->netagent_id = necp_create_uuid_service_id_mapping(netagent_uuid);
5912 		}
5913 		if (!uuid_is_null(match_netagent_uuid)) {
5914 			new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(match_netagent_uuid);
5915 		}
5916 		new_rule->effective_type = effective_type;
5917 		new_rule->control_unit = control_unit;
5918 		new_rule->default_action = default_action;
5919 		new_rule->cellular_action = cellular_action;
5920 		new_rule->wifi_action = wifi_action;
5921 		new_rule->wired_action = wired_action;
5922 		new_rule->expensive_action = expensive_action;
5923 		new_rule->constrained_action =  constrained_action;
5924 		new_rule->companion_action =  companion_action;
5925 		memcpy(&new_rule->exception_if_indices, &if_indices, sizeof(if_indices));
5926 		memcpy(&new_rule->exception_if_actions, &if_actions, sizeof(if_actions));
5927 		os_ref_init(&new_rule->refcount, &necp_refgrp);
5928 		LIST_INSERT_HEAD(list, new_rule, chain);
5929 	}
5930 	return route_rule_id;
5931 }
5932 
5933 static void
necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)5934 necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
5935 {
5936 	if (rule_id) {
5937 		lck_rw_lock_exclusive(&necp_route_rule_lock);
5938 
5939 		struct necp_aggregate_route_rule *existing_rule = NULL;
5940 		struct necp_aggregate_route_rule *tmp_rule = NULL;
5941 
5942 		LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
5943 			int index = 0;
5944 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
5945 				u_int32_t route_rule_id = existing_rule->rule_ids[index];
5946 				if (route_rule_id == rule_id) {
5947 					LIST_REMOVE(existing_rule, chain);
5948 					kfree_type(struct necp_aggregate_route_rule, existing_rule);
5949 					break;
5950 				}
5951 			}
5952 		}
5953 
5954 		lck_rw_done(&necp_route_rule_lock);
5955 	}
5956 }
5957 
5958 static bool
necp_remove_route_rule(struct necp_route_rule_list * list,u_int32_t route_rule_id)5959 necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5960 {
5961 	struct necp_route_rule *existing_rule = NULL;
5962 
5963 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5964 
5965 	existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
5966 	if (existing_rule != NULL) {
5967 		if (os_ref_release_locked(&existing_rule->refcount) == 0) {
5968 			necp_remove_aggregate_route_rule_for_id(existing_rule->id);
5969 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->netagent_id);
5970 			necp_remove_uuid_service_id_mapping_with_service_id(existing_rule->match_netagent_id);
5971 			LIST_REMOVE(existing_rule, chain);
5972 			kfree_type(struct necp_route_rule, existing_rule);
5973 		}
5974 		return TRUE;
5975 	}
5976 
5977 	return FALSE;
5978 }
5979 
5980 static struct necp_aggregate_route_rule *
necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)5981 necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
5982 {
5983 	struct necp_aggregate_route_rule *searchentry = NULL;
5984 	struct necp_aggregate_route_rule *foundentry = NULL;
5985 
5986 	lck_rw_lock_shared(&necp_route_rule_lock);
5987 
5988 	LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
5989 		if (searchentry->id == route_rule_id) {
5990 			foundentry = searchentry;
5991 			break;
5992 		}
5993 	}
5994 
5995 	lck_rw_done(&necp_route_rule_lock);
5996 
5997 	return foundentry;
5998 }
5999 
6000 static u_int32_t
necp_create_aggregate_route_rule(u_int32_t * rule_ids)6001 necp_create_aggregate_route_rule(u_int32_t *rule_ids)
6002 {
6003 	u_int32_t aggregate_route_rule_id = 0;
6004 	struct necp_aggregate_route_rule *new_rule = NULL;
6005 	struct necp_aggregate_route_rule *existing_rule = NULL;
6006 
6007 	lck_rw_lock_exclusive(&necp_route_rule_lock);
6008 
6009 	// Check if the rule already exists
6010 	LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6011 		if (memcmp(existing_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6012 			lck_rw_done(&necp_route_rule_lock);
6013 			return existing_rule->id;
6014 		}
6015 	}
6016 
6017 	new_rule = kalloc_type(struct necp_aggregate_route_rule,
6018 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6019 	aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6020 	new_rule->id = aggregate_route_rule_id;
6021 	memcpy(new_rule->rule_ids, rule_ids, (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6022 	LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6023 	lck_rw_done(&necp_route_rule_lock);
6024 
6025 	return aggregate_route_rule_id;
6026 }
6027 
6028 #define NECP_NULL_SERVICE_ID 1
6029 #define NECP_FIRST_VALID_SERVICE_ID  2
6030 #define NECP_FIRST_VALID_APP_ID  UINT16_MAX
6031 static u_int32_t
necp_get_new_uuid_id(bool service)6032 necp_get_new_uuid_id(bool service)
6033 {
6034 	static u_int32_t necp_last_service_uuid_id = 0;
6035 	static u_int32_t necp_last_app_uuid_id = 0;
6036 
6037 	u_int32_t newid = 0;
6038 
6039 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6040 
6041 	if (service) {
6042 		bool wrapped = FALSE;
6043 		do {
6044 			necp_last_service_uuid_id++;
6045 			if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6046 			    necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6047 				if (wrapped) {
6048 					// Already wrapped, give up
6049 					NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6050 					return NECP_NULL_SERVICE_ID;
6051 				}
6052 				necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6053 				wrapped = TRUE;
6054 			}
6055 			newid = necp_last_service_uuid_id;
6056 		} while (necp_uuid_lookup_uuid_with_service_id_locked(newid) != NULL); // If already used, keep trying
6057 	} else {
6058 		bool wrapped = FALSE;
6059 		do {
6060 			necp_last_app_uuid_id++;
6061 			if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6062 				if (wrapped) {
6063 					// Already wrapped, give up
6064 					NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6065 					return NECP_NULL_SERVICE_ID;
6066 				}
6067 				necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6068 				wrapped = TRUE;
6069 			}
6070 			newid = necp_last_app_uuid_id;
6071 		} while (necp_uuid_lookup_uuid_with_app_id_locked(newid) != NULL); // If already used, keep trying
6072 	}
6073 
6074 	if (newid == NECP_NULL_SERVICE_ID) {
6075 		NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6076 		return NECP_NULL_SERVICE_ID;
6077 	}
6078 
6079 	return newid;
6080 }
6081 
6082 static struct necp_uuid_id_mapping *
necp_uuid_lookup_app_id_locked(uuid_t uuid)6083 necp_uuid_lookup_app_id_locked(uuid_t uuid)
6084 {
6085 	struct necp_uuid_id_mapping *searchentry = NULL;
6086 	struct necp_uuid_id_mapping *foundentry = NULL;
6087 
6088 	LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6089 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6090 			foundentry = searchentry;
6091 			break;
6092 		}
6093 	}
6094 
6095 	return foundentry;
6096 }
6097 
6098 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)6099 necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6100 {
6101 	struct necp_uuid_id_mapping *searchentry = NULL;
6102 	struct necp_uuid_id_mapping *foundentry = NULL;
6103 
6104 	struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6105 	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--) {
6106 		LIST_FOREACH(searchentry, uuid_list_head, chain) {
6107 			if (searchentry->id == local_id) {
6108 				foundentry = searchentry;
6109 				break;
6110 			}
6111 		}
6112 	}
6113 
6114 	return foundentry;
6115 }
6116 
6117 static u_int32_t
necp_create_uuid_app_id_mapping(uuid_t uuid,bool * allocated_mapping,bool uuid_policy_table)6118 necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6119 {
6120 	u_int32_t local_id = 0;
6121 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6122 
6123 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6124 
6125 	if (allocated_mapping) {
6126 		*allocated_mapping = FALSE;
6127 	}
6128 
6129 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6130 	if (existing_mapping != NULL) {
6131 		local_id = existing_mapping->id;
6132 		os_ref_retain_locked(&existing_mapping->refcount);
6133 		if (uuid_policy_table) {
6134 			existing_mapping->table_usecount++;
6135 		}
6136 	} else {
6137 		struct necp_uuid_id_mapping *new_mapping = NULL;
6138 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6139 		    Z_WAITOK | Z_NOFAIL);
6140 		uuid_copy(new_mapping->uuid, uuid);
6141 		new_mapping->id = necp_get_new_uuid_id(false);
6142 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6143 		if (uuid_policy_table) {
6144 			new_mapping->table_usecount = 1;
6145 		} else {
6146 			new_mapping->table_usecount = 0;
6147 		}
6148 
6149 		LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6150 
6151 		if (allocated_mapping) {
6152 			*allocated_mapping = TRUE;
6153 		}
6154 
6155 		local_id = new_mapping->id;
6156 	}
6157 
6158 	return local_id;
6159 }
6160 
6161 static bool
necp_remove_uuid_app_id_mapping(uuid_t uuid,bool * removed_mapping,bool uuid_policy_table)6162 necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6163 {
6164 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6165 
6166 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6167 
6168 	if (removed_mapping) {
6169 		*removed_mapping = FALSE;
6170 	}
6171 
6172 	existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6173 	if (existing_mapping != NULL) {
6174 		if (uuid_policy_table) {
6175 			existing_mapping->table_usecount--;
6176 		}
6177 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6178 			LIST_REMOVE(existing_mapping, chain);
6179 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6180 			if (removed_mapping) {
6181 				*removed_mapping = TRUE;
6182 			}
6183 		}
6184 		return TRUE;
6185 	}
6186 
6187 	return FALSE;
6188 }
6189 
6190 static struct necp_uuid_id_mapping *
necp_uuid_get_null_service_id_mapping(void)6191 necp_uuid_get_null_service_id_mapping(void)
6192 {
6193 	static struct necp_uuid_id_mapping null_mapping;
6194 	uuid_clear(null_mapping.uuid);
6195 	null_mapping.id = NECP_NULL_SERVICE_ID;
6196 
6197 	return &null_mapping;
6198 }
6199 
6200 static struct necp_uuid_id_mapping *
necp_uuid_lookup_service_id_locked(uuid_t uuid)6201 necp_uuid_lookup_service_id_locked(uuid_t uuid)
6202 {
6203 	struct necp_uuid_id_mapping *searchentry = NULL;
6204 	struct necp_uuid_id_mapping *foundentry = NULL;
6205 
6206 	if (uuid_is_null(uuid)) {
6207 		return necp_uuid_get_null_service_id_mapping();
6208 	}
6209 
6210 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6211 		if (uuid_compare(searchentry->uuid, uuid) == 0) {
6212 			foundentry = searchentry;
6213 			break;
6214 		}
6215 	}
6216 
6217 	return foundentry;
6218 }
6219 
6220 static struct necp_uuid_id_mapping *
necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)6221 necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6222 {
6223 	struct necp_uuid_id_mapping *searchentry = NULL;
6224 	struct necp_uuid_id_mapping *foundentry = NULL;
6225 
6226 	if (local_id == NECP_NULL_SERVICE_ID) {
6227 		return necp_uuid_get_null_service_id_mapping();
6228 	}
6229 
6230 	LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6231 		if (searchentry->id == local_id) {
6232 			foundentry = searchentry;
6233 			break;
6234 		}
6235 	}
6236 
6237 	return foundentry;
6238 }
6239 
6240 static u_int32_t
necp_create_uuid_service_id_mapping(uuid_t uuid)6241 necp_create_uuid_service_id_mapping(uuid_t uuid)
6242 {
6243 	u_int32_t local_id = 0;
6244 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6245 
6246 	if (uuid_is_null(uuid)) {
6247 		return NECP_NULL_SERVICE_ID;
6248 	}
6249 
6250 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6251 
6252 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6253 	if (existing_mapping != NULL) {
6254 		local_id = existing_mapping->id;
6255 		os_ref_retain_locked(&existing_mapping->refcount);
6256 	} else {
6257 		struct necp_uuid_id_mapping *new_mapping = NULL;
6258 		new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6259 		    Z_WAITOK | Z_NOFAIL);
6260 		uuid_copy(new_mapping->uuid, uuid);
6261 		new_mapping->id = necp_get_new_uuid_id(true);
6262 		os_ref_init(&new_mapping->refcount, &necp_refgrp);
6263 
6264 		LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6265 
6266 		local_id = new_mapping->id;
6267 	}
6268 
6269 	return local_id;
6270 }
6271 
6272 static bool
necp_remove_uuid_service_id_mapping(uuid_t uuid)6273 necp_remove_uuid_service_id_mapping(uuid_t uuid)
6274 {
6275 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6276 
6277 	if (uuid_is_null(uuid)) {
6278 		return TRUE;
6279 	}
6280 
6281 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6282 
6283 	existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6284 	if (existing_mapping != NULL) {
6285 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6286 			LIST_REMOVE(existing_mapping, chain);
6287 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6288 		}
6289 		return TRUE;
6290 	}
6291 
6292 	return FALSE;
6293 }
6294 
6295 static bool
necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)6296 necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6297 {
6298 	struct necp_uuid_id_mapping *existing_mapping = NULL;
6299 
6300 	if (service_id == 0) {
6301 		return TRUE;
6302 	}
6303 
6304 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6305 
6306 	existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(service_id);
6307 	if (existing_mapping != NULL) {
6308 		if (os_ref_release_locked(&existing_mapping->refcount) == 0) {
6309 			LIST_REMOVE(existing_mapping, chain);
6310 			kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6311 		}
6312 		return TRUE;
6313 	}
6314 
6315 	return FALSE;
6316 }
6317 
6318 static bool
necp_kernel_socket_policies_update_uuid_table(void)6319 necp_kernel_socket_policies_update_uuid_table(void)
6320 {
6321 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6322 
6323 	if (necp_uuid_app_id_mappings_dirty) {
6324 		if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, NULL, PROC_UUID_NECP_APP_POLICY) < 0) {
6325 			NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6326 			return FALSE;
6327 		}
6328 
6329 		if (necp_num_uuid_app_id_mappings > 0) {
6330 			struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6331 			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--) {
6332 				struct necp_uuid_id_mapping *mapping = NULL;
6333 				LIST_FOREACH(mapping, uuid_list_head, chain) {
6334 					if (mapping->table_usecount > 0 &&
6335 					    proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6336 						NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6337 					}
6338 				}
6339 			}
6340 		}
6341 
6342 		necp_uuid_app_id_mappings_dirty = FALSE;
6343 	}
6344 
6345 	return TRUE;
6346 }
6347 
6348 #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)
6349 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,necp_kernel_policy_result result,necp_kernel_policy_result_parameter result_parameter)6350 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, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6351 {
6352 	struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6353 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6354 
6355 	new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6356 	new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6357 	new_kernel_policy->suborder = suborder;
6358 	new_kernel_policy->order = order;
6359 	new_kernel_policy->session_order = session_order;
6360 	new_kernel_policy->session_pid = session_pid;
6361 
6362 	// Sanitize condition mask
6363 	new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6364 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6365 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6366 	}
6367 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6368 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6369 	}
6370 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6371 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6372 	}
6373 	if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6374 		new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6375 	}
6376 	new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6377 
6378 	// Set condition values
6379 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6380 		new_kernel_policy->cond_policy_id = cond_policy_id;
6381 	}
6382 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6383 		if (cond_bound_interface) {
6384 			ifnet_reference(cond_bound_interface);
6385 		}
6386 		new_kernel_policy->cond_bound_interface = cond_bound_interface;
6387 	}
6388 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6389 		new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6390 	}
6391 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6392 		new_kernel_policy->cond_protocol = cond_protocol;
6393 	}
6394 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6395 		memcpy(&new_kernel_policy->cond_local_start, cond_local_start, cond_local_start->sa.sa_len);
6396 	}
6397 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6398 		memcpy(&new_kernel_policy->cond_local_end, cond_local_end, cond_local_end->sa.sa_len);
6399 	}
6400 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6401 		new_kernel_policy->cond_local_prefix = cond_local_prefix;
6402 	}
6403 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6404 		memcpy(&new_kernel_policy->cond_remote_start, cond_remote_start, cond_remote_start->sa.sa_len);
6405 	}
6406 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6407 		memcpy(&new_kernel_policy->cond_remote_end, cond_remote_end, cond_remote_end->sa.sa_len);
6408 	}
6409 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6410 		new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
6411 	}
6412 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
6413 		new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
6414 	}
6415 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
6416 		new_kernel_policy->cond_scheme_port = cond_scheme_port;
6417 	}
6418 	if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
6419 		new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
6420 		new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
6421 		new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
6422 	}
6423 	new_kernel_policy->result = result;
6424 	memcpy(&new_kernel_policy->result_parameter, &result_parameter, sizeof(result_parameter));
6425 
6426 	if (necp_debug) {
6427 		NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
6428 	}
6429 	LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
6430 
6431 	return new_kernel_policy ? new_kernel_policy->id : 0;
6432 }
6433 
6434 static struct necp_kernel_ip_output_policy *
necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)6435 necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
6436 {
6437 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6438 	struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6439 
6440 	if (policy_id == 0) {
6441 		return NULL;
6442 	}
6443 
6444 	LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
6445 		if (kernel_policy->id == policy_id) {
6446 			return kernel_policy;
6447 		}
6448 	}
6449 
6450 	return NULL;
6451 }
6452 
6453 static bool
necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)6454 necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
6455 {
6456 	struct necp_kernel_ip_output_policy *policy = NULL;
6457 
6458 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6459 
6460 	policy = necp_kernel_ip_output_policy_find(policy_id);
6461 	if (policy) {
6462 		LIST_REMOVE(policy, chain);
6463 
6464 		if (policy->cond_bound_interface) {
6465 			ifnet_release(policy->cond_bound_interface);
6466 			policy->cond_bound_interface = NULL;
6467 		}
6468 
6469 		zfree(necp_ip_policy_zone, policy);
6470 		return TRUE;
6471 	}
6472 
6473 	return FALSE;
6474 }
6475 
6476 static void
necp_kernel_ip_output_policies_dump_all(void)6477 necp_kernel_ip_output_policies_dump_all(void)
6478 {
6479 	if (necp_debug) {
6480 		struct necp_kernel_ip_output_policy *policy = NULL;
6481 		int policy_i;
6482 		int id_i;
6483 		char result_string[MAX_RESULT_STRING_LEN];
6484 		char proc_name_string[MAXCOMLEN + 1];
6485 		memset(result_string, 0, MAX_RESULT_STRING_LEN);
6486 		memset(proc_name_string, 0, MAXCOMLEN + 1);
6487 
6488 		NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
6489 		NECPLOG0(LOG_DEBUG, "-----------\n");
6490 		for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
6491 			NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
6492 			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++) {
6493 				policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
6494 				proc_name(policy->session_pid, proc_name_string, MAXCOMLEN);
6495 				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));
6496 			}
6497 			NECPLOG0(LOG_DEBUG, "-----------\n");
6498 		}
6499 	}
6500 }
6501 
6502 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)6503 necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
6504 {
6505 	if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6506 		if (upper_policy->session_order != lower_policy->session_order) {
6507 			// A skip cannot override a policy of a different session
6508 			return FALSE;
6509 		} else {
6510 			if (upper_policy->result_parameter.skip_policy_order == 0 ||
6511 			    lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
6512 				// This policy is beyond the skip
6513 				return FALSE;
6514 			} else {
6515 				// This policy is inside the skip
6516 				return TRUE;
6517 			}
6518 		}
6519 	}
6520 
6521 	// All other IP Output policy results (drop, tunnel, hard pass) currently overlap
6522 	return TRUE;
6523 }
6524 
6525 static bool
necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy * policy,struct necp_kernel_ip_output_policy ** policy_array,int valid_indices)6526 necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy **policy_array, int valid_indices)
6527 {
6528 	bool can_skip = FALSE;
6529 	u_int32_t highest_skip_session_order = 0;
6530 	u_int32_t highest_skip_order = 0;
6531 	int i;
6532 	for (i = 0; i < valid_indices; i++) {
6533 		struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
6534 
6535 		// For policies in a skip window, we can't mark conflicting policies as unnecessary
6536 		if (can_skip) {
6537 			if (highest_skip_session_order != compared_policy->session_order ||
6538 			    (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
6539 				// If we've moved on to the next session, or passed the skip window
6540 				highest_skip_session_order = 0;
6541 				highest_skip_order = 0;
6542 				can_skip = FALSE;
6543 			} else {
6544 				// If this policy is also a skip, in can increase the skip window
6545 				if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6546 					if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
6547 						highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6548 					}
6549 				}
6550 				continue;
6551 			}
6552 		}
6553 
6554 		if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6555 			// This policy is a skip. Set the skip window accordingly
6556 			can_skip = TRUE;
6557 			highest_skip_session_order = compared_policy->session_order;
6558 			highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6559 		}
6560 
6561 		// The result of the compared policy must be able to block out this policy result
6562 		if (!necp_kernel_ip_output_policy_results_overlap(compared_policy, policy)) {
6563 			continue;
6564 		}
6565 
6566 		// If new policy matches All Interfaces, compared policy must also
6567 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
6568 			continue;
6569 		}
6570 
6571 		// If new policy matches Local Networks, compared policy must also
6572 		if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
6573 			continue;
6574 		}
6575 
6576 		// Default makes lower policies unnecessary always
6577 		if (compared_policy->condition_mask == 0) {
6578 			return TRUE;
6579 		}
6580 
6581 		// Compared must be more general than policy, and include only conditions within policy
6582 		if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
6583 			continue;
6584 		}
6585 
6586 		// Negative conditions must match for the overlapping conditions
6587 		if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
6588 			continue;
6589 		}
6590 
6591 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
6592 		    compared_policy->cond_policy_id != policy->cond_policy_id) {
6593 			continue;
6594 		}
6595 
6596 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
6597 		    compared_policy->cond_bound_interface != policy->cond_bound_interface) {
6598 			continue;
6599 		}
6600 
6601 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
6602 		    compared_policy->cond_protocol != policy->cond_protocol) {
6603 			continue;
6604 		}
6605 
6606 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6607 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6608 				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&policy->cond_local_end, (struct sockaddr *)&compared_policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_end)) {
6609 					continue;
6610 				}
6611 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6612 				if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
6613 				    !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_local_start, (struct sockaddr *)&compared_policy->cond_local_start, compared_policy->cond_local_prefix)) {
6614 					continue;
6615 				}
6616 			}
6617 		}
6618 
6619 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6620 			if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6621 				if (!necp_is_range_in_range((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&policy->cond_remote_end, (struct sockaddr *)&compared_policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_end)) {
6622 					continue;
6623 				}
6624 			} else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6625 				if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
6626 				    !necp_is_addr_in_subnet((struct sockaddr *)&policy->cond_remote_start, (struct sockaddr *)&compared_policy->cond_remote_start, compared_policy->cond_remote_prefix)) {
6627 					continue;
6628 				}
6629 			}
6630 		}
6631 
6632 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
6633 		    compared_policy->cond_scheme_port != policy->cond_scheme_port) {
6634 			continue;
6635 		}
6636 
6637 		if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
6638 		    (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
6639 		    compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
6640 		    compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
6641 			continue;
6642 		}
6643 
6644 		return TRUE;
6645 	}
6646 
6647 	return FALSE;
6648 }
6649 
6650 static bool
necp_kernel_ip_output_policies_reprocess(void)6651 necp_kernel_ip_output_policies_reprocess(void)
6652 {
6653 	int i;
6654 	int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
6655 	struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6656 
6657 	LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6658 
6659 	// Reset mask to 0
6660 	necp_kernel_ip_output_policies_condition_mask = 0;
6661 	necp_kernel_ip_output_policies_count = 0;
6662 	necp_kernel_ip_output_policies_non_id_count = 0;
6663 
6664 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6665 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
6666 			kfree_type(struct necp_kernel_ip_output_policy *,
6667 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
6668 			    necp_kernel_ip_output_policies_map[i]);
6669 			necp_kernel_ip_output_policies_map[i] = NULL;
6670 		}
6671 
6672 		// Init counts
6673 		necp_kernel_ip_output_policies_map_counts[i] = 0;
6674 	}
6675 
6676 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6677 		// Update mask
6678 		necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
6679 		necp_kernel_ip_output_policies_count++;
6680 
6681 		/* Update bucket counts:
6682 		 * Non-id and SKIP policies will be added to all buckets
6683 		 * Add local networks policy to all buckets for incoming IP
6684 		 */
6685 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6686 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6687 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6688 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6689 				necp_kernel_ip_output_policies_map_counts[i]++;
6690 			}
6691 		}
6692 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
6693 			necp_kernel_ip_output_policies_non_id_count++;
6694 		} else {
6695 			necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
6696 		}
6697 	}
6698 
6699 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6700 		if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
6701 			// Allocate a NULL-terminated array of policy pointers for each bucket
6702 			necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
6703 			    necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
6704 			if (necp_kernel_ip_output_policies_map[i] == NULL) {
6705 				goto fail;
6706 			}
6707 		}
6708 		bucket_current_free_index[i] = 0;
6709 	}
6710 
6711 	u_int32_t current_session_order = 0;
6712 	u_int32_t current_session_last_non_skip_policy = 0;
6713 
6714 	LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6715 		// For each new session, find the last non-skip policy. We can
6716 		// avoid adding any skip policies that don't actually skip over
6717 		// any non-skip policies.
6718 		if (current_session_order != kernel_policy->session_order) {
6719 			current_session_order = kernel_policy->session_order;
6720 			current_session_last_non_skip_policy = 0;
6721 
6722 			struct necp_kernel_ip_output_policy *inner_policy = NULL;
6723 			LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
6724 				if (inner_policy->session_order < current_session_order) {
6725 					continue;
6726 				}
6727 				if (inner_policy->session_order > current_session_order) {
6728 					break;
6729 				}
6730 				if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6731 					continue;
6732 				}
6733 
6734 				current_session_last_non_skip_policy = inner_policy->order;
6735 			}
6736 		}
6737 
6738 		if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6739 			if (current_session_last_non_skip_policy == 0) {
6740 				// No useful policies to skip over, don't add
6741 				continue;
6742 			}
6743 			if (kernel_policy->order >= current_session_last_non_skip_policy) {
6744 				// Skip policy is after the last useful policy, don't add
6745 				continue;
6746 			}
6747 		}
6748 
6749 		// Insert pointers into map
6750 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6751 		    (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6752 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6753 			for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6754 				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])) {
6755 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
6756 					bucket_current_free_index[i]++;
6757 					(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
6758 				}
6759 			}
6760 		} else {
6761 			i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
6762 			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])) {
6763 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
6764 				bucket_current_free_index[i]++;
6765 				(necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
6766 			}
6767 		}
6768 	}
6769 
6770 	if (bucket_current_free_index[0] == 0) {
6771 		// No non-id policies were actually added
6772 		necp_kernel_ip_output_policies_non_id_count = 0;
6773 
6774 		// Also check if no policies at all were added
6775 		bool policies_added = FALSE;
6776 		for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6777 			if (bucket_current_free_index[i] != 0) {
6778 				policies_added = TRUE;
6779 				break;
6780 			}
6781 		}
6782 		if (!policies_added) {
6783 			necp_kernel_ip_output_policies_condition_mask = 0;
6784 			necp_kernel_ip_output_policies_count = 0;
6785 		}
6786 	}
6787 
6788 	necp_kernel_ip_output_policies_dump_all();
6789 	return TRUE;
6790 
6791 fail:
6792 	// Free memory, reset mask to 0
6793 	necp_kernel_ip_output_policies_condition_mask = 0;
6794 	necp_kernel_ip_output_policies_count = 0;
6795 	necp_kernel_ip_output_policies_non_id_count = 0;
6796 	for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6797 		if (necp_kernel_ip_output_policies_map[i] != NULL) {
6798 			kfree_type(struct necp_kernel_ip_output_policy *,
6799 			    necp_kernel_ip_output_policies_map_counts[i] + 1,
6800 			    necp_kernel_ip_output_policies_map[i]);
6801 			necp_kernel_ip_output_policies_map[i] = NULL;
6802 		}
6803 	}
6804 	return FALSE;
6805 }
6806 
6807 // Outbound Policy Matching
6808 // ---------------------
6809 struct substring {
6810 	char *string;
6811 	size_t length;
6812 };
6813 
6814 static struct substring
necp_trim_dots_and_stars(char * string,size_t length)6815 necp_trim_dots_and_stars(char *string, size_t length)
6816 {
6817 	struct substring sub;
6818 	sub.string = string;
6819 	sub.length = string ? length : 0;
6820 
6821 	while (sub.length && (sub.string[0] == '.' || sub.string[0] == '*')) {
6822 		sub.string++;
6823 		sub.length--;
6824 	}
6825 
6826 	while (sub.length && (sub.string[sub.length - 1] == '.' || sub.string[sub.length - 1] == '*')) {
6827 		sub.length--;
6828 	}
6829 
6830 	return sub;
6831 }
6832 
6833 static char *
necp_create_trimmed_domain(char * string,size_t length)6834 necp_create_trimmed_domain(char *string, size_t length)
6835 {
6836 	char *trimmed_domain = NULL;
6837 	struct substring sub = necp_trim_dots_and_stars(string, length);
6838 
6839 	trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
6840 	if (trimmed_domain == NULL) {
6841 		return NULL;
6842 	}
6843 
6844 	memcpy(trimmed_domain, sub.string, sub.length);
6845 	trimmed_domain[sub.length] = 0;
6846 
6847 	return trimmed_domain;
6848 }
6849 
6850 static inline int
necp_count_dots(char * string,size_t length)6851 necp_count_dots(char *string, size_t length)
6852 {
6853 	int dot_count = 0;
6854 	size_t i = 0;
6855 
6856 	for (i = 0; i < length; i++) {
6857 		if (string[i] == '.') {
6858 			dot_count++;
6859 		}
6860 	}
6861 
6862 	return dot_count;
6863 }
6864 
6865 static bool
necp_check_suffix(struct substring parent,struct substring suffix,bool require_dot_before_suffix)6866 necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
6867 {
6868 	if (parent.length <= suffix.length) {
6869 		return FALSE;
6870 	}
6871 
6872 	size_t length_difference = (parent.length - suffix.length);
6873 
6874 	if (require_dot_before_suffix) {
6875 		if (((char *)(parent.string + length_difference - 1))[0] != '.') {
6876 			return FALSE;
6877 		}
6878 	}
6879 
6880 	// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6881 	return strncasecmp(parent.string + length_difference, suffix.string, suffix.length) == 0;
6882 }
6883 
6884 static bool
necp_hostname_matches_domain(struct substring hostname_substring,u_int8_t hostname_dot_count,char * domain,u_int8_t domain_dot_count)6885 necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain, u_int8_t domain_dot_count)
6886 {
6887 	if (hostname_substring.string == NULL || domain == NULL) {
6888 		return hostname_substring.string == domain;
6889 	}
6890 
6891 	struct substring domain_substring;
6892 	domain_substring.string = domain;
6893 	domain_substring.length = strlen(domain);
6894 
6895 	if (hostname_dot_count == domain_dot_count) {
6896 		// strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6897 		if (hostname_substring.length == domain_substring.length &&
6898 		    strncasecmp(hostname_substring.string, domain_substring.string, hostname_substring.length) == 0) {
6899 			return TRUE;
6900 		}
6901 	} else if (domain_dot_count < hostname_dot_count) {
6902 		if (necp_check_suffix(hostname_substring, domain_substring, TRUE)) {
6903 			return TRUE;
6904 		}
6905 	}
6906 
6907 	return FALSE;
6908 }
6909 
6910 bool
net_domain_contains_hostname(char * hostname_string,char * domain_string)6911 net_domain_contains_hostname(char *hostname_string, char *domain_string)
6912 {
6913 	if (hostname_string == NULL ||
6914 	    domain_string == NULL) {
6915 		return false;
6916 	}
6917 
6918 	struct substring hostname_substring;
6919 	hostname_substring.string = hostname_string;
6920 	hostname_substring.length = strlen(hostname_string);
6921 
6922 	return necp_hostname_matches_domain(hostname_substring,
6923 	           necp_count_dots(hostname_string, hostname_substring.length),
6924 	           domain_string,
6925 	           necp_count_dots(domain_string, strlen(domain_string)));
6926 }
6927 
6928 #define NECP_MAX_STRING_LEN 1024
6929 
6930 static char *
necp_copy_string(char * string,size_t length)6931 necp_copy_string(char *string, size_t length)
6932 {
6933 	char *copied_string = NULL;
6934 
6935 	if (length > NECP_MAX_STRING_LEN) {
6936 		return NULL;
6937 	}
6938 
6939 	copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
6940 	if (copied_string == NULL) {
6941 		return NULL;
6942 	}
6943 
6944 	memcpy(copied_string, string, length);
6945 	copied_string[length] = 0;
6946 
6947 	return copied_string;
6948 }
6949 
6950 static u_int32_t
necp_get_primary_direct_interface_index(void)6951 necp_get_primary_direct_interface_index(void)
6952 {
6953 	u_int32_t interface_index = IFSCOPE_NONE;
6954 
6955 	ifnet_head_lock_shared();
6956 	struct ifnet *ordered_interface = NULL;
6957 	TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
6958 		const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
6959 		if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
6960 		    functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
6961 			// All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
6962 			interface_index = ordered_interface->if_index;
6963 			break;
6964 		}
6965 	}
6966 	ifnet_head_done();
6967 
6968 	return interface_index;
6969 }
6970 
6971 static inline bool
necp_task_has_match_entitlement(task_t task)6972 necp_task_has_match_entitlement(task_t task)
6973 {
6974 	return task != NULL &&
6975 	       (IOTaskHasEntitlement(task, "com.apple.private.necp.match") ||
6976 	       IOTaskHasEntitlement(task, "com.apple.developer.CaptiveNetworkPlugin"));
6977 }
6978 
6979 static inline void
necp_get_parent_is_entitled(task_t task,struct necp_socket_info * info)6980 necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
6981 {
6982 	coalition_t coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
6983 
6984 	if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
6985 		// No parent, nothing to do
6986 		return;
6987 	}
6988 
6989 	task_t lead_task = coalition_get_leader(coal);
6990 	if (lead_task != NULL) {
6991 		info->is_entitled = necp_task_has_match_entitlement(lead_task);
6992 		task_deallocate(lead_task);
6993 	}
6994 }
6995 
6996 // Some processes, due to particular entitlements, require using an NECP client to
6997 // access networking. Returns true if the result should be a Drop.
6998 static inline bool
necp_check_missing_client_drop(proc_t proc,struct necp_socket_info * info)6999 necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7000 {
7001 	if (necp_is_platform_binary(proc)) {
7002 		// This check is currently for the "on-demand-install-capable"
7003 		// entitlement, which by definition cannot be a built-in platform
7004 		// binary.
7005 		return false;
7006 	}
7007 
7008 	task_t task = proc_task(proc ? proc : current_proc());
7009 
7010 	if (!info->has_client &&
7011 	    task != NULL &&
7012 	    IOTaskHasEntitlement(task, "com.apple.developer.on-demand-install-capable")) {
7013 		// Drop connections that don't use NECP clients and have the
7014 		// com.apple.developer.on-demand-install-capable entitlement.
7015 		// This effectively restricts those processes to only using
7016 		// an NECP-aware path for networking.
7017 		return true;
7018 	} else {
7019 		return false;
7020 	}
7021 }
7022 
7023 static inline bool
necp_check_restricted_multicast_drop(proc_t proc,struct necp_socket_info * info,bool check_minor_version)7024 necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7025 {
7026 	if (!necp_restrict_multicast || proc == NULL) {
7027 		return false;
7028 	}
7029 
7030 	// Check for multicast/broadcast here
7031 	if (info->remote_addr.sa.sa_family == AF_INET) {
7032 		if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7033 		    info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7034 			return false;
7035 		}
7036 	} else if (info->remote_addr.sa.sa_family == AF_INET6) {
7037 		if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7038 			return false;
7039 		}
7040 	} else {
7041 		// Not IPv4/IPv6
7042 		return false;
7043 	}
7044 
7045 	if (necp_is_platform_binary(proc)) {
7046 		return false;
7047 	}
7048 
7049 	const uint32_t platform = proc_platform(proc);
7050 	const uint32_t sdk = proc_sdk(proc);
7051 
7052 	// Enforce for iOS, linked on or after version 14
7053 	// If the caller set `check_minor_version`, only enforce starting at 14.5
7054 	if ((platform != PLATFORM_IOS ||
7055 	    sdk == 0 ||
7056 	    (sdk >> 16) < 14 ||
7057 	    (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7058 		return false;
7059 	}
7060 
7061 	// Allow entitled processes to use multicast
7062 	task_t task = proc_task(proc);
7063 	if (task != NULL &&
7064 	    IOTaskHasEntitlement(task, "com.apple.developer.networking.multicast")) {
7065 		return false;
7066 	}
7067 
7068 	const uint32_t min_sdk = proc_min_sdk(proc);
7069 	NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7070 
7071 	return true;
7072 }
7073 
7074 #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)
7075 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,char * domain,char * url,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)7076 necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, char *url, 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)
7077 {
7078 	memset(info, 0, sizeof(struct necp_socket_info));
7079 
7080 	info->pid = pid;
7081 	info->pid_version = pid_version;
7082 	info->uid = uid;
7083 	info->real_uid = real_uid;
7084 	info->protocol = protocol;
7085 	info->bound_interface_index = bound_interface_index;
7086 	info->traffic_class = traffic_class;
7087 	info->has_client = has_client;
7088 	info->has_system_signed_result = has_system_signed_result;
7089 	info->drop_order = drop_order;
7090 	info->client_flags = client_flags;
7091 	info->is_loopback = is_loopback;
7092 	info->is_delegated = is_delegated;
7093 
7094 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7095 	    info->bound_interface_index != IFSCOPE_NONE) {
7096 		ifnet_head_lock_shared();
7097 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7098 		if (interface != NULL) {
7099 			info->bound_interface_flags = interface->if_flags;
7100 			info->bound_interface_eflags = interface->if_eflags;
7101 			info->bound_interface_xflags = interface->if_xflags;
7102 		}
7103 		ifnet_head_done();
7104 	}
7105 
7106 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(application_uuid)) {
7107 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(application_uuid);
7108 		if (existing_mapping) {
7109 			info->application_id = existing_mapping->id;
7110 		}
7111 	}
7112 
7113 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(real_application_uuid)) {
7114 		if (uuid_compare(application_uuid, real_application_uuid) == 0) {
7115 			info->real_application_id = info->application_id;
7116 		} else {
7117 			struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(real_application_uuid);
7118 			if (existing_mapping) {
7119 				info->real_application_id = existing_mapping->id;
7120 			}
7121 		}
7122 	}
7123 
7124 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(responsible_application_uuid)) {
7125 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(responsible_application_uuid);
7126 		if (existing_mapping != NULL) {
7127 			info->real_application_id = info->application_id;
7128 			info->application_id = existing_mapping->id;
7129 			info->used_responsible_pid = true;
7130 		}
7131 	}
7132 
7133 	if (info->used_responsible_pid) {
7134 		proc = responsible_proc;
7135 	}
7136 
7137 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7138 		info->is_entitled = necp_task_has_match_entitlement(task);
7139 		if (!info->is_entitled) {
7140 			// Task does not have entitlement, check the parent task
7141 			necp_get_parent_is_entitled(task, info);
7142 		}
7143 	}
7144 
7145 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY && proc != NULL) {
7146 		info->is_platform_binary = necp_is_platform_binary(proc) ? true : false;
7147 	}
7148 
7149 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7150 		info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
7151 	}
7152 
7153 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7154 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, account);
7155 		if (existing_mapping) {
7156 			info->account_id = existing_mapping->id;
7157 		}
7158 	}
7159 
7160 	if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7161 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7162 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7163 		info->domain = domain;
7164 	}
7165 
7166 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7167 		info->url = url;
7168 	}
7169 
7170 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
7171 	    necp_restrict_multicast ||
7172 	    (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7173 		if (local_addr && local_addr->sa.sa_len > 0) {
7174 			memcpy(&info->local_addr, local_addr, local_addr->sa.sa_len);
7175 			if (local_port != 0) {
7176 				info->local_addr.sin6.sin6_port = local_port;
7177 			}
7178 		} else {
7179 			if (remote_addr && remote_addr->sa.sa_len > 0) {
7180 				info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7181 				info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7182 			} else {
7183 				info->local_addr.sin6.sin6_family = AF_INET6;
7184 				info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7185 			}
7186 			if (local_port != 0) {
7187 				info->local_addr.sin6.sin6_port = local_port;
7188 			}
7189 		}
7190 		if (remote_addr && remote_addr->sa.sa_len > 0) {
7191 			memcpy(&info->remote_addr, remote_addr, remote_addr->sa.sa_len);
7192 			if (remote_port != 0) {
7193 				info->remote_addr.sin6.sin6_port = remote_port;
7194 			}
7195 		} else if (remote_port != 0) {
7196 			info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7197 			info->remote_addr.sin6.sin6_family = AF_INET6;
7198 			info->remote_addr.sin6.sin6_port = remote_port;
7199 		}
7200 	}
7201 
7202 	if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7203 		info->scheme_port = scheme_port;
7204 	}
7205 }
7206 
7207 static void
necp_send_application_interface_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t if_functional_type)7208 necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7209 {
7210 	struct kev_netpolicy_ifdenied ev_ifdenied;
7211 
7212 	bzero(&ev_ifdenied, sizeof(ev_ifdenied));
7213 
7214 	ev_ifdenied.ev_data.epid = pid;
7215 	uuid_copy(ev_ifdenied.ev_data.euuid, proc_uuid);
7216 	ev_ifdenied.ev_if_functional_type = if_functional_type;
7217 
7218 	netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7219 }
7220 
7221 static void
necp_send_network_denied_event(pid_t pid,uuid_t proc_uuid,u_int32_t network_type)7222 necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7223 {
7224 	struct kev_netpolicy_netdenied ev_netdenied = {};
7225 
7226 	bzero(&ev_netdenied, sizeof(ev_netdenied));
7227 
7228 	ev_netdenied.ev_data.epid = pid;
7229 	uuid_copy(ev_netdenied.ev_data.euuid, proc_uuid);
7230 	ev_netdenied.ev_network_type = network_type;
7231 
7232 	netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7233 }
7234 
7235 extern char *proc_name_address(void *p);
7236 
7237 #define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7238 	if (!has_checked_delegation_entitlement) { \
7239 	        has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7240 	        has_checked_delegation_entitlement = TRUE; \
7241 	} \
7242 	if (!has_delegation_entitlement) { \
7243 	        NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7244 	                                          proc_name_address(_p), proc_pid(_p), _d); \
7245 	        break; \
7246 	}
7247 
7248 int
necp_application_find_policy_match_internal(proc_t proc,u_int8_t * 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)7249 necp_application_find_policy_match_internal(proc_t proc,
7250     u_int8_t *parameters,
7251     u_int32_t parameters_size,
7252     struct necp_aggregate_result *returned_result,
7253     u_int32_t *flags,
7254     u_int32_t *reason,
7255     u_int required_interface_index,
7256     const union necp_sockaddr_union *override_local_addr,
7257     const union necp_sockaddr_union *override_remote_addr,
7258     struct necp_client_endpoint *returned_v4_gateway,
7259     struct necp_client_endpoint *returned_v6_gateway,
7260     struct rtentry **returned_route, bool ignore_address,
7261     bool has_client,
7262     uuid_t *returned_override_euuid)
7263 {
7264 	int error = 0;
7265 	size_t offset = 0;
7266 
7267 	struct necp_kernel_socket_policy *matched_policy = NULL;
7268 	struct necp_socket_info info = {};
7269 	necp_kernel_policy_filter filter_control_unit = 0;
7270 	necp_kernel_policy_result service_action = 0;
7271 	necp_kernel_policy_service service = { 0, 0 };
7272 
7273 	u_int16_t protocol = 0;
7274 	u_int32_t bound_interface_index = required_interface_index;
7275 	u_int32_t traffic_class = 0;
7276 	u_int32_t client_flags = 0;
7277 	u_int16_t scheme_port = 0;
7278 	union necp_sockaddr_union local_addr;
7279 	union necp_sockaddr_union remote_addr;
7280 	bool no_remote_addr = FALSE;
7281 	u_int8_t remote_family = 0;
7282 	bool no_local_addr = FALSE;
7283 	u_int16_t local_port = 0;
7284 	u_int16_t remote_port = 0;
7285 	u_int32_t remote_endpoint_type = 0;
7286 	bool remote_address_is_empty = false;
7287 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7288 	bool is_delegated = false;
7289 
7290 	if (override_local_addr) {
7291 		memcpy(&local_addr, override_local_addr, sizeof(local_addr));
7292 	} else {
7293 		memset(&local_addr, 0, sizeof(local_addr));
7294 	}
7295 	if (override_remote_addr) {
7296 		memcpy(&remote_addr, override_remote_addr, sizeof(remote_addr));
7297 	} else {
7298 		memset(&remote_addr, 0, sizeof(remote_addr));
7299 	}
7300 
7301 	// Initialize UID, PID, and UUIDs to the current process
7302 	uid_t uid = 0;
7303 	uid_t real_uid = 0;
7304 	kauth_cred_t cred = kauth_cred_proc_ref(proc);
7305 	if (cred != NULL) {
7306 		uid = kauth_cred_getuid(cred);
7307 		real_uid = uid;
7308 	}
7309 	task_t task = proc_task(proc);
7310 	pid_t pid = proc_pid(proc);
7311 	int32_t pid_version = proc_pidversion(proc);
7312 	uuid_t application_uuid;
7313 	uuid_clear(application_uuid);
7314 	uuid_t real_application_uuid;
7315 	uuid_clear(real_application_uuid);
7316 	proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7317 	uuid_copy(application_uuid, real_application_uuid);
7318 	uuid_t responsible_application_uuid;
7319 	uuid_clear(responsible_application_uuid);
7320 
7321 	char *domain = NULL;
7322 	char *url = NULL;
7323 	char *account = NULL;
7324 
7325 #define NECP_MAX_REQUIRED_AGENTS 16
7326 	u_int32_t num_required_agent_types = 0;
7327 	struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7328 	memset(&required_agent_types, 0, sizeof(required_agent_types));
7329 
7330 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7331 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7332 	memset(&netagent_ids, 0, sizeof(netagent_ids));
7333 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
7334 	int netagent_cursor;
7335 
7336 	bool has_checked_delegation_entitlement = false;
7337 	bool has_delegation_entitlement = false;
7338 	bool has_system_signed_result = false;
7339 
7340 	proc_t responsible_proc = PROC_NULL;
7341 	proc_t effective_proc = proc;
7342 	bool release_eproc = false;
7343 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7344 
7345 	u_int32_t flow_divert_aggregate_unit = 0;
7346 
7347 	if (returned_result == NULL) {
7348 		if (cred != NULL) {
7349 			kauth_cred_unref(&cred);
7350 		}
7351 		return EINVAL;
7352 	}
7353 
7354 	if (returned_v4_gateway != NULL) {
7355 		memset(returned_v4_gateway, 0, sizeof(struct necp_client_endpoint));
7356 	}
7357 
7358 	if (returned_v6_gateway != NULL) {
7359 		memset(returned_v6_gateway, 0, sizeof(struct necp_client_endpoint));
7360 	}
7361 
7362 	if (returned_override_euuid != NULL) {
7363 		uuid_clear(*returned_override_euuid);
7364 	}
7365 
7366 	memset(returned_result, 0, sizeof(struct necp_aggregate_result));
7367 
7368 	u_int32_t drop_order = necp_process_drop_order(cred);
7369 
7370 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7371 
7372 	lck_rw_lock_shared(&necp_kernel_policy_lock);
7373 	if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7374 		if (necp_drop_all_order > 0 || drop_order > 0) {
7375 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7376 			lck_rw_done(&necp_kernel_policy_lock);
7377 			if (cred != NULL) {
7378 				kauth_cred_unref(&cred);
7379 			}
7380 			return 0;
7381 		}
7382 	}
7383 	lck_rw_done(&necp_kernel_policy_lock);
7384 
7385 	while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
7386 		u_int8_t type = necp_buffer_get_tlv_type(parameters, offset);
7387 		u_int32_t length = necp_buffer_get_tlv_length(parameters, offset);
7388 
7389 		if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
7390 			// If the length is larger than what can fit in the remaining parameters size, bail
7391 			NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
7392 			break;
7393 		}
7394 
7395 		if (length > 0) {
7396 			u_int8_t *value = necp_buffer_get_tlv_value(parameters, offset, NULL);
7397 			if (value != NULL) {
7398 				switch (type) {
7399 				case NECP_CLIENT_PARAMETER_APPLICATION: {
7400 					if (length >= sizeof(uuid_t)) {
7401 						if (uuid_compare(application_uuid, value) == 0) {
7402 							// No delegation
7403 							break;
7404 						}
7405 
7406 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
7407 
7408 						is_delegated = true;
7409 						uuid_copy(application_uuid, value);
7410 					}
7411 					break;
7412 				}
7413 				case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
7414 					if (length >= sizeof(uuid_t)) {
7415 						if (uuid_compare(real_application_uuid, value) == 0) {
7416 							// No delegation
7417 							break;
7418 						}
7419 
7420 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
7421 
7422 						is_delegated = true;
7423 						uuid_copy(real_application_uuid, value);
7424 					}
7425 					break;
7426 				}
7427 				case NECP_CLIENT_PARAMETER_PID: {
7428 					if (length >= sizeof(pid_t)) {
7429 						if (memcmp(&pid, value, sizeof(pid_t)) == 0) {
7430 							// No delegation
7431 							break;
7432 						}
7433 
7434 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
7435 
7436 						is_delegated = true;
7437 						memcpy(&pid, value, sizeof(pid_t));
7438 					}
7439 					break;
7440 				}
7441 				case NECP_CLIENT_PARAMETER_UID: {
7442 					if (length >= sizeof(uid_t)) {
7443 						if (memcmp(&uid, value, sizeof(uid_t)) == 0) {
7444 							// No delegation
7445 							break;
7446 						}
7447 
7448 						NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
7449 
7450 						is_delegated = true;
7451 						memcpy(&uid, value, sizeof(uid_t));
7452 					}
7453 					break;
7454 				}
7455 				case NECP_CLIENT_PARAMETER_DOMAIN: {
7456 					domain = (char *)value;
7457 					domain[length - 1] = 0;
7458 					break;
7459 				}
7460 				case NECP_CLIENT_PARAMETER_URL: {
7461 					url = (char *)value;
7462 					url[length - 1] = 0;
7463 					break;
7464 				}
7465 				case NECP_CLIENT_PARAMETER_ACCOUNT: {
7466 					account = (char *)value;
7467 					account[length - 1] = 0;
7468 					break;
7469 				}
7470 				case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
7471 					if (length >= sizeof(u_int32_t)) {
7472 						memcpy(&traffic_class, value, sizeof(u_int32_t));
7473 					}
7474 					break;
7475 				}
7476 				case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
7477 					if (length >= sizeof(u_int16_t)) {
7478 						memcpy(&protocol, value, sizeof(u_int16_t));
7479 					} else if (length >= sizeof(u_int8_t)) {
7480 						memcpy(&protocol, value, sizeof(u_int8_t));
7481 					}
7482 					break;
7483 				}
7484 				case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
7485 					if (length <= IFXNAMSIZ && length > 0) {
7486 						ifnet_t bound_interface = NULL;
7487 						char interface_name[IFXNAMSIZ];
7488 						memcpy(interface_name, value, length);
7489 						interface_name[length - 1] = 0;         // Make sure the string is NULL terminated
7490 						if (ifnet_find_by_name(interface_name, &bound_interface) == 0) {
7491 							bound_interface_index = bound_interface->if_index;
7492 							ifnet_release(bound_interface);
7493 						}
7494 					}
7495 					break;
7496 				}
7497 				case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
7498 					if (ignore_address || override_local_addr) {
7499 						break;
7500 					}
7501 
7502 					if (length >= sizeof(struct necp_policy_condition_addr)) {
7503 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7504 						if (necp_address_is_valid(&address_struct->address.sa)) {
7505 							memcpy(&local_addr, &address_struct->address, sizeof(address_struct->address));
7506 						}
7507 					}
7508 					break;
7509 				}
7510 				case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
7511 					if (ignore_address || override_remote_addr) {
7512 						break;
7513 					}
7514 
7515 					if (length >= sizeof(struct necp_policy_condition_addr)) {
7516 						struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7517 						if (necp_address_is_valid(&address_struct->address.sa)) {
7518 							memcpy(&remote_addr, &address_struct->address, sizeof(address_struct->address));
7519 						}
7520 					}
7521 					break;
7522 				}
7523 				case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
7524 					if (ignore_address || override_local_addr) {
7525 						break;
7526 					}
7527 
7528 					if (length >= sizeof(struct necp_client_endpoint)) {
7529 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7530 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
7531 						    endpoint->u.endpoint.endpoint_port != 0) {
7532 							// Save port
7533 							local_port = endpoint->u.endpoint.endpoint_port;
7534 						}
7535 					}
7536 					break;
7537 				}
7538 				case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
7539 					if (ignore_address || override_remote_addr) {
7540 						break;
7541 					}
7542 
7543 					if (length >= sizeof(struct necp_client_endpoint)) {
7544 						struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7545 						if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
7546 							remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
7547 							if (endpoint->u.endpoint.endpoint_port != 0) {
7548 								// Save port
7549 								remote_port = endpoint->u.endpoint.endpoint_port;
7550 							}
7551 						} else if (necp_addr_is_empty(&endpoint->u.sa)) {
7552 							remote_address_is_empty = true;
7553 						}
7554 					}
7555 					break;
7556 				}
7557 				case NECP_CLIENT_PARAMETER_FLAGS: {
7558 					if (length >= sizeof(client_flags)) {
7559 						memcpy(&client_flags, value, sizeof(client_flags));
7560 					}
7561 					break;
7562 				}
7563 				case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
7564 				case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
7565 					if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
7566 						break;
7567 					}
7568 					if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
7569 						memcpy(&required_agent_types[num_required_agent_types], value, sizeof(struct necp_client_parameter_netagent_type));
7570 						num_required_agent_types++;
7571 					}
7572 					break;
7573 				}
7574 				case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
7575 					if (length >= sizeof(scheme_port)) {
7576 						memcpy(&scheme_port, value, sizeof(scheme_port));
7577 					}
7578 					break;
7579 				}
7580 				case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
7581 					has_system_signed_result = true;
7582 					struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
7583 					if (length >= sizeof(struct necp_client_validatable)) {
7584 						// Check for system-signed sign_type values
7585 						if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
7586 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
7587 						    validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
7588 							has_system_signed_result = true;
7589 						}
7590 					}
7591 					break;
7592 				}
7593 				default: {
7594 					break;
7595 				}
7596 				}
7597 			}
7598 		}
7599 
7600 		offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
7601 	}
7602 
7603 	// Check for loopback exception
7604 	if (necp_pass_loopback > 0 && necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
7605 		bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
7606 	} else if (bound_interface_index != IFSCOPE_NONE) {
7607 		// Check for inter-process exception
7608 		struct sockaddr *dst = SA(&remote_addr.sa);
7609 		if (dst->sa_family == AF_INET6) {
7610 			struct in6_addr *addrv6 = &(((struct sockaddr_in6 *)(void *)dst)->sin6_addr);
7611 			if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
7612 				ifnet_head_lock_shared();
7613 				ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
7614 				if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
7615 					bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
7616 				}
7617 				ifnet_head_done();
7618 			}
7619 		}
7620 	}
7621 
7622 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
7623 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7624 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7625 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7626 		if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
7627 			returned_result->routed_interface_index = lo_ifp->if_index;
7628 			*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7629 		} else {
7630 			returned_result->routed_interface_index = bound_interface_index;
7631 		}
7632 		if (cred != NULL) {
7633 			kauth_cred_unref(&cred);
7634 		}
7635 		return 0;
7636 	}
7637 
7638 	if (drop_order != 0) {
7639 		if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
7640 		    client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
7641 		    ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
7642 			// Allow listeners, inbound connections without remote addresses, and
7643 			// application service connections to bypass the unentitled drop order,
7644 			// to allow them to connect to application services (not directly over
7645 			// physical networking interfaces)
7646 			drop_order = 0;
7647 		}
7648 	}
7649 
7650 	if (proc_pid(effective_proc) != pid) {
7651 		proc_t found_proc = proc_find(pid);
7652 		if (found_proc != PROC_NULL) {
7653 			effective_proc = found_proc;
7654 			pid_version = proc_pidversion(effective_proc);
7655 			release_eproc = true;
7656 		}
7657 	}
7658 #if defined(XNU_TARGET_OS_OSX)
7659 	if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
7660 		proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
7661 		responsible_proc = proc_find(effective_proc->p_responsible_pid);
7662 	}
7663 #endif /* defined(XNU_TARGET_OS_OSX) */
7664 
7665 	// Lock
7666 	lck_rw_lock_shared(&necp_kernel_policy_lock);
7667 
7668 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
7669 	size_t route_rule_id_array_count = 0;
7670 	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);
7671 
7672 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
7673 	NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
7674 
7675 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
7676 	matched_policy = necp_socket_find_policy_match_with_info_locked(necp_kernel_socket_policies_app_layer_map, &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, netagent_use_flags, NECP_MAX_NETAGENTS, required_agent_types, num_required_agent_types, info.used_responsible_pid ? responsible_proc : effective_proc, 0, &skip_policy_id, NULL, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit, NULL, debug);
7677 
7678 	// Check for loopback exception again after the policy match
7679 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
7680 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
7681 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
7682 		if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7683 			returned_result->filter_control_unit = 0;
7684 		} else {
7685 			returned_result->filter_control_unit = filter_control_unit;
7686 		}
7687 
7688 		if (flow_divert_aggregate_unit > 0) {
7689 			returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7690 		}
7691 
7692 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7693 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7694 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7695 		returned_result->routed_interface_index = lo_ifp->if_index;
7696 		*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7697 		error = 0;
7698 		goto done;
7699 	}
7700 
7701 	if (matched_policy) {
7702 		returned_result->policy_id = matched_policy->id;
7703 		returned_result->skip_policy_id = skip_policy_id;
7704 		returned_result->routing_result = matched_policy->result;
7705 		memcpy(&returned_result->routing_result_parameter, &matched_policy->result_parameter, sizeof(returned_result->routing_result_parameter));
7706 		if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
7707 			uuid_copy(*returned_override_euuid, responsible_application_uuid);
7708 		}
7709 	} else {
7710 		bool drop_all = false;
7711 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
7712 			// Mark socket as a drop if drop_all is set
7713 			drop_all = true;
7714 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
7715 				drop_all_bypass = necp_check_drop_all_bypass_result(proc);
7716 			}
7717 		}
7718 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
7719 			returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7720 			returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7721 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7722 			NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", 0, 0);
7723 		} else {
7724 			returned_result->policy_id = 0;
7725 			returned_result->skip_policy_id = 0;
7726 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
7727 		}
7728 	}
7729 	if (necp_check_missing_client_drop(proc, &info) ||
7730 	    necp_check_restricted_multicast_drop(proc, &info, false)) {
7731 		// Mark as drop
7732 		returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7733 		returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7734 		returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7735 		NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", 0, 0);
7736 	}
7737 	if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7738 		returned_result->filter_control_unit = 0;
7739 	} else {
7740 		returned_result->filter_control_unit = filter_control_unit;
7741 	}
7742 
7743 	if (flow_divert_aggregate_unit > 0) {
7744 		returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7745 	}
7746 
7747 	returned_result->service_action = service_action;
7748 
7749 	// Fetch service registration
7750 	if (service.identifier != 0) {
7751 		struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(service.identifier);
7752 		if (mapping != NULL) {
7753 			struct necp_service_registration *service_registration = NULL;
7754 			uuid_copy(returned_result->service_uuid, mapping->uuid);
7755 			returned_result->service_data = service.data;
7756 			if (service.identifier == NECP_NULL_SERVICE_ID) {
7757 				// NULL service is always 'registered'
7758 				returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
7759 			} else {
7760 				LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
7761 					if (service.identifier == service_registration->service_id) {
7762 						returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
7763 						break;
7764 					}
7765 				}
7766 			}
7767 		}
7768 	}
7769 
7770 	// Handle netagents
7771 	size_t netagent_i = 0;
7772 	for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7773 		struct necp_uuid_id_mapping *mapping = NULL;
7774 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
7775 		if (netagent_id == 0) {
7776 			continue;
7777 		}
7778 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
7779 		if (mapping != NULL) {
7780 			uuid_copy(returned_result->netagents[netagent_i], mapping->uuid);
7781 			returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
7782 			netagent_i++;
7783 		}
7784 
7785 		// If the flags say to remove, clear the local copy
7786 		if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
7787 			netagent_ids[netagent_cursor] = 0;
7788 		}
7789 	}
7790 
7791 	// Do routing evaluation
7792 	u_int output_bound_interface = bound_interface_index;
7793 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
7794 		output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
7795 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
7796 		output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
7797 	} else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
7798 		output_bound_interface = necp_get_primary_direct_interface_index();
7799 		if (output_bound_interface == IFSCOPE_NONE) {
7800 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7801 		} else {
7802 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
7803 			returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
7804 		}
7805 	}
7806 
7807 	if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
7808 	    returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
7809 		if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
7810 			// Trigger the event that we dropped due to a local network policy
7811 			necp_send_network_denied_event(pid, application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
7812 		}
7813 		if (reason != NULL) {
7814 			*reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
7815 		}
7816 	}
7817 
7818 	if (local_addr.sa.sa_len == 0 ||
7819 	    (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
7820 	    (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
7821 		no_local_addr = TRUE;
7822 	}
7823 
7824 	if (remote_addr.sa.sa_len == 0 ||
7825 	    (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
7826 	    (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
7827 		no_remote_addr = TRUE;
7828 		remote_family = remote_addr.sa.sa_family;
7829 	}
7830 
7831 	returned_result->routed_interface_index = 0;
7832 	struct rtentry *rt = NULL;
7833 	if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
7834 		// Treat the output bound interface as the routed interface for local address
7835 		// validation later.
7836 		returned_result->routed_interface_index = output_bound_interface;
7837 	} else {
7838 		if (no_remote_addr) {
7839 			memset(&remote_addr, 0, sizeof(remote_addr));
7840 			if (remote_family == AF_INET6) {
7841 				// Reset address to ::
7842 				remote_addr.sa.sa_family = AF_INET6;
7843 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
7844 			} else {
7845 				// Reset address to 0.0.0.0
7846 				remote_addr.sa.sa_family = AF_INET;
7847 				remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
7848 			}
7849 		}
7850 
7851 		rt = rtalloc1_scoped((struct sockaddr *)&remote_addr, 0, 0,
7852 		    output_bound_interface);
7853 
7854 		if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
7855 		    IS_INTF_CLAT46(rt->rt_ifp)) {
7856 			rtfree(rt);
7857 			rt = NULL;
7858 			returned_result->routed_interface_index = 0;
7859 		}
7860 
7861 		if (no_remote_addr && remote_family == AF_UNSPEC &&
7862 		    (rt == NULL || rt->rt_ifp == NULL)) {
7863 			// Route lookup for default IPv4 failed, try IPv6
7864 
7865 			// Cleanup old route if necessary
7866 			if (rt != NULL) {
7867 				rtfree(rt);
7868 				rt = NULL;
7869 			}
7870 
7871 			// Reset address to ::
7872 			memset(&remote_addr, 0, sizeof(remote_addr));
7873 			remote_addr.sa.sa_family = AF_INET6;
7874 			remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
7875 
7876 			// Get route
7877 			rt = rtalloc1_scoped((struct sockaddr *)&remote_addr, 0, 0,
7878 			    output_bound_interface);
7879 		}
7880 
7881 		if (rt != NULL &&
7882 		    rt->rt_ifp != NULL) {
7883 			returned_result->routed_interface_index = rt->rt_ifp->if_index;
7884 			/*
7885 			 * For local addresses, we allow the interface scope to be
7886 			 * either the loopback interface or the interface hosting the
7887 			 * local address.
7888 			 */
7889 			if (bound_interface_index != IFSCOPE_NONE &&
7890 			    rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
7891 			    (output_bound_interface == lo_ifp->if_index ||
7892 			    rt->rt_ifp->if_index == lo_ifp->if_index ||
7893 			    rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
7894 				struct sockaddr_storage dst;
7895 				unsigned int ifscope = bound_interface_index;
7896 
7897 				/*
7898 				 * Transform dst into the internal routing table form
7899 				 */
7900 				(void) sa_copy((struct sockaddr *)&remote_addr,
7901 				    &dst, &ifscope);
7902 
7903 				if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
7904 				    rt_ifa_is_dst((struct sockaddr *)&dst, rt->rt_ifa)) {
7905 					returned_result->routed_interface_index =
7906 					    bound_interface_index;
7907 				}
7908 			}
7909 		}
7910 	}
7911 
7912 	if (returned_result->routed_interface_index != 0 &&
7913 	    returned_result->routed_interface_index != lo_ifp->if_index &&     // Loopback can accept any local address
7914 	    !no_local_addr) {
7915 		// Transform local_addr into the ifaddr form
7916 		// IPv6 Scope IDs are always embedded in the ifaddr list
7917 		struct sockaddr_storage local_address_sanitized;
7918 		u_int ifscope = IFSCOPE_NONE;
7919 		(void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
7920 		SIN(&local_address_sanitized)->sin_port = 0;
7921 		if (local_address_sanitized.ss_family == AF_INET6) {
7922 			if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
7923 				SIN6(&local_address_sanitized)->sin6_scope_id = 0;
7924 			}
7925 		}
7926 
7927 		// Validate local address on routed interface
7928 		struct ifaddr *ifa = ifa_ifwithaddr_scoped((struct sockaddr *)&local_address_sanitized, returned_result->routed_interface_index);
7929 		if (ifa == NULL) {
7930 			// Interface address not found, reject route
7931 			returned_result->routed_interface_index = 0;
7932 			if (rt != NULL) {
7933 				rtfree(rt);
7934 				rt = NULL;
7935 			}
7936 		} else {
7937 			ifaddr_release(ifa);
7938 			ifa = NULL;
7939 		}
7940 	}
7941 
7942 	if (flags != NULL) {
7943 #if SKYWALK && defined(XNU_TARGET_OS_OSX)
7944 		enum net_filter_event_subsystems filters = net_filter_event_get_state();
7945 
7946 		if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
7947 			*flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
7948 		}
7949 		if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
7950 			*flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
7951 		}
7952 		if (filters & NET_FILTER_EVENT_ALF) {
7953 			*flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
7954 		}
7955 		if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
7956 			*flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
7957 		}
7958 #endif /* SKYWALK && defined(XNU_TARGET_OS_OSX) */
7959 		if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
7960 			// Check for local/direct
7961 			bool is_local = FALSE;
7962 			if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
7963 				is_local = TRUE;
7964 			} else if (returned_result->routed_interface_index != 0 &&
7965 			    !no_remote_addr) {
7966 				// Clean up the address before comparison with interface addresses
7967 
7968 				// Transform remote_addr into the ifaddr form
7969 				// IPv6 Scope IDs are always embedded in the ifaddr list
7970 				struct sockaddr_storage remote_address_sanitized;
7971 				u_int ifscope = IFSCOPE_NONE;
7972 				(void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
7973 				SIN(&remote_address_sanitized)->sin_port = 0;
7974 				if (remote_address_sanitized.ss_family == AF_INET6) {
7975 					if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
7976 						SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
7977 					}
7978 				}
7979 
7980 				// Check if remote address is an interface address
7981 				struct ifaddr *ifa = ifa_ifwithaddr((struct sockaddr *)&remote_address_sanitized);
7982 				if (ifa != NULL && ifa->ifa_ifp != NULL) {
7983 					u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
7984 					if (if_index_for_remote_addr == returned_result->routed_interface_index ||
7985 					    if_index_for_remote_addr == lo_ifp->if_index) {
7986 						is_local = TRUE;
7987 					}
7988 				}
7989 				if (ifa != NULL) {
7990 					ifaddr_release(ifa);
7991 					ifa = NULL;
7992 				}
7993 			}
7994 
7995 			if (is_local) {
7996 				*flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7997 			} else if (rt != NULL) {
7998 				if (rt->rt_flags & RTF_GLOBAL) {
7999 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8000 				} else if (!(rt->rt_flags & RTF_GATEWAY) &&
8001 				    (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8002 					// Route is directly accessible
8003 					*flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8004 				}
8005 			}
8006 
8007 			if (rt != NULL &&
8008 			    rt->rt_ifp != NULL) {
8009 				// Check probe status
8010 				if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8011 					*flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8012 				}
8013 
8014 				if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8015 					struct if_cellular_status_v1 *ifsr;
8016 
8017 					ifnet_lock_shared(rt->rt_ifp);
8018 					lck_rw_lock_exclusive(&rt->rt_ifp->if_link_status_lock);
8019 
8020 					if (rt->rt_ifp->if_link_status != NULL) {
8021 						ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8022 
8023 						if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8024 							if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8025 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8026 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8027 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8028 							} else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8029 								returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8030 							}
8031 						}
8032 					}
8033 					lck_rw_done(&rt->rt_ifp->if_link_status_lock);
8034 					ifnet_lock_done(rt->rt_ifp);
8035 				}
8036 
8037 				// Check link quality
8038 				if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8039 				    (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8040 				    rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8041 					*flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8042 				}
8043 
8044 				// Check QoS marking (fastlane)
8045 				for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8046 					if (necp_update_qos_marking(rt->rt_ifp, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index])) {
8047 						*flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8048 						// If the route can use QoS markings, stop iterating route rules
8049 						break;
8050 					}
8051 				}
8052 
8053 				if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8054 					*flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8055 				}
8056 
8057 				if (traffic_class == SO_TC_BK_SYS) {
8058 					// Block BK_SYS traffic if interface is throttled
8059 					u_int32_t throttle_level = 0;
8060 					if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8061 						if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8062 							returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8063 							memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8064 						}
8065 					}
8066 				}
8067 			}
8068 		}
8069 
8070 		u_int interface_to_check = returned_result->routed_interface_index;
8071 		if (interface_to_check == 0) {
8072 			interface_to_check = output_bound_interface;
8073 		}
8074 		union necp_sockaddr_union default_address;
8075 		struct rtentry *v4Route = NULL;
8076 		struct rtentry *v6Route = NULL;
8077 
8078 		memset(&default_address, 0, sizeof(default_address));
8079 
8080 		// Reset address to 0.0.0.0
8081 		default_address.sa.sa_family = AF_INET;
8082 		default_address.sa.sa_len = sizeof(struct sockaddr_in);
8083 		v4Route = rtalloc1_scoped((struct sockaddr *)&default_address, 0, 0,
8084 		    returned_result->routed_interface_index);
8085 
8086 		// Reset address to ::
8087 		default_address.sa.sa_family = AF_INET6;
8088 		default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8089 		v6Route = rtalloc1_scoped((struct sockaddr *)&default_address, 0, 0,
8090 		    returned_result->routed_interface_index);
8091 
8092 		if (v4Route != NULL) {
8093 			if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8094 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8095 			}
8096 			if (returned_v4_gateway != NULL &&
8097 			    v4Route->rt_gateway != NULL &&
8098 			    v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8099 				memcpy(&returned_v4_gateway->u.sin, v4Route->rt_gateway, sizeof(returned_v4_gateway->u.sin));
8100 				memset(&returned_v4_gateway->u.sin.sin_zero, 0, sizeof(returned_v4_gateway->u.sin.sin_zero));
8101 			}
8102 			rtfree(v4Route);
8103 			v4Route = NULL;
8104 		}
8105 
8106 		if (v6Route != NULL) {
8107 			if (v6Route->rt_ifp != NULL) {
8108 				*flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8109 
8110 				if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8111 					*flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8112 				}
8113 			}
8114 			if (returned_v6_gateway != NULL &&
8115 			    v6Route->rt_gateway != NULL &&
8116 			    v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8117 				memcpy(&returned_v6_gateway->u.sin6, v6Route->rt_gateway, sizeof(returned_v6_gateway->u.sin6));
8118 			}
8119 			rtfree(v6Route);
8120 			v6Route = NULL;
8121 		}
8122 	}
8123 
8124 	// Take two passes through the rule list: first for rules that don't match based on agents,
8125 	// second for rules that match based on agents. Since rules can modify the agent list itself,
8126 	// this makes the logic more deterministic. This allows a non-agent matching rule to remove
8127 	// an agent before it is used for matching later.
8128 	size_t route_rule_index = 0;
8129 	bool second_pass = false;
8130 	while (route_rule_index < route_rule_id_array_count) {
8131 		bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id_array[route_rule_index]);
8132 		if (rule_matches_agents != second_pass) {
8133 			// Process rules that match based on agents only in the second pass
8134 			route_rule_index++;
8135 			if (route_rule_index == route_rule_id_array_count && !second_pass) {
8136 				route_rule_index = 0;
8137 				second_pass = true;
8138 			}
8139 			continue;
8140 		}
8141 
8142 		u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8143 		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);
8144 		if (!route_is_allowed) {
8145 			// If the route is blocked, treat the lookup as a drop
8146 			returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8147 			memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8148 
8149 			if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8150 				if (reason != NULL) {
8151 					if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8152 						*reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8153 					} else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8154 						*reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8155 					}
8156 				}
8157 				necp_send_application_interface_denied_event(pid, application_uuid, interface_type_denied);
8158 			}
8159 			// If the route gets denied, stop matching rules
8160 			break;
8161 		}
8162 
8163 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8164 		if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8165 			u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(rt, netagent_ids, NECP_MAX_NETAGENTS,
8166 			    route_rule_id_array[route_rule_index], &flow_divert_aggregate_unit);
8167 			if (flow_divert_control_unit != 0) {
8168 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8169 				returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8170 			}
8171 			if (flow_divert_aggregate_unit != 0) {
8172 				returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8173 			}
8174 		}
8175 
8176 		// Check if there is a route rule that adds or removes an agent
8177 		bool remove = false;
8178 		u_int32_t netagent_id = necp_route_get_netagent(rt, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id_array[route_rule_index], &remove);
8179 		if (netagent_id != 0) {
8180 			struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
8181 			if (mapping != NULL) {
8182 				bool agent_already_present = false;
8183 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8184 					if (uuid_compare(returned_result->netagents[netagent_cursor], mapping->uuid) == 0) {
8185 						// Found the agent already present
8186 						agent_already_present = true;
8187 						if (remove) {
8188 							// Mark as remove if necessary
8189 							returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8190 						}
8191 					} else if (uuid_is_null(returned_result->netagents[netagent_cursor])) {
8192 						// Found open slot
8193 						if (!agent_already_present) {
8194 							uuid_copy(returned_result->netagents[netagent_cursor], mapping->uuid);
8195 							if (remove) {
8196 								returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8197 							} else {
8198 								returned_result->netagent_use_flags[netagent_cursor] = 0;
8199 							}
8200 						}
8201 						break;
8202 					}
8203 				}
8204 			}
8205 
8206 			// Update the local netagent_ids array for future evaluations
8207 			if (remove) {
8208 				// Check if the agent ID is in the array, and remove it
8209 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8210 					if (netagent_id == netagent_ids[netagent_cursor]) {
8211 						netagent_ids[netagent_cursor] = 0;
8212 					}
8213 				}
8214 			} else {
8215 				// Check if the agent ID is not yet in the array, and add it
8216 				bool found = false;
8217 				for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8218 					if (netagent_id == netagent_ids[netagent_cursor]) {
8219 						found = true;
8220 						break;
8221 					}
8222 				}
8223 				if (!found) {
8224 					for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8225 						if (netagent_ids[netagent_cursor] == 0) {
8226 							// Empty slot, add the agent
8227 							netagent_ids[netagent_cursor] = netagent_id;
8228 							break;
8229 						}
8230 					}
8231 				}
8232 			}
8233 		}
8234 
8235 		route_rule_index++;
8236 		if (route_rule_index == route_rule_id_array_count && !second_pass) {
8237 			route_rule_index = 0;
8238 			second_pass = true;
8239 		}
8240 	}
8241 
8242 	if (rt != NULL && rt->rt_ifp != NULL) {
8243 		const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8244 		const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8245 		const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8246 		    IFNET_IS_EXPENSIVE(rt->rt_ifp));
8247 		const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8248 		    IFNET_IS_CONSTRAINED(rt->rt_ifp));
8249 		const bool interface_type_blocked = !necp_route_is_interface_type_allowed(rt, NULL, proc, NULL);
8250 		if (!is_listener && !is_browser) {
8251 			if (reason != NULL) {
8252 				if (expensive_prohibited) {
8253 					*reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8254 				} else if (constrained_prohibited) {
8255 					*reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8256 				}
8257 			}
8258 			if (expensive_prohibited || constrained_prohibited || interface_type_blocked) {
8259 				// If a property of the interface was not allowed, treat it as a drop
8260 				returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8261 				memset(&returned_result->routing_result_parameter, 0, sizeof(returned_result->routing_result_parameter));
8262 			}
8263 		}
8264 	}
8265 
8266 	if (rt != NULL) {
8267 		if (returned_route != NULL) {
8268 			*returned_route = rt;
8269 		} else {
8270 			rtfree(rt);
8271 		}
8272 		rt = NULL;
8273 	}
8274 
8275 done:
8276 	// Unlock
8277 	lck_rw_done(&necp_kernel_policy_lock);
8278 
8279 	if (release_eproc && effective_proc != PROC_NULL) {
8280 		proc_rele(effective_proc);
8281 	}
8282 #if defined(XNU_TARGET_OS_OSX)
8283 	if (responsible_proc != PROC_NULL) {
8284 		proc_rele(responsible_proc);
8285 	}
8286 #endif
8287 
8288 	if (cred != NULL) {
8289 		kauth_cred_unref(&cred);
8290 	}
8291 
8292 	return error;
8293 }
8294 
8295 static bool
necp_is_route_local(union necp_sockaddr_union * remote_addr)8296 necp_is_route_local(union necp_sockaddr_union *remote_addr)
8297 {
8298 	struct rtentry *rt = NULL;
8299 	bool is_local = FALSE;
8300 
8301 	if (remote_addr == NULL) {
8302 		return NULL;
8303 	}
8304 
8305 	if (remote_addr->sa.sa_len == 0 ||
8306 	    (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8307 	    (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8308 		return FALSE;
8309 	}
8310 
8311 	// Lookup route regardless of the scoped interface to check if
8312 	// remote address is in a local network.
8313 	rt = rtalloc1_scoped((struct sockaddr *)remote_addr, 0, 0, 0);
8314 
8315 	if (rt == NULL) {
8316 		goto done;
8317 	}
8318 	if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8319 		goto free_rt;
8320 	}
8321 	is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
8322 
8323 free_rt:
8324 	rtfree(rt);
8325 
8326 done:
8327 	return is_local;
8328 }
8329 
8330 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,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 * 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)8331 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, 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 *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)
8332 {
8333 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
8334 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8335 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
8336 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
8337 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
8338 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8339 				if (bound_interface_index == cond_bound_interface_index) {
8340 					// No match, matches forbidden interface
8341 					return FALSE;
8342 				}
8343 			} else {
8344 				if (bound_interface_index != cond_bound_interface_index) {
8345 					// No match, does not match required interface
8346 					return FALSE;
8347 				}
8348 			}
8349 		}
8350 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8351 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8352 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
8353 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8354 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
8355 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8356 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
8357 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8358 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8359 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8360 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8361 					// No match, matches some forbidden interface flags
8362 					return FALSE;
8363 				}
8364 			} else {
8365 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8366 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8367 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8368 					// No match, does not match some required interface xflags
8369 					return FALSE;
8370 				}
8371 			}
8372 		}
8373 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
8374 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
8375 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
8376 			if (bound_interface_index != 0) {
8377 				// No match, requires a non-bound packet
8378 				return FALSE;
8379 			}
8380 		}
8381 	}
8382 
8383 	if (kernel_policy->condition_mask == 0) {
8384 		return TRUE;
8385 	}
8386 
8387 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8388 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
8389 		    "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
8390 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
8391 			if (app_id == kernel_policy->cond_app_id) {
8392 				// No match, matches forbidden application
8393 				return FALSE;
8394 			}
8395 		} else {
8396 			if (app_id != kernel_policy->cond_app_id) {
8397 				// No match, does not match required application
8398 				return FALSE;
8399 			}
8400 		}
8401 
8402 		// Check signing identifier only after APP ID matched
8403 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
8404 		    kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8405 			u_int8_t matched = necp_boolean_state_false;
8406 			const char *signing_id = cs_identity_get(proc ? proc : current_proc());
8407 			NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
8408 			    "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
8409 			    kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
8410 			    signing_id ? signing_id : "<n/a>");
8411 			if (signing_id != NULL) {
8412 				size_t signing_id_size = strlen(signing_id) + 1;
8413 				if (memcmp(signing_id, kernel_policy->cond_signing_identifier, signing_id_size) == 0) {
8414 					matched = necp_boolean_state_true;
8415 				}
8416 			}
8417 
8418 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8419 				if (matched == necp_boolean_state_true) {
8420 					return FALSE;
8421 				}
8422 			} else {
8423 				if (matched != necp_boolean_state_true) {
8424 					return FALSE;
8425 				}
8426 			}
8427 		}
8428 	}
8429 
8430 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8431 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
8432 		    "NECP_KERNEL_CONDITION_REAL_APP_ID",
8433 		    kernel_policy->cond_real_app_id, real_app_id);
8434 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8435 			if (real_app_id == kernel_policy->cond_real_app_id) {
8436 				// No match, matches forbidden application
8437 				return FALSE;
8438 			}
8439 		} else {
8440 			if (real_app_id != kernel_policy->cond_real_app_id) {
8441 				// No match, does not match required application
8442 				return FALSE;
8443 			}
8444 		}
8445 	}
8446 
8447 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8448 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
8449 		if (!has_client) {
8450 			return FALSE;
8451 		}
8452 	}
8453 
8454 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
8455 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
8456 		if (!is_entitled) {
8457 			// Process is missing entitlement
8458 			return FALSE;
8459 		}
8460 	}
8461 
8462 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8463 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_PLATFORM_BINARY", 0, is_platform_binary);
8464 		if (is_platform_binary == 0) {
8465 			// Process is not platform binary
8466 			return FALSE;
8467 		}
8468 	}
8469 
8470 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
8471 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
8472 		if (has_signed_result == 0) {
8473 			// Client did not have a system-signed result
8474 			return FALSE;
8475 		}
8476 	}
8477 
8478 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
8479 		if (proc != NULL) {
8480 			NECP_DATA_TRACE_LOG_CONDITION3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
8481 			    kernel_policy->cond_sdk_version.platform,
8482 			    kernel_policy->cond_sdk_version.min_version,
8483 			    kernel_policy->cond_sdk_version.version,
8484 			    proc_platform(proc),
8485 			    proc_min_sdk(proc),
8486 			    proc_sdk(proc));
8487 			if (kernel_policy->cond_sdk_version.platform != 0) {
8488 				if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
8489 					// Process does not match platform
8490 					return FALSE;
8491 				}
8492 			}
8493 
8494 			if (kernel_policy->cond_sdk_version.min_version != 0) {
8495 				if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
8496 					// Process min version is older than required min version
8497 					return FALSE;
8498 				}
8499 			}
8500 
8501 			if (kernel_policy->cond_sdk_version.version != 0) {
8502 				if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
8503 					// Process SDK version is older than required version
8504 					return FALSE;
8505 				}
8506 			}
8507 		}
8508 	}
8509 
8510 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
8511 		NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
8512 		if (kernel_policy->cond_custom_entitlement != NULL) {
8513 			if (proc == NULL) {
8514 				// No process found, cannot check entitlement
8515 				return FALSE;
8516 			}
8517 			task_t task = proc_task(proc);
8518 			if (task == NULL ||
8519 			    !IOTaskHasEntitlement(task, kernel_policy->cond_custom_entitlement)) {
8520 				// Process is missing custom entitlement
8521 				return FALSE;
8522 			}
8523 		}
8524 	}
8525 
8526 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8527 		NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
8528 		    "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
8529 		// Exact match requires the number of dots to match (no suffix matching allowed)
8530 		bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
8531 		    necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count));
8532 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8533 			if (domain_matches) {
8534 				// No match, matches forbidden domain
8535 				return FALSE;
8536 			}
8537 		} else {
8538 			if (!domain_matches) {
8539 				// No match, does not match required domain
8540 				return FALSE;
8541 			}
8542 		}
8543 	} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8544 		NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
8545 		    "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
8546 		bool domain_matches = necp_hostname_matches_domain(domain, domain_dot_count, kernel_policy->cond_domain, kernel_policy->cond_domain_dot_count);
8547 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8548 			if (domain_matches) {
8549 				// No match, matches forbidden domain
8550 				return FALSE;
8551 			}
8552 		} else {
8553 			if (!domain_matches) {
8554 				// No match, does not match required domain
8555 				return FALSE;
8556 			}
8557 		}
8558 	}
8559 
8560 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8561 		struct necp_domain_filter *filter = necp_lookup_domain_filter(&necp_global_domain_filter_list, kernel_policy->cond_domain_filter);
8562 		if (filter != NULL && filter->filter != NULL) {
8563 			bool domain_matches = net_bloom_filter_contains(filter->filter, domain.string, domain.length);
8564 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8565 				if (domain_matches) {
8566 					// No match, matches forbidden domain
8567 					return FALSE;
8568 				}
8569 			} else {
8570 				if (!domain_matches) {
8571 					// No match, does not match required domain
8572 					return FALSE;
8573 				}
8574 			}
8575 		}
8576 	}
8577 
8578 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
8579 		NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
8580 		    "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
8581 		bool url_matches = (url ? strncasecmp(kernel_policy->cond_url, url, strlen(kernel_policy->cond_url)) == 0 : false);
8582 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
8583 			if (url_matches) {
8584 				// No match, matches forbidden url
8585 				return FALSE;
8586 			}
8587 		} else {
8588 			if (!url_matches) {
8589 				// No match, does not match required url
8590 				return FALSE;
8591 			}
8592 		}
8593 	}
8594 
8595 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8596 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
8597 		    "NECP_KERNEL_CONDITION_ACCOUNT_ID",
8598 		    kernel_policy->cond_account_id, account_id);
8599 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8600 			if (account_id == kernel_policy->cond_account_id) {
8601 				// No match, matches forbidden account
8602 				return FALSE;
8603 			}
8604 		} else {
8605 			if (account_id != kernel_policy->cond_account_id) {
8606 				// No match, does not match required account
8607 				return FALSE;
8608 			}
8609 		}
8610 	}
8611 
8612 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
8613 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
8614 		    "NECP_KERNEL_CONDITION_PID",
8615 		    kernel_policy->cond_pid, pid);
8616 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
8617 			if (pid == kernel_policy->cond_pid) {
8618 				// No match, matches forbidden pid
8619 				return FALSE;
8620 			}
8621 			if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
8622 				return FALSE;
8623 			}
8624 		} else {
8625 			if (pid != kernel_policy->cond_pid) {
8626 				// No match, does not match required pid
8627 				return FALSE;
8628 			}
8629 			if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
8630 				return FALSE;
8631 			}
8632 		}
8633 	}
8634 
8635 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
8636 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
8637 		    "NECP_KERNEL_CONDITION_UID",
8638 		    kernel_policy->cond_uid, uid);
8639 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
8640 			if (uid == kernel_policy->cond_uid) {
8641 				// No match, matches forbidden uid
8642 				return FALSE;
8643 			}
8644 		} else {
8645 			if (uid != kernel_policy->cond_uid) {
8646 				// No match, does not match required uid
8647 				return FALSE;
8648 			}
8649 		}
8650 	}
8651 
8652 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
8653 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
8654 		    "NECP_KERNEL_CONDITION_REAL_UID",
8655 		    kernel_policy->cond_real_uid, real_uid);
8656 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
8657 			if (real_uid == kernel_policy->cond_real_uid) {
8658 				// No match, matches forbidden uid
8659 				return FALSE;
8660 			}
8661 		} else {
8662 			if (real_uid != kernel_policy->cond_real_uid) {
8663 				// No match, does not match required uid
8664 				return FALSE;
8665 			}
8666 		}
8667 	}
8668 
8669 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8670 		NECP_DATA_TRACE_LOG_CONDITION3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
8671 		    kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
8672 		    traffic_class, 0, 0);
8673 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8674 			if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
8675 			    traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
8676 				// No match, matches forbidden traffic class
8677 				return FALSE;
8678 			}
8679 		} else {
8680 			if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
8681 			    traffic_class > kernel_policy->cond_traffic_class.end_tc) {
8682 				// No match, does not match required traffic class
8683 				return FALSE;
8684 			}
8685 		}
8686 	}
8687 
8688 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8689 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
8690 		    "NECP_KERNEL_CONDITION_PROTOCOL",
8691 		    kernel_policy->cond_protocol, protocol);
8692 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8693 			if (protocol == kernel_policy->cond_protocol) {
8694 				// No match, matches forbidden protocol
8695 				return FALSE;
8696 			}
8697 		} else {
8698 			if (protocol != kernel_policy->cond_protocol) {
8699 				// No match, does not match required protocol
8700 				return FALSE;
8701 			}
8702 		}
8703 	}
8704 
8705 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
8706 		NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
8707 		    kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
8708 		    "n/a", "n/a", "n/a");
8709 		bool matches_agent_type = FALSE;
8710 		for (u_int32_t i = 0; i < num_required_agent_types; i++) {
8711 			struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
8712 			if ((strlen(kernel_policy->cond_agent_type.agent_domain) == 0 ||
8713 			    strncmp(required_agent_type->netagent_domain, kernel_policy->cond_agent_type.agent_domain, NETAGENT_DOMAINSIZE) == 0) &&
8714 			    (strlen(kernel_policy->cond_agent_type.agent_type) == 0 ||
8715 			    strncmp(required_agent_type->netagent_type, kernel_policy->cond_agent_type.agent_type, NETAGENT_TYPESIZE) == 0)) {
8716 				// Found a required agent that matches
8717 				matches_agent_type = TRUE;
8718 				break;
8719 			}
8720 		}
8721 		if (!matches_agent_type) {
8722 			return FALSE;
8723 		}
8724 	}
8725 
8726 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
8727 		bool is_local = FALSE;
8728 
8729 		if (rt != NULL) {
8730 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
8731 		} else {
8732 			is_local = necp_is_route_local(remote);
8733 		}
8734 		if (info != NULL) {
8735 			info->is_local = is_local;
8736 		}
8737 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
8738 		if (!is_local) {
8739 			// Either no route to validate or no match for local networks
8740 			return FALSE;
8741 		}
8742 	}
8743 
8744 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
8745 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
8746 			bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
8747 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
8748 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
8749 				if (inRange) {
8750 					return FALSE;
8751 				}
8752 			} else {
8753 				if (!inRange) {
8754 					return FALSE;
8755 				}
8756 			}
8757 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
8758 			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
8759 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
8760 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
8761 				if (inSubnet) {
8762 					return FALSE;
8763 				}
8764 			} else {
8765 				if (!inSubnet) {
8766 					return FALSE;
8767 				}
8768 			}
8769 		}
8770 	}
8771 
8772 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
8773 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
8774 			bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
8775 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
8776 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
8777 				if (inRange) {
8778 					return FALSE;
8779 				}
8780 			} else {
8781 				if (!inRange) {
8782 					return FALSE;
8783 				}
8784 			}
8785 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
8786 			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
8787 			NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
8788 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
8789 				if (inSubnet) {
8790 					return FALSE;
8791 				}
8792 			} else {
8793 				if (!inSubnet) {
8794 					return FALSE;
8795 				}
8796 			}
8797 		}
8798 	}
8799 
8800 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8801 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
8802 		    "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
8803 		    kernel_policy->cond_client_flags, client_flags);
8804 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8805 			if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
8806 				// Flags do match, and condition is negative, fail.
8807 				return FALSE;
8808 			}
8809 		} else {
8810 			if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
8811 				// Flags do not match, fail.
8812 				return FALSE;
8813 			}
8814 		}
8815 	}
8816 
8817 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
8818 		bool isEmpty = necp_addr_is_empty((struct sockaddr *)local);
8819 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
8820 		    "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
8821 		    0, isEmpty);
8822 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
8823 			if (isEmpty) {
8824 				return FALSE;
8825 			}
8826 		} else {
8827 			if (!isEmpty) {
8828 				return FALSE;
8829 			}
8830 		}
8831 	}
8832 
8833 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
8834 		bool isEmpty = necp_addr_is_empty((struct sockaddr *)remote);
8835 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
8836 		    "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
8837 		    0, isEmpty);
8838 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
8839 			if (isEmpty) {
8840 				return FALSE;
8841 			}
8842 		} else {
8843 			if (!isEmpty) {
8844 				return FALSE;
8845 			}
8846 		}
8847 	}
8848 
8849 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
8850 		u_int16_t remote_port = 0;
8851 		if (((struct sockaddr *)remote)->sa_family == AF_INET || ((struct sockaddr *)remote)->sa_family == AF_INET6) {
8852 			remote_port = ((struct sockaddr_in *)remote)->sin_port;
8853 		}
8854 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
8855 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
8856 		    scheme_port, remote_port);
8857 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
8858 			if (kernel_policy->cond_scheme_port == scheme_port ||
8859 			    kernel_policy->cond_scheme_port == remote_port) {
8860 				return FALSE;
8861 			}
8862 		} else {
8863 			if (kernel_policy->cond_scheme_port != scheme_port &&
8864 			    kernel_policy->cond_scheme_port != remote_port) {
8865 				return FALSE;
8866 			}
8867 		}
8868 	}
8869 
8870 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
8871 		NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
8872 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
8873 		    kernel_policy->cond_packet_filter_tags,
8874 		    pf_tag);
8875 		bool tags_matched = false;
8876 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
8877 			if (pf_tag == PF_TAG_ID_STACK_DROP) {
8878 				tags_matched = true;
8879 			}
8880 		}
8881 
8882 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
8883 			if (tags_matched) {
8884 				return FALSE;
8885 			}
8886 		} else {
8887 			if (!tags_matched) {
8888 				return FALSE;
8889 			}
8890 		}
8891 	}
8892 
8893 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
8894 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
8895 			if (is_loopback) {
8896 				return FALSE;
8897 			}
8898 		} else {
8899 			if (!is_loopback) {
8900 				return FALSE;
8901 			}
8902 		}
8903 	}
8904 
8905 	if (is_delegated && (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
8906 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
8907 			if (real_is_platform_binary) {
8908 				return FALSE;
8909 			}
8910 		} else {
8911 			if (!real_is_platform_binary) {
8912 				return FALSE;
8913 			}
8914 		}
8915 	}
8916 
8917 	return TRUE;
8918 }
8919 
8920 static inline u_int32_t
necp_socket_calc_flowhash_locked(struct necp_socket_info * info)8921 necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
8922 {
8923 	return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
8924 }
8925 
8926 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)8927 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)
8928 {
8929 	struct socket *so = NULL;
8930 	proc_t sock_proc = NULL;
8931 	proc_t curr_proc = current_proc();
8932 
8933 	memset(info, 0, sizeof(struct necp_socket_info));
8934 
8935 	so = inp->inp_socket;
8936 
8937 	info->drop_order = drop_order;
8938 	info->is_loopback = is_loopback;
8939 	info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
8940 
8941 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
8942 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
8943 		info->uid = kauth_cred_getuid(so->so_cred);
8944 		info->real_uid = info->uid;
8945 	}
8946 
8947 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8948 		info->traffic_class = so->so_traffic_class;
8949 	}
8950 
8951 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8952 		info->has_client = !uuid_is_null(inp->necp_client_uuid);
8953 	}
8954 
8955 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8956 		info->client_flags = 0;
8957 		if (INP_NO_CONSTRAINED(inp)) {
8958 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
8959 		}
8960 		if (INP_NO_EXPENSIVE(inp)) {
8961 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
8962 		}
8963 		if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
8964 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
8965 		}
8966 		if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
8967 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
8968 		}
8969 		if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
8970 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
8971 		}
8972 		if (inp->inp_socket->so_flags1 & SOF1_INBOUND || override_is_inbound) {
8973 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
8974 		}
8975 		if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
8976 		    inp->inp_flags2 & INP2_EXTERNAL_PORT) {
8977 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
8978 		}
8979 		if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
8980 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
8981 		}
8982 		if (inp->inp_socket->so_options & SO_REUSEPORT) {
8983 			info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
8984 		}
8985 	}
8986 
8987 	if ((necp_data_tracing_level && necp_data_tracing_proto) ||
8988 	    necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8989 		if (inp->inp_ip_p) {
8990 			info->protocol = inp->inp_ip_p;
8991 		} else {
8992 			info->protocol = SOCK_PROTO(so);
8993 		}
8994 	}
8995 
8996 	if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8997 		u_int32_t responsible_application_id = 0;
8998 
8999 		struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9000 		if (existing_mapping) {
9001 			info->application_id = existing_mapping->id;
9002 		}
9003 
9004 #if defined(XNU_TARGET_OS_OSX)
9005 		if (so->so_rpid > 0) {
9006 			existing_mapping = necp_uuid_lookup_app_id_locked(so->so_ruuid);
9007 			if (existing_mapping != NULL) {
9008 				responsible_application_id = existing_mapping->id;
9009 			}
9010 		}
9011 #endif
9012 
9013 		if (responsible_application_id > 0) {
9014 			info->real_application_id = info->application_id;
9015 			info->application_id = responsible_application_id;
9016 			info->used_responsible_pid = true;
9017 		} else if (!(so->so_flags & SOF_DELEGATED)) {
9018 			info->real_application_id = info->application_id;
9019 		} else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9020 			struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(so->last_uuid);
9021 			if (real_existing_mapping) {
9022 				info->real_application_id = real_existing_mapping->id;
9023 			}
9024 		}
9025 	}
9026 
9027 	pid_t socket_pid =
9028 #if defined(XNU_TARGET_OS_OSX)
9029 	    info->used_responsible_pid ? so->so_rpid :
9030 #endif
9031 	    ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9032 	if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9033 		sock_proc = proc_find(socket_pid);
9034 		if (socket_proc) {
9035 			*socket_proc = sock_proc;
9036 		}
9037 	}
9038 
9039 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9040 		const task_t task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9041 		info->is_entitled = necp_task_has_match_entitlement(task);
9042 		if (!info->is_entitled) {
9043 			// Task does not have entitlement, check the parent task
9044 			necp_get_parent_is_entitled(task, info);
9045 		}
9046 	}
9047 
9048 	if ((necp_data_tracing_level && necp_data_tracing_pid) ||
9049 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID)) {
9050 		info->pid = socket_pid;
9051 		info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9052 	}
9053 
9054 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9055 		info->is_platform_binary = necp_is_platform_binary(sock_proc ? sock_proc : curr_proc) ? true : false;
9056 	}
9057 
9058 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9059 		proc_t real_proc = curr_proc;
9060 		bool release_real_proc = false;
9061 		if (so->last_pid != proc_pid(real_proc)) {
9062 			if (so->last_pid == socket_pid && sock_proc != NULL) {
9063 				real_proc = sock_proc;
9064 			} else {
9065 				proc_t last_proc = proc_find(so->last_pid);
9066 				if (last_proc != NULL) {
9067 					real_proc = last_proc;
9068 					release_real_proc = true;
9069 				}
9070 			}
9071 		}
9072 		if (real_proc != NULL) {
9073 			info->real_is_platform_binary = (necp_is_platform_binary(real_proc) ? true : false);
9074 			if (release_real_proc) {
9075 				proc_rele(real_proc);
9076 			}
9077 		}
9078 	}
9079 
9080 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9081 		struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(&necp_account_id_list, inp->inp_necp_attributes.inp_account);
9082 		if (existing_mapping) {
9083 			info->account_id = existing_mapping->id;
9084 		}
9085 	}
9086 
9087 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9088 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9089 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9090 		info->domain = inp->inp_necp_attributes.inp_domain;
9091 	}
9092 
9093 	if (override_bound_interface) {
9094 		info->bound_interface_index = override_bound_interface;
9095 	} else {
9096 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9097 			info->bound_interface_index = inp->inp_boundifp->if_index;
9098 		}
9099 	}
9100 
9101 	if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9102 	    info->bound_interface_index != IFSCOPE_NONE) {
9103 		ifnet_head_lock_shared();
9104 		ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9105 		if (interface != NULL) {
9106 			info->bound_interface_flags = interface->if_flags;
9107 			info->bound_interface_eflags = interface->if_eflags;
9108 			info->bound_interface_xflags = interface->if_xflags;
9109 		}
9110 		ifnet_head_done();
9111 	}
9112 
9113 	bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9114 	    uuid_is_null(inp->necp_client_uuid) &&
9115 	    necp_socket_has_resolver_signature(inp));
9116 	if ((necp_data_tracing_level && necp_data_tracing_port) ||
9117 	    necp_restrict_multicast ||
9118 	    needs_address_for_signature ||
9119 	    (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
9120 		if (override_local_addr != NULL) {
9121 			if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9122 				memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
9123 				if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9124 					struct sockaddr_in sin;
9125 					in6_sin6_2_sin(&sin, &(info->local_addr.sin6));
9126 					memset(&info->local_addr, 0, sizeof(union necp_sockaddr_union));
9127 					memcpy(&info->local_addr, &sin, sin.sin_len);
9128 				}
9129 			} else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9130 				memcpy(&info->local_addr, override_local_addr, override_local_addr->sa_len);
9131 			}
9132 		} else {
9133 			if (inp->inp_vflag & INP_IPV6) {
9134 				((struct sockaddr_in6 *)&info->local_addr)->sin6_family = AF_INET6;
9135 				((struct sockaddr_in6 *)&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9136 				((struct sockaddr_in6 *)&info->local_addr)->sin6_port = inp->inp_lport;
9137 				memcpy(&((struct sockaddr_in6 *)&info->local_addr)->sin6_addr, &inp->in6p_laddr, sizeof(struct in6_addr));
9138 			} else if (inp->inp_vflag & INP_IPV4) {
9139 				((struct sockaddr_in *)&info->local_addr)->sin_family = AF_INET;
9140 				((struct sockaddr_in *)&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9141 				((struct sockaddr_in *)&info->local_addr)->sin_port = inp->inp_lport;
9142 				memcpy(&((struct sockaddr_in *)&info->local_addr)->sin_addr, &inp->inp_laddr, sizeof(struct in_addr));
9143 			}
9144 		}
9145 
9146 		if (override_remote_addr != NULL) {
9147 			if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9148 				memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
9149 				if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9150 					struct sockaddr_in sin;
9151 					in6_sin6_2_sin(&sin, &(info->remote_addr.sin6));
9152 					memset(&info->remote_addr, 0, sizeof(union necp_sockaddr_union));
9153 					memcpy(&info->remote_addr, &sin, sin.sin_len);
9154 				}
9155 			} else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9156 				memcpy(&info->remote_addr, override_remote_addr, override_remote_addr->sa_len);
9157 			}
9158 		} else {
9159 			if (inp->inp_vflag & INP_IPV6) {
9160 				((struct sockaddr_in6 *)&info->remote_addr)->sin6_family = AF_INET6;
9161 				((struct sockaddr_in6 *)&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9162 				((struct sockaddr_in6 *)&info->remote_addr)->sin6_port = inp->inp_fport;
9163 				memcpy(&((struct sockaddr_in6 *)&info->remote_addr)->sin6_addr, &inp->in6p_faddr, sizeof(struct in6_addr));
9164 			} else if (inp->inp_vflag & INP_IPV4) {
9165 				((struct sockaddr_in *)&info->remote_addr)->sin_family = AF_INET;
9166 				((struct sockaddr_in *)&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9167 				((struct sockaddr_in *)&info->remote_addr)->sin_port = inp->inp_fport;
9168 				memcpy(&((struct sockaddr_in *)&info->remote_addr)->sin_addr, &inp->inp_faddr, sizeof(struct in_addr));
9169 			}
9170 		}
9171 		// Clear the embedded scope id from v6 addresses
9172 		if (info->local_addr.sa.sa_family == AF_INET6) {
9173 			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&info->local_addr;
9174 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9175 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9176 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9177 					sin6->sin6_addr.s6_addr16[1] = 0;
9178 				}
9179 			}
9180 		}
9181 		if (info->remote_addr.sa.sa_family == AF_INET6) {
9182 			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&info->remote_addr;
9183 			if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9184 				if (sin6->sin6_addr.s6_addr16[1] != 0) {
9185 					sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9186 					sin6->sin6_addr.s6_addr16[1] = 0;
9187 				}
9188 			}
9189 		}
9190 	}
9191 
9192 	if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9193 		// For checking sockets, only validate that there is an NECP client present. It will have
9194 		// already checked for the signature.
9195 		if (!uuid_is_null(inp->necp_client_uuid)) {
9196 			info->has_system_signed_result = true;
9197 		} else {
9198 			info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, &info->remote_addr);
9199 		}
9200 	}
9201 }
9202 
9203 #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)
9204 
9205 static inline struct necp_kernel_socket_policy *
necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy ** policy_search_array,struct necp_socket_info * info,necp_kernel_policy_filter * return_filter,u_int32_t * 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 * return_netagent_array,u_int32_t * return_netagent_use_flags_array,size_t netagent_array_count,struct necp_client_parameter_netagent_type * 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)9206 necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info,
9207     necp_kernel_policy_filter *return_filter,
9208     u_int32_t *return_route_rule_id_array, size_t *return_route_rule_id_array_count, size_t route_rule_id_array_count,
9209     necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service,
9210     u_int32_t *return_netagent_array, u_int32_t *return_netagent_use_flags_array, size_t netagent_array_count,
9211     struct necp_client_parameter_netagent_type *required_agent_types,
9212     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,
9213     necp_kernel_policy_result *return_drop_dest_policy_result, necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
9214     u_int32_t *return_flow_divert_aggregate_unit, struct socket *so, int debug)
9215 {
9216 	struct necp_kernel_socket_policy *matched_policy = NULL;
9217 	u_int32_t skip_order = 0;
9218 	u_int32_t skip_session_order = 0;
9219 	bool skipped_ip_result = false;
9220 	size_t route_rule_id_count = 0;
9221 	int i;
9222 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9223 	u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
9224 	memset(&netagent_ids, 0, sizeof(netagent_ids));
9225 	memset(&netagent_use_flags, 0, sizeof(netagent_use_flags));
9226 	size_t netagent_cursor = 0;
9227 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9228 	if (return_drop_all_bypass != NULL) {
9229 		*return_drop_all_bypass = drop_all_bypass;
9230 	}
9231 
9232 	if (netagent_array_count > NECP_MAX_NETAGENTS) {
9233 		netagent_array_count = NECP_MAX_NETAGENTS;
9234 	}
9235 
9236 	// Pre-process domain for quick matching
9237 	struct substring domain_substring = necp_trim_dots_and_stars(info->domain, info->domain ? strlen(info->domain) : 0);
9238 	u_int8_t domain_dot_count = necp_count_dots(domain_substring.string, domain_substring.length);
9239 
9240 	if (return_filter != NULL) {
9241 		*return_filter = 0;
9242 	}
9243 
9244 	if (return_route_rule_id_array_count != NULL) {
9245 		*return_route_rule_id_array_count = 0;
9246 	}
9247 
9248 	if (return_service_action != NULL) {
9249 		*return_service_action = 0;
9250 	}
9251 
9252 	if (return_service != NULL) {
9253 		return_service->identifier = 0;
9254 		return_service->data = 0;
9255 	}
9256 
9257 	// Do not subject layer-2 filter to NECP policies, return a PASS policy
9258 	if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
9259 		return &pass_policy;
9260 	}
9261 
9262 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9263 
9264 	if (policy_search_array != NULL) {
9265 		for (i = 0; policy_search_array[i] != NULL; i++) {
9266 			NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "EXAMINING");
9267 
9268 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
9269 				// We've hit a drop all rule
9270 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9271 					drop_all_bypass = necp_check_drop_all_bypass_result(proc);
9272 					if (return_drop_all_bypass != NULL) {
9273 						*return_drop_all_bypass = drop_all_bypass;
9274 					}
9275 				}
9276 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9277 					NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
9278 					break;
9279 				}
9280 			}
9281 			if (necp_drop_dest_policy.entry_count != 0 &&
9282 			    necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
9283 				// We've hit a drop by destination address rule
9284 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
9285 				break;
9286 			}
9287 			if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
9288 				// We've hit a drop order for this socket
9289 				break;
9290 			}
9291 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
9292 				// Done skipping
9293 				skip_order = 0;
9294 				skip_session_order = 0;
9295 				// If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
9296 				if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
9297 					*skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9298 					NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (cleared saved skip)");
9299 				}
9300 			}
9301 			if (skip_order) {
9302 				if (policy_search_array[i]->order < skip_order) {
9303 					// Skip this policy
9304 					// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9305 					// didn't, clear out the return value for skip ID when we are done with each session.'
9306 					if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9307 						skipped_ip_result = true;
9308 						NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIPPING IP RESULT");
9309 					}
9310 					NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (session order < skip-order)");
9311 					continue;
9312 				} else {
9313 					// Done skipping
9314 					skip_order = 0;
9315 					skip_session_order = 0;
9316 				}
9317 			} else if (skip_session_order) {
9318 				// Skip this policy
9319 				// Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9320 				// didn't, clear out the return value for skip ID when we are done with each session.'
9321 				if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9322 					skipped_ip_result = true;
9323 					NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIPPING IP RESULT");
9324 				}
9325 				NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (skip-session-order)");
9326 				continue;
9327 			}
9328 
9329 			if (necp_socket_check_policy(policy_search_array[i], info->application_id, info->real_application_id, info->is_entitled, info->account_id, domain_substring, domain_dot_count, info->url, info->pid, info->pid_version, info->uid, info->real_uid, info->bound_interface_index, info->traffic_class, info->protocol, &info->local_addr, &info->remote_addr, required_agent_types, num_required_agent_types, info->has_client, info->client_flags, info->is_platform_binary, info->has_system_signed_result, proc, pf_tag, info->scheme_port, rt, info->is_loopback, debug, info->real_is_platform_binary, info->bound_interface_flags, info->bound_interface_eflags, info->bound_interface_xflags, info, info->is_delegated)) {
9330 				if (!debug && necp_data_tracing_session_order) {
9331 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
9332 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
9333 						NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
9334 					}
9335 				}
9336 
9337 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
9338 					if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
9339 						necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
9340 						if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
9341 							*return_filter = control_unit;
9342 						} else {
9343 							// Preserve pre-existing connections only if all filters preserve.
9344 							bool preserve_bit_off = false;
9345 							if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
9346 							    (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
9347 								preserve_bit_off = true;
9348 							}
9349 							*return_filter |= control_unit;
9350 							if (preserve_bit_off == true) {
9351 								*return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
9352 							}
9353 						}
9354 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9355 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.filter_control_unit);
9356 						}
9357 					}
9358 					continue;
9359 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
9360 					if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
9361 						return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
9362 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9363 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.route_rule_id);
9364 						}
9365 					}
9366 					continue;
9367 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
9368 				    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9369 					if (netagent_cursor < netagent_array_count) {
9370 						bool agent_already_present = false;
9371 						for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9372 							if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9373 								// Already present. Mark the "SCOPED" flag if flags are necessary.
9374 								agent_already_present = true;
9375 								if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
9376 								    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9377 									netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
9378 								}
9379 							}
9380 						}
9381 
9382 						if (!agent_already_present) {
9383 							netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9384 							if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9385 								netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
9386 							}
9387 							netagent_cursor++;
9388 						}
9389 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9390 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
9391 							    info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9392 							    policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
9393 							    policy_search_array[i]->result_parameter.netagent_id);
9394 						}
9395 					}
9396 					continue;
9397 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
9398 					bool agent_already_present = false;
9399 					for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9400 						if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9401 							// Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
9402 							agent_already_present = true;
9403 							netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
9404 						}
9405 					}
9406 					if (!agent_already_present && netagent_cursor < netagent_array_count) {
9407 						// If not present, and flags are supported, add an entry with the "REMOVE" flag
9408 						netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9409 						netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
9410 						netagent_cursor++;
9411 					}
9412 					if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9413 						NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
9414 						    info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9415 						    policy_search_array[i]->result_parameter.netagent_id);
9416 					}
9417 					continue;
9418 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
9419 					u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
9420 					if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
9421 						/* For transparent proxies, accumulate the control unit and continue to the next policy */
9422 						if (return_flow_divert_aggregate_unit != NULL) {
9423 							*return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
9424 							if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9425 								NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, control_unit);
9426 							}
9427 						}
9428 						continue;
9429 					}
9430 				}
9431 
9432 				// Matched policy is a skip. Do skip and continue.
9433 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
9434 					NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "MATCHED SKIP POLICY");
9435 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
9436 					skip_session_order = policy_search_array[i]->session_order + 1;
9437 					if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
9438 						*skip_policy_id = policy_search_array[i]->id;
9439 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9440 							NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: MATCHED SKIP POLICY (Application %d Real Application %d BoundInterface %d Proto %d) set skip_policy_id %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *skip_policy_id);
9441 						}
9442 					}
9443 					continue;
9444 				}
9445 
9446 				// Matched an allow unentitled, which clears any drop order
9447 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
9448 					info->drop_order = 0;
9449 					continue;
9450 				}
9451 
9452 				// Passed all tests, found a match
9453 				matched_policy = policy_search_array[i];
9454 				NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
9455 				break;
9456 			}
9457 		}
9458 	}
9459 
9460 	if (return_netagent_array != NULL) {
9461 		if (return_netagent_use_flags_array != NULL) {
9462 			memcpy(return_netagent_array, &netagent_ids, sizeof(u_int32_t) * netagent_array_count);
9463 			memcpy(return_netagent_use_flags_array, &netagent_use_flags, sizeof(u_int32_t) * netagent_array_count);
9464 		} else {
9465 			for (size_t netagent_i = 0; netagent_i < netagent_array_count; netagent_i++) {
9466 				if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
9467 					return_netagent_array[netagent_i] = netagent_ids[netagent_i];
9468 				} else {
9469 					return_netagent_array[netagent_i] = 0;
9470 				}
9471 			}
9472 		}
9473 	}
9474 
9475 	if (return_route_rule_id_array_count != NULL) {
9476 		*return_route_rule_id_array_count = route_rule_id_count;
9477 	}
9478 	return matched_policy;
9479 }
9480 
9481 static bool
necp_socket_uses_interface(struct inpcb * inp,u_int32_t interface_index)9482 necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
9483 {
9484 	bool found_match = FALSE;
9485 	ifaddr_t ifa;
9486 	union necp_sockaddr_union address_storage;
9487 	int family = AF_INET;
9488 
9489 	ifnet_head_lock_shared();
9490 	ifnet_t interface = ifindex2ifnet[interface_index];
9491 	ifnet_head_done();
9492 
9493 	if (inp == NULL || interface == NULL) {
9494 		return FALSE;
9495 	}
9496 
9497 	if (inp->inp_vflag & INP_IPV4) {
9498 		family = AF_INET;
9499 	} else if (inp->inp_vflag & INP_IPV6) {
9500 		family = AF_INET6;
9501 	} else {
9502 		return FALSE;
9503 	}
9504 
9505 	// Match socket address against interface addresses
9506 	ifnet_lock_shared(interface);
9507 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
9508 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
9509 			if (address_storage.sa.sa_family != family) {
9510 				continue;
9511 			}
9512 
9513 			if (family == AF_INET) {
9514 				if (memcmp(&address_storage.sin.sin_addr, &inp->inp_laddr, sizeof(inp->inp_laddr)) == 0) {
9515 					found_match = TRUE;
9516 					break;
9517 				}
9518 			} else if (family == AF_INET6) {
9519 				if (memcmp(&address_storage.sin6.sin6_addr, &inp->in6p_laddr, sizeof(inp->in6p_laddr)) == 0) {
9520 					found_match = TRUE;
9521 					break;
9522 				}
9523 			}
9524 		}
9525 	}
9526 	ifnet_lock_done(interface);
9527 
9528 	return found_match;
9529 }
9530 
9531 static inline bool
necp_socket_is_connected(struct inpcb * inp)9532 necp_socket_is_connected(struct inpcb *inp)
9533 {
9534 	return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
9535 }
9536 
9537 static inline necp_socket_bypass_type_t
necp_socket_bypass(struct sockaddr * override_local_addr,struct sockaddr * override_remote_addr,struct inpcb * inp)9538 necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
9539 {
9540 	if (necp_pass_loopback > 0 && necp_is_loopback(override_local_addr, override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
9541 		return NECP_BYPASS_TYPE_LOOPBACK;
9542 	} else if (necp_is_intcoproc(inp, NULL)) {
9543 		return NECP_BYPASS_TYPE_INTCOPROC;
9544 	}
9545 
9546 	return NECP_BYPASS_TYPE_NONE;
9547 }
9548 
9549 static inline void
necp_socket_ip_tunnel_tso(struct inpcb * inp)9550 necp_socket_ip_tunnel_tso(struct inpcb *inp)
9551 {
9552 	u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
9553 	ifnet_t tunnel_interface = NULL;
9554 
9555 	ifnet_head_lock_shared();
9556 	tunnel_interface = ifindex2ifnet[tunnel_interface_index];
9557 	ifnet_head_done();
9558 
9559 	if (tunnel_interface != NULL) {
9560 		tcp_set_tso(intotcpcb(inp), tunnel_interface);
9561 	}
9562 }
9563 
9564 static inline void
necp_unscope(struct inpcb * inp)9565 necp_unscope(struct inpcb *inp)
9566 {
9567 	// If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
9568 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
9569 		inp->inp_flags &= ~INP_BOUND_IF;
9570 		inp->inp_boundifp = NULL;
9571 	}
9572 }
9573 
9574 static inline void
necp_clear_tunnel(struct inpcb * inp)9575 necp_clear_tunnel(struct inpcb *inp)
9576 {
9577 	if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
9578 		inp->inp_flags &= ~INP_BOUND_IF;
9579 		inp->inp_boundifp = NULL;
9580 	}
9581 }
9582 
9583 static inline bool
necp_socket_verify_netagents(u_int32_t * netagent_ids,int debug,struct socket * so)9584 necp_socket_verify_netagents(u_int32_t *netagent_ids, int debug, struct socket *so)
9585 {
9586 	// Verify netagents
9587 	for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
9588 		struct necp_uuid_id_mapping *mapping = NULL;
9589 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
9590 		if (netagent_id == 0) {
9591 			continue;
9592 		}
9593 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
9594 		if (mapping != NULL) {
9595 			u_int32_t agent_flags = 0;
9596 			agent_flags = netagent_get_flags(mapping->uuid);
9597 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
9598 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
9599 					continue;
9600 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
9601 					if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
9602 						int trigger_error = 0;
9603 						trigger_error = netagent_kernel_trigger(mapping->uuid);
9604 						if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9605 							NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> Triggering inactive agent (%d), error %d", (unsigned long long)so, netagent_id, trigger_error);
9606 						}
9607 					}
9608 					return false;
9609 				}
9610 			}
9611 		}
9612 	}
9613 	return true;
9614 }
9615 
9616 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)9617 necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
9618 {
9619 	struct socket *so = NULL;
9620 	necp_kernel_policy_filter filter_control_unit = 0;
9621 	struct necp_kernel_socket_policy *matched_policy = NULL;
9622 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9623 	necp_kernel_policy_result service_action = 0;
9624 	necp_kernel_policy_service service = { 0, 0 };
9625 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9626 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9627 	proc_t socket_proc = NULL;
9628 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
9629 
9630 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9631 	memset(&netagent_ids, 0, sizeof(netagent_ids));
9632 
9633 	struct necp_socket_info info = {};
9634 
9635 	u_int32_t flow_divert_aggregate_unit = 0;
9636 
9637 	if (inp == NULL) {
9638 		return NECP_KERNEL_POLICY_ID_NONE;
9639 	}
9640 
9641 	// Ignore invalid addresses
9642 	if (override_local_addr != NULL &&
9643 	    !necp_address_is_valid(override_local_addr)) {
9644 		override_local_addr = NULL;
9645 	}
9646 	if (override_remote_addr != NULL &&
9647 	    !necp_address_is_valid(override_remote_addr)) {
9648 		override_remote_addr = NULL;
9649 	}
9650 
9651 	so = inp->inp_socket;
9652 
9653 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
9654 
9655 	// Don't lock. Possible race condition, but we don't want the performance hit.
9656 	if (necp_drop_management_order == 0 &&
9657 	    (necp_kernel_socket_policies_count == 0 ||
9658 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
9659 		if (necp_drop_all_order > 0 || drop_order > 0) {
9660 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9661 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9662 			inp->inp_policyresult.policy_gencount = 0;
9663 			inp->inp_policyresult.app_id = 0;
9664 			inp->inp_policyresult.flowhash = 0;
9665 			inp->inp_policyresult.results.filter_control_unit = 0;
9666 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9667 			inp->inp_policyresult.results.route_rule_id = 0;
9668 			if (necp_socket_bypass(override_local_addr, override_remote_addr, inp) != NECP_BYPASS_TYPE_NONE) {
9669 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9670 			} else {
9671 				inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9672 			}
9673 		}
9674 		return NECP_KERNEL_POLICY_ID_NONE;
9675 	}
9676 
9677 	// Check for loopback exception
9678 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
9679 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
9680 		// Mark socket as a pass
9681 		necp_unscope(inp);
9682 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9683 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9684 		inp->inp_policyresult.policy_gencount = 0;
9685 		inp->inp_policyresult.app_id = 0;
9686 		inp->inp_policyresult.flowhash = 0;
9687 		inp->inp_policyresult.results.filter_control_unit = 0;
9688 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9689 		inp->inp_policyresult.results.route_rule_id = 0;
9690 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9691 		return NECP_KERNEL_POLICY_ID_NONE;
9692 	}
9693 
9694 	// Lock
9695 	lck_rw_lock_shared(&necp_kernel_policy_lock);
9696 	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));
9697 
9698 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
9699 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
9700 
9701 	// Check info
9702 	u_int32_t flowhash = necp_socket_calc_flowhash_locked(&info);
9703 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
9704 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
9705 	    inp->inp_policyresult.flowhash == flowhash) {
9706 		// If already matched this socket on this generation of table, skip
9707 
9708 		// Unlock
9709 		lck_rw_done(&necp_kernel_policy_lock);
9710 
9711 		if (socket_proc) {
9712 			proc_rele(socket_proc);
9713 		}
9714 
9715 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9716 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
9717 			    inp->inp_socket, info.bound_interface_index, info.protocol,
9718 			    inp->inp_policyresult.policy_id,
9719 			    inp->inp_policyresult.results.result,
9720 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
9721 		}
9722 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, 0);
9723 		return inp->inp_policyresult.policy_id;
9724 	}
9725 
9726 	inp->inp_policyresult.app_id = info.application_id;
9727 
9728 	// Match socket to policy
9729 	necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9730 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
9731 	size_t route_rule_id_array_count = 0;
9732 
9733 	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)], &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, socket_proc ? socket_proc : current_proc(), 0, &skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit, so, debug);
9734 
9735 	// Check for loopback exception again after the policy match
9736 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
9737 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
9738 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
9739 		// Mark socket as a pass
9740 		necp_unscope(inp);
9741 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9742 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9743 		inp->inp_policyresult.policy_gencount = 0;
9744 		inp->inp_policyresult.app_id = 0;
9745 		inp->inp_policyresult.flowhash = 0;
9746 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9747 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9748 		inp->inp_policyresult.results.route_rule_id = 0;
9749 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9750 
9751 		// Unlock
9752 		lck_rw_done(&necp_kernel_policy_lock);
9753 
9754 		if (socket_proc) {
9755 			proc_rele(socket_proc);
9756 		}
9757 
9758 		return NECP_KERNEL_POLICY_ID_NONE;
9759 	}
9760 
9761 	// Verify netagents
9762 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
9763 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9764 			NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (unsigned long long)so, info.bound_interface_index, info.protocol);
9765 		}
9766 
9767 		// Mark socket as a drop if required agent is not active
9768 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9769 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9770 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9771 		inp->inp_policyresult.flowhash = flowhash;
9772 		inp->inp_policyresult.results.filter_control_unit = 0;
9773 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9774 		inp->inp_policyresult.results.route_rule_id = 0;
9775 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9776 
9777 		// Unlock
9778 		lck_rw_done(&necp_kernel_policy_lock);
9779 
9780 		if (socket_proc) {
9781 			proc_rele(socket_proc);
9782 		}
9783 
9784 		return NECP_KERNEL_POLICY_ID_NONE;
9785 	}
9786 
9787 	u_int32_t route_rule_id = 0;
9788 	if (route_rule_id_array_count == 1) {
9789 		route_rule_id = route_rule_id_array[0];
9790 	} else if (route_rule_id_array_count > 1) {
9791 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
9792 	}
9793 
9794 	bool reset_tcp_tunnel_interface = false;
9795 	bool send_local_network_denied_event = false;
9796 	if (matched_policy) {
9797 		// For PASS policy result, clear previous rescope / tunnel inteface
9798 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
9799 		    (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
9800 			necp_unscope(inp);
9801 			necp_clear_tunnel(inp);
9802 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9803 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, 0);
9804 			}
9805 		}
9806 		matched_policy_id = matched_policy->id;
9807 		inp->inp_policyresult.policy_id = matched_policy->id;
9808 		inp->inp_policyresult.skip_policy_id = skip_policy_id;
9809 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9810 		inp->inp_policyresult.flowhash = flowhash;
9811 		inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9812 		inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9813 		inp->inp_policyresult.results.route_rule_id = route_rule_id;
9814 		inp->inp_policyresult.results.result = matched_policy->result;
9815 		memcpy(&inp->inp_policyresult.results.result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
9816 
9817 		if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
9818 			inp->inp_policyresult.app_id = info.real_application_id;
9819 		}
9820 
9821 		if (necp_socket_is_connected(inp) &&
9822 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
9823 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, matched_policy->result_parameter.tunnel_interface_index)))) {
9824 			NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
9825 			sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
9826 		} else if (necp_socket_is_connected(inp) &&
9827 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
9828 		    info.protocol == IPPROTO_TCP) {
9829 			// Reset TCP socket interface based parameters if tunnel policy changes
9830 			reset_tcp_tunnel_interface = true;
9831 		}
9832 
9833 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9834 			NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: %p (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d", inp->inp_socket, info.bound_interface_index, info.protocol, matched_policy->id, skip_policy_id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
9835 		}
9836 
9837 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
9838 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
9839 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
9840 			// Trigger the event that we dropped due to a local network policy
9841 			send_local_network_denied_event = true;
9842 		}
9843 	} else {
9844 		bool drop_all = false;
9845 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
9846 			// Mark socket as a drop if set
9847 			drop_all = true;
9848 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9849 				drop_all_bypass = necp_check_drop_all_bypass_result(socket_proc ? socket_proc : current_proc());
9850 			}
9851 		}
9852 
9853 		// Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
9854 		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);
9855 		if (flow_divert_control_unit != 0) {
9856 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9857 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9858 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9859 			inp->inp_policyresult.flowhash = flowhash;
9860 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9861 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9862 			inp->inp_policyresult.results.route_rule_id = route_rule_id;
9863 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
9864 			inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
9865 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "FLOW DIVERT <ROUTE RULE>", 0, 0);
9866 		} else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9867 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9868 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9869 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9870 			inp->inp_policyresult.flowhash = flowhash;
9871 			inp->inp_policyresult.results.filter_control_unit = 0;
9872 			inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9873 			inp->inp_policyresult.results.route_rule_id = 0;
9874 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9875 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <NO MATCH>", 0, 0);
9876 		} else {
9877 			// Mark non-matching socket so we don't re-check it
9878 			necp_unscope(inp);
9879 			if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
9880 				necp_clear_tunnel(inp);
9881 			}
9882 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9883 				NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for <NO MATCH>", inp->inp_policyresult.policy_id, 0);
9884 			}
9885 			inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9886 			inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9887 			inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9888 			inp->inp_policyresult.flowhash = flowhash;
9889 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
9890 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9891 			inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
9892 			inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
9893 		}
9894 	}
9895 
9896 	if (necp_check_missing_client_drop(socket_proc ? socket_proc : current_proc(), &info) ||
9897 	    necp_check_restricted_multicast_drop(socket_proc ? socket_proc : current_proc(), &info, false)) {
9898 		// Mark as drop
9899 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9900 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9901 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9902 		inp->inp_policyresult.flowhash = flowhash;
9903 		inp->inp_policyresult.results.filter_control_unit = 0;
9904 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9905 		inp->inp_policyresult.results.route_rule_id = 0;
9906 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9907 	}
9908 
9909 	// Unlock
9910 	lck_rw_done(&necp_kernel_policy_lock);
9911 
9912 	if (reset_tcp_tunnel_interface) {
9913 		// Update MSS when not holding the policy lock to avoid recursive locking
9914 		tcp_mtudisc(inp, 0);
9915 
9916 		// Update TSO flag based on the tunnel interface
9917 		necp_socket_ip_tunnel_tso(inp);
9918 	}
9919 
9920 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
9921 		inp->inp_policyresult.network_denied_notifies++;
9922 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
9923 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
9924 		    NETPOLICY_NETWORKTYPE_LOCAL);
9925 	}
9926 
9927 	if (socket_proc) {
9928 		proc_rele(socket_proc);
9929 	}
9930 
9931 	return matched_policy_id;
9932 }
9933 
9934 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)9935 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)
9936 {
9937 	u_int32_t bound_interface_flags = 0;
9938 	u_int32_t bound_interface_eflags = 0;
9939 	u_int32_t bound_interface_xflags = 0;
9940 
9941 	if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9942 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9943 			u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9944 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9945 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
9946 			    cond_bound_interface_index, bound_interface_index);
9947 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9948 				if (bound_interface_index == cond_bound_interface_index) {
9949 					// No match, matches forbidden interface
9950 					return FALSE;
9951 				}
9952 			} else {
9953 				if (bound_interface_index != cond_bound_interface_index) {
9954 					// No match, does not match required interface
9955 					return FALSE;
9956 				}
9957 			}
9958 		}
9959 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9960 			if (bound_interface_index != IFSCOPE_NONE) {
9961 				ifnet_head_lock_shared();
9962 				ifnet_t interface = ifindex2ifnet[bound_interface_index];
9963 				if (interface != NULL) {
9964 					bound_interface_flags = interface->if_flags;
9965 					bound_interface_eflags = interface->if_eflags;
9966 					bound_interface_xflags = interface->if_xflags;
9967 				}
9968 				ifnet_head_done();
9969 			}
9970 
9971 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9972 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9973 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9974 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9975 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9976 			    "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9977 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9978 				if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9979 				    (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9980 				    (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9981 					// No match, matches some forbidden interface flags
9982 					return FALSE;
9983 				}
9984 			} else {
9985 				if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9986 				    (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9987 				    (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9988 					// No match, does not match some required interface xflags
9989 					return FALSE;
9990 				}
9991 			}
9992 		}
9993 		if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9994 		    !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9995 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
9996 			if (bound_interface_index != 0) {
9997 				// No match, requires a non-bound packet
9998 				return FALSE;
9999 			}
10000 		}
10001 	}
10002 
10003 	if (kernel_policy->condition_mask == 0) {
10004 		return TRUE;
10005 	}
10006 
10007 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10008 		necp_kernel_policy_id matched_policy_id =
10009 		    kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10010 		NECP_DATA_TRACE_LOG_CONDITION3(debug, "IP", false,
10011 		    "NECP_KERNEL_CONDITION_POLICY_ID",
10012 		    kernel_policy->cond_policy_id, 0, 0,
10013 		    matched_policy_id, socket_policy_id, socket_skip_policy_id);
10014 		if (matched_policy_id != kernel_policy->cond_policy_id) {
10015 			// No match, does not match required id
10016 			return FALSE;
10017 		}
10018 	}
10019 
10020 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10021 		NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false,
10022 		    "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10023 		    kernel_policy->cond_last_interface_index, last_interface_index);
10024 		if (last_interface_index != kernel_policy->cond_last_interface_index) {
10025 			return FALSE;
10026 		}
10027 	}
10028 
10029 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10030 		NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10031 		    "NECP_KERNEL_CONDITION_PROTOCOL",
10032 		    kernel_policy->cond_protocol, protocol);
10033 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10034 			if (protocol == kernel_policy->cond_protocol) {
10035 				// No match, matches forbidden protocol
10036 				return FALSE;
10037 			}
10038 		} else {
10039 			if (protocol != kernel_policy->cond_protocol) {
10040 				// No match, does not match required protocol
10041 				return FALSE;
10042 			}
10043 		}
10044 	}
10045 
10046 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10047 		bool is_local = FALSE;
10048 
10049 		if (rt != NULL) {
10050 			is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
10051 		} else {
10052 			is_local = necp_is_route_local(remote);
10053 		}
10054 		NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
10055 		if (!is_local) {
10056 			// Either no route to validate or no match for local networks
10057 			return FALSE;
10058 		}
10059 	}
10060 
10061 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
10062 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10063 			bool inRange = necp_is_addr_in_range((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, (struct sockaddr *)&kernel_policy->cond_local_end);
10064 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
10065 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10066 				if (inRange) {
10067 					return FALSE;
10068 				}
10069 			} else {
10070 				if (!inRange) {
10071 					return FALSE;
10072 				}
10073 			}
10074 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10075 			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)local, (struct sockaddr *)&kernel_policy->cond_local_start, kernel_policy->cond_local_prefix);
10076 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
10077 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10078 				if (inSubnet) {
10079 					return FALSE;
10080 				}
10081 			} else {
10082 				if (!inSubnet) {
10083 					return FALSE;
10084 				}
10085 			}
10086 		}
10087 	}
10088 
10089 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
10090 		if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10091 			bool inRange = necp_is_addr_in_range((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, (struct sockaddr *)&kernel_policy->cond_remote_end);
10092 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
10093 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10094 				if (inRange) {
10095 					return FALSE;
10096 				}
10097 			} else {
10098 				if (!inRange) {
10099 					return FALSE;
10100 				}
10101 			}
10102 		} else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10103 			bool inSubnet = necp_is_addr_in_subnet((struct sockaddr *)remote, (struct sockaddr *)&kernel_policy->cond_remote_start, kernel_policy->cond_remote_prefix);
10104 			NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
10105 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10106 				if (inSubnet) {
10107 					return FALSE;
10108 				}
10109 			} else {
10110 				if (!inSubnet) {
10111 					return FALSE;
10112 				}
10113 			}
10114 		}
10115 	}
10116 
10117 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10118 		u_int16_t remote_port = 0;
10119 		if (((struct sockaddr *)remote)->sa_family == AF_INET || ((struct sockaddr *)remote)->sa_family == AF_INET6) {
10120 			remote_port = ((struct sockaddr_in *)remote)->sin_port;
10121 		}
10122 		NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
10123 		    "NECP_KERNEL_CONDITION_SCHEME_PORT",
10124 		    0, remote_port);
10125 		if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10126 			if (kernel_policy->cond_scheme_port == remote_port) {
10127 				return FALSE;
10128 			}
10129 		} else {
10130 			if (kernel_policy->cond_scheme_port != remote_port) {
10131 				return FALSE;
10132 			}
10133 		}
10134 	}
10135 
10136 	if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10137 		bool tags_matched = false;
10138 		NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
10139 		    "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
10140 		    kernel_policy->cond_packet_filter_tags, pf_tag);
10141 		if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
10142 			if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
10143 				tags_matched = true;
10144 			}
10145 
10146 			if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10147 				if (tags_matched) {
10148 					return FALSE;
10149 				}
10150 			} else {
10151 				if (!tags_matched) {
10152 					return FALSE;
10153 				}
10154 			}
10155 		}
10156 	}
10157 
10158 	return TRUE;
10159 }
10160 
10161 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)10162 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)
10163 {
10164 	u_int32_t skip_order = 0;
10165 	u_int32_t skip_session_order = 0;
10166 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
10167 	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)];
10168 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
10169 	size_t route_rule_id_count = 0;
10170 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10171 	if (return_drop_all_bypass != NULL) {
10172 		*return_drop_all_bypass = drop_all_bypass;
10173 	}
10174 
10175 	if (return_route_rule_id != NULL) {
10176 		*return_route_rule_id = 0;
10177 	}
10178 
10179 	*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10180 
10181 	if (policy_search_array != NULL) {
10182 		for (int i = 0; policy_search_array[i] != NULL; i++) {
10183 			NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "EXAMINING");
10184 			if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10185 				// We've hit a drop all rule
10186 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10187 					drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10188 					if (return_drop_all_bypass != NULL) {
10189 						*return_drop_all_bypass = drop_all_bypass;
10190 					}
10191 				}
10192 				if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10193 					NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
10194 					break;
10195 				}
10196 			}
10197 			if (necp_drop_dest_policy.entry_count > 0 &&
10198 			    necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
10199 				// We've hit a drop by destination address rule
10200 				*return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10201 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
10202 				break;
10203 			}
10204 			if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10205 				// Done skipping
10206 				skip_order = 0;
10207 				skip_session_order = 0;
10208 			}
10209 			if (skip_order) {
10210 				if (policy_search_array[i]->order < skip_order) {
10211 					// Skip this policy
10212 					NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "SKIP (session order < skip-order)");
10213 					continue;
10214 				} else {
10215 					// Done skipping
10216 					skip_order = 0;
10217 					skip_session_order = 0;
10218 				}
10219 			} else if (skip_session_order) {
10220 				// Skip this policy
10221 				NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "SKIP (skip-session-order)");
10222 				continue;
10223 			}
10224 
10225 			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)) {
10226 				if (!debug && necp_data_tracing_session_order) {
10227 					if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10228 					    (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10229 						NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
10230 					}
10231 				}
10232 
10233 				if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10234 					if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
10235 						route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10236 					}
10237 					continue;
10238 				} else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10239 					skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10240 					skip_session_order = policy_search_array[i]->session_order + 1;
10241 					NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "MATCHED SKIP POLICY");
10242 					continue;
10243 				}
10244 
10245 				// Passed all tests, found a match
10246 				matched_policy = policy_search_array[i];
10247 				NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
10248 				break;
10249 			}
10250 		}
10251 	}
10252 
10253 	if (route_rule_id_count == 1) {
10254 		*return_route_rule_id = route_rule_id_array[0];
10255 	} else if (route_rule_id_count > 1) {
10256 		*return_route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
10257 	}
10258 
10259 	return matched_policy;
10260 }
10261 
10262 static inline bool
necp_output_bypass(struct mbuf * packet)10263 necp_output_bypass(struct mbuf *packet)
10264 {
10265 	if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
10266 		return true;
10267 	}
10268 	if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
10269 		return true;
10270 	}
10271 	if (necp_is_intcoproc(NULL, packet)) {
10272 		return true;
10273 	}
10274 	return false;
10275 }
10276 
10277 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)10278 necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
10279     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
10280 {
10281 	struct ip *ip = NULL;
10282 	int hlen = sizeof(struct ip);
10283 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10284 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10285 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10286 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
10287 	u_int16_t protocol = 0;
10288 	u_int32_t bound_interface_index = 0;
10289 	u_int32_t last_interface_index = 0;
10290 	union necp_sockaddr_union local_addr = { };
10291 	union necp_sockaddr_union remote_addr = { };
10292 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10293 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10294 	u_int16_t pf_tag = 0;
10295 
10296 	if (result) {
10297 		*result = 0;
10298 	}
10299 
10300 	if (result_parameter) {
10301 		memset(result_parameter, 0, sizeof(*result_parameter));
10302 	}
10303 
10304 	if (packet == NULL) {
10305 		return NECP_KERNEL_POLICY_ID_NONE;
10306 	}
10307 
10308 	socket_policy_id = necp_get_policy_id_from_packet(packet);
10309 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
10310 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
10311 
10312 	// Exit early for an empty list
10313 	// Don't lock. Possible race condition, but we don't want the performance hit.
10314 	if (necp_kernel_ip_output_policies_count == 0 ||
10315 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
10316 		if (necp_drop_all_order > 0) {
10317 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10318 			if (result) {
10319 				if (necp_output_bypass(packet)) {
10320 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
10321 				} else {
10322 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
10323 				}
10324 			}
10325 		}
10326 
10327 		return matched_policy_id;
10328 	}
10329 
10330 	// Check for loopback exception
10331 	if (necp_output_bypass(packet)) {
10332 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10333 		if (result) {
10334 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
10335 		}
10336 		return matched_policy_id;
10337 	}
10338 
10339 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
10340 
10341 	// Process packet to get relevant fields
10342 	ip = mtod(packet, struct ip *);
10343 #ifdef _IP_VHL
10344 	hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
10345 #else
10346 	hlen = ip->ip_hl << 2;
10347 #endif
10348 
10349 	protocol = ip->ip_p;
10350 
10351 	if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
10352 	    (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
10353 	    ipoa->ipoa_boundif != IFSCOPE_NONE) {
10354 		bound_interface_index = ipoa->ipoa_boundif;
10355 	}
10356 
10357 	local_addr.sin.sin_family = AF_INET;
10358 	local_addr.sin.sin_len = sizeof(struct sockaddr_in);
10359 	memcpy(&local_addr.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src));
10360 
10361 	remote_addr.sin.sin_family = AF_INET;
10362 	remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
10363 	memcpy(&((struct sockaddr_in *)&remote_addr)->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));
10364 
10365 	switch (protocol) {
10366 	case IPPROTO_TCP: {
10367 		struct tcphdr th;
10368 		if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
10369 			m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
10370 			((struct sockaddr_in *)&local_addr)->sin_port = th.th_sport;
10371 			((struct sockaddr_in *)&remote_addr)->sin_port = th.th_dport;
10372 		}
10373 		break;
10374 	}
10375 	case IPPROTO_UDP: {
10376 		struct udphdr uh;
10377 		if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
10378 			m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
10379 			((struct sockaddr_in *)&local_addr)->sin_port = uh.uh_sport;
10380 			((struct sockaddr_in *)&remote_addr)->sin_port = uh.uh_dport;
10381 		}
10382 		break;
10383 	}
10384 	default: {
10385 		((struct sockaddr_in *)&local_addr)->sin_port = 0;
10386 		((struct sockaddr_in *)&remote_addr)->sin_port = 0;
10387 		break;
10388 	}
10389 	}
10390 
10391 	// Match packet to policy
10392 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10393 	u_int32_t route_rule_id = 0;
10394 
10395 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
10396 	NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
10397 
10398 	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);
10399 	if (matched_policy) {
10400 		matched_policy_id = matched_policy->id;
10401 		if (result) {
10402 			*result = matched_policy->result;
10403 		}
10404 
10405 		if (result_parameter) {
10406 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10407 		}
10408 
10409 		if (route_rule_id != 0 &&
10410 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10411 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10412 		}
10413 
10414 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10415 			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);
10416 		}
10417 	} else {
10418 		bool drop_all = false;
10419 		/*
10420 		 * Apply drop-all only to packets which have never matched a primary policy (check
10421 		 * if the packet saved policy id is none or falls within the socket policy id range).
10422 		 */
10423 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10424 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10425 			drop_all = true;
10426 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10427 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10428 			}
10429 		}
10430 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10431 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10432 			if (result) {
10433 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
10434 				NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
10435 			}
10436 		} else if (route_rule_id != 0 &&
10437 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10438 			// If we matched a route rule, mark it
10439 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10440 		}
10441 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10442 			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);
10443 		}
10444 	}
10445 
10446 	lck_rw_done(&necp_kernel_policy_lock);
10447 
10448 	return matched_policy_id;
10449 }
10450 
10451 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)10452 necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
10453     necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
10454 {
10455 	struct ip6_hdr *ip6 = NULL;
10456 	int next = -1;
10457 	int offset = 0;
10458 	necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10459 	necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10460 	necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10461 	struct necp_kernel_ip_output_policy *matched_policy = NULL;
10462 	u_int16_t protocol = 0;
10463 	u_int32_t bound_interface_index = 0;
10464 	u_int32_t last_interface_index = 0;
10465 	union necp_sockaddr_union local_addr = { };
10466 	union necp_sockaddr_union remote_addr = { };
10467 	u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10468 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10469 	u_int16_t pf_tag = 0;
10470 
10471 	if (result) {
10472 		*result = 0;
10473 	}
10474 
10475 	if (result_parameter) {
10476 		memset(result_parameter, 0, sizeof(*result_parameter));
10477 	}
10478 
10479 	if (packet == NULL) {
10480 		return NECP_KERNEL_POLICY_ID_NONE;
10481 	}
10482 
10483 	socket_policy_id = necp_get_policy_id_from_packet(packet);
10484 	socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
10485 	pf_tag = necp_get_packet_filter_tags_from_packet(packet);
10486 
10487 	// Exit early for an empty list
10488 	// Don't lock. Possible race condition, but we don't want the performance hit.
10489 	if (necp_drop_management_order == 0 &&
10490 	    (necp_kernel_ip_output_policies_count == 0 ||
10491 	    (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
10492 		if (necp_drop_all_order > 0) {
10493 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10494 			if (result) {
10495 				if (necp_output_bypass(packet)) {
10496 					*result = NECP_KERNEL_POLICY_RESULT_PASS;
10497 				} else {
10498 					*result = NECP_KERNEL_POLICY_RESULT_DROP;
10499 				}
10500 			}
10501 		}
10502 
10503 		return matched_policy_id;
10504 	}
10505 
10506 	// Check for loopback exception
10507 	if (necp_output_bypass(packet)) {
10508 		matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10509 		if (result) {
10510 			*result = NECP_KERNEL_POLICY_RESULT_PASS;
10511 		}
10512 		return matched_policy_id;
10513 	}
10514 
10515 	last_interface_index = necp_get_last_interface_index_from_packet(packet);
10516 
10517 	// Process packet to get relevant fields
10518 	ip6 = mtod(packet, struct ip6_hdr *);
10519 
10520 	if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
10521 	    (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
10522 	    ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
10523 		bound_interface_index = ip6oa->ip6oa_boundif;
10524 	}
10525 
10526 	((struct sockaddr_in6 *)&local_addr)->sin6_family = AF_INET6;
10527 	((struct sockaddr_in6 *)&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
10528 	memcpy(&((struct sockaddr_in6 *)&local_addr)->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
10529 
10530 	((struct sockaddr_in6 *)&remote_addr)->sin6_family = AF_INET6;
10531 	((struct sockaddr_in6 *)&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
10532 	memcpy(&((struct sockaddr_in6 *)&remote_addr)->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
10533 
10534 	offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
10535 	if (offset >= 0 && packet->m_pkthdr.len >= offset) {
10536 		protocol = next;
10537 		switch (protocol) {
10538 		case IPPROTO_TCP: {
10539 			struct tcphdr th;
10540 			if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
10541 				m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
10542 				((struct sockaddr_in6 *)&local_addr)->sin6_port = th.th_sport;
10543 				((struct sockaddr_in6 *)&remote_addr)->sin6_port = th.th_dport;
10544 			}
10545 			break;
10546 		}
10547 		case IPPROTO_UDP: {
10548 			struct udphdr uh;
10549 			if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
10550 				m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
10551 				((struct sockaddr_in6 *)&local_addr)->sin6_port = uh.uh_sport;
10552 				((struct sockaddr_in6 *)&remote_addr)->sin6_port = uh.uh_dport;
10553 			}
10554 			break;
10555 		}
10556 		default: {
10557 			((struct sockaddr_in6 *)&local_addr)->sin6_port = 0;
10558 			((struct sockaddr_in6 *)&remote_addr)->sin6_port = 0;
10559 			break;
10560 		}
10561 		}
10562 	}
10563 
10564 	// Match packet to policy
10565 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10566 	u_int32_t route_rule_id = 0;
10567 
10568 	int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
10569 	NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
10570 
10571 	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);
10572 	if (matched_policy) {
10573 		matched_policy_id = matched_policy->id;
10574 		if (result) {
10575 			*result = matched_policy->result;
10576 		}
10577 
10578 		if (result_parameter) {
10579 			memcpy(result_parameter, &matched_policy->result_parameter, sizeof(matched_policy->result_parameter));
10580 		}
10581 
10582 		if (route_rule_id != 0 &&
10583 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10584 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10585 		}
10586 
10587 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10588 			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);
10589 		}
10590 	} else {
10591 		bool drop_all = false;
10592 		/*
10593 		 * Apply drop-all only to packets which have never matched a primary policy (check
10594 		 * if the packet saved policy id is none or falls within the socket policy id range).
10595 		 */
10596 		if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10597 		    (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10598 			drop_all = true;
10599 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10600 				drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10601 			}
10602 		}
10603 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10604 			matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10605 			if (result) {
10606 				*result = NECP_KERNEL_POLICY_RESULT_DROP;
10607 				NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
10608 			}
10609 		} else if (route_rule_id != 0 &&
10610 		    packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10611 			// If we matched a route rule, mark it
10612 			packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10613 		}
10614 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10615 			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);
10616 		}
10617 	}
10618 
10619 	lck_rw_done(&necp_kernel_policy_lock);
10620 
10621 	return matched_policy_id;
10622 }
10623 
10624 // Utilities
10625 static bool
necp_is_addr_in_range(struct sockaddr * addr,struct sockaddr * range_start,struct sockaddr * range_end)10626 necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
10627 {
10628 	int cmp = 0;
10629 
10630 	if (addr == NULL || range_start == NULL || range_end == NULL) {
10631 		return FALSE;
10632 	}
10633 
10634 	/* Must be greater than or equal to start */
10635 	cmp = necp_addr_compare(addr, range_start, 1);
10636 	if (cmp != 0 && cmp != 1) {
10637 		return FALSE;
10638 	}
10639 
10640 	/* Must be less than or equal to end */
10641 	cmp = necp_addr_compare(addr, range_end, 1);
10642 	if (cmp != 0 && cmp != -1) {
10643 		return FALSE;
10644 	}
10645 
10646 	return TRUE;
10647 }
10648 
10649 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)10650 necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
10651 {
10652 	int cmp = 0;
10653 
10654 	if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
10655 		return FALSE;
10656 	}
10657 
10658 	/* Must be greater than or equal to start */
10659 	cmp = necp_addr_compare(inner_range_start, range_start, 1);
10660 	if (cmp != 0 && cmp != 1) {
10661 		return FALSE;
10662 	}
10663 
10664 	/* Must be less than or equal to end */
10665 	cmp = necp_addr_compare(inner_range_end, range_end, 1);
10666 	if (cmp != 0 && cmp != -1) {
10667 		return FALSE;
10668 	}
10669 
10670 	return TRUE;
10671 }
10672 
10673 static bool
necp_is_addr_in_subnet(struct sockaddr * addr,struct sockaddr * subnet_addr,u_int8_t subnet_prefix)10674 necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
10675 {
10676 	if (addr == NULL || subnet_addr == NULL) {
10677 		return FALSE;
10678 	}
10679 
10680 	if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
10681 		return FALSE;
10682 	}
10683 
10684 	switch (addr->sa_family) {
10685 	case AF_INET: {
10686 		if (satosin(subnet_addr)->sin_port != 0 &&
10687 		    satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
10688 			return FALSE;
10689 		}
10690 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin(addr)->sin_addr, (u_int8_t *)&satosin(subnet_addr)->sin_addr, subnet_prefix);
10691 	}
10692 	case AF_INET6: {
10693 		if (satosin6(subnet_addr)->sin6_port != 0 &&
10694 		    satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
10695 			return FALSE;
10696 		}
10697 		if (satosin6(addr)->sin6_scope_id &&
10698 		    satosin6(subnet_addr)->sin6_scope_id &&
10699 		    satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
10700 			return FALSE;
10701 		}
10702 		return necp_buffer_compare_with_bit_prefix((u_int8_t *)&satosin6(addr)->sin6_addr, (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, subnet_prefix);
10703 	}
10704 	default: {
10705 		return FALSE;
10706 	}
10707 	}
10708 
10709 	return FALSE;
10710 }
10711 
10712 /*
10713  * Return values:
10714  * -1: sa1 < sa2
10715  * 0: sa1 == sa2
10716  * 1: sa1 > sa2
10717  * 2: Not comparable or error
10718  */
10719 static int
necp_addr_compare(struct sockaddr * sa1,struct sockaddr * sa2,int check_port)10720 necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
10721 {
10722 	int result = 0;
10723 	int port_result = 0;
10724 
10725 	if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
10726 		return 2;
10727 	}
10728 
10729 	if (sa1->sa_len == 0) {
10730 		return 0;
10731 	}
10732 
10733 	switch (sa1->sa_family) {
10734 	case AF_INET: {
10735 		if (sa1->sa_len != sizeof(struct sockaddr_in)) {
10736 			return 2;
10737 		}
10738 
10739 		result = memcmp(&satosin(sa1)->sin_addr.s_addr, &satosin(sa2)->sin_addr.s_addr, sizeof(satosin(sa1)->sin_addr.s_addr));
10740 
10741 		if (check_port) {
10742 			if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
10743 				port_result = -1;
10744 			} else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
10745 				port_result = 1;
10746 			}
10747 
10748 			if (result == 0) {
10749 				result = port_result;
10750 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
10751 				return 2;
10752 			}
10753 		}
10754 
10755 		break;
10756 	}
10757 	case AF_INET6: {
10758 		if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
10759 			return 2;
10760 		}
10761 
10762 		if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
10763 			return 2;
10764 		}
10765 
10766 		result = memcmp(&satosin6(sa1)->sin6_addr.s6_addr[0], &satosin6(sa2)->sin6_addr.s6_addr[0], sizeof(struct in6_addr));
10767 
10768 		if (check_port) {
10769 			if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
10770 				port_result = -1;
10771 			} else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
10772 				port_result = 1;
10773 			}
10774 
10775 			if (result == 0) {
10776 				result = port_result;
10777 			} else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
10778 				return 2;
10779 			}
10780 		}
10781 
10782 		break;
10783 	}
10784 	default: {
10785 		result = memcmp(sa1, sa2, sa1->sa_len);
10786 		break;
10787 	}
10788 	}
10789 
10790 	if (result < 0) {
10791 		result = (-1);
10792 	} else if (result > 0) {
10793 		result = (1);
10794 	}
10795 
10796 	return result;
10797 }
10798 
10799 static bool
necp_buffer_compare_with_bit_prefix(u_int8_t * p1,u_int8_t * p2,u_int32_t bits)10800 necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits)
10801 {
10802 	u_int8_t mask;
10803 
10804 	/* Handle null pointers */
10805 	if (p1 == NULL || p2 == NULL) {
10806 		return p1 == p2;
10807 	}
10808 
10809 	while (bits >= 8) {
10810 		if (*p1++ != *p2++) {
10811 			return FALSE;
10812 		}
10813 		bits -= 8;
10814 	}
10815 
10816 	if (bits > 0) {
10817 		mask = ~((1 << (8 - bits)) - 1);
10818 		if ((*p1 & mask) != (*p2 & mask)) {
10819 			return FALSE;
10820 		}
10821 	}
10822 	return TRUE;
10823 }
10824 
10825 static bool
necp_addr_is_empty(struct sockaddr * addr)10826 necp_addr_is_empty(struct sockaddr *addr)
10827 {
10828 	if (addr == NULL) {
10829 		return TRUE;
10830 	}
10831 
10832 	if (addr->sa_len == 0) {
10833 		return TRUE;
10834 	}
10835 
10836 	switch (addr->sa_family) {
10837 	case AF_INET: {
10838 		static struct sockaddr_in ipv4_empty_address = {
10839 			.sin_len = sizeof(struct sockaddr_in),
10840 			.sin_family = AF_INET,
10841 			.sin_port = 0,
10842 			.sin_addr = { .s_addr = 0 }, // 0.0.0.0
10843 			.sin_zero = {0},
10844 		};
10845 		if (necp_addr_compare(addr, (struct sockaddr *)&ipv4_empty_address, 0) == 0) {
10846 			return TRUE;
10847 		} else {
10848 			return FALSE;
10849 		}
10850 	}
10851 	case AF_INET6: {
10852 		static struct sockaddr_in6 ipv6_empty_address = {
10853 			.sin6_len = sizeof(struct sockaddr_in6),
10854 			.sin6_family = AF_INET6,
10855 			.sin6_port = 0,
10856 			.sin6_flowinfo = 0,
10857 			.sin6_addr = IN6ADDR_ANY_INIT, // ::
10858 			.sin6_scope_id = 0,
10859 		};
10860 		if (necp_addr_compare(addr, (struct sockaddr *)&ipv6_empty_address, 0) == 0) {
10861 			return TRUE;
10862 		} else {
10863 			return FALSE;
10864 		}
10865 	}
10866 	default:
10867 		return FALSE;
10868 	}
10869 
10870 	return FALSE;
10871 }
10872 
10873 static bool
necp_update_qos_marking(struct ifnet * ifp,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)10874 necp_update_qos_marking(struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
10875 {
10876 	bool qos_marking = FALSE;
10877 	int exception_index = 0;
10878 	struct necp_route_rule *route_rule = NULL;
10879 
10880 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
10881 	if (route_rule == NULL) {
10882 		qos_marking = FALSE;
10883 		goto done;
10884 	}
10885 
10886 	if (route_rule->match_netagent_id != 0) {
10887 		if (netagent_array == NULL || netagent_array_count == 0) {
10888 			// No agents, ignore rule
10889 			goto done;
10890 		}
10891 		bool found_match = FALSE;
10892 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
10893 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
10894 				found_match = TRUE;
10895 				break;
10896 			}
10897 		}
10898 		if (!found_match) {
10899 			// Agents don't match, ignore rule
10900 			goto done;
10901 		}
10902 	}
10903 
10904 	qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
10905 
10906 	if (ifp == NULL) {
10907 		goto done;
10908 	}
10909 
10910 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
10911 		if (route_rule->exception_if_indices[exception_index] == 0) {
10912 			break;
10913 		}
10914 		if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
10915 			continue;
10916 		}
10917 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
10918 			qos_marking = TRUE;
10919 			if (necp_debug > 2) {
10920 				NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
10921 				    route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
10922 			}
10923 			goto done;
10924 		}
10925 	}
10926 
10927 	if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
10928 	    (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
10929 	    (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
10930 	    (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
10931 	    (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
10932 	    (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp))) {
10933 		qos_marking = TRUE;
10934 		if (necp_debug > 2) {
10935 			NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d for Rule %d Allowed %d",
10936 			    route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
10937 			    route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule_id, qos_marking);
10938 		}
10939 		goto done;
10940 	}
10941 done:
10942 	if (necp_debug > 1) {
10943 		NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
10944 		    route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
10945 	}
10946 	return qos_marking;
10947 }
10948 
10949 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)10950 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)
10951 {
10952 	bool new_qos_marking = old_qos_marking;
10953 	struct ifnet *ifp = interface;
10954 
10955 	if (net_qos_policy_restricted == 0) {
10956 		return new_qos_marking;
10957 	}
10958 
10959 	/*
10960 	 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
10961 	 */
10962 	if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
10963 		return new_qos_marking;
10964 	}
10965 
10966 	lck_rw_lock_shared(&necp_kernel_policy_lock);
10967 
10968 	if (ifp == NULL && route != NULL) {
10969 		ifp = route->rt_ifp;
10970 	}
10971 	/*
10972 	 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
10973 	 */
10974 	if (ifp == NULL || route_rule_id == 0) {
10975 		new_qos_marking = FALSE;
10976 		goto done;
10977 	}
10978 
10979 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
10980 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
10981 		if (aggregate_route_rule != NULL) {
10982 			int index = 0;
10983 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
10984 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
10985 				if (sub_route_rule_id == 0) {
10986 					break;
10987 				}
10988 				new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, sub_route_rule_id);
10989 				if (new_qos_marking == TRUE) {
10990 					break;
10991 				}
10992 			}
10993 		}
10994 	} else {
10995 		new_qos_marking = necp_update_qos_marking(ifp, NULL, 0, route_rule_id);
10996 	}
10997 	/*
10998 	 * Now that we have an interface we remember the gencount
10999 	 */
11000 	*qos_marking_gencount = necp_kernel_socket_policies_gencount;
11001 
11002 done:
11003 	lck_rw_done(&necp_kernel_policy_lock);
11004 	return new_qos_marking;
11005 }
11006 
11007 void
necp_socket_update_qos_marking(struct inpcb * inp,struct rtentry * route,u_int32_t route_rule_id)11008 necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11009 {
11010 	bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11011 
11012 	if (net_qos_policy_restricted == 0) {
11013 		return;
11014 	}
11015 	if (inp->inp_socket == NULL) {
11016 		return;
11017 	}
11018 	if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11019 		return;
11020 	}
11021 
11022 	qos_marking = necp_lookup_current_qos_marking(&(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, qos_marking);
11023 
11024 	if (qos_marking == TRUE) {
11025 		inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11026 	} else {
11027 		inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11028 	}
11029 }
11030 
11031 static bool
necp_route_is_lqm_abort(struct ifnet * ifp,struct ifnet * delegated_ifp)11032 necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11033 {
11034 	if (ifp != NULL &&
11035 	    (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11036 	    ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11037 		return true;
11038 	}
11039 	if (delegated_ifp != NULL &&
11040 	    (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11041 	    delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11042 		return true;
11043 	}
11044 	return false;
11045 }
11046 
11047 static bool
necp_route_is_allowed_inner(struct rtentry * route,struct ifnet * ifp,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)11048 necp_route_is_allowed_inner(struct rtentry *route, struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count,
11049     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11050 {
11051 	bool default_is_allowed = TRUE;
11052 	u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
11053 	int exception_index = 0;
11054 	struct ifnet *delegated_ifp = NULL;
11055 	struct necp_route_rule *route_rule = NULL;
11056 
11057 	route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11058 	if (route_rule == NULL) {
11059 		return TRUE;
11060 	}
11061 
11062 	if (route_rule->match_netagent_id != 0) {
11063 		if (netagent_array == NULL || netagent_array_count == 0) {
11064 			// No agents, ignore rule
11065 			return TRUE;
11066 		}
11067 		bool found_match = FALSE;
11068 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11069 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11070 				found_match = TRUE;
11071 				break;
11072 			}
11073 		}
11074 		if (!found_match) {
11075 			// Agents don't match, ignore rule
11076 			return TRUE;
11077 		}
11078 	}
11079 
11080 	default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
11081 	if (ifp == NULL && route != NULL) {
11082 		ifp = route->rt_ifp;
11083 	}
11084 	if (ifp == NULL) {
11085 		if (necp_debug > 1 && !default_is_allowed) {
11086 			NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11087 		}
11088 		return default_is_allowed;
11089 	}
11090 
11091 	delegated_ifp = ifp->if_delegated.ifp;
11092 	for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11093 		if (route_rule->exception_if_indices[exception_index] == 0) {
11094 			break;
11095 		}
11096 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
11097 		    (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
11098 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11099 				const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
11100 				if (necp_debug > 1 && lqm_abort) {
11101 					NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
11102 					    route_rule->exception_if_indices[exception_index], route_rule_id);
11103 				}
11104 				return false;
11105 			} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
11106 				if (necp_debug > 1) {
11107 					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));
11108 				}
11109 				if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
11110 					*interface_type_denied = route_rule->effective_type;
11111 				}
11112 				return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
11113 			}
11114 		}
11115 	}
11116 
11117 	if (IFNET_IS_CELLULAR(ifp)) {
11118 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11119 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11120 				if (interface_type_denied != NULL) {
11121 					*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11122 					if (route_rule->effective_type != 0) {
11123 						*interface_type_denied = route_rule->effective_type;
11124 					}
11125 				}
11126 				// Mark aggregate action as deny
11127 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11128 			}
11129 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
11130 			if (interface_type_denied != NULL) {
11131 				*interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11132 				if (route_rule->effective_type != 0) {
11133 					*interface_type_denied = route_rule->effective_type;
11134 				}
11135 			}
11136 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11137 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11138 			    IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
11139 				// Deny wins if there is a conflict
11140 				type_aggregate_action = route_rule->cellular_action;
11141 			}
11142 		}
11143 	}
11144 
11145 	if (IFNET_IS_WIFI(ifp)) {
11146 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11147 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11148 				if (interface_type_denied != NULL) {
11149 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11150 					if (route_rule->effective_type != 0) {
11151 						*interface_type_denied = route_rule->effective_type;
11152 					}
11153 				}
11154 				// Mark aggregate action as deny
11155 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11156 			}
11157 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
11158 			if (interface_type_denied != NULL) {
11159 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11160 				if (route_rule->effective_type != 0) {
11161 					*interface_type_denied = route_rule->effective_type;
11162 				}
11163 			}
11164 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11165 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11166 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
11167 				// Deny wins if there is a conflict
11168 				type_aggregate_action = route_rule->wifi_action;
11169 			}
11170 		}
11171 	}
11172 
11173 	if (IFNET_IS_COMPANION_LINK(ifp) ||
11174 	    (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
11175 		if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11176 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11177 				if (interface_type_denied != NULL) {
11178 					*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11179 					if (route_rule->effective_type != 0) {
11180 						*interface_type_denied = route_rule->effective_type;
11181 					}
11182 				}
11183 				// Mark aggregate action as deny
11184 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11185 			}
11186 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
11187 			if (interface_type_denied != NULL) {
11188 				*interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11189 				if (route_rule->effective_type != 0) {
11190 					*interface_type_denied = route_rule->effective_type;
11191 				}
11192 			}
11193 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11194 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11195 			    IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
11196 				// Deny wins if there is a conflict
11197 				type_aggregate_action = route_rule->companion_action;
11198 			}
11199 		}
11200 	}
11201 
11202 	if (IFNET_IS_WIRED(ifp)) {
11203 		if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11204 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11205 				if (interface_type_denied != NULL) {
11206 					*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11207 					if (route_rule->effective_type != 0) {
11208 						*interface_type_denied = route_rule->effective_type;
11209 					}
11210 				}
11211 				// Mark aggregate action as deny
11212 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11213 			}
11214 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
11215 			if (interface_type_denied != NULL) {
11216 				*interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11217 				if (route_rule->effective_type != 0) {
11218 					*interface_type_denied = route_rule->effective_type;
11219 				}
11220 			}
11221 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11222 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11223 			    IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
11224 				// Deny wins if there is a conflict
11225 				type_aggregate_action = route_rule->wired_action;
11226 			}
11227 		}
11228 	}
11229 
11230 	if (IFNET_IS_EXPENSIVE(ifp)) {
11231 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11232 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11233 				// Mark aggregate action as deny
11234 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11235 			}
11236 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
11237 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11238 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11239 			    IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
11240 				// Deny wins if there is a conflict
11241 				type_aggregate_action = route_rule->expensive_action;
11242 			}
11243 		}
11244 	}
11245 
11246 	if (IFNET_IS_CONSTRAINED(ifp)) {
11247 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11248 			if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11249 				// Mark aggregate action as deny
11250 				type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11251 			}
11252 		} else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
11253 			if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11254 			    (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11255 			    IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
11256 				// Deny wins if there is a conflict
11257 				type_aggregate_action = route_rule->constrained_action;
11258 			}
11259 		}
11260 	}
11261 
11262 	if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
11263 		if (necp_debug > 1) {
11264 			NECPLOG(LOG_DEBUG, "Route Allowed: C:%d WF:%d W:%d E:%d Cmpn:%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_id, (IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE));
11265 		}
11266 		return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
11267 	}
11268 
11269 	if (necp_debug > 1 && !default_is_allowed) {
11270 		NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11271 	}
11272 	return default_is_allowed;
11273 }
11274 
11275 static bool
necp_proc_is_allowed_on_management_interface(proc_t proc)11276 necp_proc_is_allowed_on_management_interface(proc_t proc)
11277 {
11278 	bool allowed = false;
11279 	const task_t task = proc_task(proc);
11280 
11281 	if (task != NULL) {
11282 		if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
11283 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
11284 #if DEBUG || DEVELOPMENT
11285 		    || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
11286 		    || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
11287 #endif /* DEBUG || DEVELOPMENT */
11288 		    ) {
11289 			allowed = true;
11290 		}
11291 	}
11292 	return allowed;
11293 }
11294 
11295 __attribute__((noinline))
11296 static void
necp_log_interface_not_allowed(struct ifnet * ifp,proc_t proc,struct inpcb * inp)11297 necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11298 {
11299 	char buf[128];
11300 
11301 	if (inp != NULL) {
11302 		inp_snprintf_tuple(inp, buf, sizeof(buf));
11303 	} else {
11304 		*buf = 0;
11305 	}
11306 	os_log(OS_LOG_DEFAULT,
11307 	    "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
11308 	    proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
11309 	    proc != NULL ? proc_getpid(proc) : proc_selfpid(),
11310 	    inp != NULL ? buf : "",
11311 	    ifp->if_xname);
11312 }
11313 
11314 static bool
necp_route_is_interface_type_allowed(struct rtentry * route,struct ifnet * ifp,proc_t proc,struct inpcb * inp)11315 necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11316 {
11317 	if (if_management_interface_check_needed == false) {
11318 		return true;
11319 	}
11320 	if (necp_drop_management_order == 0) {
11321 		return true;
11322 	}
11323 	if (ifp == NULL && route != NULL) {
11324 		ifp = route->rt_ifp;
11325 	}
11326 	if (ifp == NULL) {
11327 		return true;
11328 	}
11329 
11330 	if (IFNET_IS_MANAGEMENT(ifp)) {
11331 		bool allowed = true;
11332 
11333 		if (inp != NULL) {
11334 			/*
11335 			 * The entitlement check is already performed for socket flows
11336 			 */
11337 			allowed = INP_MANAGEMENT_ALLOWED(inp);
11338 		} else if (proc != NULL) {
11339 			allowed = necp_proc_is_allowed_on_management_interface(proc);
11340 		}
11341 		if (__improbable(if_management_verbose > 1 && allowed == false)) {
11342 			necp_log_interface_not_allowed(ifp, proc, inp);
11343 		}
11344 		return allowed;
11345 	}
11346 	return true;
11347 }
11348 
11349 static bool
necp_route_is_allowed(struct rtentry * route,struct ifnet * interface,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * interface_type_denied)11350 necp_route_is_allowed(struct rtentry *route, struct ifnet *interface, u_int32_t *netagent_array, size_t netagent_array_count,
11351     u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11352 {
11353 	if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
11354 		if (necp_debug > 1) {
11355 			NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
11356 		}
11357 		return TRUE;
11358 	}
11359 
11360 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11361 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11362 		if (aggregate_route_rule != NULL) {
11363 			int index = 0;
11364 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11365 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11366 				if (sub_route_rule_id == 0) {
11367 					break;
11368 				}
11369 				if (!necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, sub_route_rule_id, interface_type_denied)) {
11370 					return FALSE;
11371 				}
11372 			}
11373 		}
11374 	} else {
11375 		return necp_route_is_allowed_inner(route, interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
11376 	}
11377 
11378 	return TRUE;
11379 }
11380 
11381 static bool
necp_route_rule_matches_agents(u_int32_t route_rule_id)11382 necp_route_rule_matches_agents(u_int32_t route_rule_id)
11383 {
11384 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11385 	if (route_rule == NULL) {
11386 		return false;
11387 	}
11388 
11389 	return route_rule->match_netagent_id != 0;
11390 }
11391 
11392 static uint32_t
necp_route_get_netagent(struct rtentry * route,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,bool * remove)11393 necp_route_get_netagent(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove)
11394 {
11395 	if (remove == NULL) {
11396 		return 0;
11397 	}
11398 
11399 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11400 	if (route_rule == NULL) {
11401 		return 0;
11402 	}
11403 
11404 	// No netagent, skip
11405 	if (route_rule->netagent_id == 0) {
11406 		return 0;
11407 	}
11408 
11409 	if (route_rule->match_netagent_id != 0) {
11410 		if (netagent_array == NULL || netagent_array_count == 0) {
11411 			// No agents, ignore rule
11412 			return 0;
11413 		}
11414 		bool found_match = FALSE;
11415 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11416 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11417 				found_match = TRUE;
11418 				break;
11419 			}
11420 		}
11421 		if (!found_match) {
11422 			// Agents don't match, ignore rule
11423 			return 0;
11424 		}
11425 	}
11426 
11427 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
11428 	if (ifp == NULL) {
11429 		// No interface, apply the default action
11430 		if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11431 		    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11432 			*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11433 			return route_rule->netagent_id;
11434 		}
11435 		return 0;
11436 	}
11437 
11438 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11439 		if (route_rule->exception_if_indices[exception_index] == 0) {
11440 			break;
11441 		}
11442 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
11443 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
11444 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
11445 			    route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11446 				*remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11447 				return route_rule->netagent_id;
11448 			}
11449 			return 0;
11450 		}
11451 	}
11452 
11453 	if (ifp->if_type == IFT_CELLULAR &&
11454 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
11455 		if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11456 		    route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11457 			*remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11458 			return route_rule->netagent_id;
11459 		}
11460 		return 0;
11461 	}
11462 
11463 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
11464 	    route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
11465 		if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11466 		    route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
11467 			*remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11468 			return route_rule->netagent_id;
11469 		}
11470 		return 0;
11471 	}
11472 
11473 	if (IFNET_IS_COMPANION_LINK(ifp) &&
11474 	    route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
11475 		if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11476 		    route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
11477 			*remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11478 			return route_rule->netagent_id;
11479 		}
11480 		return 0;
11481 	}
11482 
11483 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
11484 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
11485 		if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11486 		    route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
11487 			*remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11488 			return route_rule->netagent_id;
11489 		}
11490 		return 0;
11491 	}
11492 
11493 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
11494 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
11495 		if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11496 		    route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11497 			*remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11498 			return route_rule->netagent_id;
11499 		}
11500 		return 0;
11501 	}
11502 
11503 	if (ifp->if_xflags & IFXF_CONSTRAINED &&
11504 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
11505 		if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11506 		    route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11507 			*remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11508 			return route_rule->netagent_id;
11509 		}
11510 		return 0;
11511 	}
11512 
11513 	// No more specific case matched, apply the default action
11514 	if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11515 	    route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11516 		*remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11517 		return route_rule->netagent_id;
11518 	}
11519 
11520 	return 0;
11521 }
11522 
11523 static uint32_t
necp_route_get_flow_divert_inner(struct rtentry * route,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id)11524 necp_route_get_flow_divert_inner(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
11525 {
11526 	struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(&necp_route_rules, route_rule_id);
11527 	if (route_rule == NULL) {
11528 		return 0;
11529 	}
11530 
11531 	// No control unit, skip
11532 	if (route_rule->control_unit == 0) {
11533 		return 0;
11534 	}
11535 
11536 	if (route_rule->match_netagent_id != 0) {
11537 		if (netagent_array == NULL || netagent_array_count == 0) {
11538 			// No agents, ignore rule
11539 			return 0;
11540 		}
11541 		bool found_match = FALSE;
11542 		for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11543 			if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11544 				found_match = TRUE;
11545 				break;
11546 			}
11547 		}
11548 		if (!found_match) {
11549 			// Agents don't match, ignore rule
11550 			return 0;
11551 		}
11552 	}
11553 
11554 	struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
11555 	if (ifp == NULL) {
11556 		// No interface, apply the default action
11557 		if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11558 			return route_rule->control_unit;
11559 		}
11560 		return 0;
11561 	}
11562 
11563 	for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11564 		if (route_rule->exception_if_indices[exception_index] == 0) {
11565 			break;
11566 		}
11567 		if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
11568 		    route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
11569 			if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11570 				return route_rule->control_unit;
11571 			}
11572 			return 0;
11573 		}
11574 	}
11575 
11576 	if (ifp->if_type == IFT_CELLULAR &&
11577 	    route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
11578 		if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11579 			return route_rule->control_unit;
11580 		}
11581 		return 0;
11582 	}
11583 
11584 	if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
11585 	    route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11586 		if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11587 			return route_rule->control_unit;
11588 		}
11589 		return 0;
11590 	}
11591 
11592 	if (IFNET_IS_COMPANION_LINK(ifp) &&
11593 	    route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11594 		if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11595 			return route_rule->control_unit;
11596 		}
11597 		return 0;
11598 	}
11599 
11600 	if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
11601 	    route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
11602 		if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11603 			return route_rule->control_unit;
11604 		}
11605 		return 0;
11606 	}
11607 
11608 	if (ifp->if_eflags & IFEF_EXPENSIVE &&
11609 	    route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
11610 		if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11611 			return route_rule->control_unit;
11612 		}
11613 		return 0;
11614 	}
11615 
11616 	if (ifp->if_xflags & IFXF_CONSTRAINED &&
11617 	    route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
11618 		if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11619 			return route_rule->control_unit;
11620 		}
11621 		return 0;
11622 	}
11623 
11624 	// No more specific case matched, apply the default action
11625 	if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11626 		return route_rule->control_unit;
11627 	}
11628 	return 0;
11629 }
11630 
11631 static uint32_t
necp_route_get_flow_divert(struct rtentry * route,u_int32_t * netagent_array,size_t netagent_array_count,u_int32_t route_rule_id,u_int32_t * flow_divert_aggregate_unit)11632 necp_route_get_flow_divert(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id,
11633     u_int32_t *flow_divert_aggregate_unit)
11634 {
11635 	if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
11636 		return 0;
11637 	}
11638 
11639 	if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11640 		struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11641 		if (aggregate_route_rule != NULL) {
11642 			int index = 0;
11643 			for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11644 				u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11645 				if (sub_route_rule_id == 0) {
11646 					break;
11647 				}
11648 				uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, sub_route_rule_id);
11649 				if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
11650 					// For transparent proxies, accumulate the control unit and continue to the next route rule
11651 					*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
11652 					continue;
11653 				}
11654 
11655 				if (control_unit != 0) {
11656 					return control_unit;
11657 				}
11658 			}
11659 		}
11660 	} else {
11661 		uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
11662 		if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
11663 			// For transparent proxies, accumulate the control unit and let the caller continue
11664 			*flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
11665 			return 0;
11666 		}
11667 		return control_unit;
11668 	}
11669 
11670 	return 0;
11671 }
11672 
11673 bool
necp_packet_is_allowed_over_interface(struct mbuf * packet,struct ifnet * interface)11674 necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
11675 {
11676 	bool is_allowed = true;
11677 	u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
11678 	if (route_rule_id != 0 &&
11679 	    interface != NULL) {
11680 		lck_rw_lock_shared(&necp_kernel_policy_lock);
11681 		is_allowed = necp_route_is_allowed(NULL, interface, NULL, 0, necp_get_route_rule_id_from_packet(packet), NULL);
11682 		lck_rw_done(&necp_kernel_policy_lock);
11683 	}
11684 	return is_allowed;
11685 }
11686 
11687 static bool
necp_netagents_allow_traffic(u_int32_t * netagent_ids,size_t netagent_id_count)11688 necp_netagents_allow_traffic(u_int32_t *netagent_ids, size_t netagent_id_count)
11689 {
11690 	size_t netagent_cursor;
11691 	for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
11692 		struct necp_uuid_id_mapping *mapping = NULL;
11693 		u_int32_t netagent_id = netagent_ids[netagent_cursor];
11694 		if (netagent_id == 0) {
11695 			continue;
11696 		}
11697 		mapping = necp_uuid_lookup_uuid_with_service_id_locked(netagent_id);
11698 		if (mapping != NULL) {
11699 			u_int32_t agent_flags = 0;
11700 			agent_flags = netagent_get_flags(mapping->uuid);
11701 			if (agent_flags & NETAGENT_FLAG_REGISTERED) {
11702 				if (agent_flags & NETAGENT_FLAG_ACTIVE) {
11703 					continue;
11704 				} else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
11705 					return FALSE;
11706 				}
11707 			}
11708 		}
11709 	}
11710 	return TRUE;
11711 }
11712 
11713 static bool
necp_packet_filter_tags_receive(u_int16_t pf_tag,u_int32_t pass_flags)11714 necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
11715 {
11716 	bool allowed_to_receive = TRUE;
11717 
11718 	if (pf_tag == PF_TAG_ID_STACK_DROP &&
11719 	    (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
11720 		allowed_to_receive = FALSE;
11721 	}
11722 
11723 	return allowed_to_receive;
11724 }
11725 
11726 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)11727 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)
11728 {
11729 	u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
11730 	bool allowed_to_receive = TRUE;
11731 	struct necp_socket_info info = {};
11732 	u_int32_t flowhash = 0;
11733 	necp_kernel_policy_result service_action = 0;
11734 	necp_kernel_policy_service service = { 0, 0 };
11735 	u_int32_t route_rule_id = 0;
11736 	struct rtentry *route = NULL;
11737 	u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
11738 	necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11739 	necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11740 	u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
11741 	proc_t socket_proc = NULL;
11742 	necp_kernel_policy_filter filter_control_unit = 0;
11743 	u_int32_t pass_flags = 0;
11744 	u_int32_t flow_divert_aggregate_unit = 0;
11745 	necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
11746 
11747 	memset(&netagent_ids, 0, sizeof(netagent_ids));
11748 
11749 	if (return_policy_id) {
11750 		*return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11751 	}
11752 	if (return_skip_policy_id) {
11753 		*return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11754 	}
11755 	if (return_route_rule_id) {
11756 		*return_route_rule_id = 0;
11757 	}
11758 	if (return_pass_flags) {
11759 		*return_pass_flags = 0;
11760 	}
11761 
11762 	if (inp == NULL) {
11763 		goto done;
11764 	}
11765 
11766 	route = inp->inp_route.ro_rt;
11767 
11768 	struct socket *so = inp->inp_socket;
11769 
11770 	u_int32_t drop_order = necp_process_drop_order(so->so_cred);
11771 
11772 	// Don't lock. Possible race condition, but we don't want the performance hit.
11773 	if (necp_drop_management_order == 0 &&
11774 	    (necp_kernel_socket_policies_count == 0 ||
11775 	    (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
11776 		if (necp_drop_all_order > 0 || drop_order > 0) {
11777 			if (necp_socket_bypass(override_local_addr, override_remote_addr, inp) != NECP_BYPASS_TYPE_NONE) {
11778 				allowed_to_receive = TRUE;
11779 			} else {
11780 				allowed_to_receive = FALSE;
11781 			}
11782 		}
11783 		goto done;
11784 	}
11785 
11786 	// If this socket is connected, or we are not taking addresses into account, try to reuse last result
11787 	if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
11788 		bool policies_have_changed = FALSE;
11789 		bool route_allowed = necp_route_is_interface_type_allowed(route, input_interface, NULL, inp);
11790 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
11791 			policies_have_changed = TRUE;
11792 		} else {
11793 			if (inp->inp_policyresult.results.route_rule_id != 0) {
11794 				lck_rw_lock_shared(&necp_kernel_policy_lock);
11795 				if (!necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied)) {
11796 					route_allowed = FALSE;
11797 				}
11798 				lck_rw_done(&necp_kernel_policy_lock);
11799 			}
11800 		}
11801 
11802 		if (!policies_have_changed) {
11803 			if (!route_allowed ||
11804 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
11805 			    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11806 			    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11807 			    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
11808 				allowed_to_receive = FALSE;
11809 			} else {
11810 				if (return_policy_id) {
11811 					*return_policy_id = inp->inp_policyresult.policy_id;
11812 				}
11813 				if (return_skip_policy_id) {
11814 					*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
11815 				}
11816 				if (return_route_rule_id) {
11817 					*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11818 				}
11819 				if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
11820 					pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
11821 				}
11822 			}
11823 			goto done;
11824 		}
11825 	}
11826 
11827 	// Check for loopback exception
11828 	bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
11829 	if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
11830 		allowed_to_receive = TRUE;
11831 		goto done;
11832 	}
11833 
11834 	// Actually calculate policy result
11835 	lck_rw_lock_shared(&necp_kernel_policy_lock);
11836 	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));
11837 
11838 	int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
11839 	NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
11840 
11841 	flowhash = necp_socket_calc_flowhash_locked(&info);
11842 	if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
11843 	    inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
11844 	    inp->inp_policyresult.flowhash == flowhash) {
11845 		if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
11846 		    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11847 		    (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11848 		    inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
11849 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
11850 		    (inp->inp_policyresult.results.route_rule_id != 0 &&
11851 		    !necp_route_is_allowed(route, input_interface, NULL, 0, inp->inp_policyresult.results.route_rule_id, &interface_type_denied))) {
11852 			allowed_to_receive = FALSE;
11853 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <DROP>", 0, 0);
11854 		} else {
11855 			if (return_policy_id) {
11856 				*return_policy_id = inp->inp_policyresult.policy_id;
11857 			}
11858 			if (return_route_rule_id) {
11859 				*return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11860 			}
11861 			if (return_skip_policy_id) {
11862 				*return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
11863 			}
11864 			if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
11865 				pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
11866 			}
11867 			if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11868 				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",
11869 				    inp->inp_socket, info.bound_interface_index, info.protocol,
11870 				    inp->inp_policyresult.policy_id,
11871 				    inp->inp_policyresult.skip_policy_id,
11872 				    inp->inp_policyresult.results.result,
11873 				    inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
11874 			}
11875 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
11876 			    return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
11877 		}
11878 		lck_rw_done(&necp_kernel_policy_lock);
11879 		goto done;
11880 	}
11881 
11882 	u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11883 	size_t route_rule_id_array_count = 0;
11884 	struct necp_kernel_socket_policy *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)], &info, &filter_control_unit, route_rule_id_array, &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, &service_action, &service, netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, 0, socket_proc ? socket_proc : current_proc(), pf_tag, return_skip_policy_id, inp->inp_route.ro_rt, &drop_dest_policy_result, &drop_all_bypass, &flow_divert_aggregate_unit, so, debug);
11885 
11886 	// Check for loopback exception again after the policy match
11887 	if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
11888 	    necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
11889 	    (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
11890 		// If policies haven't changed since last evaluation, do not update filter result in order to
11891 		// preserve the very first filter result for the socket.  Otherwise, update the filter result to
11892 		// allow content filter to detect and drop pre-existing flows.
11893 		if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11894 		    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11895 			inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11896 		}
11897 		if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11898 			inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11899 		}
11900 		allowed_to_receive = TRUE;
11901 		lck_rw_done(&necp_kernel_policy_lock);
11902 		goto done;
11903 	}
11904 
11905 	if (info.protocol != IPPROTO_UDP) {
11906 		goto skip_agent_check;
11907 	}
11908 
11909 	// Verify netagents
11910 	if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
11911 		if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11912 			NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (unsigned long long)so, info.bound_interface_index, info.protocol);
11913 		}
11914 
11915 		// Mark socket as a drop if required agent is not active
11916 		inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11917 		inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11918 		inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
11919 		inp->inp_policyresult.flowhash = flowhash;
11920 		inp->inp_policyresult.results.filter_control_unit = 0;
11921 		inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
11922 		inp->inp_policyresult.results.route_rule_id = 0;
11923 		inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
11924 
11925 		// Unlock
11926 		allowed_to_receive = FALSE;
11927 		lck_rw_done(&necp_kernel_policy_lock);
11928 		goto done;
11929 	}
11930 
11931 skip_agent_check:
11932 
11933 	if (route_rule_id_array_count == 1) {
11934 		route_rule_id = route_rule_id_array[0];
11935 	} else if (route_rule_id_array_count > 1) {
11936 		route_rule_id = necp_create_aggregate_route_rule(route_rule_id_array);
11937 	}
11938 
11939 	bool send_local_network_denied_event = false;
11940 	if (matched_policy != NULL) {
11941 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
11942 		    matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
11943 		    !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
11944 			// Trigger the event that we dropped due to a local network policy
11945 			send_local_network_denied_event = true;
11946 		}
11947 
11948 		if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
11949 		    matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11950 		    (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11951 		    matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
11952 		    !necp_route_is_interface_type_allowed(route, input_interface, NULL, inp) ||
11953 		    (route_rule_id != 0 &&
11954 		    !necp_route_is_allowed(route, input_interface, netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, &interface_type_denied)) ||
11955 		    !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
11956 			allowed_to_receive = FALSE;
11957 		} else {
11958 			if (return_policy_id) {
11959 				*return_policy_id = matched_policy->id;
11960 			}
11961 			if (return_route_rule_id) {
11962 				*return_route_rule_id = route_rule_id;
11963 			}
11964 			if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
11965 				pass_flags = matched_policy->result_parameter.pass_flags;
11966 			}
11967 			// If policies haven't changed since last evaluation, do not update filter result in order to
11968 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
11969 			// allow content filter to detect and drop pre-existing flows.
11970 			if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11971 			    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11972 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11973 			}
11974 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11975 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11976 			}
11977 		}
11978 
11979 		if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
11980 			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>",
11981 			    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);
11982 		}
11983 	} else {
11984 		bool drop_all = false;
11985 		if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
11986 			drop_all = true;
11987 			if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11988 				drop_all_bypass = necp_check_drop_all_bypass_result(socket_proc ? socket_proc : current_proc());
11989 			}
11990 		}
11991 		if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11992 			allowed_to_receive = FALSE;
11993 			NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
11994 		} else {
11995 			if (return_policy_id) {
11996 				*return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11997 			}
11998 			if (return_route_rule_id) {
11999 				*return_route_rule_id = route_rule_id;
12000 			}
12001 
12002 			// If policies haven't changed since last evaluation, do not update filter result in order to
12003 			// preserve the very first filter result for the socket.  Otherwise, update the filter result to
12004 			// allow content filter to detect and drop pre-existing flows.
12005 			if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12006 			    inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12007 				inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12008 			}
12009 			if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12010 				inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12011 			}
12012 		}
12013 	}
12014 
12015 	if (necp_check_restricted_multicast_drop(socket_proc ? socket_proc : current_proc(), &info, true)) {
12016 		allowed_to_receive = FALSE;
12017 		NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
12018 	}
12019 
12020 	lck_rw_done(&necp_kernel_policy_lock);
12021 
12022 	if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
12023 		inp->inp_policyresult.network_denied_notifies++;
12024 		necp_send_network_denied_event(((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
12025 		    ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
12026 		    NETPOLICY_NETWORKTYPE_LOCAL);
12027 	}
12028 
12029 done:
12030 	if (return_pass_flags != NULL) {
12031 		*return_pass_flags = pass_flags;
12032 	}
12033 
12034 	if (pf_tag != 0 && allowed_to_receive) {
12035 		allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
12036 	}
12037 
12038 	if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
12039 		soevent(inp->inp_socket, (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
12040 	}
12041 
12042 	if (socket_proc) {
12043 		proc_rele(socket_proc);
12044 	}
12045 
12046 	return allowed_to_receive;
12047 }
12048 
12049 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)12050 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)
12051 {
12052 	struct sockaddr_in local = {};
12053 	struct sockaddr_in remote = {};
12054 	local.sin_family = remote.sin_family = AF_INET;
12055 	local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
12056 	local.sin_port = local_port;
12057 	remote.sin_port = remote_port;
12058 	memcpy(&local.sin_addr, local_addr, sizeof(local.sin_addr));
12059 	memcpy(&remote.sin_addr, remote_addr, sizeof(remote.sin_addr));
12060 
12061 	return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, input_interface,
12062 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12063 }
12064 
12065 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)12066 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)
12067 {
12068 	struct sockaddr_in6 local = {};
12069 	struct sockaddr_in6 remote = {};
12070 	local.sin6_family = remote.sin6_family = AF_INET6;
12071 	local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
12072 	local.sin6_port = local_port;
12073 	remote.sin6_port = remote_port;
12074 	memcpy(&local.sin6_addr, local_addr, sizeof(local.sin6_addr));
12075 	memcpy(&remote.sin6_addr, remote_addr, sizeof(remote.sin6_addr));
12076 
12077 	return necp_socket_is_allowed_to_send_recv_internal(inp, (struct sockaddr *)&local, (struct sockaddr *)&remote, input_interface,
12078 	           pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12079 }
12080 
12081 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)12082 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,
12083     u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
12084 {
12085 	return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
12086 	           return_policy_id, return_route_rule_id,
12087 	           return_skip_policy_id, return_pass_flags);
12088 }
12089 
12090 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)12091 necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
12092     necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
12093 {
12094 	if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
12095 		return EINVAL;
12096 	}
12097 
12098 	// Mark ID for Pass and IP Tunnel
12099 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12100 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12101 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
12102 	    inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
12103 		packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
12104 	} else {
12105 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12106 	}
12107 	packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
12108 	if (route_rule_id != 0) {
12109 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
12110 	} else {
12111 		packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12112 	}
12113 	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);
12114 
12115 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12116 	    skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
12117 		// Only mark the skip policy if it is a valid policy ID
12118 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12119 	} else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
12120 		// Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
12121 		// to indicate that NECP_FILTER_UNIT_NO_FILTER was set
12122 		// See necp_get_skip_policy_id_from_packet() and
12123 		// necp_packet_should_skip_filters().
12124 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12125 	} else {
12126 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12127 	}
12128 
12129 	if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
12130 	    ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
12131 		m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
12132 	}
12133 
12134 	return 0;
12135 }
12136 
12137 int
necp_mark_packet_from_ip(struct mbuf * packet,necp_kernel_policy_id policy_id)12138 necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
12139 {
12140 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12141 		return EINVAL;
12142 	}
12143 
12144 	// Mark ID for Pass and IP Tunnel
12145 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12146 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12147 	} else {
12148 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12149 	}
12150 
12151 	return 0;
12152 }
12153 
12154 int
necp_mark_packet_from_ip_with_skip(struct mbuf * packet,necp_kernel_policy_id policy_id,necp_kernel_policy_id skip_policy_id)12155 necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
12156 {
12157 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12158 		return EINVAL;
12159 	}
12160 
12161 	// Mark ID for Pass and IP Tunnel
12162 	if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12163 		packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12164 	} else {
12165 		packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12166 	}
12167 
12168 	if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12169 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12170 	} else {
12171 		packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12172 	}
12173 	return 0;
12174 }
12175 
12176 int
necp_mark_packet_from_interface(struct mbuf * packet,ifnet_t interface)12177 necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
12178 {
12179 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12180 		return EINVAL;
12181 	}
12182 
12183 	// Mark ID for Pass and IP Tunnel
12184 	if (interface != NULL) {
12185 		packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
12186 	}
12187 
12188 	return 0;
12189 }
12190 
12191 int
necp_mark_packet_as_keepalive(struct mbuf * packet,bool is_keepalive)12192 necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
12193 {
12194 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12195 		return EINVAL;
12196 	}
12197 
12198 	if (is_keepalive) {
12199 		packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
12200 	} else {
12201 		packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
12202 	}
12203 
12204 	return 0;
12205 }
12206 
12207 necp_kernel_policy_id
necp_get_policy_id_from_packet(struct mbuf * packet)12208 necp_get_policy_id_from_packet(struct mbuf *packet)
12209 {
12210 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12211 		return NECP_KERNEL_POLICY_ID_NONE;
12212 	}
12213 
12214 	return packet->m_pkthdr.necp_mtag.necp_policy_id;
12215 }
12216 
12217 necp_kernel_policy_id
necp_get_skip_policy_id_from_packet(struct mbuf * packet)12218 necp_get_skip_policy_id_from_packet(struct mbuf *packet)
12219 {
12220 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12221 		return NECP_KERNEL_POLICY_ID_NONE;
12222 	}
12223 
12224 	// Check for overloaded value. See necp_mark_packet_from_socket().
12225 	if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
12226 		return NECP_KERNEL_POLICY_ID_NONE;
12227 	}
12228 
12229 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
12230 }
12231 
12232 u_int16_t
necp_get_packet_filter_tags_from_packet(struct mbuf * packet)12233 necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
12234 {
12235 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12236 		return 0;
12237 	}
12238 
12239 	return m_pftag(packet)->pftag_tag;
12240 }
12241 
12242 bool
necp_packet_should_skip_filters(struct mbuf * packet)12243 necp_packet_should_skip_filters(struct mbuf *packet)
12244 {
12245 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12246 		return false;
12247 	}
12248 
12249 	// Check for overloaded value. See necp_mark_packet_from_socket().
12250 	return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
12251 }
12252 
12253 u_int32_t
necp_get_last_interface_index_from_packet(struct mbuf * packet)12254 necp_get_last_interface_index_from_packet(struct mbuf *packet)
12255 {
12256 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12257 		return 0;
12258 	}
12259 
12260 	return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
12261 }
12262 
12263 u_int32_t
necp_get_route_rule_id_from_packet(struct mbuf * packet)12264 necp_get_route_rule_id_from_packet(struct mbuf *packet)
12265 {
12266 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12267 		return 0;
12268 	}
12269 
12270 	return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
12271 }
12272 
12273 int
necp_get_app_uuid_from_packet(struct mbuf * packet,uuid_t app_uuid)12274 necp_get_app_uuid_from_packet(struct mbuf *packet,
12275     uuid_t app_uuid)
12276 {
12277 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12278 		return EINVAL;
12279 	}
12280 
12281 	bool found_mapping = FALSE;
12282 	if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
12283 		lck_rw_lock_shared(&necp_kernel_policy_lock);
12284 		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);
12285 		struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(app_id);
12286 		if (entry != NULL) {
12287 			uuid_copy(app_uuid, entry->uuid);
12288 			found_mapping = true;
12289 		}
12290 		lck_rw_done(&necp_kernel_policy_lock);
12291 	}
12292 	if (!found_mapping) {
12293 		uuid_clear(app_uuid);
12294 	}
12295 	return 0;
12296 }
12297 
12298 bool
necp_get_is_keepalive_from_packet(struct mbuf * packet)12299 necp_get_is_keepalive_from_packet(struct mbuf *packet)
12300 {
12301 	if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12302 		return FALSE;
12303 	}
12304 
12305 	return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
12306 }
12307 
12308 u_int32_t
necp_socket_get_content_filter_control_unit(struct socket * so)12309 necp_socket_get_content_filter_control_unit(struct socket *so)
12310 {
12311 	struct inpcb *inp = sotoinpcb(so);
12312 
12313 	if (inp == NULL) {
12314 		return 0;
12315 	}
12316 	return inp->inp_policyresult.results.filter_control_unit;
12317 }
12318 
12319 bool
necp_socket_should_use_flow_divert(struct inpcb * inp)12320 necp_socket_should_use_flow_divert(struct inpcb *inp)
12321 {
12322 	if (inp == NULL) {
12323 		return FALSE;
12324 	}
12325 
12326 	return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
12327 	       (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12328 	       (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
12329 }
12330 
12331 u_int32_t
necp_socket_get_flow_divert_control_unit(struct inpcb * inp,uint32_t * aggregate_unit)12332 necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
12333 {
12334 	if (inp == NULL) {
12335 		return 0;
12336 	}
12337 
12338 	if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
12339 		return 0;
12340 	}
12341 
12342 	if (aggregate_unit != NULL &&
12343 	    inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
12344 		*aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
12345 	}
12346 
12347 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
12348 		return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
12349 	}
12350 
12351 	return 0;
12352 }
12353 
12354 bool
necp_socket_should_rescope(struct inpcb * inp)12355 necp_socket_should_rescope(struct inpcb *inp)
12356 {
12357 	if (inp == NULL) {
12358 		return FALSE;
12359 	}
12360 
12361 	return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
12362 	       inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
12363 }
12364 
12365 u_int
necp_socket_get_rescope_if_index(struct inpcb * inp)12366 necp_socket_get_rescope_if_index(struct inpcb *inp)
12367 {
12368 	if (inp == NULL) {
12369 		return 0;
12370 	}
12371 
12372 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
12373 		return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
12374 	} else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
12375 		return necp_get_primary_direct_interface_index();
12376 	}
12377 
12378 	return 0;
12379 }
12380 
12381 u_int32_t
necp_socket_get_effective_mtu(struct inpcb * inp,u_int32_t current_mtu)12382 necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
12383 {
12384 	if (inp == NULL) {
12385 		return current_mtu;
12386 	}
12387 
12388 	if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
12389 	    (inp->inp_flags & INP_BOUND_IF) &&
12390 	    inp->inp_boundifp) {
12391 		u_int bound_interface_index = inp->inp_boundifp->if_index;
12392 		u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
12393 
12394 		// The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
12395 		if (bound_interface_index != tunnel_interface_index) {
12396 			ifnet_t tunnel_interface = NULL;
12397 
12398 			ifnet_head_lock_shared();
12399 			tunnel_interface = ifindex2ifnet[tunnel_interface_index];
12400 			ifnet_head_done();
12401 
12402 			if (tunnel_interface != NULL) {
12403 				u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
12404 				u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
12405 				if (delegate_tunnel_mtu != 0 &&
12406 				    strncmp(tunnel_interface->if_name, "ipsec", strlen("ipsec")) == 0) {
12407 					// For ipsec interfaces, calculate the overhead from the delegate interface
12408 					u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
12409 					if (delegate_tunnel_mtu > tunnel_overhead) {
12410 						delegate_tunnel_mtu -= tunnel_overhead;
12411 					}
12412 
12413 					if (delegate_tunnel_mtu < direct_tunnel_mtu) {
12414 						// If the (delegate - overhead) < direct, return (delegate - overhead)
12415 						return delegate_tunnel_mtu;
12416 					} else {
12417 						// Otherwise return direct
12418 						return direct_tunnel_mtu;
12419 					}
12420 				} else {
12421 					// For non-ipsec interfaces, just return the tunnel MTU
12422 					return direct_tunnel_mtu;
12423 				}
12424 			}
12425 		}
12426 	}
12427 
12428 	// By default, just return the MTU passed in
12429 	return current_mtu;
12430 }
12431 
12432 ifnet_t
necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter * result_parameter)12433 necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
12434 {
12435 	if (result_parameter == NULL) {
12436 		return NULL;
12437 	}
12438 
12439 	return ifindex2ifnet[result_parameter->tunnel_interface_index];
12440 }
12441 
12442 bool
necp_packet_can_rebind_to_ifnet(struct mbuf * packet,struct ifnet * interface,struct route * new_route,int family)12443 necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
12444 {
12445 	bool found_match = FALSE;
12446 	bool can_rebind = FALSE;
12447 	ifaddr_t ifa;
12448 	union necp_sockaddr_union address_storage;
12449 
12450 	if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
12451 		return FALSE;
12452 	}
12453 
12454 	// Match source address against interface addresses
12455 	ifnet_lock_shared(interface);
12456 	TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
12457 		if (ifaddr_address(ifa, SA(&address_storage.sa), sizeof(address_storage)) == 0) {
12458 			if (address_storage.sa.sa_family != family) {
12459 				continue;
12460 			}
12461 
12462 			if (family == AF_INET) {
12463 				struct ip *ip = mtod(packet, struct ip *);
12464 				if (memcmp(&address_storage.sin.sin_addr, &ip->ip_src, sizeof(ip->ip_src)) == 0) {
12465 					found_match = TRUE;
12466 					break;
12467 				}
12468 			} else if (family == AF_INET6) {
12469 				struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12470 				if (memcmp(&address_storage.sin6.sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src)) == 0) {
12471 					found_match = TRUE;
12472 					break;
12473 				}
12474 			}
12475 		}
12476 	}
12477 	const uint32_t if_idx = interface->if_index;
12478 	ifnet_lock_done(interface);
12479 
12480 	// If source address matched, attempt to construct a route to the destination address
12481 	if (found_match) {
12482 		ROUTE_RELEASE(new_route);
12483 
12484 		if (family == AF_INET) {
12485 			struct ip *ip = mtod(packet, struct ip *);
12486 			struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)&new_route->ro_dst;
12487 			dst4->sin_family = AF_INET;
12488 			dst4->sin_len = sizeof(struct sockaddr_in);
12489 			dst4->sin_addr = ip->ip_dst;
12490 			rtalloc_scoped(new_route, if_idx);
12491 			if (!ROUTE_UNUSABLE(new_route)) {
12492 				can_rebind = TRUE;
12493 			}
12494 		} else if (family == AF_INET6) {
12495 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12496 			struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)&new_route->ro_dst;
12497 			dst6->sin6_family = AF_INET6;
12498 			dst6->sin6_len = sizeof(struct sockaddr_in6);
12499 			dst6->sin6_addr = ip6->ip6_dst;
12500 			rtalloc_scoped(new_route, if_idx);
12501 			if (!ROUTE_UNUSABLE(new_route)) {
12502 				can_rebind = TRUE;
12503 			}
12504 		}
12505 	}
12506 
12507 	return can_rebind;
12508 }
12509 
12510 static bool
necp_addr_is_loopback(struct sockaddr * address)12511 necp_addr_is_loopback(struct sockaddr *address)
12512 {
12513 	if (address == NULL) {
12514 		return FALSE;
12515 	}
12516 
12517 	if (address->sa_family == AF_INET) {
12518 		return ntohl(((struct sockaddr_in *)(void *)address)->sin_addr.s_addr) == INADDR_LOOPBACK;
12519 	} else if (address->sa_family == AF_INET6) {
12520 		if (!IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)address)->sin6_addr)) {
12521 			return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)address)->sin6_addr);
12522 		} else {
12523 			// Match ::ffff:127.0.0.1 loopback address
12524 			in6_addr_t *in6_addr_ptr = &(((struct sockaddr_in6 *)(void *)address)->sin6_addr);
12525 			return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
12526 		}
12527 	}
12528 
12529 	return FALSE;
12530 }
12531 
12532 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)12533 necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
12534 {
12535 	// Note: This function only checks for the loopback addresses.
12536 	// In the future, we may want to expand to also allow any traffic
12537 	// going through the loopback interface, but until then, this
12538 	// check is cheaper.
12539 
12540 	if (local_addr != NULL && necp_addr_is_loopback(local_addr)) {
12541 		return TRUE;
12542 	}
12543 
12544 	if (remote_addr != NULL && necp_addr_is_loopback(remote_addr)) {
12545 		return TRUE;
12546 	}
12547 
12548 	if (inp != NULL) {
12549 		if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
12550 			return TRUE;
12551 		}
12552 		if (inp->inp_vflag & INP_IPV4) {
12553 			if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
12554 			    ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
12555 				return TRUE;
12556 			}
12557 		} else if (inp->inp_vflag & INP_IPV6) {
12558 			if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
12559 			    IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
12560 				return TRUE;
12561 			}
12562 		}
12563 	} else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
12564 		return TRUE;
12565 	}
12566 
12567 	if (packet != NULL) {
12568 		struct ip *ip = mtod(packet, struct ip *);
12569 		if (ip->ip_v == 4) {
12570 			if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
12571 				return TRUE;
12572 			}
12573 			if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
12574 				return TRUE;
12575 			}
12576 		} else if (ip->ip_v == 6) {
12577 			struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12578 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
12579 				return TRUE;
12580 			}
12581 			if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
12582 				return TRUE;
12583 			}
12584 		}
12585 	}
12586 
12587 	return FALSE;
12588 }
12589 
12590 static bool
necp_is_intcoproc(struct inpcb * inp,struct mbuf * packet)12591 necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
12592 {
12593 	if (inp != NULL) {
12594 		if (!(inp->inp_vflag & INP_IPV6)) {
12595 			return false;
12596 		}
12597 		if (INP_INTCOPROC_ALLOWED(inp)) {
12598 			return true;
12599 		}
12600 		if ((inp->inp_flags & INP_BOUND_IF) &&
12601 		    IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
12602 			return true;
12603 		}
12604 		return false;
12605 	}
12606 	if (packet != NULL) {
12607 		struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12608 		struct in6_addr *addrv6 = &ip6->ip6_dst;
12609 		if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
12610 		    NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
12611 			return true;
12612 		}
12613 	}
12614 
12615 	return false;
12616 }
12617 
12618 static bool
necp_address_matches_drop_dest_policy(union necp_sockaddr_union * sau,u_int32_t session_order)12619 necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
12620 {
12621 	char dest_str[MAX_IPv6_STR_LEN];
12622 
12623 	if (necp_drop_dest_debug > 0) {
12624 		if (sau->sa.sa_family == AF_INET) {
12625 			(void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
12626 		} else if (sau->sa.sa_family == AF_INET6) {
12627 			(void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
12628 		} else {
12629 			dest_str[0] = 0;
12630 		}
12631 	}
12632 	for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
12633 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
12634 		struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
12635 
12636 		if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), npca->prefix)) {
12637 			if (necp_drop_dest_debug > 0) {
12638 				char subnet_str[MAX_IPv6_STR_LEN];
12639 				struct proc *p = current_proc();
12640 				pid_t pid = proc_pid(p);
12641 
12642 				if (sau->sa.sa_family == AF_INET) {
12643 					(void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
12644 					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);
12645 				} else if (sau->sa.sa_family == AF_INET6) {
12646 					(void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
12647 					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);
12648 				}
12649 			}
12650 			return true;
12651 		}
12652 	}
12653 	if (necp_drop_dest_debug > 1) {
12654 		struct proc *p = current_proc();
12655 		pid_t pid = proc_pid(p);
12656 
12657 		os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
12658 	}
12659 	return false;
12660 }
12661 
12662 static int
12663 sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
12664 {
12665 #pragma unused(arg1, arg2, oidp)
12666 	int changed = 0;
12667 	int error = 0;
12668 	struct necp_drop_dest_policy tmp_drop_dest_policy;
12669 	struct proc *p = current_proc();
12670 	pid_t pid = proc_pid(p);
12671 
12672 	if (req->newptr != USER_ADDR_NULL && proc_suser(current_proc()) != 0 &&
12673 	    priv_check_cred(kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, 0) != 0) {
12674 		NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
12675 		return EPERM;
12676 	}
12677 	if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
12678 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
12679 		return EINVAL;
12680 	}
12681 
12682 	memcpy(&tmp_drop_dest_policy, &necp_drop_dest_policy, sizeof(struct necp_drop_dest_policy));
12683 	error = sysctl_io_opaque(req, &tmp_drop_dest_policy, sizeof(struct necp_drop_dest_policy), &changed);
12684 	if (error != 0) {
12685 		NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
12686 		return error;
12687 	}
12688 	if (changed == 0 || req->newptr == USER_ADDR_NULL) {
12689 		return error;
12690 	}
12691 
12692 	//
12693 	// Validate the passed parameters
12694 	//
12695 	if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
12696 		NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
12697 		return EINVAL;
12698 	}
12699 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
12700 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
12701 		struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
12702 
12703 		switch (tmp_drop_dest_entry->level) {
12704 		case NECP_SESSION_PRIORITY_UNKNOWN:
12705 			if (tmp_drop_dest_policy.entry_count != 0) {
12706 				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);
12707 				return EINVAL;
12708 			}
12709 			break;
12710 		case NECP_SESSION_PRIORITY_CONTROL:
12711 		case NECP_SESSION_PRIORITY_CONTROL_1:
12712 		case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
12713 		case NECP_SESSION_PRIORITY_HIGH:
12714 		case NECP_SESSION_PRIORITY_HIGH_1:
12715 		case NECP_SESSION_PRIORITY_HIGH_2:
12716 		case NECP_SESSION_PRIORITY_HIGH_3:
12717 		case NECP_SESSION_PRIORITY_HIGH_4:
12718 		case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
12719 		case NECP_SESSION_PRIORITY_DEFAULT:
12720 		case NECP_SESSION_PRIORITY_LOW:
12721 			if (tmp_drop_dest_policy.entry_count == 0) {
12722 				NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
12723 				return EINVAL;
12724 			}
12725 			break;
12726 		default: {
12727 			NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
12728 			return EINVAL;
12729 		}
12730 		}
12731 
12732 		switch (npca->address.sa.sa_family) {
12733 		case AF_INET: {
12734 			if (npca->prefix > 32) {
12735 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
12736 				return EINVAL;
12737 			}
12738 			if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
12739 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
12740 				return EINVAL;
12741 			}
12742 			if (npca->address.sin.sin_port != 0) {
12743 				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);
12744 				return EINVAL;
12745 			}
12746 			break;
12747 		}
12748 		case AF_INET6: {
12749 			if (npca->prefix > 128) {
12750 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
12751 				return EINVAL;
12752 			}
12753 			if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
12754 				NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
12755 				return EINVAL;
12756 			}
12757 			if (npca->address.sin6.sin6_port != 0) {
12758 				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);
12759 				return EINVAL;
12760 			}
12761 			if (npca->address.sin6.sin6_flowinfo != 0) {
12762 				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);
12763 				return EINVAL;
12764 			}
12765 			if (npca->address.sin6.sin6_scope_id != 0) {
12766 				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);
12767 				return EINVAL;
12768 			}
12769 			break;
12770 		}
12771 		default: {
12772 			return EINVAL;
12773 		}
12774 		}
12775 	}
12776 
12777 	//
12778 	// Commit the changed policy
12779 	//
12780 	lck_rw_lock_exclusive(&necp_kernel_policy_lock);
12781 	memset(&necp_drop_dest_policy, 0, sizeof(struct necp_drop_dest_policy));
12782 
12783 	necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
12784 	for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
12785 		struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
12786 		struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
12787 
12788 		memcpy(necp_drop_dest_entry, tmp_drop_dest_entry, sizeof(struct necp_drop_dest_entry));
12789 
12790 		necp_drop_dest_entry->order = necp_get_first_order_for_priority(necp_drop_dest_entry->level);
12791 	}
12792 	lck_rw_done(&necp_kernel_policy_lock);
12793 
12794 	return 0;
12795 }
12796 
12797 const char*
necp_get_address_string(union necp_sockaddr_union * address,char addr_str[MAX_IPv6_STR_LEN])12798 necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
12799 {
12800 	uint16_t fam = address->sa.sa_family;
12801 	memset(addr_str, 0, MAX_IPv6_STR_LEN);
12802 	if (fam == AF_INET) {
12803 		(void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
12804 	} else if (fam == AF_INET6) {
12805 		(void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
12806 	}
12807 	return addr_str;
12808 }
12809