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