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