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