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