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