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