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