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