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