1/*
2 * Copyright (c) 2013-2022 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <string.h>
30#include <sys/systm.h>
31#include <sys/types.h>
32#include <sys/queue.h>
33#include <sys/malloc.h>
34#include <sys/kernel.h>
35#include <sys/kern_control.h>
36#include <sys/mbuf.h>
37#include <sys/kpi_mbuf.h>
38#include <sys/proc_uuid_policy.h>
39#include <net/if.h>
40#include <sys/domain.h>
41#include <sys/protosw.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/coalition.h>
45#include <sys/ubc.h>
46#include <sys/codesign.h>
47#include <kern/cs_blobs.h>
48#include <netinet/ip.h>
49#include <netinet/ip6.h>
50#include <netinet/tcp.h>
51#include <netinet/tcp_var.h>
52#include <netinet/tcp_cache.h>
53#include <netinet/udp.h>
54#include <netinet/in_pcb.h>
55#include <netinet/in_tclass.h>
56#include <netinet6/esp.h>
57#include <net/flowhash.h>
58#include <net/bloom_filter.h>
59#include <net/if_var.h>
60#include <net/pfvar.h>
61#if SKYWALK && defined(XNU_TARGET_OS_OSX)
62#include <skywalk/lib/net_filter_event.h>
63#endif /* defined(SKYWALK) && defined(XNU_TARGET_OS_OSX) */
64#include <sys/kauth.h>
65#include <sys/sysctl.h>
66#include <sys/sysproto.h>
67#include <sys/priv.h>
68#include <sys/kern_event.h>
69#include <sys/file_internal.h>
70#include <IOKit/IOBSD.h>
71#include <libkern/crypto/rand.h>
72#include <corecrypto/cchmac.h>
73#include <corecrypto/ccsha2.h>
74#include <os/refcnt.h>
75#include <mach-o/loader.h>
76#include <net/network_agent.h>
77#include <net/necp.h>
78#include <netinet/flow_divert_proto.h>
79
80/*
81 * NECP - Network Extension Control Policy database
82 * ------------------------------------------------
83 * The goal of this module is to allow clients connecting via a
84 * policy file descriptor to create high-level policy sessions, which
85 * are ingested into low-level kernel policies that control and tag
86 * traffic at the application, socket, and IP layers.
87 *
88 * ------------------------------------------------
89 * Sessions
90 * ------------------------------------------------
91 * Each session owns a list of session policies, each of which can
92 * specify any combination of conditions and a single result. Each
93 * session also has a priority level (such as High, Default, or Low)
94 * which is requested by the client. Based on the requested level,
95 * a session order value is assigned to the session, which will be used
96 * to sort kernel policies generated by the session. The session client
97 * can specify the sub-order for each policy it creates which will be
98 * used to further sort the kernel policies.
99 *
100 * Policy fd --> 1 necp_session --> list of necp_session_policy structs
101 *
102 * ------------------------------------------------
103 * Kernel Policies
104 * ------------------------------------------------
105 * Whenever a session send the Apply command, its policies are ingested
106 * and generate kernel policies. There are two phases of kernel policy
107 * ingestion.
108 *
109 * 1. The session policy is parsed to create kernel policies at the socket
110 * and IP layers, when applicable. For example, a policy that requires
111 * all traffic from App1 to Pass will generate a socket kernel policy to
112 * match App1 and mark packets with ID1, and also an IP policy to match
113 * ID1 and let the packet pass. This is handled in necp_apply_policy. The
114 * resulting kernel policies are added to the global socket and IP layer
115 * policy lists.
116 * necp_session_policy --> necp_kernel_socket_policy and necp_kernel_ip_output_policy
117 * || ||
118 * \/ \/
119 * necp_kernel_socket_policies necp_kernel_ip_output_policies
120 *
121 * 2. Once the global lists of kernel policies have been filled out, each
122 * list is traversed to create optimized sub-lists ("Maps") which are used during
123 * data-path evaluation. IP policies are sent into necp_kernel_ip_output_policies_map,
124 * which hashes incoming packets based on marked socket-layer policies, and removes
125 * duplicate or overlapping policies. Socket policies are sent into two maps,
126 * necp_kernel_socket_policies_map and necp_kernel_socket_policies_app_layer_map.
127 * The app layer map is used for policy checks coming in from user space, and is one
128 * list with duplicate and overlapping policies removed. The socket map hashes based
129 * on app UUID, and removes duplicate and overlapping policies.
130 * necp_kernel_socket_policy --> necp_kernel_socket_policies_app_layer_map
131 * |-> necp_kernel_socket_policies_map
132 *
133 * necp_kernel_ip_output_policies --> necp_kernel_ip_output_policies_map
134 *
135 * ------------------------------------------------
136 * Drop All Level
137 * ------------------------------------------------
138 * The Drop All Level is a sysctl that controls the level at which policies are allowed
139 * to override a global drop rule. If the value is 0, no drop rule is applied. If the value
140 * is 1, all traffic is dropped. If the value is greater than 1, all kernel policies created
141 * by a session with a priority level better than (numerically less than) the
142 * Drop All Level will allow matching traffic to not be dropped. The Drop All Level is
143 * dynamically interpreted into necp_drop_all_order, which specifies the equivalent assigned
144 * session orders to be dropped.
145 */
146
147u_int32_t necp_drop_all_order = 0;
148u_int32_t necp_drop_all_level = 0;
149
150u_int32_t necp_pass_loopback = NECP_LOOPBACK_PASS_ALL;
151u_int32_t necp_pass_keepalives = 1; // 0=Off, 1=On
152u_int32_t necp_pass_interpose = 1; // 0=Off, 1=On
153u_int32_t necp_restrict_multicast = 1; // 0=Off, 1=On
154u_int32_t necp_dedup_policies = 0; // 0=Off, 1=On
155
156u_int32_t necp_drop_unentitled_order = 0;
157#ifdef XNU_TARGET_OS_WATCH
158u_int32_t necp_drop_unentitled_level = NECP_SESSION_PRIORITY_CONTROL + 1; // Block all unentitled traffic from policies below control level
159#else // XNU_TARGET_OS_WATCH
160u_int32_t necp_drop_unentitled_level = 0;
161#endif // XNU_TARGET_OS_WATCH
162
163u_int32_t necp_drop_management_order = 0;
164u_int32_t necp_drop_management_level = NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL;
165
166u_int32_t necp_debug = 0; // 0=None, 1=Basic, 2=EveryMatch
167
168os_log_t necp_log_handle = NULL;
169os_log_t necp_data_trace_log_handle = NULL;
170
171u_int32_t necp_session_count = 0;
172
173static KALLOC_TYPE_DEFINE(necp_session_policy_zone,
174 struct necp_session_policy, NET_KT_DEFAULT);
175static KALLOC_TYPE_DEFINE(necp_socket_policy_zone,
176 struct necp_kernel_socket_policy, NET_KT_DEFAULT);
177static KALLOC_TYPE_DEFINE(necp_ip_policy_zone,
178 struct necp_kernel_ip_output_policy, NET_KT_DEFAULT);
179
180#define LIST_INSERT_SORTED_ASCENDING(head, elm, field, sortfield, tmpelm) do { \
181 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->sortfield >= (elm)->sortfield)) { \
182 LIST_INSERT_HEAD((head), elm, field); \
183 } else { \
184 LIST_FOREACH(tmpelm, head, field) { \
185 if (LIST_NEXT(tmpelm, field) == NULL || LIST_NEXT(tmpelm, field)->sortfield >= (elm)->sortfield) { \
186 LIST_INSERT_AFTER(tmpelm, elm, field); \
187 break; \
188 } \
189 } \
190 } \
191} while (0)
192
193#define LIST_INSERT_SORTED_TWICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, tmpelm) do { \
194 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield))) { \
195 LIST_INSERT_HEAD((head), elm, field); \
196 } else { \
197 LIST_FOREACH(tmpelm, head, field) { \
198 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield))) { \
199 LIST_INSERT_AFTER(tmpelm, elm, field); \
200 break; \
201 } \
202 } \
203 } \
204} while (0)
205
206#define LIST_INSERT_SORTED_THRICE_ASCENDING(head, elm, field, firstsortfield, secondsortfield, thirdsortfield, tmpelm) do { \
207 if (LIST_EMPTY((head)) || (LIST_FIRST(head)->firstsortfield > (elm)->firstsortfield) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_FIRST(head)->firstsortfield == (elm)->firstsortfield) && (LIST_FIRST(head)->secondsortfield == (elm)->secondsortfield) && (LIST_FIRST(head)->thirdsortfield >= (elm)->thirdsortfield))) { \
208 LIST_INSERT_HEAD((head), elm, field); \
209 } else { \
210 LIST_FOREACH(tmpelm, head, field) { \
211 if (LIST_NEXT(tmpelm, field) == NULL || (LIST_NEXT(tmpelm, field)->firstsortfield > (elm)->firstsortfield) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield >= (elm)->secondsortfield)) || ((LIST_NEXT(tmpelm, field)->firstsortfield == (elm)->firstsortfield) && (LIST_NEXT(tmpelm, field)->secondsortfield == (elm)->secondsortfield) && (LIST_NEXT(tmpelm, field)->thirdsortfield >= (elm)->thirdsortfield))) { \
212 LIST_INSERT_AFTER(tmpelm, elm, field); \
213 break; \
214 } \
215 } \
216 } \
217} while (0)
218
219#define IS_NECP_ROUTE_RULE_DENY(x) ((x) == NECP_ROUTE_RULE_DENY_INTERFACE || (x) == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE)
220
221#define IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(x) (IS_NECP_ROUTE_RULE_DENY(x) || (x) == NECP_ROUTE_RULE_ALLOW_INTERFACE)
222
223#define IS_NECP_DEST_IN_LOCAL_NETWORKS(rt) \
224 ((rt) != NULL && !((rt)->rt_flags & RTF_GATEWAY) && ((rt)->rt_ifa && (rt)->rt_ifa->ifa_ifp && !((rt)->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT)))
225
226#define NECP_KERNEL_CONDITION_ALL_INTERFACES 0x000001
227#define NECP_KERNEL_CONDITION_BOUND_INTERFACE 0x000002
228#define NECP_KERNEL_CONDITION_PROTOCOL 0x000004
229#define NECP_KERNEL_CONDITION_LOCAL_START 0x000008
230#define NECP_KERNEL_CONDITION_LOCAL_END 0x000010
231#define NECP_KERNEL_CONDITION_LOCAL_PREFIX 0x000020
232#define NECP_KERNEL_CONDITION_REMOTE_START 0x000040
233#define NECP_KERNEL_CONDITION_REMOTE_END 0x000080
234#define NECP_KERNEL_CONDITION_REMOTE_PREFIX 0x000100
235#define NECP_KERNEL_CONDITION_APP_ID 0x000200
236#define NECP_KERNEL_CONDITION_REAL_APP_ID 0x000400
237#define NECP_KERNEL_CONDITION_DOMAIN 0x000800
238#define NECP_KERNEL_CONDITION_ACCOUNT_ID 0x001000
239#define NECP_KERNEL_CONDITION_POLICY_ID 0x002000
240#define NECP_KERNEL_CONDITION_PID 0x004000
241#define NECP_KERNEL_CONDITION_UID 0x008000
242#define NECP_KERNEL_CONDITION_LAST_INTERFACE 0x010000 // Only set from packets looping between interfaces
243#define NECP_KERNEL_CONDITION_TRAFFIC_CLASS 0x020000
244#define NECP_KERNEL_CONDITION_ENTITLEMENT 0x040000
245#define NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT 0x080000
246#define NECP_KERNEL_CONDITION_AGENT_TYPE 0x100000
247#define NECP_KERNEL_CONDITION_HAS_CLIENT 0x200000
248#define NECP_KERNEL_CONDITION_LOCAL_NETWORKS 0x400000
249#define NECP_KERNEL_CONDITION_CLIENT_FLAGS 0x800000
250#define NECP_KERNEL_CONDITION_LOCAL_EMPTY 0x1000000
251#define NECP_KERNEL_CONDITION_REMOTE_EMPTY 0x2000000
252#define NECP_KERNEL_CONDITION_PLATFORM_BINARY 0x4000000
253#define NECP_KERNEL_CONDITION_SDK_VERSION 0x8000000
254#define NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER 0x10000000
255#define NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS 0x20000000
256#define NECP_KERNEL_CONDITION_IS_LOOPBACK 0x40000000
257#define NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY 0x80000000
258#define NECP_KERNEL_CONDITION_SCHEME_PORT 0x100000000
259#define NECP_KERNEL_CONDITION_DOMAIN_FILTER 0x200000000
260#define NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT 0x400000000
261#define NECP_KERNEL_CONDITION_EXACT_DOMAIN 0x800000000
262#define NECP_KERNEL_CONDITION_REAL_UID 0x1000000000
263#define NECP_KERNEL_CONDITION_URL 0x2000000000
264#define NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS 0x4000000000
265
266#define NECP_MAX_POLICY_RESULT_SIZE 512
267#define NECP_MAX_ROUTE_RULES_ARRAY_SIZE 1024
268#define NECP_MAX_CONDITIONS_ARRAY_SIZE 4096
269#define NECP_MAX_POLICY_LIST_COUNT 1024
270
271#define NECP_MAX_DOMAIN_FILTER_SIZE 65536 // Allows room for 100K domains
272
273typedef enum {
274 NECP_BYPASS_TYPE_NONE = 0,
275 NECP_BYPASS_TYPE_INTCOPROC = 1,
276 NECP_BYPASS_TYPE_LOOPBACK = 2,
277} necp_socket_bypass_type_t;
278
279// Cap the policy size at the max result + conditions size, with room for extra TLVs
280#define NECP_MAX_POLICY_SIZE (1024 + NECP_MAX_POLICY_RESULT_SIZE + NECP_MAX_CONDITIONS_ARRAY_SIZE)
281
282struct necp_service_registration {
283 LIST_ENTRY(necp_service_registration) session_chain;
284 LIST_ENTRY(necp_service_registration) kernel_chain;
285 u_int32_t service_id;
286};
287
288struct necp_domain_filter {
289 LIST_ENTRY(necp_domain_filter) owner_chain;
290 LIST_ENTRY(necp_domain_filter) chain;
291 u_int32_t id;
292 struct net_bloom_filter *filter;
293 os_refcnt_t refcount;
294};
295static LIST_HEAD(necp_domain_filter_list, necp_domain_filter) necp_global_domain_filter_list;
296
297struct necp_session {
298 u_int8_t necp_fd_type;
299 u_int32_t control_unit;
300 u_int32_t session_priority; // Descriptive priority rating
301 u_int32_t session_order;
302
303 necp_policy_id last_policy_id;
304
305 decl_lck_mtx_data(, lock);
306
307 bool proc_locked; // Messages must come from proc_uuid
308 uuid_t proc_uuid;
309 int proc_pid;
310
311 bool dirty;
312 LIST_HEAD(_policies, necp_session_policy) policies;
313
314 LIST_HEAD(_services, necp_service_registration) services;
315 struct necp_domain_filter_list domain_filters;
316
317 TAILQ_ENTRY(necp_session) chain;
318};
319
320#define NECP_SESSION_LOCK(_s) lck_mtx_lock(&_s->lock)
321#define NECP_SESSION_UNLOCK(_s) lck_mtx_unlock(&_s->lock)
322
323static TAILQ_HEAD(_necp_session_list, necp_session) necp_session_list;
324
325struct necp_socket_info {
326 pid_t pid;
327 int32_t pid_version;
328 uid_t uid;
329 uid_t real_uid;
330 union necp_sockaddr_union local_addr;
331 union necp_sockaddr_union remote_addr;
332 u_int32_t bound_interface_index;
333 u_int32_t bound_interface_flags;
334 u_int32_t bound_interface_eflags;
335 u_int32_t bound_interface_xflags;
336 u_int32_t traffic_class;
337 u_int16_t protocol;
338 u_int16_t scheme_port;
339 u_int32_t application_id;
340 u_int32_t real_application_id;
341 u_int32_t account_id;
342 u_int32_t drop_order;
343 u_int32_t client_flags;
344 char *domain;
345 char *url;
346 unsigned is_entitled : 1;
347 unsigned has_client : 1;
348 unsigned has_system_signed_result : 1;
349 unsigned is_platform_binary : 1;
350 unsigned used_responsible_pid : 1;
351 unsigned is_loopback : 1;
352 unsigned real_is_platform_binary : 1;
353 unsigned is_delegated : 1;
354 unsigned is_local : 1;
355 unsigned __pad_bits : 7;
356};
357
358static LCK_GRP_DECLARE(necp_kernel_policy_mtx_grp, NECP_CONTROL_NAME);
359static LCK_ATTR_DECLARE(necp_kernel_policy_mtx_attr, 0, 0);
360static LCK_RW_DECLARE_ATTR(necp_kernel_policy_lock, &necp_kernel_policy_mtx_grp,
361 &necp_kernel_policy_mtx_attr);
362
363static LCK_GRP_DECLARE(necp_route_rule_mtx_grp, "necp_route_rule");
364static LCK_RW_DECLARE(necp_route_rule_lock, &necp_route_rule_mtx_grp);
365
366os_refgrp_decl(static, necp_refgrp, "NECPRefGroup", NULL);
367
368/*
369 * On modification, invalidate cached lookups by bumping the generation count.
370 * Other calls will need to take the slowpath of taking
371 * the subsystem lock.
372 */
373static volatile int32_t necp_kernel_socket_policies_gencount;
374#define BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT() do { \
375 if (OSIncrementAtomic(&necp_kernel_socket_policies_gencount) == (INT32_MAX - 1)) { \
376 necp_kernel_socket_policies_gencount = 1; \
377 } \
378} while (0)
379
380/*
381 * Drop-all Bypass:
382 * Allow priviledged processes to bypass the default drop-all
383 * via entitlement check. For OSX, since entitlement check is
384 * not supported for configd, configd signing identity is checked
385 * instead.
386 */
387#define SIGNING_ID_CONFIGD "com.apple.configd"
388#define SIGNING_ID_CONFIGD_LEN (sizeof(SIGNING_ID_CONFIGD) - 1)
389
390typedef enum {
391 NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE = 0,
392 NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE = 1,
393 NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE = 2,
394} necp_drop_all_bypass_check_result_t;
395
396static u_int64_t necp_kernel_application_policies_condition_mask;
397static size_t necp_kernel_application_policies_count;
398static u_int64_t necp_kernel_socket_policies_condition_mask;
399static size_t necp_kernel_socket_policies_count;
400static size_t necp_kernel_socket_policies_non_app_count;
401static LIST_HEAD(_necpkernelsocketconnectpolicies, necp_kernel_socket_policy) necp_kernel_socket_policies;
402#define NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS 5
403#define NECP_SOCKET_MAP_APP_ID_TO_BUCKET(appid) (appid ? (appid%(NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS - 1) + 1) : 0)
404static size_t necp_kernel_socket_policies_map_counts[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
405static struct necp_kernel_socket_policy **necp_kernel_socket_policies_map[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
406static size_t necp_kernel_socket_policies_app_layer_map_count;
407static struct necp_kernel_socket_policy **necp_kernel_socket_policies_app_layer_map;
408/*
409 * A note on policy 'maps': these are used for boosting efficiency when matching policies. For each dimension of the map,
410 * such as an ID, the 0 bucket is reserved for sockets/packets that do not have this parameter, while the other
411 * buckets lead to an array of policy pointers that form the list applicable when the (parameter%(NUM_BUCKETS - 1) + 1) == bucket_index.
412 *
413 * For example, a packet with policy ID of 7, when there are 4 ID buckets, will map to bucket (7%3 + 1) = 2.
414 */
415
416static u_int64_t necp_kernel_ip_output_policies_condition_mask;
417static size_t necp_kernel_ip_output_policies_count;
418static size_t necp_kernel_ip_output_policies_non_id_count;
419static LIST_HEAD(_necpkernelipoutputpolicies, necp_kernel_ip_output_policy) necp_kernel_ip_output_policies;
420#define NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS 5
421#define NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(id) (id ? (id%(NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS - 1) + 1) : 0)
422static size_t necp_kernel_ip_output_policies_map_counts[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
423static struct necp_kernel_ip_output_policy **necp_kernel_ip_output_policies_map[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
424static struct necp_kernel_socket_policy pass_policy =
425{
426 .id = NECP_KERNEL_POLICY_ID_NO_MATCH,
427 .result = NECP_KERNEL_POLICY_RESULT_PASS,
428};
429
430static struct necp_session *necp_create_session(void);
431static void necp_delete_session(struct necp_session *session);
432
433static necp_policy_id necp_handle_policy_add(struct necp_session *session,
434 u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *error);
435static int necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length);
436
437#define MAX_RESULT_STRING_LEN 64
438static inline const char * necp_get_result_description(char *result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
439
440static 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);
441static struct necp_session_policy *necp_policy_find(struct necp_session *session, necp_policy_id policy_id);
442static bool necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy);
443static bool necp_policy_mark_all_for_deletion(struct necp_session *session);
444static bool necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy);
445static void necp_policy_apply_all(struct necp_session *session);
446
447static necp_kernel_policy_id necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *cond_domain, u_int32_t cond_domain_filter, char *cond_url, pid_t cond_pid, int32_t cond_pidversion, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
448static bool necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id);
449static bool necp_kernel_socket_policies_reprocess(void);
450static bool necp_kernel_socket_policies_update_uuid_table(void);
451static inline struct necp_kernel_socket_policy *necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info, necp_kernel_policy_filter *return_filter, u_int32_t *return_route_rule_id_array, size_t *return_route_rule_id_array_count, size_t route_rule_id_array_count, necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service, u_int32_t *return_netagent_array, u_int32_t *return_netagent_use_flags_array, size_t netagent_array_count, struct necp_client_parameter_netagent_type *required_agent_types, u_int32_t num_required_agent_types, proc_t proc, u_int16_t pf_tag, necp_kernel_policy_id *skip_policy_id, struct rtentry *rt, necp_kernel_policy_result *return_drop_dest_policy_result, necp_drop_all_bypass_check_result_t *return_drop_all_bypass, u_int32_t *return_flow_divert_aggregate_unit, struct socket *, int debug);
452
453static 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, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter);
454static bool necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id);
455static bool necp_kernel_ip_output_policies_reprocess(void);
456
457static bool necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end);
458static bool necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end);
459static bool necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix);
460static int necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port);
461static bool necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits);
462static bool necp_addr_is_empty(struct sockaddr *addr);
463static bool necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index);
464static bool necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet);
465
466struct necp_uuid_id_mapping {
467 LIST_ENTRY(necp_uuid_id_mapping) chain;
468 uuid_t uuid;
469 u_int32_t id;
470 os_refcnt_t refcount;
471 u_int32_t table_usecount; // Add to UUID policy table count
472};
473static size_t necp_num_uuid_app_id_mappings;
474static bool necp_uuid_app_id_mappings_dirty;
475#define NECP_UUID_APP_ID_HASH_SIZE 64
476static u_long necp_uuid_app_id_hash_mask;
477static u_long necp_uuid_app_id_hash_num_buckets;
478static 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
479#define APPUUIDHASH(uuid) (&necp_uuid_app_id_hashtbl[uuid[0] & necp_uuid_app_id_hash_mask]) // Assume first byte of UUIDs are evenly distributed
480static u_int32_t necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table);
481static bool necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table);
482static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id);
483
484static struct necp_uuid_id_mapping *necp_uuid_lookup_service_id_locked(uuid_t uuid);
485static struct necp_uuid_id_mapping *necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id);
486static u_int32_t necp_create_uuid_service_id_mapping(uuid_t uuid);
487static bool necp_remove_uuid_service_id_mapping(uuid_t uuid);
488static bool necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id);
489
490struct necp_string_id_mapping {
491 LIST_ENTRY(necp_string_id_mapping) chain;
492 char *string;
493 necp_app_id id;
494 os_refcnt_t refcount;
495};
496static LIST_HEAD(necp_string_id_mapping_list, necp_string_id_mapping) necp_account_id_list;
497static u_int32_t necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
498static bool necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *domain);
499static struct necp_string_id_mapping *necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id);
500
501static u_int32_t necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter);
502static bool necp_remove_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, u_int32_t filter_id);
503static struct necp_domain_filter *necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id);
504
505static struct necp_kernel_socket_policy *necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id);
506static struct necp_kernel_ip_output_policy *necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id);
507
508static LIST_HEAD(_necp_kernel_service_list, necp_service_registration) necp_registered_service_list;
509
510static char *necp_create_trimmed_domain(char *string, size_t length);
511static inline int necp_count_dots(char *string, size_t length);
512
513static char *necp_copy_string(char *string, size_t length);
514static bool necp_update_qos_marking(struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id);
515
516#define ROUTE_RULE_IS_AGGREGATE(ruleid) (ruleid >= UINT16_MAX)
517
518#define MAX_ROUTE_RULE_INTERFACES 10
519struct necp_route_rule {
520 LIST_ENTRY(necp_route_rule) chain;
521 u_int32_t id;
522 u_int32_t netagent_id;
523 u_int32_t control_unit;
524 u_int32_t match_netagent_id;
525 u_int32_t effective_type;
526 u_int8_t default_action;
527 u_int8_t cellular_action;
528 u_int8_t wifi_action;
529 u_int8_t wired_action;
530 u_int8_t expensive_action;
531 u_int8_t constrained_action;
532 u_int8_t companion_action;
533 u_int exception_if_indices[MAX_ROUTE_RULE_INTERFACES];
534 u_int8_t exception_if_actions[MAX_ROUTE_RULE_INTERFACES];
535 os_refcnt_t refcount;
536};
537static LIST_HEAD(necp_route_rule_list, necp_route_rule) necp_route_rules;
538static u_int32_t necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size, bool *has_socket_only_actions);
539static bool necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id);
540static bool necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp);
541static bool necp_route_is_allowed(struct rtentry *route, ifnet_t interface, u_int32_t *netagent_array, size_t netagent_array_count,
542 u_int32_t route_rule_id, u_int32_t *interface_type_denied);
543static 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);
544static bool necp_route_rule_matches_agents(u_int32_t route_rule_id);
545static uint32_t necp_route_get_flow_divert(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, u_int32_t *flow_divert_aggregate_unit);
546static struct necp_route_rule *necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id);
547static inline void necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info);
548
549#define MAX_AGGREGATE_ROUTE_RULES 16
550struct necp_aggregate_route_rule {
551 LIST_ENTRY(necp_aggregate_route_rule) chain;
552 u_int32_t id;
553 u_int32_t rule_ids[MAX_AGGREGATE_ROUTE_RULES];
554};
555static LIST_HEAD(necp_aggregate_route_rule_list, necp_aggregate_route_rule) necp_aggregate_route_rules;
556static u_int32_t necp_create_aggregate_route_rule(u_int32_t *rule_ids);
557
558// Sysctl definitions
559static int sysctl_handle_necp_level SYSCTL_HANDLER_ARGS;
560static int sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS;
561static int sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS;
562
563SYSCTL_NODE(_net, OID_AUTO, necp, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "NECP");
564SYSCTL_INT(_net_necp, NECPCTL_DEDUP_POLICIES, dedup_policies, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_dedup_policies, 0, "");
565SYSCTL_INT(_net_necp, NECPCTL_RESTRICT_MULTICAST, restrict_multicast, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_restrict_multicast, 0, "");
566SYSCTL_INT(_net_necp, NECPCTL_PASS_LOOPBACK, pass_loopback, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_loopback, 0, "");
567SYSCTL_INT(_net_necp, NECPCTL_PASS_KEEPALIVES, pass_keepalives, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_keepalives, 0, "");
568SYSCTL_INT(_net_necp, NECPCTL_PASS_INTERPOSE, pass_interpose, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_pass_interpose, 0, "");
569SYSCTL_INT(_net_necp, NECPCTL_DEBUG, debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_debug, 0, "");
570SYSCTL_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", "");
571SYSCTL_PROC(_net_necp, NECPCTL_DROP_MANAGEMENT_LEVEL, drop_management_level, CTLTYPE_INT | CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_management_level, 0, &sysctl_handle_necp_management_level, "IU", "");
572SYSCTL_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", "");
573SYSCTL_LONG(_net_necp, NECPCTL_SOCKET_POLICY_COUNT, socket_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_socket_policies_count, "");
574SYSCTL_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, "");
575SYSCTL_LONG(_net_necp, NECPCTL_IP_POLICY_COUNT, ip_policy_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_kernel_ip_output_policies_count, "");
576SYSCTL_INT(_net_necp, NECPCTL_SESSION_COUNT, session_count, CTLFLAG_LOCKED | CTLFLAG_RD, &necp_session_count, 0, "");
577
578static struct necp_drop_dest_policy necp_drop_dest_policy;
579static int necp_drop_dest_debug = 0; // 0: off, 1: match, >1: every evaluation
580SYSCTL_INT(_net_necp, OID_AUTO, drop_dest_debug, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_drop_dest_debug, 0, "");
581
582static int sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS;
583SYSCTL_PROC(_net_necp, OID_AUTO, drop_dest_level, CTLTYPE_STRUCT | CTLFLAG_LOCKED | CTLFLAG_ANYBODY | CTLFLAG_RW,
584 0, 0, &sysctl_handle_necp_drop_dest_level, "S,necp_drop_dest_level", "");
585
586static bool necp_address_matches_drop_dest_policy(union necp_sockaddr_union *, u_int32_t);
587
588/*
589 * data tracing control -
590 *
591 * necp_data_tracing_level : 1 for brief trace, 2 for policy details, 3 for condition details
592 * necp_data_tracing_port : match traffic with specified port
593 * necp_data_tracing_proto : match traffic with specified protocol
594 * necp_data_tracing_pid : match traffic with specified pid (only applied at socket level)
595 * necp_data_tracing_ifindex : match traffic on specified ifindex
596 * necp_data_tracing_match_all: trace traffic only if ALL specified attributes matched. Default is 0 to trace traffic if any specified attributes matched.
597 * data_tracing_session_order : match policies in the specified session - log traffic that hit these policies
598 * necp_data_tracing_policy_order : match specified policy - log traffic that hit this policy
599 */
600static int necp_data_tracing_level = 0;
601SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_level, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_level, 0, "");
602
603static int necp_data_tracing_port = 0;
604SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_port, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_port, 0, "");
605
606static int necp_data_tracing_proto = 0;
607SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_proto, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_proto, 0, "");
608
609static int necp_data_tracing_pid = 0;
610SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_pid, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_pid, 0, "");
611
612static int necp_data_tracing_ifindex = 0;
613SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_ifindex, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_ifindex, 0, "");
614
615static int necp_data_tracing_match_all = 0;
616SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_match_all, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_match_all, 0, "");
617
618static int necp_data_tracing_session_order = 0;
619SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_session_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_session_order, 0, "");
620
621static int necp_data_tracing_policy_order = 0;
622SYSCTL_INT(_net_necp, OID_AUTO, data_tracing_policy_order, CTLFLAG_LOCKED | CTLFLAG_RW, &necp_data_tracing_policy_order, 0, "");
623
624#define NECP_DATA_TRACE_LEVEL_BRIEF 1
625#define NECP_DATA_TRACE_LEVEL_POLICY 2
626#define NECP_DATA_TRACE_LEVEL_CONDITION 3
627
628#define NECP_DATA_TRACE_PID_MATCHED(pid) \
629 (pid == necp_data_tracing_pid)
630#define NECP_DATA_TRACE_PROTO_MATCHED(protocol) \
631 (protocol == necp_data_tracing_proto)
632#define NECP_DATA_TRACE_LOCAL_PORT_MATCHED(local_addr) \
633 (local_addr && (ntohs(local_addr->sin.sin_port) == necp_data_tracing_port || ntohs(local_addr->sin6.sin6_port) == necp_data_tracing_port))
634#define NECP_DATA_TRACE_REMOTE_ORT_MATCHED(remote_addr) \
635 (remote_addr && (ntohs(remote_addr->sin.sin_port) == necp_data_tracing_port || ntohs(remote_addr->sin6.sin6_port) == necp_data_tracing_port))
636#define NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex) \
637 (ifindex == necp_data_tracing_ifindex)
638
639#define NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex) \
640 ((necp_data_tracing_level && \
641 ((necp_data_tracing_pid && (!pid || NECP_DATA_TRACE_PID_MATCHED(pid))) || \
642 (necp_data_tracing_proto && NECP_DATA_TRACE_PROTO_MATCHED(protocol)) || \
643 (necp_data_tracing_ifindex && NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) || \
644 (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)
645
646#define NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) \
647 ((necp_data_tracing_level && \
648 ((!necp_data_tracing_pid || !pid || NECP_DATA_TRACE_PID_MATCHED(pid)) && \
649 (!necp_data_tracing_proto || NECP_DATA_TRACE_PROTO_MATCHED(protocol)) && \
650 (!necp_data_tracing_ifindex || NECP_DATA_TRACE_IFINDEX_MATCHED(ifindex)) && \
651 (!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)
652
653#define NECP_ENABLE_DATA_TRACE(local_addr, remote_addr, protocol, pid, ifindex) \
654 (necp_data_tracing_match_all ? \
655 NECP_ENABLE_DATA_TRACE_AND(local_addr, remote_addr, protocol, pid, ifindex) : \
656 NECP_ENABLE_DATA_TRACE_OR(local_addr, remote_addr, protocol, pid, ifindex))
657
658#define NECP_DATA_TRACE_ON(debug) (debug)
659#define NECP_DATA_TRACE_POLICY_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_BRIEF)
660#define NECP_DATA_TRACE_CONDITION_ON(debug) (debug > NECP_DATA_TRACE_LEVEL_POLICY)
661
662const char* necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN]);
663
664#define NECP_DATA_TRACE_LOG_APP_LEVEL(debug, caller, log_msg, policy_id, skip_policy_id) \
665 if (NECP_DATA_TRACE_ON(debug)) { \
666 char laddr_str[MAX_IPv6_STR_LEN]; \
667 char raddr_str[MAX_IPv6_STR_LEN]; \
668 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d>", \
669 caller, log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id); \
670 }
671
672#define NECP_DATA_TRACE_LOG_SOCKET(debug, socket, caller, log_msg, policy_id, skip_policy_id) \
673 if (NECP_DATA_TRACE_ON(debug)) { \
674 char laddr_str[MAX_IPv6_STR_LEN]; \
675 char raddr_str[MAX_IPv6_STR_LEN]; \
676 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> <policy_id %d skip_policy_id %d>", \
677 caller, (unsigned long long)socket, log_msg, info.local_addr.sin.sin_family, info.protocol, ntohs(info.local_addr.sin.sin_port), ntohs(info.local_addr.sin6.sin6_port), ntohs(info.remote_addr.sin.sin_port), ntohs(info.remote_addr.sin6.sin6_port), necp_get_address_string(&info.local_addr, laddr_str), necp_get_address_string(&info.remote_addr, raddr_str), necp_drop_all_order, info.pid, info.application_id, info.real_application_id, info.bound_interface_index, policy_id, skip_policy_id); \
678 }
679
680#define NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, socket, caller, log_msg) \
681 if (NECP_DATA_TRACE_ON(debug)) { \
682 char laddr_str[MAX_IPv6_STR_LEN]; \
683 char raddr_str[MAX_IPv6_STR_LEN]; \
684 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s %llx>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <pid=%d Application %d Real Application %d BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
685 caller, (unsigned long long)socket, log_msg, info->local_addr.sin.sin_family, info->protocol, ntohs(info->local_addr.sin.sin_port), ntohs(info->local_addr.sin6.sin6_port), ntohs(info->remote_addr.sin.sin_port), ntohs(info->remote_addr.sin6.sin6_port), necp_get_address_string(&info->local_addr, laddr_str), necp_get_address_string(&info->remote_addr, raddr_str), necp_drop_all_order, info->pid, info->application_id, info->real_application_id, info->bound_interface_index, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result]); \
686 }
687
688#define NECP_DATA_TRACE_LOG_IP4(debug, caller, log_msg) \
689 if (NECP_DATA_TRACE_ON(debug)) { \
690 char laddr_str[MAX_IPv6_STR_LEN]; \
691 char raddr_str[MAX_IPv6_STR_LEN]; \
692 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d>", \
693 caller, log_msg, local_addr.sin.sin_family, protocol, ntohs(local_addr.sin.sin_port), ntohs(local_addr.sin6.sin6_port), ntohs(remote_addr.sin.sin_port), ntohs(remote_addr.sin6.sin6_port), necp_get_address_string(&local_addr, laddr_str), necp_get_address_string(&remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id, (unsigned int)packet, ip->ip_len, ntohs(ip->ip_len)); \
694 }
695
696#define NECP_DATA_TRACE_LOG_IP6(debug, caller, log_msg) \
697 if (NECP_DATA_TRACE_ON(debug)) { \
698 char laddr_str[MAX_IPv6_STR_LEN]; \
699 char raddr_str[MAX_IPv6_STR_LEN]; \
700 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> <socket policy id %d socket skip id %d> <mbuf %X len %d %d>", \
701 caller, log_msg, local_addr.sin.sin_family, protocol, ntohs(local_addr.sin.sin_port), ntohs(local_addr.sin6.sin6_port), ntohs(remote_addr.sin.sin_port), ntohs(remote_addr.sin6.sin6_port), necp_get_address_string(&local_addr, laddr_str), necp_get_address_string(&remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, socket_policy_id, socket_skip_policy_id, (unsigned int)packet, ip6->ip6_plen, ntohs(ip6->ip6_plen)); \
702 }
703
704#define NECP_DATA_TRACE_LOG_IP_RESULT(debug, caller, log_msg) \
705 if (NECP_DATA_TRACE_ON(debug)) { \
706 char laddr_str[MAX_IPv6_STR_LEN]; \
707 char raddr_str[MAX_IPv6_STR_LEN]; \
708 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - fam %d proto %d port <local %d/%d remote %d/%d> <local %s remote %s> <drop-all order %d> <BoundInterface %d> (policy id=%d session_order=%d policy_order=%d result=%s)", \
709 caller, log_msg, local_addr->sin.sin_family, protocol, ntohs(local_addr->sin.sin_port), ntohs(local_addr->sin6.sin6_port), ntohs(remote_addr->sin.sin_port), ntohs(remote_addr->sin6.sin6_port), necp_get_address_string(local_addr, laddr_str), necp_get_address_string(remote_addr, raddr_str), necp_drop_all_order, bound_interface_index, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result]); \
710 }
711
712#define NECP_DATA_TRACE_LOG_POLICY(debug, caller, log_msg) \
713 if (NECP_DATA_TRACE_POLICY_ON(debug)) { \
714 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: %s - policy id=%d session_order=%d policy_order=%d result=%s (cond_policy_id %d) (skip_session_order %d skip_order %d)", \
715 caller, log_msg, policy_search_array[i]->id, policy_search_array[i]->session_order, policy_search_array[i]->order, resultString[policy_search_array[i]->result], policy_search_array[i]->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID ? policy_search_array[i]->cond_policy_id : 0, skip_session_order, skip_order); \
716 }
717
718#define NECP_DATA_TRACE_LOG_CONDITION3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
719 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
720 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)>", \
721 caller, negate ? "!":"", name, val1, val1, val2, val2, val3, val3, input1, input1, input2, input2, input3, input3); \
722 }
723
724#define NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, caller, negate, name, val1, val2, val3, input1, input2, input3) \
725 if (NECP_DATA_TRACE_CONDITION_ON(debug)) { \
726 NECPDATATRACELOG(LOG_ERR, "DATA-TRACE <%s>: ------ %smatching <%s> <value %s %s %s input %s %s %s>", \
727 caller, negate ? "!":"", name, val1 != NULL ? val1 : "null", val2 != NULL ? val2 : "null", val3 != NULL ? val3 : "null", \
728 input1 != NULL ? input1 : "null", input2 != NULL ? input2 : "null", input3 != NULL ? input3 : "null"); \
729 }
730
731#define NECP_DATA_TRACE_LOG_CONDITION(debug, caller, negate, name, val, input) \
732 NECP_DATA_TRACE_LOG_CONDITION3(debug, caller, negate, name, val, 0, 0, input, 0, 0)
733
734#define NECP_DATA_TRACE_LOG_CONDITION_STR(debug, caller, negate, name, val, input) \
735 NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, caller, negate, name, val, "n/a", "n/a", input, "n/a", "n/a")
736
737#define NECP_IS_INTCOPROC_ADDRESS(addrv6) \
738 (IN6_IS_ADDR_LINKLOCAL(addrv6) && \
739 addrv6->s6_addr32[2] == ntohl(0xaede48ff) && addrv6->s6_addr32[3] == ntohl(0xfe334455))
740
741const char* resultString[NECP_POLICY_RESULT_MAX + 1] = {
742 "INVALID",
743 "PASS",
744 "SKIP",
745 "DROP",
746 "SOCKET_DIVERT",
747 "SOCKET_FILTER",
748 "IP_TUNNEL",
749 "IP_FILTER",
750 "TRIGGER",
751 "TRIGGER_IF_NEEDED",
752 "TRIGGER_SCOPED",
753 "NO_TRIGGER_SCOPED",
754 "SOCKET_SCOPED",
755 "ROUTE_RULES",
756 "USE_NETAGENT",
757 "NETAGENT_SCOPED",
758 "SCOPED_DIRECT",
759 "ALLOW_UNENTITLED",
760 "REMOVE_NETAGENT"
761};
762
763// Session order allocation
764static u_int32_t
765necp_allocate_new_session_order(u_int32_t priority, u_int32_t control_unit)
766{
767 u_int32_t new_order = 0;
768
769 // For now, just allocate 1000 orders for each priority
770 if (priority == NECP_SESSION_PRIORITY_UNKNOWN || priority > NECP_SESSION_NUM_PRIORITIES) {
771 priority = NECP_SESSION_PRIORITY_DEFAULT;
772 }
773
774 // Use the control unit to decide the offset into the priority list
775 new_order = (control_unit) + ((priority - 1) * 1000);
776
777 return new_order;
778}
779
780static inline u_int32_t
781necp_get_first_order_for_priority(u_int32_t priority)
782{
783 if (priority == 0) {
784 return 0;
785 }
786 return ((priority - 1) * 1000) + 1;
787}
788
789// Sysctl handler
790static int
791sysctl_handle_necp_level SYSCTL_HANDLER_ARGS
792{
793#pragma unused(arg1, arg2)
794 int error = sysctl_handle_int(oidp, arg1: oidp->oid_arg1, arg2: oidp->oid_arg2, req);
795 necp_drop_all_order = necp_get_first_order_for_priority(priority: necp_drop_all_level);
796 return error;
797}
798
799static int
800sysctl_handle_necp_unentitled_level SYSCTL_HANDLER_ARGS
801{
802#pragma unused(arg1, arg2)
803 int error = sysctl_handle_int(oidp, arg1: oidp->oid_arg1, arg2: oidp->oid_arg2, req);
804 necp_drop_unentitled_order = necp_get_first_order_for_priority(priority: necp_drop_unentitled_level);
805 return error;
806}
807
808// Use a macro here to avoid computing the kauth_cred_t when necp_drop_unentitled_level is 0
809static inline u_int32_t
810_necp_process_drop_order_inner(kauth_cred_t cred)
811{
812 if (priv_check_cred(cred, PRIV_NET_PRIVILEGED_CLIENT_ACCESS, flags: 0) != 0 &&
813 priv_check_cred(cred, PRIV_NET_PRIVILEGED_SERVER_ACCESS, flags: 0) != 0) {
814 return necp_drop_unentitled_order;
815 } else {
816 return 0;
817 }
818}
819
820#define necp_process_drop_order(_cred) (necp_drop_unentitled_order != 0 ? _necp_process_drop_order_inner(_cred) : necp_drop_unentitled_order)
821#pragma GCC poison _necp_process_drop_order_inner
822
823static int
824sysctl_handle_necp_management_level SYSCTL_HANDLER_ARGS
825{
826#pragma unused(arg1, arg2)
827 int error = sysctl_handle_int(oidp, arg1: oidp->oid_arg1, arg2: oidp->oid_arg2, req);
828 necp_drop_management_order = necp_get_first_order_for_priority(priority: necp_drop_management_level);
829 return error;
830}
831
832// Session fd
833
834static int necp_session_op_close(struct fileglob *, vfs_context_t);
835
836static const struct fileops necp_session_fd_ops = {
837 .fo_type = DTYPE_NETPOLICY,
838 .fo_read = fo_no_read,
839 .fo_write = fo_no_write,
840 .fo_ioctl = fo_no_ioctl,
841 .fo_select = fo_no_select,
842 .fo_close = necp_session_op_close,
843 .fo_drain = fo_no_drain,
844 .fo_kqfilter = fo_no_kqfilter,
845};
846
847static inline int
848necp_is_platform_binary(proc_t proc)
849{
850 return (proc != NULL) ? (csproc_get_platform_binary(proc) && cs_valid(proc)) : 0;
851}
852
853static inline necp_drop_all_bypass_check_result_t
854necp_check_drop_all_bypass_result(proc_t proc)
855{
856 if (proc == NULL) {
857 proc = current_proc();
858 if (proc == NULL) {
859 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
860 }
861 }
862
863#if defined(XNU_TARGET_OS_OSX)
864 const char *signing_id = NULL;
865 const bool isConfigd = (necp_is_platform_binary(proc) &&
866 (signing_id = cs_identity_get(proc)) &&
867 (strlen(s: signing_id) == SIGNING_ID_CONFIGD_LEN) &&
868 (memcmp(s1: signing_id, SIGNING_ID_CONFIGD, SIGNING_ID_CONFIGD_LEN) == 0));
869 if (isConfigd) {
870 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
871 }
872#endif
873
874 const task_t task = proc_task(proc);
875 if (task == NULL || !IOTaskHasEntitlement(task, entitlement: "com.apple.private.necp.drop_all_bypass")) {
876 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE;
877 } else {
878 return NECP_DROP_ALL_BYPASS_CHECK_RESULT_TRUE;
879 }
880}
881
882int
883necp_session_open(struct proc *p, struct necp_session_open_args *uap, int *retval)
884{
885#pragma unused(uap)
886 int error = 0;
887 struct necp_session *session = NULL;
888 struct fileproc *fp = NULL;
889 int fd = -1;
890 uid_t uid = kauth_cred_getuid(cred: kauth_cred_get());
891
892 if (!necp_is_platform_binary(proc: p)) {
893 NECPLOG0(LOG_ERR, "Only platform-signed binaries can open NECP sessions");
894 error = EACCES;
895 goto done;
896 }
897
898 if (uid != 0 && priv_check_cred(cred: kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, flags: 0) != 0) {
899 NECPLOG0(LOG_ERR, "Process does not hold necessary entitlement to open NECP session");
900 error = EACCES;
901 goto done;
902 }
903
904 error = falloc(p, &fp, &fd);
905 if (error != 0) {
906 goto done;
907 }
908
909 session = necp_create_session();
910 if (session == NULL) {
911 error = ENOMEM;
912 goto done;
913 }
914
915 fp->fp_flags |= FP_CLOEXEC | FP_CLOFORK;
916 fp->fp_glob->fg_flag = 0;
917 fp->fp_glob->fg_ops = &necp_session_fd_ops;
918 fp_set_data(fp, fg_data: session);
919
920 proc_fdlock(p);
921 procfdtbl_releasefd(p, fd, NULL);
922 fp_drop(p, fd, fp, locked: 1);
923 proc_fdunlock(p);
924
925 *retval = fd;
926done:
927 if (error != 0) {
928 if (fp != NULL) {
929 fp_free(p, fd, fp);
930 fp = NULL;
931 }
932 }
933
934 return error;
935}
936
937static int
938necp_session_op_close(struct fileglob *fg, vfs_context_t ctx)
939{
940#pragma unused(ctx)
941 struct necp_session *session = (struct necp_session *)fg_get_data(fg);
942 fg_set_data(fg, NULL);
943
944 if (session != NULL) {
945 necp_policy_mark_all_for_deletion(session);
946 necp_policy_apply_all(session);
947 necp_delete_session(session);
948 return 0;
949 } else {
950 return ENOENT;
951 }
952}
953
954static int
955necp_session_find_from_fd(struct proc *p, int fd,
956 struct fileproc **fpp, struct necp_session **session)
957{
958 struct fileproc *fp = NULL;
959 int error = fp_get_ftype(p, fd, ftype: DTYPE_NETPOLICY, ENODEV, fpp: &fp);
960
961 if (error == 0) {
962 *fpp = fp;
963 *session = (struct necp_session *)fp_get_data(fp);
964 if ((*session)->necp_fd_type != necp_fd_type_session) {
965 // Not a client fd, ignore
966 fp_drop(p, fd, fp, locked: 0);
967 error = EINVAL;
968 }
969 }
970
971 return error;
972}
973
974static int
975necp_session_add_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
976{
977 int error = 0;
978 u_int8_t *tlv_buffer = NULL;
979
980 if (uap->in_buffer_length == 0 || uap->in_buffer_length > NECP_MAX_POLICY_SIZE || uap->in_buffer == 0) {
981 NECPLOG(LOG_ERR, "necp_session_add_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
982 error = EINVAL;
983 goto done;
984 }
985
986 if (uap->out_buffer_length < sizeof(necp_policy_id) || uap->out_buffer == 0) {
987 NECPLOG(LOG_ERR, "necp_session_add_policy invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
988 error = EINVAL;
989 goto done;
990 }
991
992 if ((tlv_buffer = (u_int8_t *)kalloc_data(uap->in_buffer_length, Z_WAITOK | Z_ZERO)) == NULL) {
993 error = ENOMEM;
994 goto done;
995 }
996
997 error = copyin(uap->in_buffer, tlv_buffer, uap->in_buffer_length);
998 if (error != 0) {
999 NECPLOG(LOG_ERR, "necp_session_add_policy tlv copyin error (%d)", error);
1000 goto done;
1001 }
1002
1003 necp_policy_id new_policy_id = necp_handle_policy_add(session, tlv_buffer, tlv_buffer_length: uap->in_buffer_length, offset: 0, error: &error);
1004 if (error != 0) {
1005 NECPLOG(LOG_ERR, "necp_session_add_policy failed to add policy (%d)", error);
1006 goto done;
1007 }
1008
1009 error = copyout(&new_policy_id, uap->out_buffer, sizeof(new_policy_id));
1010 if (error != 0) {
1011 NECPLOG(LOG_ERR, "necp_session_add_policy policy_id copyout error (%d)", error);
1012 goto done;
1013 }
1014
1015done:
1016 if (tlv_buffer != NULL) {
1017 kfree_data(tlv_buffer, uap->in_buffer_length);
1018 tlv_buffer = NULL;
1019 }
1020 *retval = error;
1021
1022 return error;
1023}
1024
1025static int
1026necp_session_get_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1027{
1028 int error = 0;
1029 u_int8_t *response = NULL;
1030
1031 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1032 NECPLOG(LOG_ERR, "necp_session_get_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1033 error = EINVAL;
1034 goto done;
1035 }
1036
1037 necp_policy_id policy_id = 0;
1038 error = copyin(uap->in_buffer, &policy_id, sizeof(policy_id));
1039 if (error != 0) {
1040 NECPLOG(LOG_ERR, "necp_session_get_policy policy_id copyin error (%d)", error);
1041 goto done;
1042 }
1043
1044 struct necp_session_policy *policy = necp_policy_find(session, policy_id);
1045 if (policy == NULL || policy->pending_deletion) {
1046 NECPLOG(LOG_ERR, "Failed to find policy with id %d", policy_id);
1047 error = ENOENT;
1048 goto done;
1049 }
1050
1051 u_int32_t order_tlv_size = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_order);
1052 u_int32_t result_tlv_size = (policy->result_size ? (sizeof(u_int8_t) + sizeof(u_int32_t) + policy->result_size) : 0);
1053 u_int32_t response_size = order_tlv_size + result_tlv_size + policy->conditions_size;
1054
1055 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1056 NECPLOG(LOG_ERR, "necp_session_get_policy buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1057 error = EINVAL;
1058 goto done;
1059 }
1060
1061 if (response_size > NECP_MAX_POLICY_SIZE) {
1062 NECPLOG(LOG_ERR, "necp_session_get_policy size too large to copy (%u)", response_size);
1063 error = EINVAL;
1064 goto done;
1065 }
1066
1067 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1068 if (response == NULL) {
1069 error = ENOMEM;
1070 goto done;
1071 }
1072
1073 u_int8_t *cursor = response;
1074 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, length: sizeof(necp_policy_order), value: &policy->order, buffer: response, buffer_length: response_size);
1075 if (result_tlv_size) {
1076 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT, length: policy->result_size, value: &policy->result, buffer: response, buffer_length: response_size);
1077 }
1078 if (policy->conditions_size) {
1079 memcpy(dst: ((u_int8_t *)(void *)(cursor)), src: policy->conditions, n: policy->conditions_size);
1080 }
1081
1082 error = copyout(response, uap->out_buffer, response_size);
1083 if (error != 0) {
1084 NECPLOG(LOG_ERR, "necp_session_get_policy TLV copyout error (%d)", error);
1085 goto done;
1086 }
1087
1088done:
1089 if (response != NULL) {
1090 kfree_data(response, response_size);
1091 response = NULL;
1092 }
1093 *retval = error;
1094
1095 return error;
1096}
1097
1098static int
1099necp_session_delete_policy(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1100{
1101 int error = 0;
1102
1103 if (uap->in_buffer_length < sizeof(necp_policy_id) || uap->in_buffer == 0) {
1104 NECPLOG(LOG_ERR, "necp_session_delete_policy invalid input (%zu)", (size_t)uap->in_buffer_length);
1105 error = EINVAL;
1106 goto done;
1107 }
1108
1109 necp_policy_id delete_policy_id = 0;
1110 error = copyin(uap->in_buffer, &delete_policy_id, sizeof(delete_policy_id));
1111 if (error != 0) {
1112 NECPLOG(LOG_ERR, "necp_session_delete_policy policy_id copyin error (%d)", error);
1113 goto done;
1114 }
1115
1116 struct necp_session_policy *policy = necp_policy_find(session, policy_id: delete_policy_id);
1117 if (policy == NULL || policy->pending_deletion) {
1118 NECPLOG(LOG_ERR, "necp_session_delete_policy failed to find policy with id %u", delete_policy_id);
1119 error = ENOENT;
1120 goto done;
1121 }
1122
1123 necp_policy_mark_for_deletion(session, policy);
1124done:
1125 *retval = error;
1126 return error;
1127}
1128
1129static int
1130necp_session_apply_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1131{
1132#pragma unused(uap)
1133 necp_policy_apply_all(session);
1134 *retval = 0;
1135 return 0;
1136}
1137
1138static int
1139necp_session_list_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1140{
1141 u_int32_t tlv_size = (sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(necp_policy_id));
1142 u_int32_t response_size = 0;
1143 u_int8_t *response = NULL;
1144 int num_policies = 0;
1145 int cur_policy_index = 0;
1146 int error = 0;
1147 struct necp_session_policy *policy;
1148
1149 LIST_FOREACH(policy, &session->policies, chain) {
1150 if (!policy->pending_deletion) {
1151 num_policies++;
1152 }
1153 }
1154
1155 if (num_policies > NECP_MAX_POLICY_LIST_COUNT) {
1156 NECPLOG(LOG_ERR, "necp_session_list_all size too large to copy (%u policies)", num_policies);
1157 error = EINVAL;
1158 goto done;
1159 }
1160
1161 response_size = num_policies * tlv_size;
1162 if (uap->out_buffer_length < response_size || uap->out_buffer == 0) {
1163 NECPLOG(LOG_ERR, "necp_session_list_all buffer not large enough (%zu < %u)", (size_t)uap->out_buffer_length, response_size);
1164 error = EINVAL;
1165 goto done;
1166 }
1167
1168 // Create a response with one Policy ID TLV for each policy
1169 response = (u_int8_t *)kalloc_data(response_size, Z_WAITOK | Z_ZERO);
1170 if (response == NULL) {
1171 error = ENOMEM;
1172 goto done;
1173 }
1174
1175 u_int8_t *cursor = response;
1176 LIST_FOREACH(policy, &session->policies, chain) {
1177 if (!policy->pending_deletion && cur_policy_index < num_policies) {
1178 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, length: sizeof(u_int32_t), value: &policy->local_id, buffer: response, buffer_length: response_size);
1179 cur_policy_index++;
1180 }
1181 }
1182
1183 error = copyout(response, uap->out_buffer, response_size);
1184 if (error != 0) {
1185 NECPLOG(LOG_ERR, "necp_session_list_all TLV copyout error (%d)", error);
1186 goto done;
1187 }
1188
1189done:
1190 if (response != NULL) {
1191 kfree_data(response, response_size);
1192 response = NULL;
1193 }
1194 *retval = error;
1195
1196 return error;
1197}
1198
1199
1200static int
1201necp_session_delete_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1202{
1203#pragma unused(uap)
1204 necp_policy_mark_all_for_deletion(session);
1205 *retval = 0;
1206 return 0;
1207}
1208
1209static int
1210necp_session_set_session_priority(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1211{
1212 int error = 0;
1213 struct necp_session_policy *policy = NULL;
1214 struct necp_session_policy *temp_policy = NULL;
1215
1216 if (uap->in_buffer_length < sizeof(necp_session_priority) || uap->in_buffer == 0) {
1217 NECPLOG(LOG_ERR, "necp_session_set_session_priority invalid input (%zu)", (size_t)uap->in_buffer_length);
1218 error = EINVAL;
1219 goto done;
1220 }
1221
1222 necp_session_priority requested_session_priority = 0;
1223 error = copyin(uap->in_buffer, &requested_session_priority, sizeof(requested_session_priority));
1224 if (error != 0) {
1225 NECPLOG(LOG_ERR, "necp_session_set_session_priority priority copyin error (%d)", error);
1226 goto done;
1227 }
1228
1229 // Enforce special session priorities with entitlements
1230 if (requested_session_priority == NECP_SESSION_PRIORITY_CONTROL ||
1231 requested_session_priority == NECP_SESSION_PRIORITY_CONTROL_1 ||
1232 requested_session_priority == NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL ||
1233 requested_session_priority == NECP_SESSION_PRIORITY_HIGH_RESTRICTED) {
1234 errno_t cred_result = priv_check_cred(cred: kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, flags: 0);
1235 if (cred_result != 0) {
1236 NECPLOG(LOG_ERR, "Session does not hold necessary entitlement to claim priority level %d", requested_session_priority);
1237 error = EPERM;
1238 goto done;
1239 }
1240 }
1241
1242 if (session->session_priority != requested_session_priority) {
1243 session->session_priority = requested_session_priority;
1244 session->session_order = necp_allocate_new_session_order(priority: session->session_priority, control_unit: session->control_unit);
1245 session->dirty = TRUE;
1246
1247 // Mark all policies as needing updates
1248 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
1249 policy->pending_update = TRUE;
1250 }
1251 }
1252
1253done:
1254 *retval = error;
1255 return error;
1256}
1257
1258static int
1259necp_session_lock_to_process(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1260{
1261#pragma unused(uap)
1262 session->proc_locked = TRUE;
1263 *retval = 0;
1264 return 0;
1265}
1266
1267static int
1268necp_session_register_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1269{
1270 int error = 0;
1271 struct necp_service_registration *new_service = NULL;
1272
1273 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1274 NECPLOG(LOG_ERR, "necp_session_register_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1275 error = EINVAL;
1276 goto done;
1277 }
1278
1279 uuid_t service_uuid;
1280 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1281 if (error != 0) {
1282 NECPLOG(LOG_ERR, "necp_session_register_service uuid copyin error (%d)", error);
1283 goto done;
1284 }
1285
1286 new_service = kalloc_type(struct necp_service_registration,
1287 Z_WAITOK | Z_ZERO | Z_NOFAIL);
1288
1289 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
1290 new_service->service_id = necp_create_uuid_service_id_mapping(uuid: service_uuid);
1291 LIST_INSERT_HEAD(&session->services, new_service, session_chain);
1292 LIST_INSERT_HEAD(&necp_registered_service_list, new_service, kernel_chain);
1293 lck_rw_done(lck: &necp_kernel_policy_lock);
1294
1295done:
1296 *retval = error;
1297 return error;
1298}
1299
1300static int
1301necp_session_unregister_service(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1302{
1303 int error = 0;
1304 struct necp_service_registration *service = NULL;
1305 struct necp_service_registration *temp_service = NULL;
1306 struct necp_uuid_id_mapping *mapping = NULL;
1307
1308 if (uap->in_buffer_length < sizeof(uuid_t) || uap->in_buffer == 0) {
1309 NECPLOG(LOG_ERR, "necp_session_unregister_service invalid input (%zu)", (size_t)uap->in_buffer_length);
1310 error = EINVAL;
1311 goto done;
1312 }
1313
1314 uuid_t service_uuid;
1315 error = copyin(uap->in_buffer, service_uuid, sizeof(service_uuid));
1316 if (error != 0) {
1317 NECPLOG(LOG_ERR, "necp_session_unregister_service uuid copyin error (%d)", error);
1318 goto done;
1319 }
1320
1321 // Remove all matching services for this session
1322 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
1323 mapping = necp_uuid_lookup_service_id_locked(uuid: service_uuid);
1324 if (mapping != NULL) {
1325 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
1326 if (service->service_id == mapping->id) {
1327 LIST_REMOVE(service, session_chain);
1328 LIST_REMOVE(service, kernel_chain);
1329 kfree_type(struct necp_service_registration, service);
1330 }
1331 }
1332 necp_remove_uuid_service_id_mapping(uuid: service_uuid);
1333 }
1334 lck_rw_done(lck: &necp_kernel_policy_lock);
1335
1336done:
1337 *retval = error;
1338 return error;
1339}
1340
1341static int
1342necp_session_dump_all(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1343{
1344#pragma unused(session)
1345 int error = 0;
1346
1347 if (uap->out_buffer_length == 0 || uap->out_buffer == 0) {
1348 NECPLOG(LOG_ERR, "necp_session_dump_all invalid output buffer (%zu)", (size_t)uap->out_buffer_length);
1349 error = EINVAL;
1350 goto done;
1351 }
1352
1353 error = necp_handle_policy_dump_all(out_buffer: uap->out_buffer, out_buffer_length: uap->out_buffer_length);
1354done:
1355 *retval = error;
1356 return error;
1357}
1358
1359static int
1360necp_session_add_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1361{
1362 int error = 0;
1363 struct net_bloom_filter *bloom_filter = NULL;
1364 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1365 const size_t out_buffer_length = (size_t)uap->out_buffer_length;
1366
1367 if (in_buffer_length < sizeof(struct net_bloom_filter) ||
1368 in_buffer_length > NECP_MAX_DOMAIN_FILTER_SIZE ||
1369 uap->in_buffer == 0) {
1370 NECPLOG(LOG_ERR, "necp_session_add_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1371 error = EINVAL;
1372 goto done;
1373 }
1374
1375 if (out_buffer_length < sizeof(u_int32_t) || uap->out_buffer == 0) {
1376 NECPLOG(LOG_ERR, "necp_session_add_domain_filter buffer not large enough (%zu)", (size_t)out_buffer_length);
1377 error = EINVAL;
1378 goto done;
1379 }
1380
1381 bloom_filter = (struct net_bloom_filter *)kalloc_data(in_buffer_length, Z_WAITOK | Z_ZERO);
1382 if (bloom_filter == NULL) {
1383 NECPLOG(LOG_ERR, "necp_session_add_domain_filter allocate filter error (%zu)", in_buffer_length);
1384 error = ENOMEM;
1385 goto done;
1386 }
1387
1388 error = copyin(uap->in_buffer, bloom_filter, in_buffer_length);
1389 if (error != 0) {
1390 NECPLOG(LOG_ERR, "necp_session_add_domain_filter filter copyin error (%d)", error);
1391 goto done;
1392 }
1393
1394 size_t expected_filter_size = net_bloom_filter_get_size(num_bits: bloom_filter->b_table_num_bits);
1395 if (expected_filter_size != in_buffer_length) {
1396 NECPLOG(LOG_ERR, "necp_session_add_domain_filter size mismatch (%zu != %zu)", expected_filter_size, in_buffer_length);
1397 error = EINVAL;
1398 goto done;
1399 }
1400
1401 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
1402 u_int32_t filter_id = necp_create_domain_filter(list: &necp_global_domain_filter_list, owner_list: &session->domain_filters, filter: bloom_filter);
1403 lck_rw_done(lck: &necp_kernel_policy_lock);
1404
1405 if (filter_id == 0) {
1406 error = ENOMEM;
1407 } else {
1408 // Bloom filter is taken over by the new filter entry, clear the local pointer
1409 bloom_filter = NULL;
1410
1411 error = copyout(&filter_id, uap->out_buffer, sizeof(filter_id));
1412 if (error != 0) {
1413 NECPLOG(LOG_ERR, "necp_session_add_domain_filter ID copyout error (%d)", error);
1414 goto done;
1415 }
1416 }
1417
1418done:
1419 *retval = error;
1420 if (error != 0 && bloom_filter != NULL) {
1421 uint8_t *filter_buffer = (uint8_t *)bloom_filter;
1422 kfree_data(filter_buffer, in_buffer_length);
1423 bloom_filter = NULL;
1424 }
1425 return error;
1426}
1427
1428static int
1429necp_session_remove_domain_filter(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1430{
1431 int error = 0;
1432
1433 const size_t in_buffer_length = (size_t)uap->in_buffer_length;
1434 if (in_buffer_length < sizeof(u_int32_t) || uap->in_buffer == 0) {
1435 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter invalid input (%zu)", (size_t)in_buffer_length);
1436 error = EINVAL;
1437 goto done;
1438 }
1439
1440 u_int32_t filter_id;
1441 error = copyin(uap->in_buffer, &filter_id, sizeof(filter_id));
1442 if (error != 0) {
1443 NECPLOG(LOG_ERR, "necp_session_remove_domain_filter uuid copyin error (%d)", error);
1444 goto done;
1445 }
1446
1447 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
1448 bool removed = necp_remove_domain_filter(list: &necp_global_domain_filter_list, owner_list: &session->domain_filters, filter_id);
1449 if (!removed) {
1450 error = ENOENT;
1451 }
1452 lck_rw_done(lck: &necp_kernel_policy_lock);
1453
1454done:
1455 *retval = error;
1456 return error;
1457}
1458
1459static int
1460necp_session_remove_all_domain_filters(struct necp_session *session, struct necp_session_action_args *uap, int *retval)
1461{
1462#pragma unused(uap)
1463
1464 struct necp_domain_filter *filter = NULL;
1465 struct necp_domain_filter *temp_filter = NULL;
1466 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
1467 if (os_ref_release_locked(rc: &filter->refcount) == 0) {
1468 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
1469 LIST_REMOVE(filter, chain);
1470 lck_rw_done(lck: &necp_kernel_policy_lock);
1471 LIST_REMOVE(filter, owner_chain);
1472 net_bloom_filter_destroy(filter: filter->filter);
1473 kfree_type(struct necp_domain_filter, filter);
1474 }
1475 }
1476
1477 *retval = 0;
1478 return 0;
1479}
1480
1481int
1482necp_session_action(struct proc *p, struct necp_session_action_args *uap, int *retval)
1483{
1484 struct fileproc *fp;
1485 int error = 0;
1486 int return_value = 0;
1487 struct necp_session *session = NULL;
1488
1489 error = necp_session_find_from_fd(p, fd: uap->necp_fd, fpp: &fp, session: &session);
1490 if (error != 0) {
1491 NECPLOG(LOG_ERR, "necp_session_action find fd error (%d)", error);
1492 return error;
1493 }
1494
1495 NECP_SESSION_LOCK(session);
1496
1497 if (session->proc_locked) {
1498 // Verify that the calling process is allowed to do actions
1499 uuid_t proc_uuid;
1500 proc_getexecutableuuid(current_proc(), proc_uuid, sizeof(proc_uuid));
1501 if (uuid_compare(uu1: proc_uuid, uu2: session->proc_uuid) != 0) {
1502 error = EPERM;
1503 goto done;
1504 }
1505 } else {
1506 // If not locked, update the proc_uuid and proc_pid of the session
1507 proc_getexecutableuuid(current_proc(), session->proc_uuid, sizeof(session->proc_uuid));
1508 session->proc_pid = proc_pid(current_proc());
1509 }
1510
1511 u_int32_t action = uap->action;
1512 switch (action) {
1513 case NECP_SESSION_ACTION_POLICY_ADD: {
1514 return_value = necp_session_add_policy(session, uap, retval);
1515 break;
1516 }
1517 case NECP_SESSION_ACTION_POLICY_GET: {
1518 return_value = necp_session_get_policy(session, uap, retval);
1519 break;
1520 }
1521 case NECP_SESSION_ACTION_POLICY_DELETE: {
1522 return_value = necp_session_delete_policy(session, uap, retval);
1523 break;
1524 }
1525 case NECP_SESSION_ACTION_POLICY_APPLY_ALL: {
1526 return_value = necp_session_apply_all(session, uap, retval);
1527 break;
1528 }
1529 case NECP_SESSION_ACTION_POLICY_LIST_ALL: {
1530 return_value = necp_session_list_all(session, uap, retval);
1531 break;
1532 }
1533 case NECP_SESSION_ACTION_POLICY_DELETE_ALL: {
1534 return_value = necp_session_delete_all(session, uap, retval);
1535 break;
1536 }
1537 case NECP_SESSION_ACTION_SET_SESSION_PRIORITY: {
1538 return_value = necp_session_set_session_priority(session, uap, retval);
1539 break;
1540 }
1541 case NECP_SESSION_ACTION_LOCK_SESSION_TO_PROC: {
1542 return_value = necp_session_lock_to_process(session, uap, retval);
1543 break;
1544 }
1545 case NECP_SESSION_ACTION_REGISTER_SERVICE: {
1546 return_value = necp_session_register_service(session, uap, retval);
1547 break;
1548 }
1549 case NECP_SESSION_ACTION_UNREGISTER_SERVICE: {
1550 return_value = necp_session_unregister_service(session, uap, retval);
1551 break;
1552 }
1553 case NECP_SESSION_ACTION_POLICY_DUMP_ALL: {
1554 return_value = necp_session_dump_all(session, uap, retval);
1555 break;
1556 }
1557 case NECP_SESSION_ACTION_ADD_DOMAIN_FILTER: {
1558 return_value = necp_session_add_domain_filter(session, uap, retval);
1559 break;
1560 }
1561 case NECP_SESSION_ACTION_REMOVE_DOMAIN_FILTER: {
1562 return_value = necp_session_remove_domain_filter(session, uap, retval);
1563 break;
1564 }
1565 case NECP_SESSION_ACTION_REMOVE_ALL_DOMAIN_FILTERS: {
1566 return_value = necp_session_remove_all_domain_filters(session, uap, retval);
1567 break;
1568 }
1569 default: {
1570 NECPLOG(LOG_ERR, "necp_session_action unknown action (%u)", action);
1571 return_value = EINVAL;
1572 break;
1573 }
1574 }
1575
1576done:
1577 NECP_SESSION_UNLOCK(session);
1578 fp_drop(p, fd: uap->necp_fd, fp, locked: 0);
1579 return return_value;
1580}
1581
1582struct necp_resolver_key_state {
1583 const struct ccdigest_info *digest_info;
1584 uint8_t key[CCSHA256_OUTPUT_SIZE];
1585};
1586static struct necp_resolver_key_state s_necp_resolver_key_state;
1587
1588static void
1589necp_generate_resolver_key(void)
1590{
1591 s_necp_resolver_key_state.digest_info = ccsha256_di();
1592 cc_rand_generate(out: s_necp_resolver_key_state.key, outlen: sizeof(s_necp_resolver_key_state.key));
1593}
1594
1595static void
1596necp_sign_update_context(const struct ccdigest_info *di,
1597 cchmac_ctx_t ctx,
1598 uuid_t client_id,
1599 u_int32_t sign_type,
1600 u_int8_t *data,
1601 size_t data_length)
1602{
1603 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1604 const char *context_string = "NECP Resolver Binder";
1605 uint8_t separator = 0;
1606 cchmac_update(di, ctx, data_len: sizeof(context), data: context);
1607 cchmac_update(di, ctx, data_len: strlen(s: context_string), data: context_string);
1608 cchmac_update(di, ctx, data_len: sizeof(separator), data: &separator);
1609 cchmac_update(di, ctx, data_len: sizeof(uuid_t), data: client_id);
1610 cchmac_update(di, ctx, data_len: sizeof(sign_type), data: &sign_type);
1611 cchmac_update(di, ctx, data_len: data_length, data);
1612}
1613
1614int
1615necp_sign_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1616 u_int8_t *data, size_t data_length,
1617 u_int8_t *tag, size_t *out_tag_length)
1618{
1619 if (s_necp_resolver_key_state.digest_info == NULL) {
1620 return EINVAL;
1621 }
1622
1623 if (data == NULL ||
1624 data_length == 0 ||
1625 tag == NULL ||
1626 out_tag_length == NULL) {
1627 return EINVAL;
1628 }
1629
1630 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1631 if (*out_tag_length < required_tag_length) {
1632 return ERANGE;
1633 }
1634
1635 *out_tag_length = required_tag_length;
1636
1637 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1638 s_necp_resolver_key_state.digest_info->block_size, ctx);
1639 cchmac_init(di: s_necp_resolver_key_state.digest_info, ctx,
1640 key_len: sizeof(s_necp_resolver_key_state.key),
1641 key: s_necp_resolver_key_state.key);
1642 necp_sign_update_context(di: s_necp_resolver_key_state.digest_info,
1643 ctx, client_id, sign_type, data, data_length);
1644 cchmac_final(di: s_necp_resolver_key_state.digest_info, ctx, mac: tag);
1645
1646 return 0;
1647}
1648
1649bool
1650necp_validate_resolver_answer(uuid_t client_id, u_int32_t sign_type,
1651 u_int8_t *data, size_t data_length,
1652 u_int8_t *tag, size_t tag_length)
1653{
1654 if (s_necp_resolver_key_state.digest_info == NULL) {
1655 return false;
1656 }
1657
1658 if (data == NULL ||
1659 data_length == 0 ||
1660 tag == NULL ||
1661 tag_length == 0) {
1662 return false;
1663 }
1664
1665 size_t required_tag_length = s_necp_resolver_key_state.digest_info->output_size;
1666 if (tag_length != required_tag_length) {
1667 return false;
1668 }
1669
1670 uint8_t actual_tag[required_tag_length];
1671
1672 cchmac_ctx_decl(s_necp_resolver_key_state.digest_info->state_size,
1673 s_necp_resolver_key_state.digest_info->block_size, ctx);
1674 cchmac_init(di: s_necp_resolver_key_state.digest_info, ctx,
1675 key_len: sizeof(s_necp_resolver_key_state.key),
1676 key: s_necp_resolver_key_state.key);
1677 necp_sign_update_context(di: s_necp_resolver_key_state.digest_info,
1678 ctx, client_id, sign_type, data, data_length);
1679 cchmac_final(di: s_necp_resolver_key_state.digest_info, ctx, mac: actual_tag);
1680
1681 return cc_cmp_safe(num: s_necp_resolver_key_state.digest_info->output_size, ptr1: tag, ptr2: actual_tag) == 0;
1682}
1683
1684struct necp_application_id_key_state {
1685 const struct ccdigest_info *digest_info;
1686 uint8_t key[CCSHA256_OUTPUT_SIZE];
1687};
1688static struct necp_application_id_key_state s_necp_application_id_key_state;
1689
1690static void
1691necp_generate_application_id_key(void)
1692{
1693 s_necp_application_id_key_state.digest_info = ccsha256_di();
1694 cc_rand_generate(out: s_necp_application_id_key_state.key, outlen: sizeof(s_necp_application_id_key_state.key));
1695}
1696
1697static void
1698necp_sign_application_id_update_context(const struct ccdigest_info *di,
1699 cchmac_ctx_t ctx,
1700 uuid_t client_id,
1701 u_int32_t sign_type)
1702{
1703 const uint8_t context[32] = {[0 ... 31] = 0x20}; // 0x20 repeated 32 times
1704 const char *context_string = "NECP Application ID";
1705 uint8_t separator = 0;
1706 cchmac_update(di, ctx, data_len: sizeof(context), data: context);
1707 cchmac_update(di, ctx, data_len: strlen(s: context_string), data: context_string);
1708 cchmac_update(di, ctx, data_len: sizeof(separator), data: &separator);
1709 cchmac_update(di, ctx, data_len: sizeof(uuid_t), data: client_id);
1710 cchmac_update(di, ctx, data_len: sizeof(sign_type), data: &sign_type);
1711}
1712
1713int
1714necp_sign_application_id(uuid_t client_id, u_int32_t sign_type,
1715 u_int8_t *tag, size_t *out_tag_length)
1716{
1717 if (s_necp_application_id_key_state.digest_info == NULL) {
1718 return EINVAL;
1719 }
1720
1721 if (tag == NULL ||
1722 out_tag_length == NULL) {
1723 return EINVAL;
1724 }
1725
1726 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1727 if (*out_tag_length < required_tag_length) {
1728 return ERANGE;
1729 }
1730
1731 *out_tag_length = required_tag_length;
1732
1733 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1734 s_necp_application_id_key_state.digest_info->block_size, ctx);
1735 cchmac_init(di: s_necp_application_id_key_state.digest_info, ctx,
1736 key_len: sizeof(s_necp_application_id_key_state.key),
1737 key: s_necp_application_id_key_state.key);
1738 necp_sign_application_id_update_context(di: s_necp_application_id_key_state.digest_info,
1739 ctx, client_id, sign_type);
1740 cchmac_final(di: s_necp_application_id_key_state.digest_info, ctx, mac: tag);
1741
1742 return 0;
1743}
1744
1745bool
1746necp_validate_application_id(uuid_t client_id, u_int32_t sign_type,
1747 u_int8_t *tag, size_t tag_length)
1748{
1749 if (s_necp_application_id_key_state.digest_info == NULL) {
1750 return false;
1751 }
1752
1753 if (tag == NULL ||
1754 tag_length == 0) {
1755 return false;
1756 }
1757
1758 size_t required_tag_length = s_necp_application_id_key_state.digest_info->output_size;
1759 if (tag_length != required_tag_length) {
1760 return false;
1761 }
1762
1763 uint8_t actual_tag[required_tag_length];
1764
1765 cchmac_ctx_decl(s_necp_application_id_key_state.digest_info->state_size,
1766 s_necp_application_id_key_state.digest_info->block_size, ctx);
1767 cchmac_init(di: s_necp_application_id_key_state.digest_info, ctx,
1768 key_len: sizeof(s_necp_application_id_key_state.key),
1769 key: s_necp_application_id_key_state.key);
1770 necp_sign_application_id_update_context(di: s_necp_application_id_key_state.digest_info,
1771 ctx, client_id, sign_type);
1772 cchmac_final(di: s_necp_application_id_key_state.digest_info, ctx, mac: actual_tag);
1773
1774 return cc_cmp_safe(num: s_necp_application_id_key_state.digest_info->output_size, ptr1: tag, ptr2: actual_tag) == 0;
1775}
1776
1777void
1778necp_init(void)
1779{
1780 necp_log_handle = os_log_create(subsystem: "com.apple.xnu.net.necp", category: "necp");
1781 necp_data_trace_log_handle = os_log_create(subsystem: "com.apple.xnu.net.necp", category: "necp-data-trace");
1782
1783 necp_client_init();
1784
1785 TAILQ_INIT(&necp_session_list);
1786
1787 LIST_INIT(&necp_kernel_socket_policies);
1788 LIST_INIT(&necp_kernel_ip_output_policies);
1789
1790 LIST_INIT(&necp_account_id_list);
1791
1792 LIST_INIT(&necp_uuid_service_id_list);
1793
1794 LIST_INIT(&necp_registered_service_list);
1795
1796 LIST_INIT(&necp_route_rules);
1797 LIST_INIT(&necp_aggregate_route_rules);
1798
1799 LIST_INIT(&necp_global_domain_filter_list);
1800
1801 necp_generate_resolver_key();
1802 necp_generate_application_id_key();
1803
1804 necp_uuid_app_id_hashtbl = hashinit(NECP_UUID_APP_ID_HASH_SIZE, M_NECP, hashmask: &necp_uuid_app_id_hash_mask);
1805 necp_uuid_app_id_hash_num_buckets = necp_uuid_app_id_hash_mask + 1;
1806 necp_num_uuid_app_id_mappings = 0;
1807 necp_uuid_app_id_mappings_dirty = FALSE;
1808
1809 necp_kernel_application_policies_condition_mask = 0;
1810 necp_kernel_socket_policies_condition_mask = 0;
1811 necp_kernel_ip_output_policies_condition_mask = 0;
1812
1813 necp_kernel_application_policies_count = 0;
1814 necp_kernel_socket_policies_count = 0;
1815 necp_kernel_socket_policies_non_app_count = 0;
1816 necp_kernel_ip_output_policies_count = 0;
1817 necp_kernel_ip_output_policies_non_id_count = 0;
1818
1819 necp_kernel_socket_policies_gencount = 1;
1820
1821 memset(s: &necp_kernel_socket_policies_map, c: 0, n: sizeof(necp_kernel_socket_policies_map));
1822 memset(s: &necp_kernel_ip_output_policies_map, c: 0, n: sizeof(necp_kernel_ip_output_policies_map));
1823 necp_kernel_socket_policies_app_layer_map = NULL;
1824
1825 necp_drop_unentitled_order = necp_get_first_order_for_priority(priority: necp_drop_unentitled_level);
1826 necp_drop_management_order = necp_get_first_order_for_priority(priority: necp_drop_management_level);
1827}
1828
1829static void
1830necp_post_change_event(struct kev_necp_policies_changed_data *necp_event_data)
1831{
1832 struct kev_msg ev_msg;
1833 memset(s: &ev_msg, c: 0, n: sizeof(ev_msg));
1834
1835 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1836 ev_msg.kev_class = KEV_NETWORK_CLASS;
1837 ev_msg.kev_subclass = KEV_NECP_SUBCLASS;
1838 ev_msg.event_code = KEV_NECP_POLICIES_CHANGED;
1839
1840 ev_msg.dv[0].data_ptr = necp_event_data;
1841 ev_msg.dv[0].data_length = sizeof(necp_event_data->changed_count);
1842 ev_msg.dv[1].data_length = 0;
1843
1844 kev_post_msg(event: &ev_msg);
1845}
1846
1847static inline bool
1848necp_buffer_write_tlv_validate(u_int8_t *cursor, u_int8_t type, u_int32_t length,
1849 u_int8_t *buffer, u_int32_t buffer_length)
1850{
1851 if (cursor < buffer || (uintptr_t)(cursor - buffer) > buffer_length) {
1852 NECPLOG0(LOG_ERR, "Cannot write TLV in buffer (invalid cursor)");
1853 return false;
1854 }
1855 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1856 if (next_tlv <= buffer || // make sure the next TLV start doesn't overflow
1857 (uintptr_t)(next_tlv - buffer) > buffer_length) { // make sure the next TLV has enough room in buffer
1858 NECPLOG(LOG_ERR, "Cannot write TLV in buffer (TLV length %u, buffer length %u)",
1859 length, buffer_length);
1860 return false;
1861 }
1862 return true;
1863}
1864
1865u_int8_t *
1866necp_buffer_write_tlv_if_different(u_int8_t *cursor, u_int8_t type,
1867 u_int32_t length, const void *value, bool *updated,
1868 u_int8_t *buffer, u_int32_t buffer_length)
1869{
1870 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1871 // If we can't fit this TLV, return the current cursor
1872 return cursor;
1873 }
1874 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1875 if (*updated || *(u_int8_t *)(cursor) != type) {
1876 *(u_int8_t *)(cursor) = type;
1877 *updated = TRUE;
1878 }
1879 if (*updated || *(u_int32_t *)(void *)(cursor + sizeof(type)) != length) {
1880 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1881 *updated = TRUE;
1882 }
1883 if (length > 0) {
1884 if (*updated || memcmp(s1: (u_int8_t *)(cursor + sizeof(type) + sizeof(length)), s2: value, n: length) != 0) {
1885 memcpy(dst: (u_int8_t *)(cursor + sizeof(type) + sizeof(length)), src: value, n: length);
1886 *updated = TRUE;
1887 }
1888 }
1889 return next_tlv;
1890}
1891
1892u_int8_t *
1893necp_buffer_write_tlv(u_int8_t *cursor, u_int8_t type,
1894 u_int32_t length, const void *value,
1895 u_int8_t *buffer, u_int32_t buffer_length)
1896{
1897 if (!necp_buffer_write_tlv_validate(cursor, type, length, buffer, buffer_length)) {
1898 return NULL;
1899 }
1900 u_int8_t *next_tlv = (u_int8_t *)(cursor + sizeof(type) + sizeof(length) + length);
1901 *(u_int8_t *)(cursor) = type;
1902 *(u_int32_t *)(void *)(cursor + sizeof(type)) = length;
1903 if (length > 0) {
1904 memcpy(dst: (u_int8_t *)(cursor + sizeof(type) + sizeof(length)), src: value, n: length);
1905 }
1906
1907 return next_tlv;
1908}
1909
1910u_int8_t
1911necp_buffer_get_tlv_type(u_int8_t *buffer, int tlv_offset)
1912{
1913 u_int8_t *type = NULL;
1914
1915 if (buffer == NULL) {
1916 return 0;
1917 }
1918
1919 type = (u_int8_t *)((u_int8_t *)buffer + tlv_offset);
1920 return type ? *type : 0;
1921}
1922
1923u_int32_t
1924necp_buffer_get_tlv_length(u_int8_t *buffer, int tlv_offset)
1925{
1926 u_int32_t *length = NULL;
1927
1928 if (buffer == NULL) {
1929 return 0;
1930 }
1931
1932 length = (u_int32_t *)(void *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t));
1933 return length ? *length : 0;
1934}
1935
1936u_int8_t *
1937necp_buffer_get_tlv_value(u_int8_t *buffer, int tlv_offset, u_int32_t *value_size)
1938{
1939 u_int8_t *value = NULL;
1940 u_int32_t length = necp_buffer_get_tlv_length(buffer, tlv_offset);
1941 if (length == 0) {
1942 return value;
1943 }
1944
1945 if (value_size) {
1946 *value_size = length;
1947 }
1948
1949 value = (u_int8_t *)((u_int8_t *)buffer + tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
1950 return value;
1951}
1952
1953int
1954necp_buffer_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
1955{
1956 if (err != NULL) {
1957 *err = ENOENT;
1958 }
1959 if (offset < 0) {
1960 if (err != NULL) {
1961 *err = EINVAL;
1962 }
1963 return -1;
1964 }
1965 int cursor = offset;
1966 int next_cursor;
1967 u_int32_t curr_length;
1968 u_int8_t curr_type;
1969
1970 while (TRUE) {
1971 if ((((u_int32_t)cursor) + sizeof(curr_type) + sizeof(curr_length)) > buffer_length) {
1972 return -1;
1973 }
1974 if (!next) {
1975 curr_type = necp_buffer_get_tlv_type(buffer, tlv_offset: cursor);
1976 } else {
1977 next = 0;
1978 curr_type = NECP_TLV_NIL;
1979 }
1980 curr_length = necp_buffer_get_tlv_length(buffer, tlv_offset: cursor);
1981 if (curr_length > buffer_length - ((u_int32_t)cursor + sizeof(curr_type) + sizeof(curr_length))) {
1982 return -1;
1983 }
1984
1985 next_cursor = (cursor + sizeof(curr_type) + sizeof(curr_length) + curr_length);
1986 if (curr_type == type) {
1987 // check if entire TLV fits inside buffer
1988 if (((u_int32_t)next_cursor) <= buffer_length) {
1989 if (err != NULL) {
1990 *err = 0;
1991 }
1992 return cursor;
1993 } else {
1994 return -1;
1995 }
1996 }
1997 cursor = next_cursor;
1998 }
1999}
2000
2001static int
2002necp_find_tlv(u_int8_t *buffer, u_int32_t buffer_length, int offset, u_int8_t type, int *err, int next)
2003{
2004 int cursor = -1;
2005 if (buffer != NULL) {
2006 cursor = necp_buffer_find_tlv(buffer, buffer_length, offset, type, err, next);
2007 }
2008 return cursor;
2009}
2010
2011static int
2012necp_get_tlv_at_offset(u_int8_t *buffer, u_int32_t buffer_length,
2013 int tlv_offset, u_int32_t out_buffer_length, void *out_buffer, u_int32_t *value_size)
2014{
2015 if (buffer == NULL) {
2016 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset buffer is NULL");
2017 return EINVAL;
2018 }
2019
2020 // Handle buffer parsing
2021
2022 // Validate that buffer has enough room for any TLV
2023 if (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) > buffer_length) {
2024 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV (%u < %lu)",
2025 buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t));
2026 return EINVAL;
2027 }
2028
2029 // Validate that buffer has enough room for this TLV
2030 u_int32_t tlv_length = necp_buffer_get_tlv_length(buffer, tlv_offset);
2031 if (tlv_length > buffer_length - (tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t))) {
2032 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset buffer_length is too small for TLV of length %u (%u < %lu)",
2033 tlv_length, buffer_length, tlv_offset + sizeof(u_int8_t) + sizeof(u_int32_t) + tlv_length);
2034 return EINVAL;
2035 }
2036
2037 if (out_buffer != NULL && out_buffer_length > 0) {
2038 // Validate that out buffer is large enough for value
2039 if (out_buffer_length < tlv_length) {
2040 NECPLOG(LOG_ERR, "necp_get_tlv_at_offset out_buffer_length is too small for TLV value (%u < %u)",
2041 out_buffer_length, tlv_length);
2042 return EINVAL;
2043 }
2044
2045 // Get value pointer
2046 u_int8_t *tlv_value = necp_buffer_get_tlv_value(buffer, tlv_offset, NULL);
2047 if (tlv_value == NULL) {
2048 NECPLOG0(LOG_ERR, "necp_get_tlv_at_offset tlv_value is NULL");
2049 return ENOENT;
2050 }
2051
2052 // Copy value
2053 memcpy(dst: out_buffer, src: tlv_value, n: tlv_length);
2054 }
2055
2056 // Copy out length
2057 if (value_size != NULL) {
2058 *value_size = tlv_length;
2059 }
2060
2061 return 0;
2062}
2063
2064static int
2065necp_get_tlv(u_int8_t *buffer, u_int32_t buffer_length,
2066 int offset, u_int8_t type, u_int32_t buff_len, void *buff, u_int32_t *value_size)
2067{
2068 int error = 0;
2069
2070 int tlv_offset = necp_find_tlv(buffer, buffer_length, offset, type, err: &error, next: 0);
2071 if (tlv_offset < 0) {
2072 return error;
2073 }
2074
2075 return necp_get_tlv_at_offset(buffer, buffer_length, tlv_offset, out_buffer_length: buff_len, out_buffer: buff, value_size);
2076}
2077
2078// Session Management
2079
2080static struct necp_session *
2081necp_create_session(void)
2082{
2083 struct necp_session *new_session = NULL;
2084
2085 new_session = kalloc_type(struct necp_session,
2086 Z_WAITOK | Z_ZERO | Z_NOFAIL);
2087
2088 new_session->necp_fd_type = necp_fd_type_session;
2089 new_session->session_priority = NECP_SESSION_PRIORITY_UNKNOWN;
2090 new_session->dirty = FALSE;
2091 LIST_INIT(&new_session->policies);
2092 LIST_INIT(&new_session->services);
2093 LIST_INIT(&new_session->domain_filters);
2094 lck_mtx_init(lck: &new_session->lock, grp: &necp_kernel_policy_mtx_grp, attr: &necp_kernel_policy_mtx_attr);
2095
2096 // Take the lock
2097 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
2098
2099 // Find the next available control unit
2100 u_int32_t control_unit = 1;
2101 struct necp_session *next_session = NULL;
2102 TAILQ_FOREACH(next_session, &necp_session_list, chain) {
2103 if (next_session->control_unit > control_unit) {
2104 // Found a gap, grab this control unit
2105 break;
2106 }
2107
2108 // Try the next control unit, loop around
2109 control_unit = next_session->control_unit + 1;
2110 }
2111
2112 new_session->control_unit = control_unit;
2113 new_session->session_order = necp_allocate_new_session_order(priority: new_session->session_priority, control_unit);
2114
2115 if (next_session != NULL) {
2116 TAILQ_INSERT_BEFORE(next_session, new_session, chain);
2117 } else {
2118 TAILQ_INSERT_TAIL(&necp_session_list, new_session, chain);
2119 }
2120
2121 necp_session_count++;
2122 lck_rw_done(lck: &necp_kernel_policy_lock);
2123
2124 if (necp_debug) {
2125 NECPLOG(LOG_DEBUG, "Created NECP session, control unit %d", control_unit);
2126 }
2127
2128 return new_session;
2129}
2130
2131static void
2132necp_delete_session(struct necp_session *session)
2133{
2134 if (session != NULL) {
2135 struct necp_service_registration *service = NULL;
2136 struct necp_service_registration *temp_service = NULL;
2137 LIST_FOREACH_SAFE(service, &session->services, session_chain, temp_service) {
2138 LIST_REMOVE(service, session_chain);
2139 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
2140 LIST_REMOVE(service, kernel_chain);
2141 lck_rw_done(lck: &necp_kernel_policy_lock);
2142 kfree_type(struct necp_service_registration, service);
2143 }
2144 struct necp_domain_filter *filter = NULL;
2145 struct necp_domain_filter *temp_filter = NULL;
2146 LIST_FOREACH_SAFE(filter, &session->domain_filters, owner_chain, temp_filter) {
2147 if (os_ref_release_locked(rc: &filter->refcount) == 0) {
2148 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
2149 LIST_REMOVE(filter, chain);
2150 lck_rw_done(lck: &necp_kernel_policy_lock);
2151 LIST_REMOVE(filter, owner_chain);
2152 net_bloom_filter_destroy(filter: filter->filter);
2153 kfree_type(struct necp_domain_filter, filter);
2154 }
2155 }
2156 if (necp_debug) {
2157 NECPLOG0(LOG_DEBUG, "Deleted NECP session");
2158 }
2159
2160 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
2161 TAILQ_REMOVE(&necp_session_list, session, chain);
2162 necp_session_count--;
2163 lck_rw_done(lck: &necp_kernel_policy_lock);
2164
2165 lck_mtx_destroy(lck: &session->lock, grp: &necp_kernel_policy_mtx_grp);
2166 kfree_type(struct necp_session, session);
2167 }
2168}
2169
2170// Session Policy Management
2171
2172static inline u_int8_t
2173necp_policy_result_get_type_from_buffer(u_int8_t *buffer, u_int32_t length)
2174{
2175 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2176}
2177
2178static inline u_int32_t
2179necp_policy_result_get_parameter_length_from_buffer(u_int8_t *buffer, u_int32_t length)
2180{
2181 return (buffer && length > sizeof(u_int8_t)) ? (length - sizeof(u_int8_t)) : 0;
2182}
2183
2184static inline u_int8_t *
2185necp_policy_result_get_parameter_pointer_from_buffer(u_int8_t *buffer, u_int32_t length)
2186{
2187 return (buffer && length > sizeof(u_int8_t)) ? (buffer + sizeof(u_int8_t)) : NULL;
2188}
2189
2190static bool
2191necp_policy_result_requires_route_rules(u_int8_t *buffer, u_int32_t length)
2192{
2193 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2194 if (type == NECP_POLICY_RESULT_ROUTE_RULES) {
2195 return TRUE;
2196 }
2197 return FALSE;
2198}
2199
2200static inline bool
2201_necp_address_is_valid(struct sockaddr *address)
2202{
2203 if (address->sa_family == AF_INET) {
2204 return address->sa_len == sizeof(struct sockaddr_in);
2205 } else if (address->sa_family == AF_INET6) {
2206 return address->sa_len == sizeof(struct sockaddr_in6);
2207 } else {
2208 return FALSE;
2209 }
2210}
2211
2212#define necp_address_is_valid(S) _necp_address_is_valid(SA(S))
2213
2214static bool
2215necp_policy_result_is_valid(u_int8_t *buffer, u_int32_t length, bool *is_pass_skip)
2216{
2217 bool validated = FALSE;
2218 u_int8_t type = necp_policy_result_get_type_from_buffer(buffer, length);
2219 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer, length);
2220 *is_pass_skip = FALSE;
2221 switch (type) {
2222 case NECP_POLICY_RESULT_PASS: {
2223 *is_pass_skip = TRUE;
2224 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2225 validated = TRUE;
2226 }
2227 break;
2228 }
2229 case NECP_POLICY_RESULT_DROP: {
2230 if (parameter_length == 0 || parameter_length == sizeof(u_int32_t)) {
2231 validated = TRUE;
2232 }
2233 break;
2234 }
2235 case NECP_POLICY_RESULT_ROUTE_RULES:
2236 case NECP_POLICY_RESULT_SCOPED_DIRECT:
2237 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
2238 validated = TRUE;
2239 break;
2240 }
2241 case NECP_POLICY_RESULT_SKIP:
2242 *is_pass_skip = TRUE;
2243 case NECP_POLICY_RESULT_SOCKET_DIVERT:
2244 case NECP_POLICY_RESULT_SOCKET_FILTER: {
2245 if (parameter_length >= sizeof(u_int32_t)) {
2246 validated = TRUE;
2247 }
2248 break;
2249 }
2250 case NECP_POLICY_RESULT_IP_TUNNEL: {
2251 if (parameter_length > sizeof(u_int32_t)) {
2252 validated = TRUE;
2253 }
2254 break;
2255 }
2256 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
2257 if (parameter_length > 0) {
2258 validated = TRUE;
2259 }
2260 break;
2261 }
2262 case NECP_POLICY_RESULT_USE_NETAGENT:
2263 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
2264 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
2265 if (parameter_length >= sizeof(uuid_t)) {
2266 validated = TRUE;
2267 }
2268 break;
2269 }
2270 default: {
2271 validated = FALSE;
2272 break;
2273 }
2274 }
2275
2276 if (necp_debug) {
2277 NECPLOG(LOG_DEBUG, "Policy result type %d, valid %d", type, validated);
2278 }
2279
2280 return validated;
2281}
2282
2283static inline u_int8_t
2284necp_policy_condition_get_type_from_buffer(u_int8_t *buffer, u_int32_t length)
2285{
2286 return (buffer && length >= sizeof(u_int8_t)) ? buffer[0] : 0;
2287}
2288
2289static inline u_int8_t
2290necp_policy_condition_get_flags_from_buffer(u_int8_t *buffer, u_int32_t length)
2291{
2292 return (buffer && length >= (2 * sizeof(u_int8_t))) ? buffer[1] : 0;
2293}
2294
2295static inline u_int32_t
2296necp_policy_condition_get_value_length_from_buffer(u_int8_t *buffer, u_int32_t length)
2297{
2298 return (buffer && length >= (2 * sizeof(u_int8_t))) ? (length - (2 * sizeof(u_int8_t))) : 0;
2299}
2300
2301static inline u_int8_t *
2302necp_policy_condition_get_value_pointer_from_buffer(u_int8_t *buffer, u_int32_t length)
2303{
2304 return (buffer && length > (2 * sizeof(u_int8_t))) ? (buffer + (2 * sizeof(u_int8_t))) : NULL;
2305}
2306
2307static inline bool
2308necp_policy_condition_is_default(u_int8_t *buffer, u_int32_t length)
2309{
2310 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_DEFAULT;
2311}
2312
2313static inline bool
2314necp_policy_condition_is_application(u_int8_t *buffer, u_int32_t length)
2315{
2316 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_APPLICATION;
2317}
2318
2319static inline bool
2320necp_policy_condition_is_real_application(u_int8_t *buffer, u_int32_t length)
2321{
2322 return necp_policy_condition_get_type_from_buffer(buffer, length) == NECP_POLICY_CONDITION_REAL_APPLICATION;
2323}
2324
2325static inline bool
2326necp_policy_condition_requires_application(u_int8_t *buffer, u_int32_t length)
2327{
2328 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2329 return type == NECP_POLICY_CONDITION_REAL_APPLICATION;
2330}
2331
2332static inline bool
2333necp_policy_condition_is_kernel_pid(u_int8_t *buffer, u_int32_t length)
2334{
2335 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2336 u_int32_t condition_length = 0;
2337 pid_t *condition_value = NULL;
2338
2339 if (type == NECP_POLICY_CONDITION_PID) {
2340 condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2341 if (condition_length >= sizeof(pid_t)) {
2342 condition_value = (pid_t *)(void *)necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2343 return *condition_value == 0;
2344 }
2345 }
2346 return false;
2347}
2348
2349static bool
2350necp_policy_condition_is_valid(u_int8_t *buffer, u_int32_t length, u_int8_t policy_result_type)
2351{
2352 bool validated = FALSE;
2353 bool result_cannot_have_ip_layer = (policy_result_type == NECP_POLICY_RESULT_SOCKET_DIVERT ||
2354 policy_result_type == NECP_POLICY_RESULT_SOCKET_FILTER ||
2355 policy_result_type == NECP_POLICY_RESULT_SOCKET_SCOPED ||
2356 policy_result_type == NECP_POLICY_RESULT_ROUTE_RULES ||
2357 policy_result_type == NECP_POLICY_RESULT_USE_NETAGENT ||
2358 policy_result_type == NECP_POLICY_RESULT_NETAGENT_SCOPED ||
2359 policy_result_type == NECP_POLICY_RESULT_SCOPED_DIRECT ||
2360 policy_result_type == NECP_POLICY_RESULT_ALLOW_UNENTITLED ||
2361 policy_result_type == NECP_POLICY_RESULT_REMOVE_NETAGENT) ? TRUE : FALSE;
2362 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2363 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer, length);
2364 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2365 u_int8_t flags = necp_policy_condition_get_flags_from_buffer(buffer, length);
2366 switch (type) {
2367 case NECP_POLICY_CONDITION_APPLICATION:
2368 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
2369 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2370 condition_length >= sizeof(uuid_t) &&
2371 condition_value != NULL &&
2372 !uuid_is_null(uu: condition_value)) {
2373 validated = TRUE;
2374 }
2375 break;
2376 }
2377 case NECP_POLICY_CONDITION_DOMAIN:
2378 case NECP_POLICY_CONDITION_ACCOUNT:
2379 case NECP_POLICY_CONDITION_BOUND_INTERFACE:
2380 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER:
2381 case NECP_POLICY_CONDITION_URL: {
2382 if (condition_length > 0) {
2383 validated = TRUE;
2384 }
2385 break;
2386 }
2387 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
2388 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
2389 validated = TRUE;
2390 }
2391 break;
2392 }
2393 case NECP_POLICY_CONDITION_DEFAULT:
2394 case NECP_POLICY_CONDITION_ALL_INTERFACES:
2395 case NECP_POLICY_CONDITION_ENTITLEMENT:
2396 case NECP_POLICY_CONDITION_PLATFORM_BINARY:
2397 case NECP_POLICY_CONDITION_HAS_CLIENT:
2398 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT:
2399 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
2400 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE)) {
2401 validated = TRUE;
2402 }
2403 break;
2404 }
2405 case NECP_POLICY_CONDITION_SDK_VERSION: {
2406 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2407 condition_length >= sizeof(struct necp_policy_condition_sdk_version)) {
2408 validated = TRUE;
2409 }
2410 break;
2411 }
2412 case NECP_POLICY_CONDITION_IP_PROTOCOL: {
2413 if (condition_length >= sizeof(u_int16_t)) {
2414 validated = TRUE;
2415 }
2416 break;
2417 }
2418 case NECP_POLICY_CONDITION_PID: {
2419 if (condition_length >= sizeof(pid_t) &&
2420 condition_value != NULL) {
2421 validated = TRUE;
2422 }
2423 break;
2424 }
2425 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
2426 if (condition_length >= sizeof(u_int32_t)) {
2427 validated = TRUE;
2428 }
2429 break;
2430 }
2431 case NECP_POLICY_CONDITION_UID:
2432 case NECP_POLICY_CONDITION_REAL_UID: {
2433 if (condition_length >= sizeof(uid_t)) {
2434 validated = TRUE;
2435 }
2436 break;
2437 }
2438 case NECP_POLICY_CONDITION_LOCAL_ADDR:
2439 case NECP_POLICY_CONDITION_REMOTE_ADDR: {
2440 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr) &&
2441 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2442 validated = TRUE;
2443 }
2444 break;
2445 }
2446 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
2447 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE: {
2448 if (!result_cannot_have_ip_layer && condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2449 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2450 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2451 validated = TRUE;
2452 }
2453 break;
2454 }
2455 case NECP_POLICY_CONDITION_AGENT_TYPE: {
2456 if (!(flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE) &&
2457 condition_length >= sizeof(struct necp_policy_condition_agent_type)) {
2458 validated = TRUE;
2459 }
2460 break;
2461 }
2462 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
2463 if (condition_length >= sizeof(u_int16_t)) {
2464 validated = TRUE;
2465 }
2466 break;
2467 }
2468 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR:
2469 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
2470 if (condition_length >= sizeof(struct necp_policy_condition_addr) &&
2471 necp_address_is_valid(&((struct necp_policy_condition_addr *)(void *)condition_value)->address.sa)) {
2472 validated = TRUE;
2473 }
2474 break;
2475 }
2476 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE:
2477 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
2478 if (condition_length >= sizeof(struct necp_policy_condition_addr_range) &&
2479 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->start_address.sa) &&
2480 necp_address_is_valid(&((struct necp_policy_condition_addr_range *)(void *)condition_value)->end_address.sa)) {
2481 validated = TRUE;
2482 }
2483 break;
2484 }
2485 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
2486 if (condition_length == 0 || condition_length >= sizeof(u_int32_t)) {
2487 validated = TRUE;
2488 }
2489 break;
2490 }
2491 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
2492 validated = TRUE;
2493 break;
2494 }
2495 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
2496 validated = TRUE;
2497 break;
2498 }
2499 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
2500 if (condition_length >= sizeof(u_int16_t)) {
2501 u_int16_t packet_filter_tags = *(u_int16_t *)(void *)condition_value;
2502 if (packet_filter_tags > 0 && packet_filter_tags <= NECP_POLICY_CONDITION_PACKET_FILTER_TAG_MAX) {
2503 validated = TRUE;
2504 }
2505 }
2506 break;
2507 }
2508 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
2509 validated = TRUE;
2510 break;
2511 }
2512 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
2513 validated = TRUE;
2514 break;
2515 }
2516 case NECP_POLICY_CONDITION_SCHEME_PORT: {
2517 if (condition_length >= sizeof(u_int16_t)) {
2518 validated = TRUE;
2519 }
2520 break;
2521 }
2522 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
2523 if (condition_length >= sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) {
2524 validated = TRUE;
2525 }
2526 break;
2527 }
2528 default: {
2529 validated = FALSE;
2530 break;
2531 }
2532 }
2533
2534 if (necp_debug) {
2535 NECPLOG(LOG_DEBUG, "Policy condition type %d, valid %d", type, validated);
2536 }
2537
2538 return validated;
2539}
2540
2541static bool
2542necp_policy_route_rule_is_default(u_int8_t *buffer, u_int32_t length)
2543{
2544 return necp_policy_condition_get_value_length_from_buffer(buffer, length) == 0 &&
2545 necp_policy_condition_get_flags_from_buffer(buffer, length) == 0;
2546}
2547
2548static bool
2549necp_policy_route_rule_is_valid(u_int8_t *buffer, u_int32_t length)
2550{
2551 bool validated = FALSE;
2552 u_int8_t type = necp_policy_condition_get_type_from_buffer(buffer, length);
2553 switch (type) {
2554 case NECP_ROUTE_RULE_ALLOW_INTERFACE: {
2555 validated = TRUE;
2556 break;
2557 }
2558 case NECP_ROUTE_RULE_DENY_INTERFACE: {
2559 validated = TRUE;
2560 break;
2561 }
2562 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE: {
2563 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2564 validated = (rule_length >= sizeof(u_int32_t));
2565 break;
2566 }
2567 case NECP_ROUTE_RULE_QOS_MARKING: {
2568 validated = TRUE;
2569 break;
2570 }
2571 case NECP_ROUTE_RULE_DENY_LQM_ABORT: {
2572 validated = TRUE;
2573 break;
2574 }
2575 case NECP_ROUTE_RULE_USE_NETAGENT:
2576 case NECP_ROUTE_RULE_REMOVE_NETAGENT: {
2577 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2578 validated = (rule_length >= sizeof(uuid_t));
2579 break;
2580 }
2581 case NECP_ROUTE_RULE_DIVERT_SOCKET: {
2582 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer, length);
2583 validated = (rule_length >= sizeof(uint32_t));
2584 break;
2585 }
2586 default: {
2587 validated = FALSE;
2588 break;
2589 }
2590 }
2591
2592 if (necp_debug) {
2593 NECPLOG(LOG_DEBUG, "Policy route rule type %d, valid %d", type, validated);
2594 }
2595
2596 return validated;
2597}
2598
2599static int
2600necp_get_posix_error_for_necp_error(int response_error)
2601{
2602 switch (response_error) {
2603 case NECP_ERROR_UNKNOWN_PACKET_TYPE:
2604 case NECP_ERROR_INVALID_TLV:
2605 case NECP_ERROR_POLICY_RESULT_INVALID:
2606 case NECP_ERROR_POLICY_CONDITIONS_INVALID:
2607 case NECP_ERROR_ROUTE_RULES_INVALID: {
2608 return EINVAL;
2609 }
2610 case NECP_ERROR_POLICY_ID_NOT_FOUND: {
2611 return ENOENT;
2612 }
2613 case NECP_ERROR_INVALID_PROCESS: {
2614 return EPERM;
2615 }
2616 case NECP_ERROR_INTERNAL:
2617 default: {
2618 return ENOMEM;
2619 }
2620 }
2621}
2622
2623static necp_policy_id
2624necp_handle_policy_add(struct necp_session *session,
2625 u_int8_t *tlv_buffer, size_t tlv_buffer_length, int offset, int *return_error)
2626{
2627 bool has_default_condition = FALSE;
2628 bool has_non_default_condition = FALSE;
2629 bool has_application_condition = FALSE;
2630 bool has_real_application_condition = FALSE;
2631 bool requires_application_condition = FALSE;
2632 bool has_kernel_pid = FALSE;
2633 bool is_pass_skip = FALSE;
2634 u_int8_t *conditions_array = NULL;
2635 u_int32_t conditions_array_size = 0;
2636 int conditions_array_cursor;
2637
2638 bool has_default_route_rule = FALSE;
2639 u_int8_t *route_rules_array = NULL;
2640 u_int32_t route_rules_array_size = 0;
2641 int route_rules_array_cursor;
2642
2643 int cursor;
2644 int error = 0;
2645 u_int32_t response_error = NECP_ERROR_INTERNAL;
2646
2647 necp_policy_order order = 0;
2648 struct necp_session_policy *policy = NULL;
2649 u_int8_t *policy_result = NULL;
2650 u_int32_t policy_result_size = 0;
2651
2652 // Read policy order
2653 error = necp_get_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset, NECP_TLV_POLICY_ORDER, buff_len: sizeof(order), buff: &order, NULL);
2654 if (error) {
2655 NECPLOG(LOG_ERR, "Failed to get policy order: %d", error);
2656 response_error = NECP_ERROR_INVALID_TLV;
2657 goto fail;
2658 }
2659
2660 // Read policy result
2661 cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset, NECP_TLV_POLICY_RESULT, err: &error, next: 0);
2662 if (error || cursor < 0) {
2663 NECPLOG(LOG_ERR, "Failed to find policy result TLV: %d", error);
2664 response_error = NECP_ERROR_INVALID_TLV;
2665 goto fail;
2666 }
2667 error = necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: 0, NULL, value_size: &policy_result_size);
2668 if (error || policy_result_size == 0) {
2669 NECPLOG(LOG_ERR, "Failed to get policy result length: %d", error);
2670 response_error = NECP_ERROR_INVALID_TLV;
2671 goto fail;
2672 }
2673 if (policy_result_size > NECP_MAX_POLICY_RESULT_SIZE) {
2674 NECPLOG(LOG_ERR, "Policy result length too large: %u", policy_result_size);
2675 response_error = NECP_ERROR_INVALID_TLV;
2676 goto fail;
2677 }
2678 policy_result = (u_int8_t *)kalloc_data(policy_result_size, Z_WAITOK);
2679 if (policy_result == NULL) {
2680 NECPLOG(LOG_ERR, "Failed to allocate a policy result buffer (size %d)", policy_result_size);
2681 response_error = NECP_ERROR_INTERNAL;
2682 goto fail;
2683 }
2684 error = necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: policy_result_size, out_buffer: policy_result, NULL);
2685 if (error) {
2686 NECPLOG(LOG_ERR, "Failed to get policy result: %d", error);
2687 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2688 goto fail;
2689 }
2690 if (!necp_policy_result_is_valid(buffer: policy_result, length: policy_result_size, is_pass_skip: &is_pass_skip)) {
2691 NECPLOG0(LOG_ERR, "Failed to validate policy result");
2692 response_error = NECP_ERROR_POLICY_RESULT_INVALID;
2693 goto fail;
2694 }
2695
2696 if (necp_policy_result_requires_route_rules(buffer: policy_result, length: policy_result_size)) {
2697 // Read route rules conditions
2698 for (cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, err: &error, next: 0);
2699 cursor >= 0;
2700 cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset: cursor, NECP_TLV_ROUTE_RULE, err: &error, next: 1)) {
2701 u_int32_t route_rule_size = 0;
2702 necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: 0, NULL, value_size: &route_rule_size);
2703 if (os_add_overflow(route_rules_array_size,
2704 (sizeof(u_int8_t) + sizeof(u_int32_t) + route_rule_size),
2705 &route_rules_array_size)) {
2706 NECPLOG0(LOG_ERR, "Route rules size overflowed, too large");
2707 response_error = NECP_ERROR_INVALID_TLV;
2708 goto fail;
2709 }
2710 }
2711
2712 if (route_rules_array_size == 0) {
2713 NECPLOG0(LOG_ERR, "Failed to get policy route rules");
2714 response_error = NECP_ERROR_INVALID_TLV;
2715 goto fail;
2716 }
2717 if (route_rules_array_size > NECP_MAX_ROUTE_RULES_ARRAY_SIZE) {
2718 NECPLOG(LOG_ERR, "Route rules length too large: %u", route_rules_array_size);
2719 response_error = NECP_ERROR_INVALID_TLV;
2720 goto fail;
2721 }
2722 route_rules_array = (u_int8_t *)kalloc_data(route_rules_array_size, Z_WAITOK);
2723 if (route_rules_array == NULL) {
2724 NECPLOG(LOG_ERR, "Failed to allocate a policy route rules array (size %d)", route_rules_array_size);
2725 response_error = NECP_ERROR_INTERNAL;
2726 goto fail;
2727 }
2728
2729 route_rules_array_cursor = 0;
2730 for (cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset, NECP_TLV_ROUTE_RULE, err: &error, next: 0);
2731 cursor >= 0;
2732 cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset: cursor, NECP_TLV_ROUTE_RULE, err: &error, next: 1)) {
2733 u_int8_t route_rule_type = NECP_TLV_ROUTE_RULE;
2734 u_int32_t route_rule_size = 0;
2735 necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: 0, NULL, value_size: &route_rule_size);
2736 if (route_rule_size > 0 &&
2737 (sizeof(route_rule_type) + sizeof(route_rule_size) + route_rule_size) <= (route_rules_array_size - route_rules_array_cursor)) {
2738 // Add type
2739 memcpy(dst: (route_rules_array + route_rules_array_cursor), src: &route_rule_type, n: sizeof(route_rule_type));
2740 route_rules_array_cursor += sizeof(route_rule_type);
2741
2742 // Add length
2743 memcpy(dst: (route_rules_array + route_rules_array_cursor), src: &route_rule_size, n: sizeof(route_rule_size));
2744 route_rules_array_cursor += sizeof(route_rule_size);
2745
2746 // Add value
2747 necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: route_rule_size, out_buffer: (route_rules_array + route_rules_array_cursor), NULL);
2748
2749 if (!necp_policy_route_rule_is_valid(buffer: (route_rules_array + route_rules_array_cursor), length: route_rule_size)) {
2750 NECPLOG0(LOG_ERR, "Failed to validate policy route rule");
2751 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2752 goto fail;
2753 }
2754
2755 if (necp_policy_route_rule_is_default(buffer: (route_rules_array + route_rules_array_cursor), length: route_rule_size)) {
2756 if (has_default_route_rule) {
2757 NECPLOG0(LOG_ERR, "Failed to validate route rule; contained multiple default route rules");
2758 response_error = NECP_ERROR_ROUTE_RULES_INVALID;
2759 goto fail;
2760 }
2761 has_default_route_rule = TRUE;
2762 }
2763
2764 route_rules_array_cursor += route_rule_size;
2765 }
2766 }
2767 }
2768
2769 // Read policy conditions
2770 for (cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, err: &error, next: 0);
2771 cursor >= 0;
2772 cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset: cursor, NECP_TLV_POLICY_CONDITION, err: &error, next: 1)) {
2773 u_int32_t condition_size = 0;
2774 necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: 0, NULL, value_size: &condition_size);
2775
2776 if (condition_size > 0) {
2777 if (os_add_overflow(conditions_array_size,
2778 (sizeof(u_int8_t) + sizeof(u_int32_t) + condition_size),
2779 &conditions_array_size)) {
2780 NECPLOG0(LOG_ERR, "Conditions size overflowed, too large");
2781 response_error = NECP_ERROR_INVALID_TLV;
2782 goto fail;
2783 }
2784 }
2785 }
2786
2787 if (conditions_array_size == 0) {
2788 NECPLOG0(LOG_ERR, "Failed to get policy conditions");
2789 response_error = NECP_ERROR_INVALID_TLV;
2790 goto fail;
2791 }
2792 if (conditions_array_size > NECP_MAX_CONDITIONS_ARRAY_SIZE) {
2793 NECPLOG(LOG_ERR, "Conditions length too large: %u", conditions_array_size);
2794 response_error = NECP_ERROR_INVALID_TLV;
2795 goto fail;
2796 }
2797 conditions_array = (u_int8_t *)kalloc_data(conditions_array_size, Z_WAITOK);
2798 if (conditions_array == NULL) {
2799 NECPLOG(LOG_ERR, "Failed to allocate a policy conditions array (size %d)", conditions_array_size);
2800 response_error = NECP_ERROR_INTERNAL;
2801 goto fail;
2802 }
2803
2804 conditions_array_cursor = 0;
2805 for (cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset, NECP_TLV_POLICY_CONDITION, err: &error, next: 0);
2806 cursor >= 0;
2807 cursor = necp_find_tlv(buffer: tlv_buffer, buffer_length: tlv_buffer_length, offset: cursor, NECP_TLV_POLICY_CONDITION, err: &error, next: 1)) {
2808 u_int8_t condition_type = NECP_TLV_POLICY_CONDITION;
2809 u_int32_t condition_size = 0;
2810 necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: 0, NULL, value_size: &condition_size);
2811 if (condition_size > 0 &&
2812 (sizeof(condition_type) + sizeof(condition_size) + condition_size) <= (conditions_array_size - conditions_array_cursor)) {
2813 // Add type
2814 memcpy(dst: (conditions_array + conditions_array_cursor), src: &condition_type, n: sizeof(condition_type));
2815 conditions_array_cursor += sizeof(condition_type);
2816
2817 // Add length
2818 memcpy(dst: (conditions_array + conditions_array_cursor), src: &condition_size, n: sizeof(condition_size));
2819 conditions_array_cursor += sizeof(condition_size);
2820
2821 // Add value
2822 necp_get_tlv_at_offset(buffer: tlv_buffer, buffer_length: tlv_buffer_length, tlv_offset: cursor, out_buffer_length: condition_size, out_buffer: (conditions_array + conditions_array_cursor), NULL);
2823 if (!necp_policy_condition_is_valid(buffer: (conditions_array + conditions_array_cursor), length: condition_size, policy_result_type: necp_policy_result_get_type_from_buffer(buffer: policy_result, length: policy_result_size))) {
2824 NECPLOG0(LOG_ERR, "Failed to validate policy condition");
2825 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2826 goto fail;
2827 }
2828
2829 if (necp_policy_condition_is_default(buffer: (conditions_array + conditions_array_cursor), length: condition_size)) {
2830 has_default_condition = TRUE;
2831 } else {
2832 has_non_default_condition = TRUE;
2833 }
2834 if (has_default_condition && has_non_default_condition) {
2835 NECPLOG0(LOG_ERR, "Failed to validate conditions; contained default and non-default conditions");
2836 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2837 goto fail;
2838 }
2839
2840 if (necp_policy_condition_is_application(buffer: (conditions_array + conditions_array_cursor), length: condition_size)) {
2841 has_application_condition = TRUE;
2842 }
2843
2844 if (necp_policy_condition_is_real_application(buffer: (conditions_array + conditions_array_cursor), length: condition_size)) {
2845 has_real_application_condition = TRUE;
2846 }
2847
2848 if (necp_policy_condition_requires_application(buffer: (conditions_array + conditions_array_cursor), length: condition_size)) {
2849 requires_application_condition = TRUE;
2850 }
2851
2852 if (necp_policy_condition_is_kernel_pid(buffer: (conditions_array + conditions_array_cursor), length: condition_size)) {
2853 has_kernel_pid = TRUE;
2854 }
2855
2856 conditions_array_cursor += condition_size;
2857 }
2858 }
2859
2860 if (requires_application_condition && !has_application_condition) {
2861 NECPLOG0(LOG_ERR, "Failed to validate conditions; did not contain application condition");
2862 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2863 goto fail;
2864 }
2865
2866 if (has_kernel_pid && !is_pass_skip) {
2867 NECPLOG0(LOG_ERR, "Failed to validate conditions; kernel pid (0) condition allows only Pass/Skip result");
2868 response_error = NECP_ERROR_POLICY_CONDITIONS_INVALID;
2869 goto fail;
2870 }
2871
2872 if ((policy = necp_policy_create(session, order, conditions_array, conditions_array_size, route_rules_array, route_rules_array_size, result: policy_result, result_size: policy_result_size)) == NULL) {
2873 response_error = NECP_ERROR_INTERNAL;
2874 goto fail;
2875 }
2876
2877 return policy->local_id;
2878
2879fail:
2880 if (policy_result != NULL) {
2881 kfree_data(policy_result, policy_result_size);
2882 }
2883 if (conditions_array != NULL) {
2884 kfree_data(conditions_array, conditions_array_size);
2885 }
2886 if (route_rules_array != NULL) {
2887 kfree_data(route_rules_array, route_rules_array_size);
2888 }
2889
2890 if (return_error != NULL) {
2891 *return_error = necp_get_posix_error_for_necp_error(response_error);
2892 }
2893 return 0;
2894}
2895
2896static necp_policy_id
2897necp_policy_get_new_id(struct necp_session *session)
2898{
2899 session->last_policy_id++;
2900 if (session->last_policy_id < 1) {
2901 session->last_policy_id = 1;
2902 }
2903
2904 necp_policy_id newid = session->last_policy_id;
2905
2906 if (newid == 0) {
2907 NECPLOG0(LOG_ERR, "Allocate policy id failed.\n");
2908 return 0;
2909 }
2910
2911 return newid;
2912}
2913
2914/*
2915 * For the policy dump response this is the structure:
2916 *
2917 * <NECP_PACKET_HEADER>
2918 * {
2919 * type : NECP_TLV_POLICY_DUMP
2920 * length : ...
2921 * value :
2922 * {
2923 * {
2924 * type : NECP_TLV_POLICY_ID
2925 * len : ...
2926 * value : ...
2927 * }
2928 * {
2929 * type : NECP_TLV_POLICY_ORDER
2930 * len : ...
2931 * value : ...
2932 * }
2933 * {
2934 * type : NECP_TLV_POLICY_RESULT_STRING
2935 * len : ...
2936 * value : ...
2937 * }
2938 * {
2939 * type : NECP_TLV_POLICY_OWNER
2940 * len : ...
2941 * value : ...
2942 * }
2943 * {
2944 * type : NECP_TLV_POLICY_CONDITION
2945 * len : ...
2946 * value :
2947 * {
2948 * {
2949 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2950 * len : ...
2951 * value : ...
2952 * }
2953 * {
2954 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
2955 * len : ...
2956 * value : ...
2957 * }
2958 * ...
2959 * }
2960 * }
2961 * }
2962 * }
2963 * {
2964 * type : NECP_TLV_POLICY_DUMP
2965 * length : ...
2966 * value :
2967 * {
2968 * {
2969 * type : NECP_TLV_POLICY_ID
2970 * len : ...
2971 * value : ...
2972 * }
2973 * {
2974 * type : NECP_TLV_POLICY_ORDER
2975 * len : ...
2976 * value : ...
2977 * }
2978 * {
2979 * type : NECP_TLV_POLICY_RESULT_STRING
2980 * len : ...
2981 * value : ...
2982 * }
2983 * {
2984 * type : NECP_TLV_POLICY_OWNER
2985 * len : ...
2986 * value : ...
2987 * }
2988 * {
2989 * type : NECP_TLV_POLICY_CONDITION
2990 * len : ...
2991 * value :
2992 * {
2993 * {
2994 * type : NECP_POLICY_CONDITION_ALL_INTERFACES
2995 * len : ...
2996 * value : ...
2997 * }
2998 * {
2999 * type : NECP_POLICY_CONDITION_BOUND_INTERFACES
3000 * len : ...
3001 * value : ...
3002 * }
3003 * ...
3004 * }
3005 * }
3006 * }
3007 * }
3008 * ...
3009 */
3010static int
3011necp_handle_policy_dump_all(user_addr_t out_buffer, size_t out_buffer_length)
3012{
3013 struct necp_kernel_socket_policy *policy = NULL;
3014 int policy_i;
3015 int policy_count = 0;
3016 u_int8_t **tlv_buffer_pointers = NULL;
3017 u_int32_t *tlv_buffer_lengths = NULL;
3018 u_int32_t total_tlv_len = 0;
3019 u_int8_t *result_buf = NULL;
3020 u_int8_t *result_buf_cursor = result_buf;
3021 char result_string[MAX_RESULT_STRING_LEN];
3022 char proc_name_string[MAXCOMLEN + 1];
3023
3024 int error_code = 0;
3025 bool error_occured = false;
3026 u_int32_t response_error = NECP_ERROR_INTERNAL;
3027
3028#define REPORT_ERROR(error) error_occured = true; \
3029 response_error = error; \
3030 goto done
3031
3032#define UNLOCK_AND_REPORT_ERROR(lock, error) lck_rw_done(lock); \
3033 REPORT_ERROR(error)
3034
3035 errno_t cred_result = priv_check_cred(cred: kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, flags: 0);
3036 if (cred_result != 0) {
3037 NECPLOG0(LOG_ERR, "Session does not hold the necessary entitlement to get Network Extension Policy information");
3038 REPORT_ERROR(NECP_ERROR_INTERNAL);
3039 }
3040
3041 // LOCK
3042 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
3043
3044 if (necp_debug) {
3045 NECPLOG0(LOG_DEBUG, "Gathering policies");
3046 }
3047
3048 policy_count = necp_kernel_application_policies_count;
3049
3050 tlv_buffer_pointers = kalloc_type(u_int8_t *, policy_count, M_WAITOK | Z_ZERO);
3051 if (tlv_buffer_pointers == NULL) {
3052 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_pointers (%lu bytes)", sizeof(u_int8_t *) * policy_count);
3053 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3054 }
3055
3056 tlv_buffer_lengths = (u_int32_t *)kalloc_data(sizeof(u_int32_t) * policy_count, Z_NOWAIT | Z_ZERO);
3057 if (tlv_buffer_lengths == NULL) {
3058 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer_lengths (%lu bytes)", sizeof(u_int32_t) * policy_count);
3059 UNLOCK_AND_REPORT_ERROR(&necp_kernel_policy_lock, NECP_ERROR_INTERNAL);
3060 }
3061
3062 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
3063 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
3064
3065 memset(s: result_string, c: 0, MAX_RESULT_STRING_LEN);
3066 memset(s: proc_name_string, c: 0, MAXCOMLEN + 1);
3067
3068 necp_get_result_description(result_string, result: policy->result, result_parameter: policy->result_parameter);
3069 proc_name(pid: policy->session_pid, buf: proc_name_string, MAXCOMLEN);
3070
3071 u_int16_t proc_name_len = strlen(s: proc_name_string) + 1;
3072 u_int16_t result_string_len = strlen(s: result_string) + 1;
3073
3074 if (necp_debug) {
3075 NECPLOG(LOG_DEBUG, "Policy: process: %s, result: %s", proc_name_string, result_string);
3076 }
3077
3078 u_int32_t total_allocated_bytes = sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->id) + // NECP_TLV_POLICY_ID
3079 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->order) + // NECP_TLV_POLICY_ORDER
3080 sizeof(u_int8_t) + sizeof(u_int32_t) + sizeof(policy->session_order) + // NECP_TLV_POLICY_SESSION_ORDER
3081 sizeof(u_int8_t) + sizeof(u_int32_t) + result_string_len + // NECP_TLV_POLICY_RESULT_STRING
3082 sizeof(u_int8_t) + sizeof(u_int32_t) + proc_name_len + // NECP_TLV_POLICY_OWNER
3083 sizeof(u_int8_t) + sizeof(u_int32_t); // NECP_TLV_POLICY_CONDITION
3084
3085 // We now traverse the condition_mask to see how much space we need to allocate
3086 u_int64_t condition_mask = policy->condition_mask;
3087 u_int8_t num_conditions = 0;
3088 struct necp_string_id_mapping *account_id_entry = NULL;
3089 char if_name[IFXNAMSIZ];
3090 u_int32_t condition_tlv_length = 0;
3091 memset(s: if_name, c: 0, n: sizeof(if_name));
3092
3093 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3094 num_conditions++;
3095 } else {
3096 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3097 num_conditions++;
3098 }
3099 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3100 num_conditions++;
3101 }
3102 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3103 snprintf(if_name, IFXNAMSIZ, "%s%d", ifnet_name(interface: policy->cond_bound_interface), ifnet_unit(interface: policy->cond_bound_interface));
3104 condition_tlv_length += strlen(s: if_name) + 1;
3105 num_conditions++;
3106 }
3107 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3108 condition_tlv_length += sizeof(policy->cond_protocol);
3109 num_conditions++;
3110 }
3111 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3112 condition_tlv_length += sizeof(uuid_t);
3113 num_conditions++;
3114 }
3115 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3116 condition_tlv_length += sizeof(uuid_t);
3117 num_conditions++;
3118 }
3119 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3120 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3121 u_int32_t domain_len = strlen(s: policy->cond_domain) + 1;
3122 condition_tlv_length += domain_len;
3123 num_conditions++;
3124 }
3125 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3126 condition_tlv_length += sizeof(u_int32_t);
3127 num_conditions++;
3128 }
3129 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3130 u_int32_t url_len = strlen(s: policy->cond_url) + 1;
3131 condition_tlv_length += url_len;
3132 num_conditions++;
3133 }
3134 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3135 account_id_entry = necp_lookup_string_with_id_locked(list: &necp_account_id_list, local_id: policy->cond_account_id);
3136 u_int32_t account_id_len = 0;
3137 if (account_id_entry) {
3138 account_id_len = account_id_entry->string ? strlen(s: account_id_entry->string) + 1 : 0;
3139 }
3140 condition_tlv_length += account_id_len;
3141 num_conditions++;
3142 }
3143 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3144 condition_tlv_length += (sizeof(pid_t) + sizeof(int32_t));
3145 num_conditions++;
3146 }
3147 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3148 condition_tlv_length += sizeof(uid_t);
3149 num_conditions++;
3150 }
3151 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3152 condition_tlv_length += sizeof(uid_t);
3153 num_conditions++;
3154 }
3155 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3156 condition_tlv_length += sizeof(struct necp_policy_condition_tc_range);
3157 num_conditions++;
3158 }
3159 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3160 num_conditions++;
3161 }
3162 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3163 u_int32_t entitlement_len = strlen(s: policy->cond_custom_entitlement) + 1;
3164 condition_tlv_length += entitlement_len;
3165 num_conditions++;
3166 }
3167 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3168 num_conditions++;
3169 }
3170 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3171 num_conditions++;
3172 }
3173 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3174 condition_tlv_length += sizeof(struct necp_policy_condition_sdk_version);
3175 num_conditions++;
3176 }
3177 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3178 num_conditions++;
3179 }
3180 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3181 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3182 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3183 } else {
3184 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3185 }
3186 num_conditions++;
3187 }
3188 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3189 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3190 condition_tlv_length += sizeof(struct necp_policy_condition_addr_range);
3191 } else {
3192 condition_tlv_length += sizeof(struct necp_policy_condition_addr);
3193 }
3194 num_conditions++;
3195 }
3196 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3197 condition_tlv_length += sizeof(struct necp_policy_condition_agent_type);
3198 num_conditions++;
3199 }
3200 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3201 condition_tlv_length += sizeof(u_int32_t);
3202 num_conditions++;
3203 }
3204 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3205 num_conditions++;
3206 }
3207 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3208 num_conditions++;
3209 }
3210 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3211 u_int32_t identifier_len = strlen(s: policy->cond_signing_identifier) + 1;
3212 condition_tlv_length += identifier_len;
3213 num_conditions++;
3214 }
3215 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3216 condition_tlv_length += sizeof(u_int16_t);
3217 num_conditions++;
3218 }
3219 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3220 num_conditions++;
3221 }
3222 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3223 num_conditions++;
3224 }
3225 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3226 condition_tlv_length += sizeof(u_int16_t);
3227 num_conditions++;
3228 }
3229 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3230 condition_tlv_length += (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX);
3231 num_conditions++;
3232 }
3233 }
3234
3235 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.
3236 total_allocated_bytes += condition_tlv_length;
3237
3238 u_int8_t *tlv_buffer;
3239 tlv_buffer = (u_int8_t *)kalloc_data(total_allocated_bytes, Z_NOWAIT | Z_ZERO);
3240 if (tlv_buffer == NULL) {
3241 NECPLOG(LOG_DEBUG, "Failed to allocate tlv_buffer (%u bytes)", total_allocated_bytes);
3242 continue;
3243 }
3244
3245 u_int8_t *cursor = tlv_buffer;
3246 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ID, length: sizeof(policy->id), value: &policy->id, buffer: tlv_buffer, buffer_length: total_allocated_bytes);
3247 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_ORDER, length: sizeof(necp_policy_order), value: &policy->order, buffer: tlv_buffer, buffer_length: total_allocated_bytes);
3248 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_SESSION_ORDER, length: sizeof(policy->session_order), value: &policy->session_order, buffer: tlv_buffer, buffer_length: total_allocated_bytes);
3249 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_RESULT_STRING, length: result_string_len, value: result_string, buffer: tlv_buffer, buffer_length: total_allocated_bytes);
3250 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_OWNER, length: proc_name_len, value: proc_name_string, buffer: tlv_buffer, buffer_length: total_allocated_bytes);
3251
3252#define N_QUICK 256
3253 u_int8_t q_cond_buf[N_QUICK]; // Minor optimization
3254
3255 u_int8_t *cond_buf; // To be used for condition TLVs
3256 if (condition_tlv_length <= N_QUICK) {
3257 cond_buf = q_cond_buf;
3258 } else {
3259 cond_buf = (u_int8_t *)kalloc_data(condition_tlv_length, Z_NOWAIT);
3260 if (cond_buf == NULL) {
3261 NECPLOG(LOG_DEBUG, "Failed to allocate cond_buffer (%u bytes)", condition_tlv_length);
3262 kfree_data(tlv_buffer, total_allocated_bytes);
3263 continue;
3264 }
3265 }
3266
3267 memset(s: cond_buf, c: 0, n: condition_tlv_length);
3268 u_int8_t *cond_buf_cursor = cond_buf;
3269 if (condition_mask == NECP_POLICY_CONDITION_DEFAULT) {
3270 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_DEFAULT, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3271 } else {
3272 if (condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) {
3273 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_ALL_INTERFACES, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3274 }
3275 if (condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
3276 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_HAS_CLIENT, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3277 }
3278 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
3279 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_NETWORKS, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3280 }
3281 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
3282 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE, length: strlen(s: if_name) + 1,
3283 value: if_name, buffer: cond_buf, buffer_length: condition_tlv_length);
3284 }
3285 if (condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
3286 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_IP_PROTOCOL, length: sizeof(policy->cond_protocol), value: &policy->cond_protocol,
3287 buffer: cond_buf, buffer_length: condition_tlv_length);
3288 }
3289 if (condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
3290 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(local_id: policy->cond_app_id);
3291 if (entry != NULL) {
3292 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_APPLICATION, length: sizeof(entry->uuid), value: entry->uuid,
3293 buffer: cond_buf, buffer_length: condition_tlv_length);
3294 }
3295 }
3296 if (condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
3297 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(local_id: policy->cond_real_app_id);
3298 if (entry != NULL) {
3299 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_REAL_APPLICATION, length: sizeof(entry->uuid), value: entry->uuid,
3300 buffer: cond_buf, buffer_length: condition_tlv_length);
3301 }
3302 }
3303 if ((condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
3304 (condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
3305 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN, length: strlen(s: policy->cond_domain) + 1, value: policy->cond_domain,
3306 buffer: cond_buf, buffer_length: condition_tlv_length);
3307 }
3308 if (condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
3309 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_DOMAIN_FILTER, length: sizeof(policy->cond_domain_filter), value: &policy->cond_domain_filter,
3310 buffer: cond_buf, buffer_length: condition_tlv_length);
3311 }
3312 if (condition_mask & NECP_KERNEL_CONDITION_URL) {
3313 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_URL, length: strlen(s: policy->cond_url) + 1, value: policy->cond_url,
3314 buffer: cond_buf, buffer_length: condition_tlv_length);
3315 }
3316 if (condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
3317 if (account_id_entry != NULL) {
3318 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_ACCOUNT, length: strlen(s: account_id_entry->string) + 1, value: account_id_entry->string,
3319 buffer: cond_buf, buffer_length: condition_tlv_length);
3320 }
3321 }
3322 if (condition_mask & NECP_KERNEL_CONDITION_PID) {
3323 uint8_t pid_buffer[sizeof(policy->cond_pid) + sizeof(policy->cond_pid_version)] = { };
3324 memcpy(dst: pid_buffer, src: &policy->cond_pid, n: sizeof(policy->cond_pid));
3325 memcpy(dst: pid_buffer + sizeof(policy->cond_pid), src: &policy->cond_pid_version, n: sizeof(policy->cond_pid_version));
3326 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_PID, length: sizeof(pid_buffer), value: &pid_buffer,
3327 buffer: cond_buf, buffer_length: condition_tlv_length);
3328 }
3329 if (condition_mask & NECP_KERNEL_CONDITION_UID) {
3330 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_UID, length: sizeof(policy->cond_uid), value: &policy->cond_uid,
3331 buffer: cond_buf, buffer_length: condition_tlv_length);
3332 }
3333 if (condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
3334 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_REAL_UID, length: sizeof(policy->cond_real_uid), value: &policy->cond_real_uid,
3335 buffer: cond_buf, buffer_length: condition_tlv_length);
3336 }
3337 if (condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
3338 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_TRAFFIC_CLASS, length: sizeof(policy->cond_traffic_class), value: &policy->cond_traffic_class,
3339 buffer: cond_buf, buffer_length: condition_tlv_length);
3340 }
3341 if (condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
3342 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, length: 0, value: "",
3343 buffer: cond_buf, buffer_length: condition_tlv_length);
3344 }
3345 if (condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
3346 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_ENTITLEMENT, length: strlen(s: policy->cond_custom_entitlement) + 1, value: policy->cond_custom_entitlement,
3347 buffer: cond_buf, buffer_length: condition_tlv_length);
3348 }
3349 if (condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
3350 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_PLATFORM_BINARY, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3351 }
3352 if (condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
3353 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3354 }
3355 if (condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
3356 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_SDK_VERSION,
3357 length: sizeof(policy->cond_sdk_version), value: &policy->cond_sdk_version,
3358 buffer: cond_buf, buffer_length: condition_tlv_length);
3359 }
3360 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
3361 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
3362 struct necp_policy_condition_addr_range range;
3363 memcpy(dst: &range.start_address, src: &policy->cond_local_start, n: sizeof(policy->cond_local_start));
3364 memcpy(dst: &range.end_address, src: &policy->cond_local_end, n: sizeof(policy->cond_local_end));
3365 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE, length: sizeof(range), value: &range,
3366 buffer: cond_buf, buffer_length: condition_tlv_length);
3367 } else {
3368 struct necp_policy_condition_addr addr;
3369 addr.prefix = policy->cond_local_prefix;
3370 memcpy(dst: &addr.address, src: &policy->cond_local_start, n: sizeof(policy->cond_local_start));
3371 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_LOCAL_ADDR, length: sizeof(addr), value: &addr,
3372 buffer: cond_buf, buffer_length: condition_tlv_length);
3373 }
3374 }
3375 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
3376 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
3377 struct necp_policy_condition_addr_range range;
3378 memcpy(dst: &range.start_address, src: &policy->cond_remote_start, n: sizeof(policy->cond_remote_start));
3379 memcpy(dst: &range.end_address, src: &policy->cond_remote_end, n: sizeof(policy->cond_remote_end));
3380 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE, length: sizeof(range), value: &range,
3381 buffer: cond_buf, buffer_length: condition_tlv_length);
3382 } else {
3383 struct necp_policy_condition_addr addr;
3384 addr.prefix = policy->cond_remote_prefix;
3385 memcpy(dst: &addr.address, src: &policy->cond_remote_start, n: sizeof(policy->cond_remote_start));
3386 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_REMOTE_ADDR, length: sizeof(addr), value: &addr,
3387 buffer: cond_buf, buffer_length: condition_tlv_length);
3388 }
3389 }
3390 if (condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
3391 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_AGENT_TYPE,
3392 length: sizeof(policy->cond_agent_type), value: &policy->cond_agent_type,
3393 buffer: cond_buf, buffer_length: condition_tlv_length);
3394 }
3395 if (condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
3396 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_CLIENT_FLAGS, length: sizeof(policy->cond_client_flags), value: &policy->cond_client_flags, buffer: cond_buf, buffer_length: condition_tlv_length);
3397 }
3398 if (condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
3399 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3400 }
3401 if (condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
3402 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3403 }
3404 if (condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
3405 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_SIGNING_IDENTIFIER, length: strlen(s: policy->cond_signing_identifier) + 1, value: policy->cond_signing_identifier,
3406 buffer: cond_buf, buffer_length: condition_tlv_length);
3407 }
3408 if (condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
3409 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_PACKET_FILTER_TAGS, length: sizeof(policy->cond_packet_filter_tags), value: &policy->cond_packet_filter_tags, buffer: cond_buf, buffer_length: condition_tlv_length);
3410 }
3411 if (condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
3412 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3413 }
3414 if (condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
3415 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY, length: 0, value: "", buffer: cond_buf, buffer_length: condition_tlv_length);
3416 }
3417 if (condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
3418 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_SCHEME_PORT, length: sizeof(policy->cond_scheme_port), value: &policy->cond_scheme_port, buffer: cond_buf, buffer_length: condition_tlv_length);
3419 }
3420 if (condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
3421 uint32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
3422 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS] = policy->cond_bound_interface_flags;
3423 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS] = policy->cond_bound_interface_eflags;
3424 flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS] = policy->cond_bound_interface_xflags;
3425 cond_buf_cursor = necp_buffer_write_tlv(cursor: cond_buf_cursor, NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS, length: sizeof(flags), value: &flags,
3426 buffer: cond_buf, buffer_length: condition_tlv_length);
3427 }
3428 }
3429
3430 cursor = necp_buffer_write_tlv(cursor, NECP_TLV_POLICY_CONDITION, length: cond_buf_cursor - cond_buf, value: cond_buf, buffer: tlv_buffer, buffer_length: total_allocated_bytes);
3431 if (cond_buf != q_cond_buf) {
3432 kfree_data(cond_buf, condition_tlv_length);
3433 }
3434
3435 tlv_buffer_pointers[policy_i] = tlv_buffer;
3436 tlv_buffer_lengths[policy_i] = (cursor - tlv_buffer);
3437
3438 // This is the length of the TLV for NECP_TLV_POLICY_DUMP
3439 total_tlv_len += sizeof(u_int8_t) + sizeof(u_int32_t) + (cursor - tlv_buffer);
3440 }
3441
3442 // UNLOCK
3443 lck_rw_done(lck: &necp_kernel_policy_lock);
3444
3445 // Copy out
3446 if (out_buffer != 0) {
3447 if (out_buffer_length < total_tlv_len + sizeof(u_int32_t)) {
3448 NECPLOG(LOG_DEBUG, "out_buffer_length too small (%lu < %lu)", out_buffer_length, total_tlv_len + sizeof(u_int32_t));
3449 REPORT_ERROR(NECP_ERROR_INVALID_TLV);
3450 }
3451
3452 // Allow malloc to wait, since the total buffer may be large and we are not holding any locks
3453 result_buf = (u_int8_t *)kalloc_data(total_tlv_len + sizeof(u_int32_t), Z_WAITOK | Z_ZERO);
3454 if (result_buf == NULL) {
3455 NECPLOG(LOG_DEBUG, "Failed to allocate result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3456 REPORT_ERROR(NECP_ERROR_INTERNAL);
3457 }
3458
3459 // Add four bytes for total length at the start
3460 memcpy(dst: result_buf, src: &total_tlv_len, n: sizeof(u_int32_t));
3461
3462 // Copy the TLVs
3463 result_buf_cursor = result_buf + sizeof(u_int32_t);
3464 for (int i = 0; i < policy_count; i++) {
3465 if (tlv_buffer_pointers[i] != NULL) {
3466 result_buf_cursor = necp_buffer_write_tlv(cursor: result_buf_cursor, NECP_TLV_POLICY_DUMP, length: tlv_buffer_lengths[i], value: tlv_buffer_pointers[i],
3467 buffer: result_buf, buffer_length: total_tlv_len + sizeof(u_int32_t));
3468 }
3469 }
3470
3471 int copy_error = copyout(result_buf, out_buffer, total_tlv_len + sizeof(u_int32_t));
3472 if (copy_error) {
3473 NECPLOG(LOG_DEBUG, "Failed to copy out result_buffer (%lu bytes)", total_tlv_len + sizeof(u_int32_t));
3474 REPORT_ERROR(NECP_ERROR_INTERNAL);
3475 }
3476 }
3477
3478done:
3479
3480 if (error_occured) {
3481 error_code = necp_get_posix_error_for_necp_error(response_error);
3482 }
3483
3484 if (result_buf != NULL) {
3485 kfree_data(result_buf, total_tlv_len + sizeof(u_int32_t));
3486 }
3487
3488 if (tlv_buffer_pointers != NULL) {
3489 for (int i = 0; i < policy_count; i++) {
3490 if (tlv_buffer_pointers[i] != NULL) {
3491 kfree_data_addr(tlv_buffer_pointers[i]);
3492 tlv_buffer_pointers[i] = NULL;
3493 }
3494 }
3495 kfree_type(u_int8_t *, policy_count, tlv_buffer_pointers);
3496 }
3497
3498 if (tlv_buffer_lengths != NULL) {
3499 kfree_data(tlv_buffer_lengths, sizeof(*tlv_buffer_lengths) * policy_count);
3500 }
3501#undef N_QUICK
3502#undef RESET_COND_BUF
3503#undef REPORT_ERROR
3504#undef UNLOCK_AND_REPORT_ERROR
3505
3506 return error_code;
3507}
3508
3509static struct necp_session_policy *
3510necp_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)
3511{
3512 struct necp_session_policy *new_policy = NULL;
3513 struct necp_session_policy *tmp_policy = NULL;
3514
3515 if (session == NULL || conditions_array == NULL || result == NULL || result_size == 0) {
3516 goto done;
3517 }
3518
3519 new_policy = zalloc_flags(necp_session_policy_zone, Z_WAITOK | Z_ZERO);
3520 new_policy->applied = FALSE;
3521 new_policy->pending_deletion = FALSE;
3522 new_policy->pending_update = FALSE;
3523 new_policy->order = order;
3524 new_policy->conditions = conditions_array;
3525 new_policy->conditions_size = conditions_array_size;
3526 new_policy->route_rules = route_rules_array;
3527 new_policy->route_rules_size = route_rules_array_size;
3528 new_policy->result = result;
3529 new_policy->result_size = result_size;
3530 new_policy->local_id = necp_policy_get_new_id(session);
3531
3532 LIST_INSERT_SORTED_ASCENDING(&session->policies, new_policy, chain, order, tmp_policy);
3533
3534 session->dirty = TRUE;
3535
3536 if (necp_debug) {
3537 NECPLOG(LOG_DEBUG, "Created NECP policy, order %d", order);
3538 }
3539done:
3540 return new_policy;
3541}
3542
3543static struct necp_session_policy *
3544necp_policy_find(struct necp_session *session, necp_policy_id policy_id)
3545{
3546 struct necp_session_policy *policy = NULL;
3547 if (policy_id == 0) {
3548 return NULL;
3549 }
3550
3551 LIST_FOREACH(policy, &session->policies, chain) {
3552 if (policy->local_id == policy_id) {
3553 return policy;
3554 }
3555 }
3556
3557 return NULL;
3558}
3559
3560static inline u_int8_t
3561necp_policy_get_result_type(struct necp_session_policy *policy)
3562{
3563 return policy ? necp_policy_result_get_type_from_buffer(buffer: policy->result, length: policy->result_size) : 0;
3564}
3565
3566static inline u_int32_t
3567necp_policy_get_result_parameter_length(struct necp_session_policy *policy)
3568{
3569 return policy ? necp_policy_result_get_parameter_length_from_buffer(buffer: policy->result, length: policy->result_size) : 0;
3570}
3571
3572static bool
3573necp_policy_get_result_parameter(struct necp_session_policy *policy, u_int8_t *parameter_buffer, u_int32_t parameter_buffer_length)
3574{
3575 if (policy) {
3576 u_int32_t parameter_length = necp_policy_result_get_parameter_length_from_buffer(buffer: policy->result, length: policy->result_size);
3577 if (parameter_buffer_length >= parameter_length) {
3578 u_int8_t *parameter = necp_policy_result_get_parameter_pointer_from_buffer(buffer: policy->result, length: policy->result_size);
3579 if (parameter && parameter_buffer) {
3580 memcpy(dst: parameter_buffer, src: parameter, n: parameter_length);
3581 return TRUE;
3582 }
3583 }
3584 }
3585
3586 return FALSE;
3587}
3588
3589static bool
3590necp_policy_mark_for_deletion(struct necp_session *session, struct necp_session_policy *policy)
3591{
3592 if (session == NULL || policy == NULL) {
3593 return FALSE;
3594 }
3595
3596 policy->pending_deletion = TRUE;
3597 session->dirty = TRUE;
3598
3599 if (necp_debug) {
3600 NECPLOG0(LOG_DEBUG, "Marked NECP policy for removal");
3601 }
3602 return TRUE;
3603}
3604
3605static bool
3606necp_policy_mark_all_for_deletion(struct necp_session *session)
3607{
3608 struct necp_session_policy *policy = NULL;
3609 struct necp_session_policy *temp_policy = NULL;
3610
3611 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
3612 necp_policy_mark_for_deletion(session, policy);
3613 }
3614
3615 return TRUE;
3616}
3617
3618static bool
3619necp_policy_delete(struct necp_session *session, struct necp_session_policy *policy)
3620{
3621 if (session == NULL || policy == NULL) {
3622 return FALSE;
3623 }
3624
3625 LIST_REMOVE(policy, chain);
3626
3627 if (policy->result) {
3628 kfree_data(policy->result, policy->result_size);
3629 policy->result = NULL;
3630 }
3631
3632 if (policy->conditions) {
3633 kfree_data(policy->conditions, policy->conditions_size);
3634 policy->conditions = NULL;
3635 }
3636
3637 if (policy->route_rules) {
3638 kfree_data(policy->route_rules, policy->route_rules_size);
3639 policy->route_rules = NULL;
3640 }
3641
3642 zfree(necp_session_policy_zone, policy);
3643
3644 if (necp_debug) {
3645 NECPLOG0(LOG_DEBUG, "Removed NECP policy");
3646 }
3647 return TRUE;
3648}
3649
3650static bool
3651necp_policy_unapply(struct necp_session_policy *policy)
3652{
3653 int i = 0;
3654 if (policy == NULL) {
3655 return FALSE;
3656 }
3657
3658 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3659
3660 // Release local uuid mappings
3661 if (!uuid_is_null(uu: policy->applied_app_uuid)) {
3662 bool removed_mapping = FALSE;
3663 if (necp_remove_uuid_app_id_mapping(uuid: policy->applied_app_uuid, removed_mapping: &removed_mapping, TRUE) && removed_mapping) {
3664 necp_uuid_app_id_mappings_dirty = TRUE;
3665 necp_num_uuid_app_id_mappings--;
3666 }
3667 uuid_clear(uu: policy->applied_app_uuid);
3668 }
3669 if (!uuid_is_null(uu: policy->applied_real_app_uuid)) {
3670 necp_remove_uuid_app_id_mapping(uuid: policy->applied_real_app_uuid, NULL, FALSE);
3671 uuid_clear(uu: policy->applied_real_app_uuid);
3672 }
3673 if (!uuid_is_null(uu: policy->applied_result_uuid)) {
3674 necp_remove_uuid_service_id_mapping(uuid: policy->applied_result_uuid);
3675 uuid_clear(uu: policy->applied_result_uuid);
3676 }
3677
3678 // Release string mappings
3679 if (policy->applied_account != NULL) {
3680 necp_remove_string_to_id_mapping(list: &necp_account_id_list, domain: policy->applied_account);
3681 kfree_data(policy->applied_account, policy->applied_account_size);
3682 policy->applied_account = NULL;
3683 }
3684
3685 // Release route rule
3686 if (policy->applied_route_rules_id != 0) {
3687 necp_remove_route_rule(list: &necp_route_rules, route_rule_id: policy->applied_route_rules_id);
3688 policy->applied_route_rules_id = 0;
3689 }
3690
3691 // Remove socket policies
3692 for (i = 0; i < MAX_KERNEL_SOCKET_POLICIES; i++) {
3693 if (policy->kernel_socket_policies[i] != 0) {
3694 necp_kernel_socket_policy_delete(policy_id: policy->kernel_socket_policies[i]);
3695 policy->kernel_socket_policies[i] = 0;
3696 }
3697 }
3698
3699 // Remove IP output policies
3700 for (i = 0; i < MAX_KERNEL_IP_OUTPUT_POLICIES; i++) {
3701 if (policy->kernel_ip_output_policies[i] != 0) {
3702 necp_kernel_ip_output_policy_delete(policy_id: policy->kernel_ip_output_policies[i]);
3703 policy->kernel_ip_output_policies[i] = 0;
3704 }
3705 }
3706
3707 policy->applied = FALSE;
3708
3709 return TRUE;
3710}
3711
3712#define NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION 0
3713#define NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION 1
3714#define NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION 2
3715#define NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS 3
3716struct necp_policy_result_ip_tunnel {
3717 u_int32_t secondary_result;
3718 char interface_name[IFXNAMSIZ];
3719} __attribute__((__packed__));
3720
3721struct necp_policy_result_service {
3722 uuid_t identifier;
3723 u_int32_t data;
3724} __attribute__((__packed__));
3725
3726static bool
3727necp_policy_apply(struct necp_session *session, struct necp_session_policy *policy)
3728{
3729 bool socket_only_conditions = FALSE;
3730 bool socket_ip_conditions = FALSE;
3731
3732 bool socket_layer_non_id_conditions = FALSE;
3733 bool ip_output_layer_non_id_conditions = FALSE;
3734 bool ip_output_layer_non_id_only = FALSE;
3735 bool ip_output_layer_id_condition = FALSE;
3736 bool ip_output_layer_tunnel_condition_from_id = FALSE;
3737 bool ip_output_layer_tunnel_condition_from_non_id = FALSE;
3738 necp_kernel_policy_id cond_ip_output_layer_id = NECP_KERNEL_POLICY_ID_NONE;
3739
3740 u_int64_t master_condition_mask = 0;
3741 u_int64_t master_condition_negated_mask = 0;
3742 ifnet_t cond_bound_interface = NULL;
3743 u_int32_t cond_account_id = 0;
3744 char *cond_domain = NULL;
3745 u_int32_t cond_domain_filter = 0;
3746 char *cond_url = NULL;
3747 char *cond_custom_entitlement = NULL;
3748 char *cond_signing_identifier = NULL;
3749 pid_t cond_pid = 0;
3750 int32_t cond_pid_version = 0;
3751 uid_t cond_uid = 0;
3752 uid_t cond_real_uid = 0;
3753 necp_app_id cond_app_id = 0;
3754 necp_app_id cond_real_app_id = 0;
3755 struct necp_policy_condition_tc_range cond_traffic_class;
3756 cond_traffic_class.start_tc = 0;
3757 cond_traffic_class.end_tc = 0;
3758 u_int16_t cond_protocol = 0;
3759 union necp_sockaddr_union cond_local_start;
3760 union necp_sockaddr_union cond_local_end;
3761 u_int8_t cond_local_prefix = 0;
3762 union necp_sockaddr_union cond_remote_start;
3763 union necp_sockaddr_union cond_remote_end;
3764 u_int8_t cond_remote_prefix = 0;
3765 u_int32_t cond_client_flags = 0;
3766 u_int32_t offset = 0;
3767 u_int8_t ultimate_result = 0;
3768 u_int32_t secondary_result = 0;
3769 struct necp_policy_condition_agent_type cond_agent_type = {};
3770 struct necp_policy_condition_sdk_version cond_sdk_version = {};
3771 u_int16_t cond_packet_filter_tags = 0;
3772 u_int16_t cond_scheme_port = 0;
3773 u_int32_t cond_bound_interface_flags = 0;
3774 u_int32_t cond_bound_interface_eflags = 0;
3775 u_int32_t cond_bound_interface_xflags = 0;
3776 necp_kernel_policy_result_parameter secondary_result_parameter;
3777 memset(s: &secondary_result_parameter, c: 0, n: sizeof(secondary_result_parameter));
3778 u_int32_t cond_last_interface_index = 0;
3779 necp_kernel_policy_result_parameter ultimate_result_parameter;
3780 memset(s: &ultimate_result_parameter, c: 0, n: sizeof(ultimate_result_parameter));
3781
3782 if (policy == NULL) {
3783 return FALSE;
3784 }
3785
3786 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
3787
3788 // Process conditions
3789 while (offset < policy->conditions_size) {
3790 u_int32_t length = 0;
3791 u_int8_t *value = necp_buffer_get_tlv_value(buffer: policy->conditions, tlv_offset: offset, value_size: &length);
3792
3793 u_int8_t condition_type = necp_policy_condition_get_type_from_buffer(buffer: value, length);
3794 u_int8_t condition_flags = necp_policy_condition_get_flags_from_buffer(buffer: value, length);
3795 bool condition_is_negative = condition_flags & NECP_POLICY_CONDITION_FLAGS_NEGATIVE;
3796 u_int32_t condition_length = necp_policy_condition_get_value_length_from_buffer(buffer: value, length);
3797 u_int8_t *condition_value = necp_policy_condition_get_value_pointer_from_buffer(buffer: value, length);
3798 switch (condition_type) {
3799 case NECP_POLICY_CONDITION_DEFAULT: {
3800 socket_ip_conditions = TRUE;
3801 break;
3802 }
3803 case NECP_POLICY_CONDITION_ALL_INTERFACES: {
3804 master_condition_mask |= NECP_KERNEL_CONDITION_ALL_INTERFACES;
3805 socket_ip_conditions = TRUE;
3806 break;
3807 }
3808 case NECP_POLICY_CONDITION_HAS_CLIENT: {
3809 master_condition_mask |= NECP_KERNEL_CONDITION_HAS_CLIENT;
3810 socket_only_conditions = TRUE;
3811 break;
3812 }
3813 case NECP_POLICY_CONDITION_ENTITLEMENT: {
3814 if (condition_length > 0) {
3815 if (cond_custom_entitlement == NULL) {
3816 cond_custom_entitlement = necp_copy_string(string: (char *)condition_value, length: condition_length);
3817 if (cond_custom_entitlement != NULL) {
3818 master_condition_mask |= NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT;
3819 socket_only_conditions = TRUE;
3820 }
3821 }
3822 } else {
3823 master_condition_mask |= NECP_KERNEL_CONDITION_ENTITLEMENT;
3824 socket_only_conditions = TRUE;
3825 }
3826 break;
3827 }
3828 case NECP_POLICY_CONDITION_PLATFORM_BINARY: {
3829 master_condition_mask |= NECP_KERNEL_CONDITION_PLATFORM_BINARY;
3830 socket_only_conditions = TRUE;
3831 break;
3832 }
3833 case NECP_POLICY_CONDITION_SYSTEM_SIGNED_RESULT: {
3834 master_condition_mask |= NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT;
3835 socket_only_conditions = TRUE;
3836 break;
3837 }
3838 case NECP_POLICY_CONDITION_SDK_VERSION: {
3839 if (condition_length >= sizeof(cond_sdk_version)) {
3840 master_condition_mask |= NECP_KERNEL_CONDITION_SDK_VERSION;
3841 memcpy(dst: &cond_sdk_version, src: condition_value, n: sizeof(cond_sdk_version));
3842 socket_only_conditions = TRUE;
3843 }
3844 break;
3845 }
3846 case NECP_POLICY_CONDITION_DOMAIN: {
3847 // Make sure there is only one such rule
3848 if (condition_length > 0 && cond_domain == NULL) {
3849 const bool condition_is_exact = condition_flags & NECP_POLICY_CONDITION_FLAGS_EXACT;
3850
3851 u_int64_t mask_value = condition_is_exact ? NECP_KERNEL_CONDITION_EXACT_DOMAIN : NECP_KERNEL_CONDITION_DOMAIN;
3852 cond_domain = necp_create_trimmed_domain(string: (char *)condition_value, length: condition_length);
3853 if (cond_domain != NULL) {
3854 master_condition_mask |= mask_value;
3855 if (condition_is_negative) {
3856 master_condition_negated_mask |= mask_value;
3857 }
3858 socket_only_conditions = TRUE;
3859 }
3860 }
3861 break;
3862 }
3863 case NECP_POLICY_CONDITION_DOMAIN_FILTER: {
3864 // Make sure there is only one such rule
3865 if (condition_length >= sizeof(cond_domain_filter) && cond_domain_filter == 0) {
3866 memcpy(dst: &cond_domain_filter, src: condition_value, n: sizeof(cond_domain_filter));
3867 if (cond_domain_filter != 0) {
3868 master_condition_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
3869 if (condition_is_negative) {
3870 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DOMAIN_FILTER;
3871 }
3872 socket_only_conditions = TRUE;
3873 }
3874 }
3875 break;
3876 }
3877 case NECP_POLICY_CONDITION_URL: {
3878 // Make sure there is only one such rule
3879 if (condition_length > 0 && cond_url == NULL) {
3880 u_int64_t mask_value = NECP_KERNEL_CONDITION_URL;
3881 cond_url = necp_create_trimmed_domain(string: (char *)condition_value, length: condition_length);
3882 if (cond_url != NULL) {
3883 master_condition_mask |= mask_value;
3884 if (condition_is_negative) {
3885 master_condition_negated_mask |= mask_value;
3886 }
3887 socket_only_conditions = TRUE;
3888 }
3889 }
3890 break;
3891 }
3892 case NECP_POLICY_CONDITION_ACCOUNT: {
3893 // Make sure there is only one such rule
3894 if (condition_length > 0 && condition_length < UINT32_MAX && cond_account_id == 0 && policy->applied_account == NULL) {
3895 char *string = NULL;
3896 string = (char *)kalloc_data(condition_length + 1, Z_WAITOK);
3897 if (string != NULL) {
3898 memcpy(dst: string, src: condition_value, n: condition_length);
3899 string[condition_length] = 0;
3900 cond_account_id = necp_create_string_to_id_mapping(list: &necp_account_id_list, domain: string);
3901 if (cond_account_id != 0) {
3902 policy->applied_account = string; // Save the string in parent policy
3903 policy->applied_account_size = condition_length + 1;
3904 master_condition_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
3905 if (condition_is_negative) {
3906 master_condition_negated_mask |= NECP_KERNEL_CONDITION_ACCOUNT_ID;
3907 }
3908 socket_only_conditions = TRUE;
3909 } else {
3910 kfree_data(string, condition_length + 1);
3911 }
3912 }
3913 }
3914 break;
3915 }
3916 case NECP_POLICY_CONDITION_APPLICATION: {
3917 // Make sure there is only one such rule, because we save the uuid in the policy
3918 if (condition_length >= sizeof(uuid_t) && cond_app_id == 0) {
3919 bool allocated_mapping = FALSE;
3920 uuid_t application_uuid;
3921 memcpy(dst: application_uuid, src: condition_value, n: sizeof(uuid_t));
3922 cond_app_id = necp_create_uuid_app_id_mapping(uuid: application_uuid, allocated_mapping: &allocated_mapping, TRUE);
3923 if (cond_app_id != 0) {
3924 if (allocated_mapping) {
3925 necp_uuid_app_id_mappings_dirty = TRUE;
3926 necp_num_uuid_app_id_mappings++;
3927 }
3928 uuid_copy(dst: policy->applied_app_uuid, src: application_uuid);
3929 master_condition_mask |= NECP_KERNEL_CONDITION_APP_ID;
3930 if (condition_is_negative) {
3931 master_condition_negated_mask |= NECP_KERNEL_CONDITION_APP_ID;
3932 }
3933 socket_only_conditions = TRUE;
3934 }
3935 }
3936 break;
3937 }
3938 case NECP_POLICY_CONDITION_REAL_APPLICATION: {
3939 // Make sure there is only one such rule, because we save the uuid in the policy
3940 if (condition_length >= sizeof(uuid_t) && cond_real_app_id == 0) {
3941 uuid_t real_application_uuid;
3942 memcpy(dst: real_application_uuid, src: condition_value, n: sizeof(uuid_t));
3943 cond_real_app_id = necp_create_uuid_app_id_mapping(uuid: real_application_uuid, NULL, FALSE);
3944 if (cond_real_app_id != 0) {
3945 uuid_copy(dst: policy->applied_real_app_uuid, src: real_application_uuid);
3946 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
3947 if (condition_is_negative) {
3948 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_APP_ID;
3949 }
3950 socket_only_conditions = TRUE;
3951 }
3952 }
3953 break;
3954 }
3955 case NECP_POLICY_CONDITION_PID: {
3956 if (condition_length >= sizeof(pid_t)) {
3957 master_condition_mask |= NECP_KERNEL_CONDITION_PID;
3958 if (condition_is_negative) {
3959 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PID;
3960 }
3961 memcpy(dst: &cond_pid, src: condition_value, n: sizeof(cond_pid));
3962 if (condition_length >= (sizeof(pid_t) + sizeof(cond_pid_version))) {
3963 memcpy(dst: &cond_pid_version, src: (condition_value + sizeof(pid_t)), n: sizeof(cond_pid_version));
3964 }
3965 socket_only_conditions = TRUE;
3966 }
3967 break;
3968 }
3969 case NECP_POLICY_CONDITION_UID: {
3970 if (condition_length >= sizeof(uid_t)) {
3971 master_condition_mask |= NECP_KERNEL_CONDITION_UID;
3972 if (condition_is_negative) {
3973 master_condition_negated_mask |= NECP_KERNEL_CONDITION_UID;
3974 }
3975 memcpy(dst: &cond_uid, src: condition_value, n: sizeof(cond_uid));
3976 socket_only_conditions = TRUE;
3977 }
3978 break;
3979 }
3980 case NECP_POLICY_CONDITION_REAL_UID: {
3981 if (condition_length >= sizeof(uid_t)) {
3982 master_condition_mask |= NECP_KERNEL_CONDITION_REAL_UID;
3983 if (condition_is_negative) {
3984 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REAL_UID;
3985 }
3986 memcpy(dst: &cond_real_uid, src: condition_value, n: sizeof(cond_real_uid));
3987 socket_only_conditions = TRUE;
3988 }
3989 break;
3990 }
3991 case NECP_POLICY_CONDITION_TRAFFIC_CLASS: {
3992 if (condition_length >= sizeof(struct necp_policy_condition_tc_range)) {
3993 master_condition_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
3994 if (condition_is_negative) {
3995 master_condition_negated_mask |= NECP_KERNEL_CONDITION_TRAFFIC_CLASS;
3996 }
3997 memcpy(dst: &cond_traffic_class, src: condition_value, n: sizeof(cond_traffic_class));
3998 socket_only_conditions = TRUE;
3999 }
4000 break;
4001 }
4002 case NECP_POLICY_CONDITION_BOUND_INTERFACE: {
4003 if (condition_length <= IFXNAMSIZ && condition_length > 0) {
4004 char interface_name[IFXNAMSIZ];
4005 memcpy(dst: interface_name, src: condition_value, n: condition_length);
4006 interface_name[condition_length - 1] = 0; // Make sure the string is NULL terminated
4007 if (ifnet_find_by_name(ifname: interface_name, interface: &cond_bound_interface) == 0) {
4008 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4009 if (condition_is_negative) {
4010 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4011 }
4012 }
4013 socket_ip_conditions = TRUE;
4014 }
4015 break;
4016 }
4017 case NECP_POLICY_CONDITION_IP_PROTOCOL:
4018 case NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL: {
4019 if (condition_length >= sizeof(u_int16_t)) {
4020 master_condition_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4021 if (condition_is_negative) {
4022 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PROTOCOL;
4023 }
4024 memcpy(dst: &cond_protocol, src: condition_value, n: sizeof(cond_protocol));
4025 if (condition_type == NECP_POLICY_CONDITION_FLOW_IP_PROTOCOL) {
4026 socket_only_conditions = TRUE;
4027 } else {
4028 socket_ip_conditions = TRUE;
4029 }
4030 }
4031 break;
4032 }
4033 case NECP_POLICY_CONDITION_LOCAL_NETWORKS: {
4034 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_NETWORKS;
4035 socket_ip_conditions = TRUE;
4036 break;
4037 }
4038 case NECP_POLICY_CONDITION_LOCAL_ADDR:
4039 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR: {
4040 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4041 if (!necp_address_is_valid(&address_struct->address.sa)) {
4042 break;
4043 }
4044
4045 cond_local_prefix = address_struct->prefix;
4046 memcpy(dst: &cond_local_start, src: &address_struct->address, n: sizeof(address_struct->address));
4047 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4048 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4049 if (condition_is_negative) {
4050 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4051 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4052 }
4053 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR) {
4054 socket_only_conditions = TRUE;
4055 } else {
4056 socket_ip_conditions = TRUE;
4057 }
4058 break;
4059 }
4060 case NECP_POLICY_CONDITION_REMOTE_ADDR:
4061 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR: {
4062 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)condition_value;
4063 if (!necp_address_is_valid(&address_struct->address.sa)) {
4064 break;
4065 }
4066
4067 cond_remote_prefix = address_struct->prefix;
4068 memcpy(dst: &cond_remote_start, src: &address_struct->address, n: sizeof(address_struct->address));
4069 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4070 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4071 if (condition_is_negative) {
4072 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4073 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4074 }
4075 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR) {
4076 socket_only_conditions = TRUE;
4077 } else {
4078 socket_ip_conditions = TRUE;
4079 }
4080 break;
4081 }
4082 case NECP_POLICY_CONDITION_LOCAL_ADDR_RANGE:
4083 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE: {
4084 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4085 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4086 !necp_address_is_valid(&address_struct->end_address.sa)) {
4087 break;
4088 }
4089
4090 memcpy(dst: &cond_local_start, src: &address_struct->start_address, n: sizeof(address_struct->start_address));
4091 memcpy(dst: &cond_local_end, src: &address_struct->end_address, n: sizeof(address_struct->end_address));
4092 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4093 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4094 if (condition_is_negative) {
4095 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_START;
4096 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_END;
4097 }
4098 if (condition_type == NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_RANGE) {
4099 socket_only_conditions = TRUE;
4100 } else {
4101 socket_ip_conditions = TRUE;
4102 }
4103 break;
4104 }
4105 case NECP_POLICY_CONDITION_REMOTE_ADDR_RANGE:
4106 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE: {
4107 struct necp_policy_condition_addr_range *address_struct = (struct necp_policy_condition_addr_range *)(void *)condition_value;
4108 if (!necp_address_is_valid(&address_struct->start_address.sa) ||
4109 !necp_address_is_valid(&address_struct->end_address.sa)) {
4110 break;
4111 }
4112
4113 memcpy(dst: &cond_remote_start, src: &address_struct->start_address, n: sizeof(address_struct->start_address));
4114 memcpy(dst: &cond_remote_end, src: &address_struct->end_address, n: sizeof(address_struct->end_address));
4115 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4116 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4117 if (condition_is_negative) {
4118 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_START;
4119 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_END;
4120 }
4121 if (condition_type == NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_RANGE) {
4122 socket_only_conditions = TRUE;
4123 } else {
4124 socket_ip_conditions = TRUE;
4125 }
4126 break;
4127 }
4128 case NECP_POLICY_CONDITION_AGENT_TYPE: {
4129 if (condition_length >= sizeof(cond_agent_type)) {
4130 master_condition_mask |= NECP_KERNEL_CONDITION_AGENT_TYPE;
4131 memcpy(dst: &cond_agent_type, src: condition_value, n: sizeof(cond_agent_type));
4132 socket_only_conditions = TRUE;
4133 }
4134 break;
4135 }
4136 case NECP_POLICY_CONDITION_CLIENT_FLAGS: {
4137 if (condition_is_negative) {
4138 master_condition_negated_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4139 }
4140 master_condition_mask |= NECP_KERNEL_CONDITION_CLIENT_FLAGS;
4141 socket_only_conditions = TRUE;
4142 if (condition_length >= sizeof(u_int32_t)) {
4143 memcpy(dst: &cond_client_flags, src: condition_value, n: sizeof(cond_client_flags));
4144 } else {
4145 // Empty means match on fallback traffic
4146 cond_client_flags = NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
4147 }
4148 break;
4149 }
4150 case NECP_POLICY_CONDITION_FLOW_LOCAL_ADDR_EMPTY: {
4151 master_condition_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4152 if (condition_is_negative) {
4153 master_condition_negated_mask |= NECP_KERNEL_CONDITION_LOCAL_EMPTY;
4154 }
4155 socket_only_conditions = TRUE;
4156 break;
4157 }
4158 case NECP_POLICY_CONDITION_FLOW_REMOTE_ADDR_EMPTY: {
4159 master_condition_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4160 if (condition_is_negative) {
4161 master_condition_negated_mask |= NECP_KERNEL_CONDITION_REMOTE_EMPTY;
4162 }
4163 socket_only_conditions = TRUE;
4164 break;
4165 }
4166 case NECP_POLICY_CONDITION_SCHEME_PORT: {
4167 master_condition_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4168 if (condition_is_negative) {
4169 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SCHEME_PORT;
4170 }
4171 memcpy(dst: &cond_scheme_port, src: condition_value, n: sizeof(cond_scheme_port));
4172 socket_ip_conditions = TRUE;
4173 break;
4174 }
4175 case NECP_POLICY_CONDITION_SIGNING_IDENTIFIER: {
4176 if (condition_length > 0) {
4177 if (cond_signing_identifier == NULL) {
4178 cond_signing_identifier = necp_copy_string(string: (char *)condition_value, length: condition_length);
4179 if (cond_signing_identifier != NULL) {
4180 master_condition_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4181 socket_only_conditions = TRUE;
4182 if (condition_is_negative) {
4183 master_condition_negated_mask |= NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER;
4184 }
4185 }
4186 }
4187 }
4188 break;
4189 }
4190 case NECP_POLICY_CONDITION_PACKET_FILTER_TAGS: {
4191 if (condition_length >= sizeof(u_int16_t)) {
4192 master_condition_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4193 if (condition_is_negative) {
4194 master_condition_negated_mask |= NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS;
4195 }
4196 memcpy(dst: &cond_packet_filter_tags, src: condition_value, n: sizeof(cond_packet_filter_tags));
4197 socket_ip_conditions = TRUE;
4198 }
4199 break;
4200 }
4201 case NECP_POLICY_CONDITION_FLOW_IS_LOOPBACK: {
4202 master_condition_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4203 if (condition_is_negative) {
4204 master_condition_negated_mask |= NECP_KERNEL_CONDITION_IS_LOOPBACK;
4205 }
4206 socket_only_conditions = TRUE;
4207 break;
4208 }
4209 case NECP_POLICY_CONDITION_DELEGATE_IS_PLATFORM_BINARY: {
4210 master_condition_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4211 if (condition_is_negative) {
4212 master_condition_negated_mask |= NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY;
4213 }
4214 socket_only_conditions = TRUE;
4215 break;
4216 }
4217 case NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS: {
4218 if (condition_length <= (sizeof(u_int32_t) * NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX) && condition_length > 0) {
4219 u_int32_t flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_MAX] = {};
4220 memcpy(dst: &flags, src: condition_value, n: sizeof(flags));
4221 cond_bound_interface_flags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_FLAGS];
4222 cond_bound_interface_eflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_EFLAGS];
4223 cond_bound_interface_xflags = flags[NECP_POLICY_CONDITION_BOUND_INTERFACE_FLAGS_IDX_XFLAGS];
4224 master_condition_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4225 if (condition_is_negative) {
4226 master_condition_negated_mask |= NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4227 }
4228 socket_ip_conditions = TRUE;
4229 }
4230 break;
4231 }
4232 default: {
4233 break;
4234 }
4235 }
4236
4237 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
4238 }
4239
4240 // Process result
4241 ultimate_result = necp_policy_get_result_type(policy);
4242 switch (ultimate_result) {
4243 case NECP_POLICY_RESULT_PASS: {
4244 u_int32_t pass_flags = 0;
4245 if (necp_policy_result_get_parameter_length_from_buffer(buffer: policy->result, length: policy->result_size) > 0) {
4246 if (necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)&pass_flags, parameter_buffer_length: sizeof(pass_flags))) {
4247 ultimate_result_parameter.pass_flags = pass_flags;
4248 }
4249 }
4250 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4251 socket_layer_non_id_conditions = TRUE;
4252 ip_output_layer_id_condition = TRUE;
4253 } else if (socket_ip_conditions) {
4254 socket_layer_non_id_conditions = TRUE;
4255 ip_output_layer_id_condition = TRUE;
4256 ip_output_layer_non_id_conditions = TRUE;
4257 }
4258 break;
4259 }
4260 case NECP_POLICY_RESULT_DROP: {
4261 u_int32_t drop_flags = 0;
4262 if (necp_policy_result_get_parameter_length_from_buffer(buffer: policy->result, length: policy->result_size) > 0) {
4263 if (necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)&drop_flags, parameter_buffer_length: sizeof(drop_flags))) {
4264 ultimate_result_parameter.drop_flags = drop_flags;
4265 }
4266 }
4267 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4268 socket_layer_non_id_conditions = TRUE;
4269 } else if (socket_ip_conditions) {
4270 socket_layer_non_id_conditions = TRUE;
4271 ip_output_layer_non_id_conditions = TRUE;
4272 ip_output_layer_non_id_only = TRUE; // Only apply drop to packets that didn't go through socket layer
4273 }
4274 break;
4275 }
4276 case NECP_POLICY_RESULT_SKIP: {
4277 u_int32_t skip_policy_order = 0;
4278 if (necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)&skip_policy_order, parameter_buffer_length: sizeof(skip_policy_order))) {
4279 ultimate_result_parameter.skip_policy_order = skip_policy_order;
4280 }
4281
4282 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4283 socket_layer_non_id_conditions = TRUE;
4284 ip_output_layer_id_condition = TRUE;
4285 } else if (socket_ip_conditions) {
4286 socket_layer_non_id_conditions = TRUE;
4287 ip_output_layer_non_id_conditions = TRUE;
4288 }
4289 break;
4290 }
4291 case NECP_POLICY_RESULT_SOCKET_DIVERT:
4292 case NECP_POLICY_RESULT_SOCKET_FILTER: {
4293 u_int32_t control_unit = 0;
4294 if (necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)&control_unit, parameter_buffer_length: sizeof(control_unit))) {
4295 ultimate_result_parameter.flow_divert_control_unit = control_unit;
4296 }
4297 socket_layer_non_id_conditions = TRUE;
4298 break;
4299 }
4300 case NECP_POLICY_RESULT_IP_TUNNEL: {
4301 struct necp_policy_result_ip_tunnel tunnel_parameters;
4302 u_int32_t tunnel_parameters_length = necp_policy_get_result_parameter_length(policy);
4303 if (tunnel_parameters_length > sizeof(u_int32_t) &&
4304 tunnel_parameters_length <= sizeof(struct necp_policy_result_ip_tunnel) &&
4305 necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)&tunnel_parameters, parameter_buffer_length: sizeof(tunnel_parameters))) {
4306 ifnet_t tunnel_interface = NULL;
4307 tunnel_parameters.interface_name[tunnel_parameters_length - sizeof(u_int32_t) - 1] = 0; // Make sure the string is NULL terminated
4308 if (ifnet_find_by_name(ifname: tunnel_parameters.interface_name, interface: &tunnel_interface) == 0) {
4309 ultimate_result_parameter.tunnel_interface_index = tunnel_interface->if_index;
4310 ifnet_release(interface: tunnel_interface);
4311 }
4312
4313 secondary_result = tunnel_parameters.secondary_result;
4314 if (secondary_result) {
4315 cond_last_interface_index = ultimate_result_parameter.tunnel_interface_index;
4316 }
4317 }
4318
4319 if (socket_only_conditions) { // socket_ip_conditions can be TRUE or FALSE
4320 socket_layer_non_id_conditions = TRUE;
4321 ip_output_layer_id_condition = TRUE;
4322 if (secondary_result) {
4323 ip_output_layer_tunnel_condition_from_id = TRUE;
4324 }
4325 } else if (socket_ip_conditions) {
4326 socket_layer_non_id_conditions = TRUE;
4327 ip_output_layer_id_condition = TRUE;
4328 ip_output_layer_non_id_conditions = TRUE;
4329 if (secondary_result) {
4330 ip_output_layer_tunnel_condition_from_id = TRUE;
4331 ip_output_layer_tunnel_condition_from_non_id = TRUE;
4332 }
4333 }
4334 break;
4335 }
4336 case NECP_POLICY_RESULT_USE_NETAGENT:
4337 case NECP_POLICY_RESULT_NETAGENT_SCOPED:
4338 case NECP_POLICY_RESULT_REMOVE_NETAGENT: {
4339 uuid_t netagent_uuid;
4340 if (necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)&netagent_uuid, parameter_buffer_length: sizeof(netagent_uuid))) {
4341 ultimate_result_parameter.netagent_id = necp_create_uuid_service_id_mapping(uuid: netagent_uuid);
4342 if (ultimate_result_parameter.netagent_id != 0) {
4343 uuid_copy(dst: policy->applied_result_uuid, src: netagent_uuid);
4344 socket_layer_non_id_conditions = TRUE;
4345 }
4346 }
4347 break;
4348 }
4349 case NECP_POLICY_RESULT_SOCKET_SCOPED: {
4350 u_int32_t interface_name_length = necp_policy_get_result_parameter_length(policy);
4351 if (interface_name_length <= IFXNAMSIZ && interface_name_length > 0) {
4352 char interface_name[IFXNAMSIZ];
4353 ifnet_t scope_interface = NULL;
4354 necp_policy_get_result_parameter(policy, parameter_buffer: (u_int8_t *)interface_name, parameter_buffer_length: interface_name_length);
4355 interface_name[interface_name_length - 1] = 0; // Make sure the string is NULL terminated
4356 if (ifnet_find_by_name(ifname: interface_name, interface: &scope_interface) == 0) {
4357 ultimate_result_parameter.scoped_interface_index = scope_interface->if_index;
4358 socket_layer_non_id_conditions = TRUE;
4359 ifnet_release(interface: scope_interface);
4360 }
4361 }
4362 break;
4363 }
4364 case NECP_POLICY_RESULT_SCOPED_DIRECT: {
4365 socket_layer_non_id_conditions = TRUE;
4366 break;
4367 }
4368 case NECP_POLICY_RESULT_ALLOW_UNENTITLED: {
4369 socket_layer_non_id_conditions = TRUE;
4370 break;
4371 }
4372 case NECP_POLICY_RESULT_ROUTE_RULES: {
4373 if (policy->route_rules != NULL && policy->route_rules_size > 0) {
4374 bool has_socket_only_actions = FALSE;
4375 u_int32_t route_rule_id = necp_create_route_rule(list: &necp_route_rules, route_rules_array: policy->route_rules, route_rules_array_size: policy->route_rules_size, has_socket_only_actions: &has_socket_only_actions);
4376 if (route_rule_id > 0) {
4377 policy->applied_route_rules_id = route_rule_id;
4378 ultimate_result_parameter.route_rule_id = route_rule_id;
4379 if (socket_only_conditions || has_socket_only_actions) { // socket_ip_conditions can be TRUE or FALSE
4380 socket_layer_non_id_conditions = TRUE;
4381 } else if (socket_ip_conditions) {
4382 socket_layer_non_id_conditions = TRUE;
4383 ip_output_layer_non_id_conditions = TRUE;
4384 ip_output_layer_non_id_only = TRUE; // Only apply route rules to packets that didn't go through socket layer
4385 }
4386 }
4387 }
4388 break;
4389 }
4390 default: {
4391 break;
4392 }
4393 }
4394
4395 if (socket_layer_non_id_conditions) {
4396 necp_kernel_policy_id policy_id = necp_kernel_socket_policy_add(order: policy->order, session_order: session->session_order, session_pid: session->proc_pid, condition_mask: master_condition_mask, condition_negated_mask: master_condition_negated_mask, cond_app_id, cond_real_app_id, cond_custom_entitlement, cond_account_id, cond_domain, cond_domain_filter, cond_url, cond_pid, cond_pidversion: cond_pid_version, cond_uid, cond_real_uid, cond_bound_interface, cond_traffic_class, cond_protocol, cond_local_start: &cond_local_start, cond_local_end: &cond_local_end, cond_local_prefix, cond_remote_start: &cond_remote_start, cond_remote_end: &cond_remote_end, cond_remote_prefix, cond_agent_type: &cond_agent_type, cond_sdk_version: &cond_sdk_version, cond_client_flags, cond_signing_identifier, cond_packet_filter_tags, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, result: ultimate_result, result_parameter: ultimate_result_parameter);
4397
4398 if (policy_id == 0) {
4399 NECPLOG0(LOG_DEBUG, "Error applying socket kernel policy");
4400 goto fail;
4401 }
4402
4403 cond_ip_output_layer_id = policy_id;
4404 policy->kernel_socket_policies[0] = policy_id;
4405 }
4406
4407 if (ip_output_layer_non_id_conditions) {
4408 u_int64_t condition_mask = master_condition_mask;
4409 if (ip_output_layer_non_id_only) {
4410 condition_mask |= NECP_KERNEL_CONDITION_POLICY_ID;
4411 }
4412
4413 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(order: policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS, session_order: session->session_order, session_pid: session->proc_pid, condition_mask, condition_negated_mask: master_condition_negated_mask, NECP_KERNEL_POLICY_ID_NONE, cond_bound_interface, cond_last_interface_index: 0, cond_protocol, cond_local_start: &cond_local_start, cond_local_end: &cond_local_end, cond_local_prefix, cond_remote_start: &cond_remote_start, cond_remote_end: &cond_remote_end, cond_remote_prefix, cond_packet_filter_tags, cond_scheme_port, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, result: ultimate_result, result_parameter: ultimate_result_parameter);
4414
4415 if (policy_id == 0) {
4416 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4417 goto fail;
4418 }
4419
4420 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS] = policy_id;
4421 }
4422
4423 if (ip_output_layer_id_condition) {
4424 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(order: policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION, session_order: session->session_order, session_pid: session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_ALL_INTERFACES, condition_negated_mask: 0, cond_policy_id: cond_ip_output_layer_id, NULL, cond_last_interface_index: 0, cond_protocol: 0, NULL, NULL, cond_local_prefix: 0, NULL, NULL, cond_remote_prefix: 0, cond_packet_filter_tags: 0, cond_scheme_port: 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, result: ultimate_result, result_parameter: ultimate_result_parameter);
4425
4426 if (policy_id == 0) {
4427 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4428 goto fail;
4429 }
4430
4431 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION] = policy_id;
4432 }
4433
4434 // Extra policies for IP Output tunnels for when packets loop back
4435 if (ip_output_layer_tunnel_condition_from_id) {
4436 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(order: policy->order, NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION, session_order: session->session_order, session_pid: session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, condition_negated_mask: 0, cond_policy_id: policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_CONDITIONS], NULL, cond_last_interface_index, cond_protocol: 0, NULL, NULL, cond_local_prefix: 0, NULL, NULL, cond_remote_prefix: 0, cond_packet_filter_tags: 0, cond_scheme_port: 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, result: secondary_result, result_parameter: secondary_result_parameter);
4437
4438 if (policy_id == 0) {
4439 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4440 goto fail;
4441 }
4442
4443 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_NON_ID_TUNNEL_CONDITION] = policy_id;
4444 }
4445
4446 if (ip_output_layer_tunnel_condition_from_id) {
4447 necp_kernel_policy_id policy_id = necp_kernel_ip_output_policy_add(order: policy->order, NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION, session_order: session->session_order, session_pid: session->proc_pid, NECP_KERNEL_CONDITION_POLICY_ID | NECP_KERNEL_CONDITION_LAST_INTERFACE | NECP_KERNEL_CONDITION_ALL_INTERFACES, condition_negated_mask: 0, cond_policy_id: policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_CONDITION], NULL, cond_last_interface_index, cond_protocol: 0, NULL, NULL, cond_local_prefix: 0, NULL, NULL, cond_remote_prefix: 0, cond_packet_filter_tags: 0, cond_scheme_port: 0, cond_bound_interface_flags, cond_bound_interface_eflags, cond_bound_interface_xflags, result: secondary_result, result_parameter: secondary_result_parameter);
4448
4449 if (policy_id == 0) {
4450 NECPLOG0(LOG_DEBUG, "Error applying IP output kernel policy");
4451 goto fail;
4452 }
4453
4454 policy->kernel_ip_output_policies[NECP_KERNEL_POLICY_SUBORDER_ID_TUNNEL_CONDITION] = policy_id;
4455 }
4456
4457 policy->applied = TRUE;
4458 policy->pending_update = FALSE;
4459 return TRUE;
4460
4461fail:
4462 return FALSE;
4463}
4464
4465static void
4466necp_policy_apply_all(struct necp_session *session)
4467{
4468 struct necp_session_policy *policy = NULL;
4469 struct necp_session_policy *temp_policy = NULL;
4470 struct kev_necp_policies_changed_data kev_data;
4471 kev_data.changed_count = 0;
4472
4473 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
4474
4475 // Remove exisiting applied policies
4476 if (session->dirty) {
4477 LIST_FOREACH_SAFE(policy, &session->policies, chain, temp_policy) {
4478 if (policy->pending_deletion) {
4479 if (policy->applied) {
4480 necp_policy_unapply(policy);
4481 }
4482 // Delete the policy
4483 necp_policy_delete(session, policy);
4484 } else if (!policy->applied) {
4485 necp_policy_apply(session, policy);
4486 } else if (policy->pending_update) {
4487 // Must have been applied, but needs an update. Remove and re-add.
4488 necp_policy_unapply(policy);
4489 necp_policy_apply(session, policy);
4490 }
4491 }
4492
4493 necp_kernel_socket_policies_update_uuid_table();
4494 necp_kernel_socket_policies_reprocess();
4495 necp_kernel_ip_output_policies_reprocess();
4496
4497 // Clear dirty bit flags
4498 session->dirty = FALSE;
4499 }
4500
4501 lck_rw_done(lck: &necp_kernel_policy_lock);
4502
4503 necp_update_all_clients();
4504 necp_post_change_event(necp_event_data: &kev_data);
4505
4506 if (necp_debug) {
4507 NECPLOG0(LOG_DEBUG, "Applied NECP policies");
4508 }
4509}
4510
4511// Kernel Policy Management
4512// ---------------------
4513// Kernel policies are derived from session policies
4514static necp_kernel_policy_id
4515necp_kernel_policy_get_new_id(bool socket_level)
4516{
4517 static necp_kernel_policy_id necp_last_kernel_socket_policy_id = 0;
4518 static necp_kernel_policy_id necp_last_kernel_ip_policy_id = 0;
4519
4520 necp_kernel_policy_id newid = NECP_KERNEL_POLICY_ID_NONE;
4521
4522 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4523
4524 if (socket_level) {
4525 bool wrapped = FALSE;
4526 do {
4527 necp_last_kernel_socket_policy_id++;
4528 if (necp_last_kernel_socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET ||
4529 necp_last_kernel_socket_policy_id >= NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4530 if (wrapped) {
4531 // Already wrapped, give up
4532 NECPLOG0(LOG_ERR, "Failed to find a free socket kernel policy ID.\n");
4533 return NECP_KERNEL_POLICY_ID_NONE;
4534 }
4535 necp_last_kernel_socket_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_SOCKET;
4536 wrapped = TRUE;
4537 }
4538 newid = necp_last_kernel_socket_policy_id;
4539 } while (necp_kernel_socket_policy_find(policy_id: newid) != NULL); // If already used, keep trying
4540 } else {
4541 bool wrapped = FALSE;
4542 do {
4543 necp_last_kernel_ip_policy_id++;
4544 if (necp_last_kernel_ip_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP) {
4545 if (wrapped) {
4546 // Already wrapped, give up
4547 NECPLOG0(LOG_ERR, "Failed to find a free IP kernel policy ID.\n");
4548 return NECP_KERNEL_POLICY_ID_NONE;
4549 }
4550 necp_last_kernel_ip_policy_id = NECP_KERNEL_POLICY_ID_FIRST_VALID_IP;
4551 wrapped = TRUE;
4552 }
4553 newid = necp_last_kernel_ip_policy_id;
4554 } while (necp_kernel_ip_output_policy_find(policy_id: newid) != NULL); // If already used, keep trying
4555 }
4556
4557 if (newid == NECP_KERNEL_POLICY_ID_NONE) {
4558 NECPLOG0(LOG_ERR, "Allocate kernel policy id failed.\n");
4559 return NECP_KERNEL_POLICY_ID_NONE;
4560 }
4561
4562 return newid;
4563}
4564
4565#define NECP_KERNEL_VALID_SOCKET_CONDITIONS (NECP_KERNEL_CONDITION_APP_ID | NECP_KERNEL_CONDITION_REAL_APP_ID | NECP_KERNEL_CONDITION_DOMAIN | NECP_KERNEL_CONDITION_ACCOUNT_ID | NECP_KERNEL_CONDITION_PID | NECP_KERNEL_CONDITION_UID | NECP_KERNEL_CONDITION_REAL_UID | NECP_KERNEL_CONDITION_ALL_INTERFACES | NECP_KERNEL_CONDITION_BOUND_INTERFACE | NECP_KERNEL_CONDITION_TRAFFIC_CLASS | NECP_KERNEL_CONDITION_PROTOCOL | NECP_KERNEL_CONDITION_LOCAL_START | NECP_KERNEL_CONDITION_LOCAL_END | NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_REMOTE_START | NECP_KERNEL_CONDITION_REMOTE_END | NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_ENTITLEMENT | NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT | NECP_KERNEL_CONDITION_AGENT_TYPE | NECP_KERNEL_CONDITION_HAS_CLIENT | NECP_KERNEL_CONDITION_LOCAL_NETWORKS | NECP_KERNEL_CONDITION_CLIENT_FLAGS | NECP_KERNEL_CONDITION_LOCAL_EMPTY | NECP_KERNEL_CONDITION_REMOTE_EMPTY | NECP_KERNEL_CONDITION_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SDK_VERSION | NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER | NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS | NECP_KERNEL_CONDITION_IS_LOOPBACK | NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY | NECP_KERNEL_CONDITION_SCHEME_PORT | NECP_KERNEL_CONDITION_DOMAIN_FILTER | NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT | NECP_KERNEL_CONDITION_EXACT_DOMAIN | NECP_KERNEL_CONDITION_URL | NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)
4566
4567static necp_kernel_policy_id
4568necp_kernel_socket_policy_add(necp_policy_order order, u_int32_t session_order, int session_pid, u_int64_t condition_mask, u_int64_t condition_negated_mask, necp_app_id cond_app_id, necp_app_id cond_real_app_id, char *cond_custom_entitlement, u_int32_t cond_account_id, char *cond_domain, u_int32_t cond_domain_filter, char *cond_url, pid_t cond_pid, int32_t cond_pid_version, uid_t cond_uid, uid_t cond_real_uid, ifnet_t cond_bound_interface, struct necp_policy_condition_tc_range cond_traffic_class, u_int16_t cond_protocol, union necp_sockaddr_union *cond_local_start, union necp_sockaddr_union *cond_local_end, u_int8_t cond_local_prefix, union necp_sockaddr_union *cond_remote_start, union necp_sockaddr_union *cond_remote_end, u_int8_t cond_remote_prefix, struct necp_policy_condition_agent_type *cond_agent_type, struct necp_policy_condition_sdk_version *cond_sdk_version, u_int32_t cond_client_flags, char *cond_signing_identifier, u_int16_t cond_packet_filter_tags, u_int16_t cond_scheme_port, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
4569{
4570 struct necp_kernel_socket_policy *new_kernel_policy = NULL;
4571 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4572
4573 new_kernel_policy = zalloc_flags(necp_socket_policy_zone, Z_WAITOK | Z_ZERO);
4574
4575 new_kernel_policy->id = necp_kernel_policy_get_new_id(true);
4576 new_kernel_policy->order = order;
4577 new_kernel_policy->session_order = session_order;
4578 new_kernel_policy->session_pid = session_pid;
4579
4580 // Sanitize condition mask
4581 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_SOCKET_CONDITIONS);
4582 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
4583 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
4584 }
4585 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
4586 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
4587 }
4588 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) && !(new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID)) {
4589 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REAL_APP_ID;
4590 }
4591 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
4592 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
4593 }
4594 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
4595 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
4596 }
4597 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
4598 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_LOCAL_PREFIX | NECP_KERNEL_CONDITION_LOCAL_END);
4599 }
4600 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY)) {
4601 new_kernel_policy->condition_mask &= ~(NECP_KERNEL_CONDITION_REMOTE_PREFIX | NECP_KERNEL_CONDITION_REMOTE_END);
4602 }
4603 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
4604
4605 // Set condition values
4606 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
4607 new_kernel_policy->cond_app_id = cond_app_id;
4608 }
4609 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
4610 new_kernel_policy->cond_real_app_id = cond_real_app_id;
4611 }
4612 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
4613 new_kernel_policy->cond_custom_entitlement = cond_custom_entitlement;
4614 }
4615 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
4616 new_kernel_policy->cond_account_id = cond_account_id;
4617 }
4618 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
4619 (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN)) {
4620 new_kernel_policy->cond_domain = cond_domain;
4621 new_kernel_policy->cond_domain_dot_count = necp_count_dots(string: cond_domain, length: strlen(s: cond_domain));
4622 }
4623 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
4624 new_kernel_policy->cond_domain_filter = cond_domain_filter;
4625 }
4626 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
4627 new_kernel_policy->cond_url = cond_url;
4628 }
4629 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
4630 new_kernel_policy->cond_pid = cond_pid;
4631 new_kernel_policy->cond_pid_version = cond_pid_version;
4632 }
4633 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
4634 new_kernel_policy->cond_uid = cond_uid;
4635 }
4636 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
4637 new_kernel_policy->cond_real_uid = cond_real_uid;
4638 }
4639 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
4640 if (cond_bound_interface) {
4641 ifnet_reference(interface: cond_bound_interface);
4642 }
4643 new_kernel_policy->cond_bound_interface = cond_bound_interface;
4644 }
4645 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
4646 new_kernel_policy->cond_traffic_class = cond_traffic_class;
4647 }
4648 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
4649 new_kernel_policy->cond_protocol = cond_protocol;
4650 }
4651 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
4652 memcpy(dst: &new_kernel_policy->cond_local_start, src: cond_local_start, n: cond_local_start->sa.sa_len);
4653 }
4654 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
4655 memcpy(dst: &new_kernel_policy->cond_local_end, src: cond_local_end, n: cond_local_end->sa.sa_len);
4656 }
4657 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
4658 new_kernel_policy->cond_local_prefix = cond_local_prefix;
4659 }
4660 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
4661 memcpy(dst: &new_kernel_policy->cond_remote_start, src: cond_remote_start, n: cond_remote_start->sa.sa_len);
4662 }
4663 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
4664 memcpy(dst: &new_kernel_policy->cond_remote_end, src: cond_remote_end, n: cond_remote_end->sa.sa_len);
4665 }
4666 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
4667 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
4668 }
4669 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
4670 memcpy(dst: &new_kernel_policy->cond_agent_type, src: cond_agent_type, n: sizeof(*cond_agent_type));
4671 }
4672 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
4673 memcpy(dst: &new_kernel_policy->cond_sdk_version, src: cond_sdk_version, n: sizeof(*cond_sdk_version));
4674 }
4675 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
4676 new_kernel_policy->cond_client_flags = cond_client_flags;
4677 }
4678 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
4679 new_kernel_policy->cond_signing_identifier = cond_signing_identifier;
4680 }
4681 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
4682 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
4683 }
4684 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
4685 new_kernel_policy->cond_scheme_port = cond_scheme_port;
4686 }
4687 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
4688 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
4689 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
4690 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
4691 }
4692
4693 new_kernel_policy->result = result;
4694 memcpy(dst: &new_kernel_policy->result_parameter, src: &result_parameter, n: sizeof(result_parameter));
4695
4696 if (necp_debug) {
4697 NECPLOG(LOG_DEBUG, "Added kernel policy: socket, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
4698 }
4699 LIST_INSERT_SORTED_TWICE_ASCENDING(&necp_kernel_socket_policies, new_kernel_policy, chain, session_order, order, tmp_kernel_policy);
4700
4701 return new_kernel_policy ? new_kernel_policy->id : 0;
4702}
4703
4704static struct necp_kernel_socket_policy *
4705necp_kernel_socket_policy_find(necp_kernel_policy_id policy_id)
4706{
4707 struct necp_kernel_socket_policy *kernel_policy = NULL;
4708 struct necp_kernel_socket_policy *tmp_kernel_policy = NULL;
4709
4710 if (policy_id == 0) {
4711 return NULL;
4712 }
4713
4714 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_socket_policies, chain, tmp_kernel_policy) {
4715 if (kernel_policy->id == policy_id) {
4716 return kernel_policy;
4717 }
4718 }
4719
4720 return NULL;
4721}
4722
4723static bool
4724necp_kernel_socket_policy_delete(necp_kernel_policy_id policy_id)
4725{
4726 struct necp_kernel_socket_policy *policy = NULL;
4727
4728 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
4729
4730 policy = necp_kernel_socket_policy_find(policy_id);
4731 if (policy) {
4732 LIST_REMOVE(policy, chain);
4733
4734 if (policy->cond_bound_interface) {
4735 ifnet_release(interface: policy->cond_bound_interface);
4736 policy->cond_bound_interface = NULL;
4737 }
4738
4739 if (policy->cond_domain) {
4740 kfree_data_addr(policy->cond_domain);
4741 policy->cond_domain = NULL;
4742 }
4743
4744 if (policy->cond_url) {
4745 kfree_data_addr(policy->cond_url);
4746 policy->cond_url = NULL;
4747 }
4748
4749 if (policy->cond_custom_entitlement) {
4750 kfree_data_addr(policy->cond_custom_entitlement);
4751 policy->cond_custom_entitlement = NULL;
4752 }
4753
4754 if (policy->cond_signing_identifier) {
4755 kfree_data_addr(policy->cond_signing_identifier);
4756 policy->cond_signing_identifier = NULL;
4757 }
4758
4759 zfree(necp_socket_policy_zone, policy);
4760 return TRUE;
4761 }
4762
4763 return FALSE;
4764}
4765
4766static inline const char *
4767necp_get_result_description(char *result_string, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
4768{
4769 uuid_string_t uuid_string;
4770 switch (result) {
4771 case NECP_KERNEL_POLICY_RESULT_NONE: {
4772 snprintf(result_string, MAX_RESULT_STRING_LEN, "None");
4773 break;
4774 }
4775 case NECP_KERNEL_POLICY_RESULT_PASS: {
4776 snprintf(result_string, MAX_RESULT_STRING_LEN, "Pass (%X)", result_parameter.pass_flags);
4777 break;
4778 }
4779 case NECP_KERNEL_POLICY_RESULT_SKIP: {
4780 snprintf(result_string, MAX_RESULT_STRING_LEN, "Skip (%u)", result_parameter.skip_policy_order);
4781 break;
4782 }
4783 case NECP_KERNEL_POLICY_RESULT_DROP: {
4784 snprintf(result_string, MAX_RESULT_STRING_LEN, "Drop (%X)", result_parameter.drop_flags);
4785 break;
4786 }
4787 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT: {
4788 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketDivert (%d)", result_parameter.flow_divert_control_unit);
4789 break;
4790 }
4791 case NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER: {
4792 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketFilter (%d)", result_parameter.filter_control_unit);
4793 break;
4794 }
4795 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
4796 ifnet_t interface = ifindex2ifnet[result_parameter.tunnel_interface_index];
4797 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPTunnel (%s%d)", ifnet_name(interface), ifnet_unit(interface));
4798 break;
4799 }
4800 case NECP_KERNEL_POLICY_RESULT_IP_FILTER: {
4801 snprintf(result_string, MAX_RESULT_STRING_LEN, "IPFilter");
4802 break;
4803 }
4804 case NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED: {
4805 ifnet_t interface = ifindex2ifnet[result_parameter.scoped_interface_index];
4806 snprintf(result_string, MAX_RESULT_STRING_LEN, "SocketScoped (%s%d)", ifnet_name(interface), ifnet_unit(interface));
4807 break;
4808 }
4809 case NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT: {
4810 snprintf(result_string, MAX_RESULT_STRING_LEN, "ScopedDirect");
4811 break;
4812 }
4813 case NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED: {
4814 snprintf(result_string, MAX_RESULT_STRING_LEN, "AllowUnentitled");
4815 break;
4816 }
4817 case NECP_KERNEL_POLICY_RESULT_ROUTE_RULES: {
4818 int index = 0;
4819 char interface_names[MAX_ROUTE_RULE_INTERFACES][IFXNAMSIZ];
4820 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id: result_parameter.route_rule_id);
4821 if (route_rule != NULL) {
4822 for (index = 0; index < MAX_ROUTE_RULE_INTERFACES; index++) {
4823 if (route_rule->exception_if_indices[index] != 0) {
4824 ifnet_t interface = ifindex2ifnet[route_rule->exception_if_indices[index]];
4825 snprintf(interface_names[index], IFXNAMSIZ, "%s%d", ifnet_name(interface), ifnet_unit(interface));
4826 } else {
4827 memset(s: interface_names[index], c: 0, IFXNAMSIZ);
4828 }
4829 }
4830 switch (route_rule->default_action) {
4831 case NECP_ROUTE_RULE_DENY_INTERFACE:
4832 case NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE:
4833 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Only %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4834 (route_rule->cellular_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Cell " : "",
4835 (route_rule->wifi_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "WiFi " : "",
4836 (route_rule->wired_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Wired " : "",
4837 (route_rule->expensive_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Exp " : "",
4838 (route_rule->constrained_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Constrained " : "",
4839 (route_rule->companion_action == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? "Companion " : "",
4840 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[0] : "",
4841 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4842 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[1] : "",
4843 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4844 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[2] : "",
4845 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4846 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[3] : "",
4847 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4848 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[4] : "",
4849 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4850 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[5] : "",
4851 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4852 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[6] : "",
4853 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4854 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[7] : "",
4855 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4856 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[8] : "",
4857 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? " " : "",
4858 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_ALLOW_INTERFACE) ? interface_names[9] : "");
4859 break;
4860 case NECP_ROUTE_RULE_ALLOW_INTERFACE:
4861 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4862 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action) ? "!Cell " : "",
4863 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action) ? "!WiFi " : "",
4864 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action) ? "!Wired " : "",
4865 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action) ? "!Exp " : "",
4866 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action) ? "!Constrained " : "",
4867 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action) ? "!Companion " : "",
4868 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? "!" : "",
4869 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[0]) ? interface_names[0] : "",
4870 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? "!" : "",
4871 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[1]) ? interface_names[1] : "",
4872 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? "!" : "",
4873 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[2]) ? interface_names[2] : "",
4874 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? "!" : "",
4875 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[3]) ? interface_names[3] : "",
4876 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? "!" : "",
4877 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[4]) ? interface_names[4] : "",
4878 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? "!" : "",
4879 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[5]) ? interface_names[5] : "",
4880 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? "!" : "",
4881 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[6]) ? interface_names[6] : "",
4882 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? "!" : "",
4883 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[7]) ? interface_names[7] : "",
4884 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? "!" : "",
4885 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[8]) ? interface_names[8] : "",
4886 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? "!" : "",
4887 IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[9]) ? interface_names[9] : "");
4888 break;
4889 case NECP_ROUTE_RULE_QOS_MARKING:
4890 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (QoSMarking %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s)",
4891 (route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Cell " : "",
4892 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING) ? "WiFi " : "",
4893 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Wired " : "",
4894 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Exp " : "",
4895 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Constrained " : "",
4896 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING) ? "Companion " : "",
4897 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[0] : "",
4898 (route_rule->exception_if_actions[0] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4899 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[1] : "",
4900 (route_rule->exception_if_actions[1] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4901 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[2] : "",
4902 (route_rule->exception_if_actions[2] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4903 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[3] : "",
4904 (route_rule->exception_if_actions[3] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4905 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[4] : "",
4906 (route_rule->exception_if_actions[4] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4907 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[5] : "",
4908 (route_rule->exception_if_actions[5] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4909 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[6] : "",
4910 (route_rule->exception_if_actions[6] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4911 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[7] : "",
4912 (route_rule->exception_if_actions[7] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4913 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[8] : "",
4914 (route_rule->exception_if_actions[8] == NECP_ROUTE_RULE_QOS_MARKING) ? " " : "",
4915 (route_rule->exception_if_actions[9] == NECP_ROUTE_RULE_QOS_MARKING) ? interface_names[9] : "");
4916 break;
4917 default:
4918 snprintf(result_string, MAX_RESULT_STRING_LEN, "RouteRules (Unknown)");
4919 break;
4920 }
4921 }
4922 break;
4923 }
4924 case NECP_KERNEL_POLICY_RESULT_USE_NETAGENT: {
4925 bool found_mapping = FALSE;
4926 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: result_parameter.netagent_id);
4927 if (mapping != NULL) {
4928 uuid_unparse(uu: mapping->uuid, out: uuid_string);
4929 found_mapping = TRUE;
4930 }
4931 snprintf(result_string, MAX_RESULT_STRING_LEN, "UseNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
4932 break;
4933 }
4934 case NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED: {
4935 bool found_mapping = FALSE;
4936 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: result_parameter.netagent_id);
4937 if (mapping != NULL) {
4938 uuid_unparse(uu: mapping->uuid, out: uuid_string);
4939 found_mapping = TRUE;
4940 }
4941 snprintf(result_string, MAX_RESULT_STRING_LEN, "NetAgentScoped (%s)", found_mapping ? uuid_string : "Unknown");
4942 break;
4943 }
4944 case NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT: {
4945 bool found_mapping = FALSE;
4946 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: result_parameter.netagent_id);
4947 if (mapping != NULL) {
4948 uuid_unparse(uu: mapping->uuid, out: uuid_string);
4949 found_mapping = TRUE;
4950 }
4951 snprintf(result_string, MAX_RESULT_STRING_LEN, "RemoveNetAgent (%s)", found_mapping ? uuid_string : "Unknown");
4952 break;
4953 }
4954 default: {
4955 snprintf(result_string, MAX_RESULT_STRING_LEN, "Unknown %d (%d)", result, result_parameter.tunnel_interface_index);
4956 break;
4957 }
4958 }
4959 return result_string;
4960}
4961
4962static void
4963necp_kernel_socket_policies_dump_all(void)
4964{
4965 if (necp_debug) {
4966 struct necp_kernel_socket_policy *policy = NULL;
4967 int policy_i;
4968 int app_i;
4969 char result_string[MAX_RESULT_STRING_LEN];
4970 char proc_name_string[MAXCOMLEN + 1];
4971 memset(s: result_string, c: 0, MAX_RESULT_STRING_LEN);
4972 memset(s: proc_name_string, c: 0, MAXCOMLEN + 1);
4973
4974 NECPLOG0(LOG_DEBUG, "NECP Application Policies:\n");
4975 NECPLOG0(LOG_DEBUG, "-----------\n");
4976 for (policy_i = 0; necp_kernel_socket_policies_app_layer_map != NULL && necp_kernel_socket_policies_app_layer_map[policy_i] != NULL; policy_i++) {
4977 policy = necp_kernel_socket_policies_app_layer_map[policy_i];
4978 proc_name(pid: policy->session_pid, buf: proc_name_string, MAXCOMLEN);
4979 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));
4980 }
4981 if (necp_kernel_socket_policies_app_layer_map[0] != NULL) {
4982 NECPLOG0(LOG_DEBUG, "-----------\n");
4983 }
4984
4985 NECPLOG0(LOG_DEBUG, "NECP Socket Policies:\n");
4986 NECPLOG0(LOG_DEBUG, "-----------\n");
4987 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
4988 NECPLOG(LOG_DEBUG, "\tApp Bucket: %d\n", app_i);
4989 for (policy_i = 0; necp_kernel_socket_policies_map[app_i] != NULL && (necp_kernel_socket_policies_map[app_i])[policy_i] != NULL; policy_i++) {
4990 policy = (necp_kernel_socket_policies_map[app_i])[policy_i];
4991 proc_name(pid: policy->session_pid, buf: proc_name_string, MAXCOMLEN);
4992 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));
4993 }
4994 NECPLOG0(LOG_DEBUG, "-----------\n");
4995 }
4996 }
4997}
4998
4999static inline bool
5000necp_kernel_socket_policy_results_overlap(struct necp_kernel_socket_policy *upper_policy, struct necp_kernel_socket_policy *lower_policy)
5001{
5002 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_DROP) {
5003 // Drop always cancels out lower policies
5004 return TRUE;
5005 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER ||
5006 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES ||
5007 upper_policy->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
5008 upper_policy->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED ||
5009 upper_policy->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED ||
5010 upper_policy->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
5011 // Filters and route rules never cancel out lower policies
5012 return FALSE;
5013 } else if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5014 if (upper_policy->session_order != lower_policy->session_order) {
5015 // A skip cannot override a policy of a different session
5016 return FALSE;
5017 } else {
5018 if (upper_policy->result_parameter.skip_policy_order == 0 ||
5019 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
5020 // This policy is beyond the skip
5021 return FALSE;
5022 } else {
5023 // This policy is inside the skip
5024 return TRUE;
5025 }
5026 }
5027 }
5028
5029 // A hard pass, flow divert, tunnel, or scope will currently block out lower policies
5030 return TRUE;
5031}
5032
5033static bool
5034necp_kernel_socket_policy_is_unnecessary(struct necp_kernel_socket_policy *policy, struct necp_kernel_socket_policy **policy_array, int valid_indices)
5035{
5036 bool can_skip = FALSE;
5037 u_int32_t highest_skip_session_order = 0;
5038 u_int32_t highest_skip_order = 0;
5039 int i;
5040 for (i = 0; i < valid_indices; i++) {
5041 struct necp_kernel_socket_policy *compared_policy = policy_array[i];
5042
5043 // For policies in a skip window, we can't mark conflicting policies as unnecessary
5044 if (can_skip) {
5045 if (highest_skip_session_order != compared_policy->session_order ||
5046 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
5047 // If we've moved on to the next session, or passed the skip window
5048 highest_skip_session_order = 0;
5049 highest_skip_order = 0;
5050 can_skip = FALSE;
5051 } else {
5052 // If this policy is also a skip, in can increase the skip window
5053 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5054 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
5055 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5056 }
5057 }
5058 continue;
5059 }
5060 }
5061
5062 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
5063 // This policy is a skip. Set the skip window accordingly
5064 can_skip = TRUE;
5065 highest_skip_session_order = compared_policy->session_order;
5066 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
5067 }
5068
5069 // The result of the compared policy must be able to block out this policy result
5070 if (!necp_kernel_socket_policy_results_overlap(upper_policy: compared_policy, lower_policy: policy)) {
5071 continue;
5072 }
5073
5074 // If new policy matches All Interfaces, compared policy must also
5075 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
5076 continue;
5077 }
5078
5079 // If new policy matches Local Networks, compared policy must also
5080 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
5081 continue;
5082 }
5083
5084 // Default makes lower policies unecessary always
5085 if (compared_policy->condition_mask == 0) {
5086 return TRUE;
5087 }
5088
5089 // Compared must be more general than policy, and include only conditions within policy
5090 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
5091 continue;
5092 }
5093
5094 // Negative conditions must match for the overlapping conditions
5095 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
5096 continue;
5097 }
5098
5099 if ((compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN ||
5100 compared_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) &&
5101 strcmp(s1: compared_policy->cond_domain, s2: policy->cond_domain) != 0) {
5102 continue;
5103 }
5104
5105 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER &&
5106 compared_policy->cond_domain_filter != policy->cond_domain_filter) {
5107 continue;
5108 }
5109
5110 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_URL &&
5111 strcmp(s1: compared_policy->cond_url, s2: policy->cond_url) != 0) {
5112 continue;
5113 }
5114
5115 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT &&
5116 strcmp(s1: compared_policy->cond_custom_entitlement, s2: policy->cond_custom_entitlement) != 0) {
5117 continue;
5118 }
5119
5120 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID &&
5121 compared_policy->cond_account_id != policy->cond_account_id) {
5122 continue;
5123 }
5124
5125 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
5126 compared_policy->cond_policy_id != policy->cond_policy_id) {
5127 continue;
5128 }
5129
5130 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID &&
5131 compared_policy->cond_app_id != policy->cond_app_id) {
5132 continue;
5133 }
5134
5135 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID &&
5136 compared_policy->cond_real_app_id != policy->cond_real_app_id) {
5137 continue;
5138 }
5139
5140 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PID &&
5141 (compared_policy->cond_pid != policy->cond_pid || compared_policy->cond_pid_version != policy->cond_pid_version)) {
5142 continue;
5143 }
5144
5145 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_UID &&
5146 compared_policy->cond_uid != policy->cond_uid) {
5147 continue;
5148 }
5149
5150 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID &&
5151 compared_policy->cond_real_uid != policy->cond_real_uid) {
5152 continue;
5153 }
5154
5155 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
5156 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
5157 continue;
5158 }
5159
5160 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
5161 compared_policy->cond_protocol != policy->cond_protocol) {
5162 continue;
5163 }
5164
5165 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS &&
5166 compared_policy->cond_client_flags != policy->cond_client_flags) {
5167 continue;
5168 }
5169
5170 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS &&
5171 !(compared_policy->cond_traffic_class.start_tc <= policy->cond_traffic_class.start_tc &&
5172 compared_policy->cond_traffic_class.end_tc >= policy->cond_traffic_class.end_tc)) {
5173 continue;
5174 }
5175
5176 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
5177 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
5178 if (!necp_is_range_in_range(inner_range_start: (struct sockaddr *)&policy->cond_local_start, inner_range_end: (struct sockaddr *)&policy->cond_local_end, range_start: (struct sockaddr *)&compared_policy->cond_local_start, range_end: (struct sockaddr *)&compared_policy->cond_local_end)) {
5179 continue;
5180 }
5181 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
5182 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
5183 !necp_is_addr_in_subnet(addr: (struct sockaddr *)&policy->cond_local_start, subnet_addr: (struct sockaddr *)&compared_policy->cond_local_start, subnet_prefix: compared_policy->cond_local_prefix)) {
5184 continue;
5185 }
5186 }
5187 }
5188
5189 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
5190 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
5191 if (!necp_is_range_in_range(inner_range_start: (struct sockaddr *)&policy->cond_remote_start, inner_range_end: (struct sockaddr *)&policy->cond_remote_end, range_start: (struct sockaddr *)&compared_policy->cond_remote_start, range_end: (struct sockaddr *)&compared_policy->cond_remote_end)) {
5192 continue;
5193 }
5194 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
5195 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
5196 !necp_is_addr_in_subnet(addr: (struct sockaddr *)&policy->cond_remote_start, subnet_addr: (struct sockaddr *)&compared_policy->cond_remote_start, subnet_prefix: compared_policy->cond_remote_prefix)) {
5197 continue;
5198 }
5199 }
5200 }
5201
5202 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE &&
5203 memcmp(s1: &compared_policy->cond_agent_type, s2: &policy->cond_agent_type, n: sizeof(policy->cond_agent_type)) == 0) {
5204 continue;
5205 }
5206
5207 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION &&
5208 memcmp(s1: &compared_policy->cond_sdk_version, s2: &policy->cond_sdk_version, n: sizeof(policy->cond_sdk_version)) == 0) {
5209 continue;
5210 }
5211
5212 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS &&
5213 memcmp(s1: &compared_policy->cond_packet_filter_tags, s2: &policy->cond_packet_filter_tags, n: sizeof(policy->cond_packet_filter_tags)) == 0) {
5214 continue;
5215 }
5216
5217 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
5218 memcmp(s1: &compared_policy->cond_scheme_port, s2: &policy->cond_scheme_port, n: sizeof(policy->cond_scheme_port)) == 0) {
5219 continue;
5220 }
5221
5222 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
5223 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
5224 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
5225 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
5226 continue;
5227 }
5228
5229 return TRUE;
5230 }
5231
5232 return FALSE;
5233}
5234
5235static bool
5236necp_kernel_socket_policies_reprocess(void)
5237{
5238 int app_i;
5239 int bucket_current_free_index[NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS];
5240 int app_layer_current_free_index = 0;
5241 struct necp_kernel_socket_policy *kernel_policy = NULL;
5242
5243 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5244
5245 // Reset mask to 0
5246 necp_kernel_application_policies_condition_mask = 0;
5247 necp_kernel_socket_policies_condition_mask = 0;
5248 necp_kernel_application_policies_count = 0;
5249 necp_kernel_socket_policies_count = 0;
5250 necp_kernel_socket_policies_non_app_count = 0;
5251
5252 // Reset all maps to NULL
5253 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5254 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5255 kfree_type(struct necp_kernel_socket_policy *,
5256 necp_kernel_socket_policies_map_counts[app_i] + 1,
5257 necp_kernel_socket_policies_map[app_i]);
5258 necp_kernel_socket_policies_map[app_i] = NULL;
5259 }
5260
5261 // Init counts
5262 necp_kernel_socket_policies_map_counts[app_i] = 0;
5263 }
5264 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5265 kfree_type(struct necp_kernel_socket_policy *,
5266 necp_kernel_socket_policies_app_layer_map_count + 1,
5267 necp_kernel_socket_policies_app_layer_map);
5268 }
5269 necp_kernel_socket_policies_app_layer_map = NULL;
5270 necp_kernel_socket_policies_app_layer_map_count = 0;
5271
5272 // Create masks and counts
5273 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5274 // App layer mask/count
5275 necp_kernel_application_policies_condition_mask |= kernel_policy->condition_mask;
5276 necp_kernel_application_policies_count++;
5277 necp_kernel_socket_policies_app_layer_map_count++;
5278
5279 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5280 // Agent type conditions only apply to app layer
5281 continue;
5282 }
5283
5284 // Update socket layer bucket mask/counts
5285 necp_kernel_socket_policies_condition_mask |= kernel_policy->condition_mask;
5286 necp_kernel_socket_policies_count++;
5287
5288 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5289 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5290 necp_kernel_socket_policies_non_app_count++;
5291 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5292 necp_kernel_socket_policies_map_counts[app_i]++;
5293 }
5294 } else {
5295 necp_kernel_socket_policies_map_counts[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id)]++;
5296 }
5297 }
5298
5299 // Allocate maps
5300 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5301 if (necp_kernel_socket_policies_map_counts[app_i] > 0) {
5302 // Allocate a NULL-terminated array of policy pointers for each bucket
5303 necp_kernel_socket_policies_map[app_i] = kalloc_type(struct necp_kernel_socket_policy *,
5304 necp_kernel_socket_policies_map_counts[app_i] + 1, Z_WAITOK | Z_ZERO);
5305 if (necp_kernel_socket_policies_map[app_i] == NULL) {
5306 goto fail;
5307 }
5308 }
5309 bucket_current_free_index[app_i] = 0;
5310 }
5311 necp_kernel_socket_policies_app_layer_map = kalloc_type(struct necp_kernel_socket_policy *,
5312 necp_kernel_socket_policies_app_layer_map_count + 1, Z_WAITOK | Z_ZERO);
5313 if (necp_kernel_socket_policies_app_layer_map == NULL) {
5314 goto fail;
5315 }
5316
5317 // Fill out maps
5318 LIST_FOREACH(kernel_policy, &necp_kernel_socket_policies, chain) {
5319 // Add app layer policies
5320 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(policy: kernel_policy, policy_array: necp_kernel_socket_policies_app_layer_map, valid_indices: app_layer_current_free_index)) {
5321 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = kernel_policy;
5322 app_layer_current_free_index++;
5323 necp_kernel_socket_policies_app_layer_map[app_layer_current_free_index] = NULL;
5324 }
5325
5326 if ((kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE)) {
5327 // Agent type conditions only apply to app layer
5328 continue;
5329 }
5330
5331 // Add socket policies
5332 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) ||
5333 kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
5334 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5335 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(policy: kernel_policy, policy_array: necp_kernel_socket_policies_map[app_i], valid_indices: bucket_current_free_index[app_i])) {
5336 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5337 bucket_current_free_index[app_i]++;
5338 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5339 }
5340 }
5341 } else {
5342 app_i = NECP_SOCKET_MAP_APP_ID_TO_BUCKET(kernel_policy->cond_app_id);
5343 if (!necp_dedup_policies || !necp_kernel_socket_policy_is_unnecessary(policy: kernel_policy, policy_array: necp_kernel_socket_policies_map[app_i], valid_indices: bucket_current_free_index[app_i])) {
5344 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = kernel_policy;
5345 bucket_current_free_index[app_i]++;
5346 (necp_kernel_socket_policies_map[app_i])[(bucket_current_free_index[app_i])] = NULL;
5347 }
5348 }
5349 }
5350 necp_kernel_socket_policies_dump_all();
5351 BUMP_KERNEL_SOCKET_POLICIES_GENERATION_COUNT();
5352 return TRUE;
5353
5354fail:
5355 // Free memory, reset masks to 0
5356 necp_kernel_application_policies_condition_mask = 0;
5357 necp_kernel_socket_policies_condition_mask = 0;
5358 necp_kernel_application_policies_count = 0;
5359 necp_kernel_socket_policies_count = 0;
5360 necp_kernel_socket_policies_non_app_count = 0;
5361 for (app_i = 0; app_i < NECP_KERNEL_SOCKET_POLICIES_MAP_NUM_APP_ID_BUCKETS; app_i++) {
5362 if (necp_kernel_socket_policies_map[app_i] != NULL) {
5363 kfree_type(struct necp_kernel_socket_policy *,
5364 necp_kernel_socket_policies_map_counts[app_i] + 1,
5365 necp_kernel_socket_policies_map[app_i]);
5366 necp_kernel_socket_policies_map[app_i] = NULL;
5367 }
5368 necp_kernel_socket_policies_map_counts[app_i] = 0;
5369 }
5370 if (necp_kernel_socket_policies_app_layer_map != NULL) {
5371 kfree_type(struct necp_kernel_socket_policy *,
5372 necp_kernel_socket_policies_app_layer_map_count + 1,
5373 necp_kernel_socket_policies_app_layer_map);
5374 necp_kernel_socket_policies_app_layer_map = NULL;
5375 }
5376 necp_kernel_socket_policies_app_layer_map_count = 0;
5377 return FALSE;
5378}
5379
5380static u_int32_t
5381necp_get_new_string_id(void)
5382{
5383 static u_int32_t necp_last_string_id = 0;
5384
5385 u_int32_t newid = 0;
5386
5387 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5388
5389 bool wrapped = FALSE;
5390 do {
5391 necp_last_string_id++;
5392 if (necp_last_string_id < 1) {
5393 if (wrapped) {
5394 // Already wrapped, give up
5395 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
5396 return 0;
5397 }
5398 necp_last_string_id = 1;
5399 wrapped = TRUE;
5400 }
5401 newid = necp_last_string_id;
5402 } while (necp_lookup_string_with_id_locked(list: &necp_account_id_list, local_id: newid) != NULL); // If already used, keep trying
5403
5404 if (newid == 0) {
5405 NECPLOG0(LOG_ERR, "Allocate string id failed.\n");
5406 return 0;
5407 }
5408
5409 return newid;
5410}
5411
5412static struct necp_string_id_mapping *
5413necp_lookup_string_to_id_locked(struct necp_string_id_mapping_list *list, char *string)
5414{
5415 struct necp_string_id_mapping *searchentry = NULL;
5416 struct necp_string_id_mapping *foundentry = NULL;
5417
5418 LIST_FOREACH(searchentry, list, chain) {
5419 if (strcmp(s1: searchentry->string, s2: string) == 0) {
5420 foundentry = searchentry;
5421 break;
5422 }
5423 }
5424
5425 return foundentry;
5426}
5427
5428static struct necp_string_id_mapping *
5429necp_lookup_string_with_id_locked(struct necp_string_id_mapping_list *list, u_int32_t local_id)
5430{
5431 struct necp_string_id_mapping *searchentry = NULL;
5432 struct necp_string_id_mapping *foundentry = NULL;
5433
5434 LIST_FOREACH(searchentry, list, chain) {
5435 if (searchentry->id == local_id) {
5436 foundentry = searchentry;
5437 break;
5438 }
5439 }
5440
5441 return foundentry;
5442}
5443
5444static u_int32_t
5445necp_create_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
5446{
5447 u_int32_t string_id = 0;
5448 struct necp_string_id_mapping *existing_mapping = NULL;
5449
5450 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5451
5452 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5453 if (existing_mapping != NULL) {
5454 string_id = existing_mapping->id;
5455 os_ref_retain_locked(rc: &existing_mapping->refcount);
5456 } else {
5457 struct necp_string_id_mapping *new_mapping = NULL;
5458 new_mapping = kalloc_type(struct necp_string_id_mapping,
5459 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5460
5461 size_t length = strlen(s: string) + 1;
5462 new_mapping->string = (char *)kalloc_data(length, Z_WAITOK);
5463 if (new_mapping->string != NULL) {
5464 memcpy(dst: new_mapping->string, src: string, n: length);
5465 new_mapping->id = necp_get_new_string_id();
5466 os_ref_init(&new_mapping->refcount, &necp_refgrp);
5467 LIST_INSERT_HEAD(list, new_mapping, chain);
5468 string_id = new_mapping->id;
5469 } else {
5470 kfree_type(struct necp_string_id_mapping, new_mapping);
5471 new_mapping = NULL;
5472 }
5473 }
5474 return string_id;
5475}
5476
5477static bool
5478necp_remove_string_to_id_mapping(struct necp_string_id_mapping_list *list, char *string)
5479{
5480 struct necp_string_id_mapping *existing_mapping = NULL;
5481
5482 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5483
5484 existing_mapping = necp_lookup_string_to_id_locked(list, string);
5485 if (existing_mapping != NULL) {
5486 if (os_ref_release_locked(rc: &existing_mapping->refcount) == 0) {
5487 LIST_REMOVE(existing_mapping, chain);
5488 kfree_data_addr(existing_mapping->string);
5489 kfree_type(struct necp_string_id_mapping, existing_mapping);
5490 }
5491 return TRUE;
5492 }
5493
5494 return FALSE;
5495}
5496
5497static struct necp_domain_filter *
5498necp_lookup_domain_filter(struct necp_domain_filter_list *list, u_int32_t filter_id)
5499{
5500 struct necp_domain_filter *searchfilter = NULL;
5501 struct necp_domain_filter *foundfilter = NULL;
5502
5503 LIST_FOREACH(searchfilter, list, chain) {
5504 if (searchfilter->id == filter_id) {
5505 foundfilter = searchfilter;
5506 break;
5507 }
5508 }
5509
5510 return foundfilter;
5511}
5512
5513static u_int32_t
5514necp_get_new_domain_filter_id(void)
5515{
5516 static u_int32_t necp_last_filter_id = 0;
5517
5518 u_int32_t newid = 0;
5519
5520 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5521
5522 bool wrapped = FALSE;
5523 do {
5524 necp_last_filter_id++;
5525 if (necp_last_filter_id < 1) {
5526 if (wrapped) {
5527 // Already wrapped, give up
5528 NECPLOG0(LOG_ERR, "Failed to find a free filter ID.\n");
5529 return 0;
5530 }
5531 necp_last_filter_id = 1;
5532 wrapped = TRUE;
5533 }
5534 newid = necp_last_filter_id;
5535 } while (necp_lookup_domain_filter(list: &necp_global_domain_filter_list, filter_id: newid) != NULL); // If already used, keep trying
5536
5537 if (newid == 0) {
5538 NECPLOG0(LOG_ERR, "Allocate filter id failed.\n");
5539 return 0;
5540 }
5541
5542 return newid;
5543}
5544
5545static u_int32_t
5546necp_create_domain_filter(struct necp_domain_filter_list *list, struct necp_domain_filter_list *owner_list, struct net_bloom_filter *filter)
5547{
5548 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5549
5550 struct necp_domain_filter *new_filter = NULL;
5551 new_filter = kalloc_type(struct necp_domain_filter,
5552 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5553
5554 new_filter->filter = filter;
5555 new_filter->id = necp_get_new_domain_filter_id();
5556 LIST_INSERT_HEAD(list, new_filter, chain);
5557 LIST_INSERT_HEAD(owner_list, new_filter, owner_chain);
5558 os_ref_init(&new_filter->refcount, &necp_refgrp);
5559
5560 return new_filter->id;
5561}
5562
5563static bool
5564necp_remove_domain_filter(struct necp_domain_filter_list *list, __unused struct necp_domain_filter_list *owner_list, u_int32_t filter_id)
5565{
5566 struct necp_domain_filter *existing_filter = NULL;
5567
5568 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5569
5570 existing_filter = necp_lookup_domain_filter(list, filter_id);
5571 if (existing_filter != NULL) {
5572 if (os_ref_release_locked(rc: &existing_filter->refcount) == 0) {
5573 LIST_REMOVE(existing_filter, chain);
5574 LIST_REMOVE(existing_filter, owner_chain);
5575 net_bloom_filter_destroy(filter: existing_filter->filter);
5576 kfree_type(struct necp_domain_filter, existing_filter);
5577 }
5578 return true;
5579 }
5580
5581 return false;
5582}
5583
5584#define NECP_FIRST_VALID_ROUTE_RULE_ID 1
5585#define NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID UINT16_MAX
5586static u_int32_t
5587necp_get_new_route_rule_id(bool aggregate)
5588{
5589 static u_int32_t necp_last_route_rule_id = 0;
5590 static u_int32_t necp_last_aggregate_route_rule_id = 0;
5591
5592 u_int32_t newid = 0;
5593
5594 if (!aggregate) {
5595 // Main necp_kernel_policy_lock protects non-aggregate rule IDs
5596 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5597
5598 bool wrapped = FALSE;
5599 do {
5600 necp_last_route_rule_id++;
5601 if (necp_last_route_rule_id < NECP_FIRST_VALID_ROUTE_RULE_ID ||
5602 necp_last_route_rule_id >= NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5603 if (wrapped) {
5604 // Already wrapped, give up
5605 NECPLOG0(LOG_ERR, "Failed to find a free route rule id.\n");
5606 return 0;
5607 }
5608 necp_last_route_rule_id = NECP_FIRST_VALID_ROUTE_RULE_ID;
5609 wrapped = TRUE;
5610 }
5611 newid = necp_last_route_rule_id;
5612 } while (necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id: newid) != NULL); // If already used, keep trying
5613 } else {
5614 // necp_route_rule_lock protects aggregate rule IDs
5615 LCK_RW_ASSERT(&necp_route_rule_lock, LCK_RW_ASSERT_EXCLUSIVE);
5616
5617 bool wrapped = FALSE;
5618 do {
5619 necp_last_aggregate_route_rule_id++;
5620 if (necp_last_aggregate_route_rule_id < NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID) {
5621 if (wrapped) {
5622 // Already wrapped, give up
5623 NECPLOG0(LOG_ERR, "Failed to find a free aggregate route rule id.\n");
5624 return 0;
5625 }
5626 necp_last_aggregate_route_rule_id = NECP_FIRST_VALID_AGGREGATE_ROUTE_RULE_ID;
5627 wrapped = TRUE;
5628 }
5629 newid = necp_last_aggregate_route_rule_id;
5630 } while (necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id: newid) != NULL); // If already used, keep trying
5631 }
5632
5633 if (newid == 0) {
5634 NECPLOG0(LOG_ERR, "Allocate route rule ID failed.\n");
5635 return 0;
5636 }
5637
5638 return newid;
5639}
5640
5641static struct necp_route_rule *
5642necp_lookup_route_rule_locked(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5643{
5644 struct necp_route_rule *searchentry = NULL;
5645 struct necp_route_rule *foundentry = NULL;
5646
5647 LIST_FOREACH(searchentry, list, chain) {
5648 if (searchentry->id == route_rule_id) {
5649 foundentry = searchentry;
5650 break;
5651 }
5652 }
5653
5654 return foundentry;
5655}
5656
5657static struct necp_route_rule *
5658necp_lookup_route_rule_by_contents_locked(struct necp_route_rule_list *list, u_int8_t default_action, u_int8_t cellular_action, u_int8_t wifi_action, u_int8_t wired_action, u_int8_t expensive_action, u_int8_t constrained_action, u_int8_t companion_action, u_int32_t *if_indices, u_int8_t *if_actions, uuid_t netagent_uuid, uuid_t match_netagent_uuid, u_int32_t control_unit, u_int32_t effective_type)
5659{
5660 struct necp_route_rule *searchentry = NULL;
5661 struct necp_route_rule *foundentry = NULL;
5662
5663 LIST_FOREACH(searchentry, list, chain) {
5664 if (searchentry->default_action == default_action &&
5665 searchentry->cellular_action == cellular_action &&
5666 searchentry->wifi_action == wifi_action &&
5667 searchentry->wired_action == wired_action &&
5668 searchentry->expensive_action == expensive_action &&
5669 searchentry->constrained_action == constrained_action &&
5670 searchentry->companion_action == companion_action &&
5671 searchentry->control_unit == control_unit &&
5672 searchentry->effective_type == effective_type) {
5673 bool match_failed = FALSE;
5674 size_t index_a = 0;
5675 size_t index_b = 0;
5676 size_t count_a = 0;
5677 size_t count_b = 0;
5678 for (index_a = 0; index_a < MAX_ROUTE_RULE_INTERFACES; index_a++) {
5679 bool found_index = FALSE;
5680 if (searchentry->exception_if_indices[index_a] == 0) {
5681 break;
5682 }
5683 count_a++;
5684 for (index_b = 0; index_b < MAX_ROUTE_RULE_INTERFACES; index_b++) {
5685 if (if_indices[index_b] == 0) {
5686 break;
5687 }
5688 if (index_b >= count_b) {
5689 count_b = index_b + 1;
5690 }
5691 if (searchentry->exception_if_indices[index_a] == if_indices[index_b] &&
5692 searchentry->exception_if_actions[index_a] == if_actions[index_b]) {
5693 found_index = TRUE;
5694 break;
5695 }
5696 }
5697 if (!found_index) {
5698 match_failed = TRUE;
5699 break;
5700 }
5701 }
5702
5703 if (match_failed || count_a != count_b) {
5704 continue;
5705 }
5706
5707 bool has_agent_a = !uuid_is_null(uu: netagent_uuid);
5708 bool has_agent_b = (searchentry->netagent_id != 0);
5709 if (has_agent_a != has_agent_b) {
5710 continue;
5711 }
5712
5713 if (has_agent_a) {
5714 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: searchentry->netagent_id);
5715 if (mapping == NULL) {
5716 // Bad mapping, doesn't match
5717 continue;
5718 }
5719 if (uuid_compare(uu1: mapping->uuid, uu2: netagent_uuid) != 0) {
5720 // UUIDs don't match
5721 continue;
5722 }
5723 }
5724
5725 bool has_match_agent_a = !uuid_is_null(uu: match_netagent_uuid);
5726 bool has_match_agent_b = (searchentry->match_netagent_id != 0);
5727 if (has_match_agent_a != has_match_agent_b) {
5728 continue;
5729 }
5730
5731 if (has_match_agent_a) {
5732 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: searchentry->match_netagent_id);
5733 if (mapping == NULL) {
5734 // Bad mapping, doesn't match
5735 continue;
5736 }
5737 if (uuid_compare(uu1: mapping->uuid, uu2: match_netagent_uuid) != 0) {
5738 // UUIDs don't match
5739 continue;
5740 }
5741 }
5742
5743 // Rules match!
5744 foundentry = searchentry;
5745 break;
5746 }
5747 }
5748
5749 return foundentry;
5750}
5751
5752static u_int32_t
5753necp_create_route_rule(struct necp_route_rule_list *list, u_int8_t *route_rules_array, u_int32_t route_rules_array_size,
5754 bool *has_socket_only_actions)
5755{
5756 size_t offset = 0;
5757 u_int32_t route_rule_id = 0;
5758 struct necp_route_rule *existing_rule = NULL;
5759 u_int8_t default_action = NECP_ROUTE_RULE_ALLOW_INTERFACE;
5760 u_int8_t cellular_action = NECP_ROUTE_RULE_NONE;
5761 u_int8_t wifi_action = NECP_ROUTE_RULE_NONE;
5762 u_int8_t wired_action = NECP_ROUTE_RULE_NONE;
5763 u_int8_t expensive_action = NECP_ROUTE_RULE_NONE;
5764 u_int8_t constrained_action = NECP_ROUTE_RULE_NONE;
5765 u_int8_t companion_action = NECP_ROUTE_RULE_NONE;
5766 u_int32_t if_indices[MAX_ROUTE_RULE_INTERFACES];
5767 size_t num_valid_indices = 0;
5768 memset(s: &if_indices, c: 0, n: sizeof(if_indices));
5769 u_int8_t if_actions[MAX_ROUTE_RULE_INTERFACES];
5770 memset(s: &if_actions, c: 0, n: sizeof(if_actions));
5771
5772 uuid_t netagent_uuid = {};
5773
5774 uuid_t match_netagent_uuid = {};
5775 uint32_t control_unit = 0;
5776 uint32_t effective_type = 0;
5777
5778 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5779
5780 if (route_rules_array == NULL || route_rules_array_size == 0 || has_socket_only_actions == NULL) {
5781 return 0;
5782 }
5783
5784 // Process rules
5785 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) < route_rules_array_size) {
5786 ifnet_t rule_interface = NULL;
5787 char interface_name[IFXNAMSIZ];
5788 u_int32_t length = 0;
5789 u_int8_t *value = necp_buffer_get_tlv_value(buffer: route_rules_array, tlv_offset: offset, value_size: &length);
5790
5791 if (offset + sizeof(u_int8_t) + sizeof(u_int32_t) + length > route_rules_array_size) {
5792 // Invalid TLV goes beyond end of the rules array
5793 break;
5794 }
5795
5796 // Increment offset for the next time through the loop
5797 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
5798
5799 u_int8_t rule_action = necp_policy_condition_get_type_from_buffer(buffer: value, length);
5800 u_int8_t rule_flags = necp_policy_condition_get_flags_from_buffer(buffer: value, length);
5801 u_int32_t rule_length = necp_policy_condition_get_value_length_from_buffer(buffer: value, length);
5802 u_int8_t *rule_value = necp_policy_condition_get_value_pointer_from_buffer(buffer: value, length);
5803
5804 if (rule_action == NECP_ROUTE_RULE_NONE) {
5805 // Don't allow an explicit rule to be None action
5806 continue;
5807 }
5808
5809 if (rule_action == NECP_ROUTE_RULE_USE_NETAGENT ||
5810 rule_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
5811 if (rule_length < sizeof(uuid_t)) {
5812 // Too short, skip
5813 continue;
5814 }
5815
5816 if (!uuid_is_null(uu: netagent_uuid)) {
5817 if (uuid_compare(uu1: netagent_uuid, uu2: rule_value) != 0) {
5818 // UUIDs don't match, skip
5819 continue;
5820 }
5821 } else {
5822 // Copy out agent UUID
5823 memcpy(dst: netagent_uuid, src: rule_value, n: sizeof(netagent_uuid));
5824 }
5825
5826 // Adjust remaining length
5827 rule_value += sizeof(netagent_uuid);
5828 rule_length -= sizeof(netagent_uuid);
5829 *has_socket_only_actions = true;
5830 } else if (rule_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
5831 if (rule_length < sizeof(control_unit)) {
5832 // Too short, skip
5833 continue;
5834 }
5835
5836 memcpy(dst: &control_unit, src: rule_value, n: sizeof(control_unit));
5837
5838 // Adjust remaining length
5839 rule_value += sizeof(control_unit);
5840 rule_length -= sizeof(control_unit);
5841 *has_socket_only_actions = true;
5842 } else if (rule_action == NECP_ROUTE_RULE_DENY_INTERFACE_WITH_TYPE) {
5843 if (rule_length < sizeof(effective_type)) {
5844 // Too short, skip
5845 continue;
5846 }
5847
5848 memcpy(dst: &effective_type, src: rule_value, n: sizeof(effective_type));
5849
5850 // Adjust remaining length
5851 rule_value += sizeof(effective_type);
5852 rule_length -= sizeof(effective_type);
5853 }
5854
5855 if (rule_length == 0) {
5856 if (rule_flags & NECP_ROUTE_RULE_FLAG_CELLULAR) {
5857 cellular_action = rule_action;
5858 }
5859 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIFI) {
5860 wifi_action = rule_action;
5861 }
5862 if (rule_flags & NECP_ROUTE_RULE_FLAG_WIRED) {
5863 wired_action = rule_action;
5864 }
5865 if (rule_flags & NECP_ROUTE_RULE_FLAG_EXPENSIVE) {
5866 expensive_action = rule_action;
5867 }
5868 if (rule_flags & NECP_ROUTE_RULE_FLAG_CONSTRAINED) {
5869 constrained_action = rule_action;
5870 }
5871 if (rule_flags & NECP_ROUTE_RULE_FLAG_COMPANION) {
5872 companion_action = rule_action;
5873 }
5874 if (rule_flags == 0) {
5875 default_action = rule_action;
5876 }
5877 continue;
5878 } else if (rule_flags & NECP_ROUTE_RULE_FLAG_NETAGENT) {
5879 if (rule_length == sizeof(uuid_t)) {
5880 memcpy(dst: match_netagent_uuid, src: rule_value, n: sizeof(match_netagent_uuid));
5881 default_action = rule_action;
5882 }
5883 continue;
5884 }
5885
5886 if (num_valid_indices >= MAX_ROUTE_RULE_INTERFACES) {
5887 continue;
5888 }
5889
5890 if (rule_length <= IFXNAMSIZ) {
5891 memcpy(dst: interface_name, src: rule_value, n: rule_length);
5892 interface_name[rule_length - 1] = 0; // Make sure the string is NULL terminated
5893 if (ifnet_find_by_name(ifname: interface_name, interface: &rule_interface) == 0) {
5894 if_actions[num_valid_indices] = rule_action;
5895 if_indices[num_valid_indices++] = rule_interface->if_index;
5896 ifnet_release(interface: rule_interface);
5897 }
5898 }
5899 }
5900
5901 existing_rule = necp_lookup_route_rule_by_contents_locked(list, default_action, cellular_action, wifi_action, wired_action, expensive_action, constrained_action, companion_action, if_indices, if_actions, netagent_uuid, match_netagent_uuid, control_unit, effective_type);
5902 if (existing_rule != NULL) {
5903 route_rule_id = existing_rule->id;
5904 os_ref_retain_locked(rc: &existing_rule->refcount);
5905 } else {
5906 struct necp_route_rule *new_rule = NULL;
5907 new_rule = kalloc_type(struct necp_route_rule,
5908 Z_WAITOK | Z_ZERO | Z_NOFAIL);
5909 route_rule_id = new_rule->id = necp_get_new_route_rule_id(false);
5910 if (!uuid_is_null(uu: netagent_uuid)) {
5911 new_rule->netagent_id = necp_create_uuid_service_id_mapping(uuid: netagent_uuid);
5912 }
5913 if (!uuid_is_null(uu: match_netagent_uuid)) {
5914 new_rule->match_netagent_id = necp_create_uuid_service_id_mapping(uuid: match_netagent_uuid);
5915 }
5916 new_rule->effective_type = effective_type;
5917 new_rule->control_unit = control_unit;
5918 new_rule->default_action = default_action;
5919 new_rule->cellular_action = cellular_action;
5920 new_rule->wifi_action = wifi_action;
5921 new_rule->wired_action = wired_action;
5922 new_rule->expensive_action = expensive_action;
5923 new_rule->constrained_action = constrained_action;
5924 new_rule->companion_action = companion_action;
5925 memcpy(dst: &new_rule->exception_if_indices, src: &if_indices, n: sizeof(if_indices));
5926 memcpy(dst: &new_rule->exception_if_actions, src: &if_actions, n: sizeof(if_actions));
5927 os_ref_init(&new_rule->refcount, &necp_refgrp);
5928 LIST_INSERT_HEAD(list, new_rule, chain);
5929 }
5930 return route_rule_id;
5931}
5932
5933static void
5934necp_remove_aggregate_route_rule_for_id(u_int32_t rule_id)
5935{
5936 if (rule_id) {
5937 lck_rw_lock_exclusive(lck: &necp_route_rule_lock);
5938
5939 struct necp_aggregate_route_rule *existing_rule = NULL;
5940 struct necp_aggregate_route_rule *tmp_rule = NULL;
5941
5942 LIST_FOREACH_SAFE(existing_rule, &necp_aggregate_route_rules, chain, tmp_rule) {
5943 int index = 0;
5944 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
5945 u_int32_t route_rule_id = existing_rule->rule_ids[index];
5946 if (route_rule_id == rule_id) {
5947 LIST_REMOVE(existing_rule, chain);
5948 kfree_type(struct necp_aggregate_route_rule, existing_rule);
5949 break;
5950 }
5951 }
5952 }
5953
5954 lck_rw_done(lck: &necp_route_rule_lock);
5955 }
5956}
5957
5958static bool
5959necp_remove_route_rule(struct necp_route_rule_list *list, u_int32_t route_rule_id)
5960{
5961 struct necp_route_rule *existing_rule = NULL;
5962
5963 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
5964
5965 existing_rule = necp_lookup_route_rule_locked(list, route_rule_id);
5966 if (existing_rule != NULL) {
5967 if (os_ref_release_locked(rc: &existing_rule->refcount) == 0) {
5968 necp_remove_aggregate_route_rule_for_id(rule_id: existing_rule->id);
5969 necp_remove_uuid_service_id_mapping_with_service_id(service_id: existing_rule->netagent_id);
5970 necp_remove_uuid_service_id_mapping_with_service_id(service_id: existing_rule->match_netagent_id);
5971 LIST_REMOVE(existing_rule, chain);
5972 kfree_type(struct necp_route_rule, existing_rule);
5973 }
5974 return TRUE;
5975 }
5976
5977 return FALSE;
5978}
5979
5980static struct necp_aggregate_route_rule *
5981necp_lookup_aggregate_route_rule_locked(u_int32_t route_rule_id)
5982{
5983 struct necp_aggregate_route_rule *searchentry = NULL;
5984 struct necp_aggregate_route_rule *foundentry = NULL;
5985
5986 lck_rw_lock_shared(lck: &necp_route_rule_lock);
5987
5988 LIST_FOREACH(searchentry, &necp_aggregate_route_rules, chain) {
5989 if (searchentry->id == route_rule_id) {
5990 foundentry = searchentry;
5991 break;
5992 }
5993 }
5994
5995 lck_rw_done(lck: &necp_route_rule_lock);
5996
5997 return foundentry;
5998}
5999
6000static u_int32_t
6001necp_create_aggregate_route_rule(u_int32_t *rule_ids)
6002{
6003 u_int32_t aggregate_route_rule_id = 0;
6004 struct necp_aggregate_route_rule *new_rule = NULL;
6005 struct necp_aggregate_route_rule *existing_rule = NULL;
6006
6007 lck_rw_lock_exclusive(lck: &necp_route_rule_lock);
6008
6009 // Check if the rule already exists
6010 LIST_FOREACH(existing_rule, &necp_aggregate_route_rules, chain) {
6011 if (memcmp(s1: existing_rule->rule_ids, s2: rule_ids, n: (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES)) == 0) {
6012 lck_rw_done(lck: &necp_route_rule_lock);
6013 return existing_rule->id;
6014 }
6015 }
6016
6017 new_rule = kalloc_type(struct necp_aggregate_route_rule,
6018 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6019 aggregate_route_rule_id = new_rule->id = necp_get_new_route_rule_id(true);
6020 new_rule->id = aggregate_route_rule_id;
6021 memcpy(dst: new_rule->rule_ids, src: rule_ids, n: (sizeof(u_int32_t) * MAX_AGGREGATE_ROUTE_RULES));
6022 LIST_INSERT_HEAD(&necp_aggregate_route_rules, new_rule, chain);
6023 lck_rw_done(lck: &necp_route_rule_lock);
6024
6025 return aggregate_route_rule_id;
6026}
6027
6028#define NECP_NULL_SERVICE_ID 1
6029#define NECP_FIRST_VALID_SERVICE_ID 2
6030#define NECP_FIRST_VALID_APP_ID UINT16_MAX
6031static u_int32_t
6032necp_get_new_uuid_id(bool service)
6033{
6034 static u_int32_t necp_last_service_uuid_id = 0;
6035 static u_int32_t necp_last_app_uuid_id = 0;
6036
6037 u_int32_t newid = 0;
6038
6039 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6040
6041 if (service) {
6042 bool wrapped = FALSE;
6043 do {
6044 necp_last_service_uuid_id++;
6045 if (necp_last_service_uuid_id < NECP_FIRST_VALID_SERVICE_ID ||
6046 necp_last_service_uuid_id >= NECP_FIRST_VALID_APP_ID) {
6047 if (wrapped) {
6048 // Already wrapped, give up
6049 NECPLOG0(LOG_ERR, "Failed to find a free service UUID.\n");
6050 return NECP_NULL_SERVICE_ID;
6051 }
6052 necp_last_service_uuid_id = NECP_FIRST_VALID_SERVICE_ID;
6053 wrapped = TRUE;
6054 }
6055 newid = necp_last_service_uuid_id;
6056 } while (necp_uuid_lookup_uuid_with_service_id_locked(local_id: newid) != NULL); // If already used, keep trying
6057 } else {
6058 bool wrapped = FALSE;
6059 do {
6060 necp_last_app_uuid_id++;
6061 if (necp_last_app_uuid_id < NECP_FIRST_VALID_APP_ID) {
6062 if (wrapped) {
6063 // Already wrapped, give up
6064 NECPLOG0(LOG_ERR, "Failed to find a free app UUID.\n");
6065 return NECP_NULL_SERVICE_ID;
6066 }
6067 necp_last_app_uuid_id = NECP_FIRST_VALID_APP_ID;
6068 wrapped = TRUE;
6069 }
6070 newid = necp_last_app_uuid_id;
6071 } while (necp_uuid_lookup_uuid_with_app_id_locked(local_id: newid) != NULL); // If already used, keep trying
6072 }
6073
6074 if (newid == NECP_NULL_SERVICE_ID) {
6075 NECPLOG0(LOG_ERR, "Allocate uuid ID failed.\n");
6076 return NECP_NULL_SERVICE_ID;
6077 }
6078
6079 return newid;
6080}
6081
6082static struct necp_uuid_id_mapping *
6083necp_uuid_lookup_app_id_locked(uuid_t uuid)
6084{
6085 struct necp_uuid_id_mapping *searchentry = NULL;
6086 struct necp_uuid_id_mapping *foundentry = NULL;
6087
6088 LIST_FOREACH(searchentry, APPUUIDHASH(uuid), chain) {
6089 if (uuid_compare(uu1: searchentry->uuid, uu2: uuid) == 0) {
6090 foundentry = searchentry;
6091 break;
6092 }
6093 }
6094
6095 return foundentry;
6096}
6097
6098static struct necp_uuid_id_mapping *
6099necp_uuid_lookup_uuid_with_app_id_locked(u_int32_t local_id)
6100{
6101 struct necp_uuid_id_mapping *searchentry = NULL;
6102 struct necp_uuid_id_mapping *foundentry = NULL;
6103
6104 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6105 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--) {
6106 LIST_FOREACH(searchentry, uuid_list_head, chain) {
6107 if (searchentry->id == local_id) {
6108 foundentry = searchentry;
6109 break;
6110 }
6111 }
6112 }
6113
6114 return foundentry;
6115}
6116
6117static u_int32_t
6118necp_create_uuid_app_id_mapping(uuid_t uuid, bool *allocated_mapping, bool uuid_policy_table)
6119{
6120 u_int32_t local_id = 0;
6121 struct necp_uuid_id_mapping *existing_mapping = NULL;
6122
6123 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6124
6125 if (allocated_mapping) {
6126 *allocated_mapping = FALSE;
6127 }
6128
6129 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6130 if (existing_mapping != NULL) {
6131 local_id = existing_mapping->id;
6132 os_ref_retain_locked(rc: &existing_mapping->refcount);
6133 if (uuid_policy_table) {
6134 existing_mapping->table_usecount++;
6135 }
6136 } else {
6137 struct necp_uuid_id_mapping *new_mapping = NULL;
6138 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6139 Z_WAITOK | Z_NOFAIL);
6140 uuid_copy(dst: new_mapping->uuid, src: uuid);
6141 new_mapping->id = necp_get_new_uuid_id(false);
6142 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6143 if (uuid_policy_table) {
6144 new_mapping->table_usecount = 1;
6145 } else {
6146 new_mapping->table_usecount = 0;
6147 }
6148
6149 LIST_INSERT_HEAD(APPUUIDHASH(uuid), new_mapping, chain);
6150
6151 if (allocated_mapping) {
6152 *allocated_mapping = TRUE;
6153 }
6154
6155 local_id = new_mapping->id;
6156 }
6157
6158 return local_id;
6159}
6160
6161static bool
6162necp_remove_uuid_app_id_mapping(uuid_t uuid, bool *removed_mapping, bool uuid_policy_table)
6163{
6164 struct necp_uuid_id_mapping *existing_mapping = NULL;
6165
6166 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6167
6168 if (removed_mapping) {
6169 *removed_mapping = FALSE;
6170 }
6171
6172 existing_mapping = necp_uuid_lookup_app_id_locked(uuid);
6173 if (existing_mapping != NULL) {
6174 if (uuid_policy_table) {
6175 existing_mapping->table_usecount--;
6176 }
6177 if (os_ref_release_locked(rc: &existing_mapping->refcount) == 0) {
6178 LIST_REMOVE(existing_mapping, chain);
6179 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6180 if (removed_mapping) {
6181 *removed_mapping = TRUE;
6182 }
6183 }
6184 return TRUE;
6185 }
6186
6187 return FALSE;
6188}
6189
6190static struct necp_uuid_id_mapping *
6191necp_uuid_get_null_service_id_mapping(void)
6192{
6193 static struct necp_uuid_id_mapping null_mapping;
6194 uuid_clear(uu: null_mapping.uuid);
6195 null_mapping.id = NECP_NULL_SERVICE_ID;
6196
6197 return &null_mapping;
6198}
6199
6200static struct necp_uuid_id_mapping *
6201necp_uuid_lookup_service_id_locked(uuid_t uuid)
6202{
6203 struct necp_uuid_id_mapping *searchentry = NULL;
6204 struct necp_uuid_id_mapping *foundentry = NULL;
6205
6206 if (uuid_is_null(uu: uuid)) {
6207 return necp_uuid_get_null_service_id_mapping();
6208 }
6209
6210 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6211 if (uuid_compare(uu1: searchentry->uuid, uu2: uuid) == 0) {
6212 foundentry = searchentry;
6213 break;
6214 }
6215 }
6216
6217 return foundentry;
6218}
6219
6220static struct necp_uuid_id_mapping *
6221necp_uuid_lookup_uuid_with_service_id_locked(u_int32_t local_id)
6222{
6223 struct necp_uuid_id_mapping *searchentry = NULL;
6224 struct necp_uuid_id_mapping *foundentry = NULL;
6225
6226 if (local_id == NECP_NULL_SERVICE_ID) {
6227 return necp_uuid_get_null_service_id_mapping();
6228 }
6229
6230 LIST_FOREACH(searchentry, &necp_uuid_service_id_list, chain) {
6231 if (searchentry->id == local_id) {
6232 foundentry = searchentry;
6233 break;
6234 }
6235 }
6236
6237 return foundentry;
6238}
6239
6240static u_int32_t
6241necp_create_uuid_service_id_mapping(uuid_t uuid)
6242{
6243 u_int32_t local_id = 0;
6244 struct necp_uuid_id_mapping *existing_mapping = NULL;
6245
6246 if (uuid_is_null(uu: uuid)) {
6247 return NECP_NULL_SERVICE_ID;
6248 }
6249
6250 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6251
6252 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6253 if (existing_mapping != NULL) {
6254 local_id = existing_mapping->id;
6255 os_ref_retain_locked(rc: &existing_mapping->refcount);
6256 } else {
6257 struct necp_uuid_id_mapping *new_mapping = NULL;
6258 new_mapping = kalloc_type(struct necp_uuid_id_mapping,
6259 Z_WAITOK | Z_NOFAIL);
6260 uuid_copy(dst: new_mapping->uuid, src: uuid);
6261 new_mapping->id = necp_get_new_uuid_id(true);
6262 os_ref_init(&new_mapping->refcount, &necp_refgrp);
6263
6264 LIST_INSERT_HEAD(&necp_uuid_service_id_list, new_mapping, chain);
6265
6266 local_id = new_mapping->id;
6267 }
6268
6269 return local_id;
6270}
6271
6272static bool
6273necp_remove_uuid_service_id_mapping(uuid_t uuid)
6274{
6275 struct necp_uuid_id_mapping *existing_mapping = NULL;
6276
6277 if (uuid_is_null(uu: uuid)) {
6278 return TRUE;
6279 }
6280
6281 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6282
6283 existing_mapping = necp_uuid_lookup_service_id_locked(uuid);
6284 if (existing_mapping != NULL) {
6285 if (os_ref_release_locked(rc: &existing_mapping->refcount) == 0) {
6286 LIST_REMOVE(existing_mapping, chain);
6287 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6288 }
6289 return TRUE;
6290 }
6291
6292 return FALSE;
6293}
6294
6295static bool
6296necp_remove_uuid_service_id_mapping_with_service_id(u_int32_t service_id)
6297{
6298 struct necp_uuid_id_mapping *existing_mapping = NULL;
6299
6300 if (service_id == 0) {
6301 return TRUE;
6302 }
6303
6304 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6305
6306 existing_mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: service_id);
6307 if (existing_mapping != NULL) {
6308 if (os_ref_release_locked(rc: &existing_mapping->refcount) == 0) {
6309 LIST_REMOVE(existing_mapping, chain);
6310 kfree_type(struct necp_uuid_id_mapping, existing_mapping);
6311 }
6312 return TRUE;
6313 }
6314
6315 return FALSE;
6316}
6317
6318static bool
6319necp_kernel_socket_policies_update_uuid_table(void)
6320{
6321 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6322
6323 if (necp_uuid_app_id_mappings_dirty) {
6324 if (proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_CLEAR, NULL, PROC_UUID_NECP_APP_POLICY) < 0) {
6325 NECPLOG0(LOG_DEBUG, "Error clearing uuids from policy table\n");
6326 return FALSE;
6327 }
6328
6329 if (necp_num_uuid_app_id_mappings > 0) {
6330 struct necp_uuid_id_mapping_head *uuid_list_head = NULL;
6331 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--) {
6332 struct necp_uuid_id_mapping *mapping = NULL;
6333 LIST_FOREACH(mapping, uuid_list_head, chain) {
6334 if (mapping->table_usecount > 0 &&
6335 proc_uuid_policy_kernel(PROC_UUID_POLICY_OPERATION_ADD, uuid: mapping->uuid, PROC_UUID_NECP_APP_POLICY) < 0) {
6336 NECPLOG0(LOG_DEBUG, "Error adding uuid to policy table\n");
6337 }
6338 }
6339 }
6340 }
6341
6342 necp_uuid_app_id_mappings_dirty = FALSE;
6343 }
6344
6345 return TRUE;
6346}
6347
6348#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 | NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)
6349static necp_kernel_policy_id
6350necp_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, u_int32_t cond_bound_interface_flags, u_int32_t cond_bound_interface_eflags, u_int32_t cond_bound_interface_xflags, necp_kernel_policy_result result, necp_kernel_policy_result_parameter result_parameter)
6351{
6352 struct necp_kernel_ip_output_policy *new_kernel_policy = NULL;
6353 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6354
6355 new_kernel_policy = zalloc_flags(necp_ip_policy_zone, Z_WAITOK | Z_ZERO);
6356 new_kernel_policy->id = necp_kernel_policy_get_new_id(false);
6357 new_kernel_policy->suborder = suborder;
6358 new_kernel_policy->order = order;
6359 new_kernel_policy->session_order = session_order;
6360 new_kernel_policy->session_pid = session_pid;
6361
6362 // Sanitize condition mask
6363 new_kernel_policy->condition_mask = (condition_mask & NECP_KERNEL_VALID_IP_OUTPUT_CONDITIONS);
6364 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE)) {
6365 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE;
6366 }
6367 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
6368 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS;
6369 }
6370 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX)) {
6371 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_LOCAL_PREFIX;
6372 }
6373 if ((new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) && (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX)) {
6374 new_kernel_policy->condition_mask &= ~NECP_KERNEL_CONDITION_REMOTE_PREFIX;
6375 }
6376 new_kernel_policy->condition_negated_mask = condition_negated_mask & new_kernel_policy->condition_mask;
6377
6378 // Set condition values
6379 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
6380 new_kernel_policy->cond_policy_id = cond_policy_id;
6381 }
6382 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
6383 if (cond_bound_interface) {
6384 ifnet_reference(interface: cond_bound_interface);
6385 }
6386 new_kernel_policy->cond_bound_interface = cond_bound_interface;
6387 }
6388 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
6389 new_kernel_policy->cond_last_interface_index = cond_last_interface_index;
6390 }
6391 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
6392 new_kernel_policy->cond_protocol = cond_protocol;
6393 }
6394 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6395 memcpy(dst: &new_kernel_policy->cond_local_start, src: cond_local_start, n: cond_local_start->sa.sa_len);
6396 }
6397 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6398 memcpy(dst: &new_kernel_policy->cond_local_end, src: cond_local_end, n: cond_local_end->sa.sa_len);
6399 }
6400 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6401 new_kernel_policy->cond_local_prefix = cond_local_prefix;
6402 }
6403 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6404 memcpy(dst: &new_kernel_policy->cond_remote_start, src: cond_remote_start, n: cond_remote_start->sa.sa_len);
6405 }
6406 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6407 memcpy(dst: &new_kernel_policy->cond_remote_end, src: cond_remote_end, n: cond_remote_end->sa.sa_len);
6408 }
6409 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6410 new_kernel_policy->cond_remote_prefix = cond_remote_prefix;
6411 }
6412 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
6413 new_kernel_policy->cond_packet_filter_tags = cond_packet_filter_tags;
6414 }
6415 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
6416 new_kernel_policy->cond_scheme_port = cond_scheme_port;
6417 }
6418 if (new_kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
6419 new_kernel_policy->cond_bound_interface_flags = cond_bound_interface_flags;
6420 new_kernel_policy->cond_bound_interface_eflags = cond_bound_interface_eflags;
6421 new_kernel_policy->cond_bound_interface_xflags = cond_bound_interface_xflags;
6422 }
6423 new_kernel_policy->result = result;
6424 memcpy(dst: &new_kernel_policy->result_parameter, src: &result_parameter, n: sizeof(result_parameter));
6425
6426 if (necp_debug) {
6427 NECPLOG(LOG_DEBUG, "Added kernel policy: ip output, id=%d, mask=%llx\n", new_kernel_policy->id, new_kernel_policy->condition_mask);
6428 }
6429 LIST_INSERT_SORTED_THRICE_ASCENDING(&necp_kernel_ip_output_policies, new_kernel_policy, chain, session_order, order, suborder, tmp_kernel_policy);
6430
6431 return new_kernel_policy ? new_kernel_policy->id : 0;
6432}
6433
6434static struct necp_kernel_ip_output_policy *
6435necp_kernel_ip_output_policy_find(necp_kernel_policy_id policy_id)
6436{
6437 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6438 struct necp_kernel_ip_output_policy *tmp_kernel_policy = NULL;
6439
6440 if (policy_id == 0) {
6441 return NULL;
6442 }
6443
6444 LIST_FOREACH_SAFE(kernel_policy, &necp_kernel_ip_output_policies, chain, tmp_kernel_policy) {
6445 if (kernel_policy->id == policy_id) {
6446 return kernel_policy;
6447 }
6448 }
6449
6450 return NULL;
6451}
6452
6453static bool
6454necp_kernel_ip_output_policy_delete(necp_kernel_policy_id policy_id)
6455{
6456 struct necp_kernel_ip_output_policy *policy = NULL;
6457
6458 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6459
6460 policy = necp_kernel_ip_output_policy_find(policy_id);
6461 if (policy) {
6462 LIST_REMOVE(policy, chain);
6463
6464 if (policy->cond_bound_interface) {
6465 ifnet_release(interface: policy->cond_bound_interface);
6466 policy->cond_bound_interface = NULL;
6467 }
6468
6469 zfree(necp_ip_policy_zone, policy);
6470 return TRUE;
6471 }
6472
6473 return FALSE;
6474}
6475
6476static void
6477necp_kernel_ip_output_policies_dump_all(void)
6478{
6479 if (necp_debug) {
6480 struct necp_kernel_ip_output_policy *policy = NULL;
6481 int policy_i;
6482 int id_i;
6483 char result_string[MAX_RESULT_STRING_LEN];
6484 char proc_name_string[MAXCOMLEN + 1];
6485 memset(s: result_string, c: 0, MAX_RESULT_STRING_LEN);
6486 memset(s: proc_name_string, c: 0, MAXCOMLEN + 1);
6487
6488 NECPLOG0(LOG_DEBUG, "NECP IP Output Policies:\n");
6489 NECPLOG0(LOG_DEBUG, "-----------\n");
6490 for (id_i = 0; id_i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; id_i++) {
6491 NECPLOG(LOG_DEBUG, " ID Bucket: %d\n", id_i);
6492 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++) {
6493 policy = (necp_kernel_ip_output_policies_map[id_i])[policy_i];
6494 proc_name(pid: policy->session_pid, buf: proc_name_string, MAXCOMLEN);
6495 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));
6496 }
6497 NECPLOG0(LOG_DEBUG, "-----------\n");
6498 }
6499 }
6500}
6501
6502static inline bool
6503necp_kernel_ip_output_policy_results_overlap(struct necp_kernel_ip_output_policy *upper_policy, struct necp_kernel_ip_output_policy *lower_policy)
6504{
6505 if (upper_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6506 if (upper_policy->session_order != lower_policy->session_order) {
6507 // A skip cannot override a policy of a different session
6508 return FALSE;
6509 } else {
6510 if (upper_policy->result_parameter.skip_policy_order == 0 ||
6511 lower_policy->order >= upper_policy->result_parameter.skip_policy_order) {
6512 // This policy is beyond the skip
6513 return FALSE;
6514 } else {
6515 // This policy is inside the skip
6516 return TRUE;
6517 }
6518 }
6519 }
6520
6521 // All other IP Output policy results (drop, tunnel, hard pass) currently overlap
6522 return TRUE;
6523}
6524
6525static bool
6526necp_kernel_ip_output_policy_is_unnecessary(struct necp_kernel_ip_output_policy *policy, struct necp_kernel_ip_output_policy **policy_array, int valid_indices)
6527{
6528 bool can_skip = FALSE;
6529 u_int32_t highest_skip_session_order = 0;
6530 u_int32_t highest_skip_order = 0;
6531 int i;
6532 for (i = 0; i < valid_indices; i++) {
6533 struct necp_kernel_ip_output_policy *compared_policy = policy_array[i];
6534
6535 // For policies in a skip window, we can't mark conflicting policies as unnecessary
6536 if (can_skip) {
6537 if (highest_skip_session_order != compared_policy->session_order ||
6538 (highest_skip_order != 0 && compared_policy->order >= highest_skip_order)) {
6539 // If we've moved on to the next session, or passed the skip window
6540 highest_skip_session_order = 0;
6541 highest_skip_order = 0;
6542 can_skip = FALSE;
6543 } else {
6544 // If this policy is also a skip, in can increase the skip window
6545 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6546 if (compared_policy->result_parameter.skip_policy_order > highest_skip_order) {
6547 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6548 }
6549 }
6550 continue;
6551 }
6552 }
6553
6554 if (compared_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6555 // This policy is a skip. Set the skip window accordingly
6556 can_skip = TRUE;
6557 highest_skip_session_order = compared_policy->session_order;
6558 highest_skip_order = compared_policy->result_parameter.skip_policy_order;
6559 }
6560
6561 // The result of the compared policy must be able to block out this policy result
6562 if (!necp_kernel_ip_output_policy_results_overlap(upper_policy: compared_policy, lower_policy: policy)) {
6563 continue;
6564 }
6565
6566 // If new policy matches All Interfaces, compared policy must also
6567 if ((policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
6568 continue;
6569 }
6570
6571 // If new policy matches Local Networks, compared policy must also
6572 if ((policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) && !(compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS)) {
6573 continue;
6574 }
6575
6576 // Default makes lower policies unnecessary always
6577 if (compared_policy->condition_mask == 0) {
6578 return TRUE;
6579 }
6580
6581 // Compared must be more general than policy, and include only conditions within policy
6582 if ((policy->condition_mask & compared_policy->condition_mask) != compared_policy->condition_mask) {
6583 continue;
6584 }
6585
6586 // Negative conditions must match for the overlapping conditions
6587 if ((policy->condition_negated_mask & compared_policy->condition_mask) != (compared_policy->condition_negated_mask & compared_policy->condition_mask)) {
6588 continue;
6589 }
6590
6591 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID &&
6592 compared_policy->cond_policy_id != policy->cond_policy_id) {
6593 continue;
6594 }
6595
6596 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE &&
6597 compared_policy->cond_bound_interface != policy->cond_bound_interface) {
6598 continue;
6599 }
6600
6601 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL &&
6602 compared_policy->cond_protocol != policy->cond_protocol) {
6603 continue;
6604 }
6605
6606 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
6607 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
6608 if (!necp_is_range_in_range(inner_range_start: (struct sockaddr *)&policy->cond_local_start, inner_range_end: (struct sockaddr *)&policy->cond_local_end, range_start: (struct sockaddr *)&compared_policy->cond_local_start, range_end: (struct sockaddr *)&compared_policy->cond_local_end)) {
6609 continue;
6610 }
6611 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
6612 if (compared_policy->cond_local_prefix > policy->cond_local_prefix ||
6613 !necp_is_addr_in_subnet(addr: (struct sockaddr *)&policy->cond_local_start, subnet_addr: (struct sockaddr *)&compared_policy->cond_local_start, subnet_prefix: compared_policy->cond_local_prefix)) {
6614 continue;
6615 }
6616 }
6617 }
6618
6619 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
6620 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
6621 if (!necp_is_range_in_range(inner_range_start: (struct sockaddr *)&policy->cond_remote_start, inner_range_end: (struct sockaddr *)&policy->cond_remote_end, range_start: (struct sockaddr *)&compared_policy->cond_remote_start, range_end: (struct sockaddr *)&compared_policy->cond_remote_end)) {
6622 continue;
6623 }
6624 } else if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
6625 if (compared_policy->cond_remote_prefix > policy->cond_remote_prefix ||
6626 !necp_is_addr_in_subnet(addr: (struct sockaddr *)&policy->cond_remote_start, subnet_addr: (struct sockaddr *)&compared_policy->cond_remote_start, subnet_prefix: compared_policy->cond_remote_prefix)) {
6627 continue;
6628 }
6629 }
6630 }
6631
6632 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT &&
6633 compared_policy->cond_scheme_port != policy->cond_scheme_port) {
6634 continue;
6635 }
6636
6637 if (compared_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS &&
6638 (compared_policy->cond_bound_interface_flags != policy->cond_bound_interface_flags ||
6639 compared_policy->cond_bound_interface_eflags != policy->cond_bound_interface_eflags ||
6640 compared_policy->cond_bound_interface_xflags != policy->cond_bound_interface_xflags)) {
6641 continue;
6642 }
6643
6644 return TRUE;
6645 }
6646
6647 return FALSE;
6648}
6649
6650static bool
6651necp_kernel_ip_output_policies_reprocess(void)
6652{
6653 int i;
6654 int bucket_current_free_index[NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS];
6655 struct necp_kernel_ip_output_policy *kernel_policy = NULL;
6656
6657 LCK_RW_ASSERT(&necp_kernel_policy_lock, LCK_RW_ASSERT_EXCLUSIVE);
6658
6659 // Reset mask to 0
6660 necp_kernel_ip_output_policies_condition_mask = 0;
6661 necp_kernel_ip_output_policies_count = 0;
6662 necp_kernel_ip_output_policies_non_id_count = 0;
6663
6664 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6665 if (necp_kernel_ip_output_policies_map[i] != NULL) {
6666 kfree_type(struct necp_kernel_ip_output_policy *,
6667 necp_kernel_ip_output_policies_map_counts[i] + 1,
6668 necp_kernel_ip_output_policies_map[i]);
6669 necp_kernel_ip_output_policies_map[i] = NULL;
6670 }
6671
6672 // Init counts
6673 necp_kernel_ip_output_policies_map_counts[i] = 0;
6674 }
6675
6676 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6677 // Update mask
6678 necp_kernel_ip_output_policies_condition_mask |= kernel_policy->condition_mask;
6679 necp_kernel_ip_output_policies_count++;
6680
6681 /* Update bucket counts:
6682 * Non-id and SKIP policies will be added to all buckets
6683 * Add local networks policy to all buckets for incoming IP
6684 */
6685 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6686 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6687 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6688 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6689 necp_kernel_ip_output_policies_map_counts[i]++;
6690 }
6691 }
6692 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID)) {
6693 necp_kernel_ip_output_policies_non_id_count++;
6694 } else {
6695 necp_kernel_ip_output_policies_map_counts[NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id)]++;
6696 }
6697 }
6698
6699 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6700 if (necp_kernel_ip_output_policies_map_counts[i] > 0) {
6701 // Allocate a NULL-terminated array of policy pointers for each bucket
6702 necp_kernel_ip_output_policies_map[i] = kalloc_type(struct necp_kernel_ip_output_policy *,
6703 necp_kernel_ip_output_policies_map_counts[i] + 1, Z_WAITOK | Z_ZERO);
6704 if (necp_kernel_ip_output_policies_map[i] == NULL) {
6705 goto fail;
6706 }
6707 }
6708 bucket_current_free_index[i] = 0;
6709 }
6710
6711 u_int32_t current_session_order = 0;
6712 u_int32_t current_session_last_non_skip_policy = 0;
6713
6714 LIST_FOREACH(kernel_policy, &necp_kernel_ip_output_policies, chain) {
6715 // For each new session, find the last non-skip policy. We can
6716 // avoid adding any skip policies that don't actually skip over
6717 // any non-skip policies.
6718 if (current_session_order != kernel_policy->session_order) {
6719 current_session_order = kernel_policy->session_order;
6720 current_session_last_non_skip_policy = 0;
6721
6722 struct necp_kernel_ip_output_policy *inner_policy = NULL;
6723 LIST_FOREACH(inner_policy, &necp_kernel_ip_output_policies, chain) {
6724 if (inner_policy->session_order < current_session_order) {
6725 continue;
6726 }
6727 if (inner_policy->session_order > current_session_order) {
6728 break;
6729 }
6730 if (inner_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6731 continue;
6732 }
6733
6734 current_session_last_non_skip_policy = inner_policy->order;
6735 }
6736 }
6737
6738 if (kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6739 if (current_session_last_non_skip_policy == 0) {
6740 // No useful policies to skip over, don't add
6741 continue;
6742 }
6743 if (kernel_policy->order >= current_session_last_non_skip_policy) {
6744 // Skip policy is after the last useful policy, don't add
6745 continue;
6746 }
6747 }
6748
6749 // Insert pointers into map
6750 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) ||
6751 (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) ||
6752 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
6753 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6754 if (!necp_dedup_policies || !necp_kernel_ip_output_policy_is_unnecessary(policy: kernel_policy, policy_array: necp_kernel_ip_output_policies_map[i], valid_indices: bucket_current_free_index[i])) {
6755 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
6756 bucket_current_free_index[i]++;
6757 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
6758 }
6759 }
6760 } else {
6761 i = NECP_IP_OUTPUT_MAP_ID_TO_BUCKET(kernel_policy->cond_policy_id);
6762 if (!necp_dedup_policies || !necp_kernel_ip_output_policy_is_unnecessary(policy: kernel_policy, policy_array: necp_kernel_ip_output_policies_map[i], valid_indices: bucket_current_free_index[i])) {
6763 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = kernel_policy;
6764 bucket_current_free_index[i]++;
6765 (necp_kernel_ip_output_policies_map[i])[(bucket_current_free_index[i])] = NULL;
6766 }
6767 }
6768 }
6769
6770 if (bucket_current_free_index[0] == 0) {
6771 // No non-id policies were actually added
6772 necp_kernel_ip_output_policies_non_id_count = 0;
6773
6774 // Also check if no policies at all were added
6775 bool policies_added = FALSE;
6776 for (i = 1; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6777 if (bucket_current_free_index[i] != 0) {
6778 policies_added = TRUE;
6779 break;
6780 }
6781 }
6782 if (!policies_added) {
6783 necp_kernel_ip_output_policies_condition_mask = 0;
6784 necp_kernel_ip_output_policies_count = 0;
6785 }
6786 }
6787
6788 necp_kernel_ip_output_policies_dump_all();
6789 return TRUE;
6790
6791fail:
6792 // Free memory, reset mask to 0
6793 necp_kernel_ip_output_policies_condition_mask = 0;
6794 necp_kernel_ip_output_policies_count = 0;
6795 necp_kernel_ip_output_policies_non_id_count = 0;
6796 for (i = 0; i < NECP_KERNEL_IP_OUTPUT_POLICIES_MAP_NUM_ID_BUCKETS; i++) {
6797 if (necp_kernel_ip_output_policies_map[i] != NULL) {
6798 kfree_type(struct necp_kernel_ip_output_policy *,
6799 necp_kernel_ip_output_policies_map_counts[i] + 1,
6800 necp_kernel_ip_output_policies_map[i]);
6801 necp_kernel_ip_output_policies_map[i] = NULL;
6802 }
6803 }
6804 return FALSE;
6805}
6806
6807// Outbound Policy Matching
6808// ---------------------
6809struct substring {
6810 char *string;
6811 size_t length;
6812};
6813
6814static struct substring
6815necp_trim_dots_and_stars(char *string, size_t length)
6816{
6817 struct substring sub;
6818 sub.string = string;
6819 sub.length = string ? length : 0;
6820
6821 while (sub.length && (sub.string[0] == '.' || sub.string[0] == '*')) {
6822 sub.string++;
6823 sub.length--;
6824 }
6825
6826 while (sub.length && (sub.string[sub.length - 1] == '.' || sub.string[sub.length - 1] == '*')) {
6827 sub.length--;
6828 }
6829
6830 return sub;
6831}
6832
6833static char *
6834necp_create_trimmed_domain(char *string, size_t length)
6835{
6836 char *trimmed_domain = NULL;
6837 struct substring sub = necp_trim_dots_and_stars(string, length);
6838
6839 trimmed_domain = (char *)kalloc_data(sub.length + 1, Z_WAITOK);
6840 if (trimmed_domain == NULL) {
6841 return NULL;
6842 }
6843
6844 memcpy(dst: trimmed_domain, src: sub.string, n: sub.length);
6845 trimmed_domain[sub.length] = 0;
6846
6847 return trimmed_domain;
6848}
6849
6850static inline int
6851necp_count_dots(char *string, size_t length)
6852{
6853 int dot_count = 0;
6854 size_t i = 0;
6855
6856 for (i = 0; i < length; i++) {
6857 if (string[i] == '.') {
6858 dot_count++;
6859 }
6860 }
6861
6862 return dot_count;
6863}
6864
6865static bool
6866necp_check_suffix(struct substring parent, struct substring suffix, bool require_dot_before_suffix)
6867{
6868 if (parent.length <= suffix.length) {
6869 return FALSE;
6870 }
6871
6872 size_t length_difference = (parent.length - suffix.length);
6873
6874 if (require_dot_before_suffix) {
6875 if (((char *)(parent.string + length_difference - 1))[0] != '.') {
6876 return FALSE;
6877 }
6878 }
6879
6880 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6881 return strncasecmp(s1: parent.string + length_difference, s2: suffix.string, n: suffix.length) == 0;
6882}
6883
6884static bool
6885necp_hostname_matches_domain(struct substring hostname_substring, u_int8_t hostname_dot_count, char *domain, u_int8_t domain_dot_count)
6886{
6887 if (hostname_substring.string == NULL || domain == NULL) {
6888 return hostname_substring.string == domain;
6889 }
6890
6891 struct substring domain_substring;
6892 domain_substring.string = domain;
6893 domain_substring.length = strlen(s: domain);
6894
6895 if (hostname_dot_count == domain_dot_count) {
6896 // strncasecmp does case-insensitive check for all UTF-8 strings (ignores non-ASCII characters)
6897 if (hostname_substring.length == domain_substring.length &&
6898 strncasecmp(s1: hostname_substring.string, s2: domain_substring.string, n: hostname_substring.length) == 0) {
6899 return TRUE;
6900 }
6901 } else if (domain_dot_count < hostname_dot_count) {
6902 if (necp_check_suffix(parent: hostname_substring, suffix: domain_substring, TRUE)) {
6903 return TRUE;
6904 }
6905 }
6906
6907 return FALSE;
6908}
6909
6910bool
6911net_domain_contains_hostname(char *hostname_string, char *domain_string)
6912{
6913 if (hostname_string == NULL ||
6914 domain_string == NULL) {
6915 return false;
6916 }
6917
6918 struct substring hostname_substring;
6919 hostname_substring.string = hostname_string;
6920 hostname_substring.length = strlen(s: hostname_string);
6921
6922 return necp_hostname_matches_domain(hostname_substring,
6923 hostname_dot_count: necp_count_dots(string: hostname_string, length: hostname_substring.length),
6924 domain: domain_string,
6925 domain_dot_count: necp_count_dots(string: domain_string, length: strlen(s: domain_string)));
6926}
6927
6928#define NECP_MAX_STRING_LEN 1024
6929
6930static char *
6931necp_copy_string(char *string, size_t length)
6932{
6933 char *copied_string = NULL;
6934
6935 if (length > NECP_MAX_STRING_LEN) {
6936 return NULL;
6937 }
6938
6939 copied_string = (char *)kalloc_data(length + 1, Z_WAITOK);
6940 if (copied_string == NULL) {
6941 return NULL;
6942 }
6943
6944 memcpy(dst: copied_string, src: string, n: length);
6945 copied_string[length] = 0;
6946
6947 return copied_string;
6948}
6949
6950static u_int32_t
6951necp_get_primary_direct_interface_index(void)
6952{
6953 u_int32_t interface_index = IFSCOPE_NONE;
6954
6955 ifnet_head_lock_shared();
6956 struct ifnet *ordered_interface = NULL;
6957 TAILQ_FOREACH(ordered_interface, &ifnet_ordered_head, if_ordered_link) {
6958 const u_int8_t functional_type = if_functional_type(ordered_interface, TRUE);
6959 if (functional_type != IFRTYPE_FUNCTIONAL_UNKNOWN &&
6960 functional_type != IFRTYPE_FUNCTIONAL_LOOPBACK) {
6961 // All known, non-loopback functional types represent direct physical interfaces (Wi-Fi, Cellular, Wired)
6962 interface_index = ordered_interface->if_index;
6963 break;
6964 }
6965 }
6966 ifnet_head_done();
6967
6968 return interface_index;
6969}
6970
6971static inline bool
6972necp_task_has_match_entitlement(task_t task)
6973{
6974 return task != NULL &&
6975 (IOTaskHasEntitlement(task, entitlement: "com.apple.private.necp.match") ||
6976 IOTaskHasEntitlement(task, entitlement: "com.apple.developer.CaptiveNetworkPlugin"));
6977}
6978
6979static inline void
6980necp_get_parent_is_entitled(task_t task, struct necp_socket_info *info)
6981{
6982 coalition_t coal = task_get_coalition(task, COALITION_TYPE_JETSAM);
6983
6984 if (coal == COALITION_NULL || coalition_is_leader(task, coal)) {
6985 // No parent, nothing to do
6986 return;
6987 }
6988
6989 task_t lead_task = coalition_get_leader(coal);
6990 if (lead_task != NULL) {
6991 info->is_entitled = necp_task_has_match_entitlement(task: lead_task);
6992 task_deallocate(lead_task);
6993 }
6994}
6995
6996// Some processes, due to particular entitlements, require using an NECP client to
6997// access networking. Returns true if the result should be a Drop.
6998static inline bool
6999necp_check_missing_client_drop(proc_t proc, struct necp_socket_info *info)
7000{
7001 if (necp_is_platform_binary(proc)) {
7002 // This check is currently for the "on-demand-install-capable"
7003 // entitlement, which by definition cannot be a built-in platform
7004 // binary.
7005 return false;
7006 }
7007
7008 task_t task = proc_task(proc ? proc : current_proc());
7009
7010 if (!info->has_client &&
7011 task != NULL &&
7012 IOTaskHasEntitlement(task, entitlement: "com.apple.developer.on-demand-install-capable")) {
7013 // Drop connections that don't use NECP clients and have the
7014 // com.apple.developer.on-demand-install-capable entitlement.
7015 // This effectively restricts those processes to only using
7016 // an NECP-aware path for networking.
7017 return true;
7018 } else {
7019 return false;
7020 }
7021}
7022
7023static inline bool
7024necp_check_restricted_multicast_drop(proc_t proc, struct necp_socket_info *info, bool check_minor_version)
7025{
7026 if (!necp_restrict_multicast || proc == NULL) {
7027 return false;
7028 }
7029
7030 // Check for multicast/broadcast here
7031 if (info->remote_addr.sa.sa_family == AF_INET) {
7032 if (!IN_MULTICAST(ntohl(info->remote_addr.sin.sin_addr.s_addr)) &&
7033 info->remote_addr.sin.sin_addr.s_addr != INADDR_BROADCAST) {
7034 return false;
7035 }
7036 } else if (info->remote_addr.sa.sa_family == AF_INET6) {
7037 if (!IN6_IS_ADDR_MULTICAST(&info->remote_addr.sin6.sin6_addr)) {
7038 return false;
7039 }
7040 } else {
7041 // Not IPv4/IPv6
7042 return false;
7043 }
7044
7045 if (necp_is_platform_binary(proc)) {
7046 return false;
7047 }
7048
7049 const uint32_t platform = proc_platform(proc);
7050 const uint32_t sdk = proc_sdk(proc);
7051
7052 // Enforce for iOS, linked on or after version 14
7053 // If the caller set `check_minor_version`, only enforce starting at 14.5
7054 if ((platform != PLATFORM_IOS ||
7055 sdk == 0 ||
7056 (sdk >> 16) < 14 ||
7057 (check_minor_version && (sdk >> 16) == 14 && ((sdk >> 8) & 0xff) < 5))) {
7058 return false;
7059 }
7060
7061 // Allow entitled processes to use multicast
7062 task_t task = proc_task(proc);
7063 if (task != NULL &&
7064 IOTaskHasEntitlement(task, entitlement: "com.apple.developer.networking.multicast")) {
7065 return false;
7066 }
7067
7068 const uint32_t min_sdk = proc_min_sdk(proc);
7069 NECPLOG(LOG_INFO, "Dropping unentitled multicast (SDK 0x%x, min 0x%x)", sdk, min_sdk);
7070
7071 return true;
7072}
7073
7074#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)
7075static void
7076necp_application_fillout_info_locked(task_t task, uuid_t application_uuid, uuid_t real_application_uuid, uuid_t responsible_application_uuid, char *account, char *domain, char *url, pid_t pid, int32_t pid_version, uid_t uid, uid_t real_uid, u_int16_t protocol, u_int32_t bound_interface_index, u_int32_t traffic_class, union necp_sockaddr_union *local_addr, union necp_sockaddr_union *remote_addr, u_int16_t local_port, u_int16_t remote_port, bool has_client, bool has_system_signed_result, proc_t real_proc, proc_t proc, proc_t responsible_proc, u_int32_t drop_order, u_int32_t client_flags, u_int16_t scheme_port, struct necp_socket_info *info, bool is_loopback, bool is_delegated)
7077{
7078 memset(s: info, c: 0, n: sizeof(struct necp_socket_info));
7079
7080 info->pid = pid;
7081 info->pid_version = pid_version;
7082 info->uid = uid;
7083 info->real_uid = real_uid;
7084 info->protocol = protocol;
7085 info->bound_interface_index = bound_interface_index;
7086 info->traffic_class = traffic_class;
7087 info->has_client = has_client;
7088 info->has_system_signed_result = has_system_signed_result;
7089 info->drop_order = drop_order;
7090 info->client_flags = client_flags;
7091 info->is_loopback = is_loopback;
7092 info->is_delegated = is_delegated;
7093
7094 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
7095 info->bound_interface_index != IFSCOPE_NONE) {
7096 ifnet_head_lock_shared();
7097 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
7098 if (interface != NULL) {
7099 info->bound_interface_flags = interface->if_flags;
7100 info->bound_interface_eflags = interface->if_eflags;
7101 info->bound_interface_xflags = interface->if_xflags;
7102 }
7103 ifnet_head_done();
7104 }
7105
7106 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(uu: application_uuid)) {
7107 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(uuid: application_uuid);
7108 if (existing_mapping) {
7109 info->application_id = existing_mapping->id;
7110 }
7111 }
7112
7113 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID && !uuid_is_null(uu: real_application_uuid)) {
7114 if (uuid_compare(uu1: application_uuid, uu2: real_application_uuid) == 0) {
7115 info->real_application_id = info->application_id;
7116 } else {
7117 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(uuid: real_application_uuid);
7118 if (existing_mapping) {
7119 info->real_application_id = existing_mapping->id;
7120 }
7121 }
7122 }
7123
7124 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID && !uuid_is_null(uu: responsible_application_uuid)) {
7125 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(uuid: responsible_application_uuid);
7126 if (existing_mapping != NULL) {
7127 info->real_application_id = info->application_id;
7128 info->application_id = existing_mapping->id;
7129 info->used_responsible_pid = true;
7130 }
7131 }
7132
7133 if (info->used_responsible_pid) {
7134 proc = responsible_proc;
7135 }
7136
7137 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT && proc != NULL) {
7138 info->is_entitled = necp_task_has_match_entitlement(task);
7139 if (!info->is_entitled) {
7140 // Task does not have entitlement, check the parent task
7141 necp_get_parent_is_entitled(task, info);
7142 }
7143 }
7144
7145 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY && proc != NULL) {
7146 info->is_platform_binary = necp_is_platform_binary(proc) ? true : false;
7147 }
7148
7149 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY && real_proc != NULL) {
7150 info->real_is_platform_binary = (necp_is_platform_binary(proc: real_proc) ? true : false);
7151 }
7152
7153 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && account != NULL) {
7154 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(list: &necp_account_id_list, string: account);
7155 if (existing_mapping) {
7156 info->account_id = existing_mapping->id;
7157 }
7158 }
7159
7160 if ((necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
7161 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
7162 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
7163 info->domain = domain;
7164 }
7165
7166 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_URL) {
7167 info->url = url;
7168 }
7169
7170 if ((necp_data_tracing_level && necp_data_tracing_port) ||
7171 necp_restrict_multicast ||
7172 (necp_kernel_application_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
7173 if (local_addr && local_addr->sa.sa_len > 0) {
7174 memcpy(dst: &info->local_addr, src: local_addr, n: local_addr->sa.sa_len);
7175 if (local_port != 0) {
7176 info->local_addr.sin6.sin6_port = local_port;
7177 }
7178 } else {
7179 if (remote_addr && remote_addr->sa.sa_len > 0) {
7180 info->local_addr.sa.sa_family = remote_addr->sa.sa_family;
7181 info->local_addr.sa.sa_len = remote_addr->sa.sa_len;
7182 } else {
7183 info->local_addr.sin6.sin6_family = AF_INET6;
7184 info->local_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7185 }
7186 if (local_port != 0) {
7187 info->local_addr.sin6.sin6_port = local_port;
7188 }
7189 }
7190 if (remote_addr && remote_addr->sa.sa_len > 0) {
7191 memcpy(dst: &info->remote_addr, src: remote_addr, n: remote_addr->sa.sa_len);
7192 if (remote_port != 0) {
7193 info->remote_addr.sin6.sin6_port = remote_port;
7194 }
7195 } else if (remote_port != 0) {
7196 info->remote_addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
7197 info->remote_addr.sin6.sin6_family = AF_INET6;
7198 info->remote_addr.sin6.sin6_port = remote_port;
7199 }
7200 }
7201
7202 if (necp_kernel_application_policies_condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
7203 info->scheme_port = scheme_port;
7204 }
7205}
7206
7207static void
7208necp_send_application_interface_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t if_functional_type)
7209{
7210 struct kev_netpolicy_ifdenied ev_ifdenied;
7211
7212 bzero(s: &ev_ifdenied, n: sizeof(ev_ifdenied));
7213
7214 ev_ifdenied.ev_data.epid = pid;
7215 uuid_copy(dst: ev_ifdenied.ev_data.euuid, src: proc_uuid);
7216 ev_ifdenied.ev_if_functional_type = if_functional_type;
7217
7218 netpolicy_post_msg(KEV_NETPOLICY_IFDENIED, &ev_ifdenied.ev_data, sizeof(ev_ifdenied));
7219}
7220
7221static void
7222necp_send_network_denied_event(pid_t pid, uuid_t proc_uuid, u_int32_t network_type)
7223{
7224 struct kev_netpolicy_netdenied ev_netdenied = {};
7225
7226 bzero(s: &ev_netdenied, n: sizeof(ev_netdenied));
7227
7228 ev_netdenied.ev_data.epid = pid;
7229 uuid_copy(dst: ev_netdenied.ev_data.euuid, src: proc_uuid);
7230 ev_netdenied.ev_network_type = network_type;
7231
7232 netpolicy_post_msg(KEV_NETPOLICY_NETDENIED, &ev_netdenied.ev_data, sizeof(ev_netdenied));
7233}
7234
7235extern char *proc_name_address(void *p);
7236
7237#define NECP_VERIFY_DELEGATION_ENTITLEMENT(_p, _c, _d) \
7238 if (!has_checked_delegation_entitlement) { \
7239 has_delegation_entitlement = (priv_check_cred(_c, PRIV_NET_PRIVILEGED_SOCKET_DELEGATE, 0) == 0); \
7240 has_checked_delegation_entitlement = TRUE; \
7241 } \
7242 if (!has_delegation_entitlement) { \
7243 NECPLOG(LOG_ERR, "%s(%d) does not hold the necessary entitlement to delegate network traffic for other processes by %s", \
7244 proc_name_address(_p), proc_pid(_p), _d); \
7245 break; \
7246 }
7247
7248int
7249necp_application_find_policy_match_internal(proc_t proc,
7250 u_int8_t *parameters,
7251 u_int32_t parameters_size,
7252 struct necp_aggregate_result *returned_result,
7253 u_int32_t *flags,
7254 u_int32_t *reason,
7255 u_int required_interface_index,
7256 const union necp_sockaddr_union *override_local_addr,
7257 const union necp_sockaddr_union *override_remote_addr,
7258 struct necp_client_endpoint *returned_v4_gateway,
7259 struct necp_client_endpoint *returned_v6_gateway,
7260 struct rtentry **returned_route, bool ignore_address,
7261 bool has_client,
7262 uuid_t *returned_override_euuid)
7263{
7264 int error = 0;
7265 size_t offset = 0;
7266
7267 struct necp_kernel_socket_policy *matched_policy = NULL;
7268 struct necp_socket_info info = {};
7269 necp_kernel_policy_filter filter_control_unit = 0;
7270 necp_kernel_policy_result service_action = 0;
7271 necp_kernel_policy_service service = { 0, 0 };
7272
7273 u_int16_t protocol = 0;
7274 u_int32_t bound_interface_index = required_interface_index;
7275 u_int32_t traffic_class = 0;
7276 u_int32_t client_flags = 0;
7277 u_int16_t scheme_port = 0;
7278 union necp_sockaddr_union local_addr;
7279 union necp_sockaddr_union remote_addr;
7280 bool no_remote_addr = FALSE;
7281 u_int8_t remote_family = 0;
7282 bool no_local_addr = FALSE;
7283 u_int16_t local_port = 0;
7284 u_int16_t remote_port = 0;
7285 u_int32_t remote_endpoint_type = 0;
7286 bool remote_address_is_empty = false;
7287 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
7288 bool is_delegated = false;
7289
7290 if (override_local_addr) {
7291 memcpy(dst: &local_addr, src: override_local_addr, n: sizeof(local_addr));
7292 } else {
7293 memset(s: &local_addr, c: 0, n: sizeof(local_addr));
7294 }
7295 if (override_remote_addr) {
7296 memcpy(dst: &remote_addr, src: override_remote_addr, n: sizeof(remote_addr));
7297 } else {
7298 memset(s: &remote_addr, c: 0, n: sizeof(remote_addr));
7299 }
7300
7301 // Initialize UID, PID, and UUIDs to the current process
7302 uid_t uid = 0;
7303 uid_t real_uid = 0;
7304 kauth_cred_t cred = kauth_cred_proc_ref(procp: proc);
7305 if (cred != NULL) {
7306 uid = kauth_cred_getuid(cred: cred);
7307 real_uid = uid;
7308 }
7309 task_t task = proc_task(proc);
7310 pid_t pid = proc_pid(proc);
7311 int32_t pid_version = proc_pidversion(proc);
7312 uuid_t application_uuid;
7313 uuid_clear(uu: application_uuid);
7314 uuid_t real_application_uuid;
7315 uuid_clear(uu: real_application_uuid);
7316 proc_getexecutableuuid(proc, real_application_uuid, sizeof(real_application_uuid));
7317 uuid_copy(dst: application_uuid, src: real_application_uuid);
7318 uuid_t responsible_application_uuid;
7319 uuid_clear(uu: responsible_application_uuid);
7320
7321 char *domain = NULL;
7322 char *url = NULL;
7323 char *account = NULL;
7324
7325#define NECP_MAX_REQUIRED_AGENTS 16
7326 u_int32_t num_required_agent_types = 0;
7327 struct necp_client_parameter_netagent_type required_agent_types[NECP_MAX_REQUIRED_AGENTS];
7328 memset(s: &required_agent_types, c: 0, n: sizeof(required_agent_types));
7329
7330 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
7331 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
7332 memset(s: &netagent_ids, c: 0, n: sizeof(netagent_ids));
7333 memset(s: &netagent_use_flags, c: 0, n: sizeof(netagent_use_flags));
7334 int netagent_cursor;
7335
7336 bool has_checked_delegation_entitlement = false;
7337 bool has_delegation_entitlement = false;
7338 bool has_system_signed_result = false;
7339
7340 proc_t responsible_proc = PROC_NULL;
7341 proc_t effective_proc = proc;
7342 bool release_eproc = false;
7343 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
7344
7345 u_int32_t flow_divert_aggregate_unit = 0;
7346
7347 if (returned_result == NULL) {
7348 if (cred != NULL) {
7349 kauth_cred_unref(&cred);
7350 }
7351 return EINVAL;
7352 }
7353
7354 if (returned_v4_gateway != NULL) {
7355 memset(s: returned_v4_gateway, c: 0, n: sizeof(struct necp_client_endpoint));
7356 }
7357
7358 if (returned_v6_gateway != NULL) {
7359 memset(s: returned_v6_gateway, c: 0, n: sizeof(struct necp_client_endpoint));
7360 }
7361
7362 if (returned_override_euuid != NULL) {
7363 uuid_clear(uu: *returned_override_euuid);
7364 }
7365
7366 memset(s: returned_result, c: 0, n: sizeof(struct necp_aggregate_result));
7367
7368 u_int32_t drop_order = necp_process_drop_order(cred);
7369
7370 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
7371
7372 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
7373 if (necp_kernel_application_policies_count == 0 && necp_drop_management_order == 0) {
7374 if (necp_drop_all_order > 0 || drop_order > 0) {
7375 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7376 lck_rw_done(lck: &necp_kernel_policy_lock);
7377 if (cred != NULL) {
7378 kauth_cred_unref(&cred);
7379 }
7380 return 0;
7381 }
7382 }
7383 lck_rw_done(lck: &necp_kernel_policy_lock);
7384
7385 while ((offset + sizeof(u_int8_t) + sizeof(u_int32_t)) <= parameters_size) {
7386 u_int8_t type = necp_buffer_get_tlv_type(buffer: parameters, tlv_offset: offset);
7387 u_int32_t length = necp_buffer_get_tlv_length(buffer: parameters, tlv_offset: offset);
7388
7389 if (length > (parameters_size - (offset + sizeof(u_int8_t) + sizeof(u_int32_t)))) {
7390 // If the length is larger than what can fit in the remaining parameters size, bail
7391 NECPLOG(LOG_ERR, "Invalid TLV length (%u)", length);
7392 break;
7393 }
7394
7395 if (length > 0) {
7396 u_int8_t *value = necp_buffer_get_tlv_value(buffer: parameters, tlv_offset: offset, NULL);
7397 if (value != NULL) {
7398 switch (type) {
7399 case NECP_CLIENT_PARAMETER_APPLICATION: {
7400 if (length >= sizeof(uuid_t)) {
7401 if (uuid_compare(uu1: application_uuid, uu2: value) == 0) {
7402 // No delegation
7403 break;
7404 }
7405
7406 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "euuid");
7407
7408 is_delegated = true;
7409 uuid_copy(dst: application_uuid, src: value);
7410 }
7411 break;
7412 }
7413 case NECP_CLIENT_PARAMETER_REAL_APPLICATION: {
7414 if (length >= sizeof(uuid_t)) {
7415 if (uuid_compare(uu1: real_application_uuid, uu2: value) == 0) {
7416 // No delegation
7417 break;
7418 }
7419
7420 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uuid");
7421
7422 is_delegated = true;
7423 uuid_copy(dst: real_application_uuid, src: value);
7424 }
7425 break;
7426 }
7427 case NECP_CLIENT_PARAMETER_PID: {
7428 if (length >= sizeof(pid_t)) {
7429 if (memcmp(s1: &pid, s2: value, n: sizeof(pid_t)) == 0) {
7430 // No delegation
7431 break;
7432 }
7433
7434 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "pid");
7435
7436 is_delegated = true;
7437 memcpy(dst: &pid, src: value, n: sizeof(pid_t));
7438 }
7439 break;
7440 }
7441 case NECP_CLIENT_PARAMETER_UID: {
7442 if (length >= sizeof(uid_t)) {
7443 if (memcmp(s1: &uid, s2: value, n: sizeof(uid_t)) == 0) {
7444 // No delegation
7445 break;
7446 }
7447
7448 NECP_VERIFY_DELEGATION_ENTITLEMENT(proc, cred, "uid");
7449
7450 is_delegated = true;
7451 memcpy(dst: &uid, src: value, n: sizeof(uid_t));
7452 }
7453 break;
7454 }
7455 case NECP_CLIENT_PARAMETER_DOMAIN: {
7456 domain = (char *)value;
7457 domain[length - 1] = 0;
7458 break;
7459 }
7460 case NECP_CLIENT_PARAMETER_URL: {
7461 url = (char *)value;
7462 url[length - 1] = 0;
7463 break;
7464 }
7465 case NECP_CLIENT_PARAMETER_ACCOUNT: {
7466 account = (char *)value;
7467 account[length - 1] = 0;
7468 break;
7469 }
7470 case NECP_CLIENT_PARAMETER_TRAFFIC_CLASS: {
7471 if (length >= sizeof(u_int32_t)) {
7472 memcpy(dst: &traffic_class, src: value, n: sizeof(u_int32_t));
7473 }
7474 break;
7475 }
7476 case NECP_CLIENT_PARAMETER_IP_PROTOCOL: {
7477 if (length >= sizeof(u_int16_t)) {
7478 memcpy(dst: &protocol, src: value, n: sizeof(u_int16_t));
7479 } else if (length >= sizeof(u_int8_t)) {
7480 memcpy(dst: &protocol, src: value, n: sizeof(u_int8_t));
7481 }
7482 break;
7483 }
7484 case NECP_CLIENT_PARAMETER_BOUND_INTERFACE: {
7485 if (length <= IFXNAMSIZ && length > 0) {
7486 ifnet_t bound_interface = NULL;
7487 char interface_name[IFXNAMSIZ];
7488 memcpy(dst: interface_name, src: value, n: length);
7489 interface_name[length - 1] = 0; // Make sure the string is NULL terminated
7490 if (ifnet_find_by_name(ifname: interface_name, interface: &bound_interface) == 0) {
7491 bound_interface_index = bound_interface->if_index;
7492 ifnet_release(interface: bound_interface);
7493 }
7494 }
7495 break;
7496 }
7497 case NECP_CLIENT_PARAMETER_LOCAL_ADDRESS: {
7498 if (ignore_address || override_local_addr) {
7499 break;
7500 }
7501
7502 if (length >= sizeof(struct necp_policy_condition_addr)) {
7503 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7504 if (necp_address_is_valid(&address_struct->address.sa)) {
7505 memcpy(dst: &local_addr, src: &address_struct->address, n: sizeof(address_struct->address));
7506 }
7507 }
7508 break;
7509 }
7510 case NECP_CLIENT_PARAMETER_REMOTE_ADDRESS: {
7511 if (ignore_address || override_remote_addr) {
7512 break;
7513 }
7514
7515 if (length >= sizeof(struct necp_policy_condition_addr)) {
7516 struct necp_policy_condition_addr *address_struct = (struct necp_policy_condition_addr *)(void *)value;
7517 if (necp_address_is_valid(&address_struct->address.sa)) {
7518 memcpy(dst: &remote_addr, src: &address_struct->address, n: sizeof(address_struct->address));
7519 }
7520 }
7521 break;
7522 }
7523 case NECP_CLIENT_PARAMETER_LOCAL_ENDPOINT: {
7524 if (ignore_address || override_local_addr) {
7525 break;
7526 }
7527
7528 if (length >= sizeof(struct necp_client_endpoint)) {
7529 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7530 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC &&
7531 endpoint->u.endpoint.endpoint_port != 0) {
7532 // Save port
7533 local_port = endpoint->u.endpoint.endpoint_port;
7534 }
7535 }
7536 break;
7537 }
7538 case NECP_CLIENT_PARAMETER_REMOTE_ENDPOINT: {
7539 if (ignore_address || override_remote_addr) {
7540 break;
7541 }
7542
7543 if (length >= sizeof(struct necp_client_endpoint)) {
7544 struct necp_client_endpoint *endpoint = (struct necp_client_endpoint *)(void *)value;
7545 if (endpoint->u.endpoint.endpoint_family == AF_UNSPEC) {
7546 remote_endpoint_type = endpoint->u.endpoint.endpoint_type;
7547 if (endpoint->u.endpoint.endpoint_port != 0) {
7548 // Save port
7549 remote_port = endpoint->u.endpoint.endpoint_port;
7550 }
7551 } else if (necp_addr_is_empty(addr: &endpoint->u.sa)) {
7552 remote_address_is_empty = true;
7553 }
7554 }
7555 break;
7556 }
7557 case NECP_CLIENT_PARAMETER_FLAGS: {
7558 if (length >= sizeof(client_flags)) {
7559 memcpy(dst: &client_flags, src: value, n: sizeof(client_flags));
7560 }
7561 break;
7562 }
7563 case NECP_CLIENT_PARAMETER_REQUIRE_AGENT_TYPE:
7564 case NECP_CLIENT_PARAMETER_PREFER_AGENT_TYPE: {
7565 if (num_required_agent_types >= NECP_MAX_REQUIRED_AGENTS) {
7566 break;
7567 }
7568 if (length >= sizeof(struct necp_client_parameter_netagent_type)) {
7569 memcpy(dst: &required_agent_types[num_required_agent_types], src: value, n: sizeof(struct necp_client_parameter_netagent_type));
7570 num_required_agent_types++;
7571 }
7572 break;
7573 }
7574 case NECP_CLIENT_PARAMETER_SCHEME_PORT: {
7575 if (length >= sizeof(scheme_port)) {
7576 memcpy(dst: &scheme_port, src: value, n: sizeof(scheme_port));
7577 }
7578 break;
7579 }
7580 case NECP_CLIENT_PARAMETER_RESOLVER_TAG: {
7581 has_system_signed_result = true;
7582 struct necp_client_validatable *validatable = (struct necp_client_validatable *)value;
7583 if (length >= sizeof(struct necp_client_validatable)) {
7584 // Check for system-signed sign_type values
7585 if (validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_RESOLVER_ANSWER ||
7586 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_BROWSE_RESULT ||
7587 validatable->signable.sign_type == NECP_CLIENT_SIGN_TYPE_SYSTEM_SERVICE_RESOLVER_ANSWER) {
7588 has_system_signed_result = true;
7589 }
7590 }
7591 break;
7592 }
7593 default: {
7594 break;
7595 }
7596 }
7597 }
7598 }
7599
7600 offset += sizeof(u_int8_t) + sizeof(u_int32_t) + length;
7601 }
7602
7603 // Check for loopback exception
7604 if (necp_pass_loopback > 0 && necp_is_loopback(SA(&local_addr.sa), SA(&remote_addr.sa), NULL, NULL, bound_interface_index)) {
7605 bypass_type = NECP_BYPASS_TYPE_LOOPBACK;
7606 } else if (bound_interface_index != IFSCOPE_NONE) {
7607 // Check for inter-process exception
7608 struct sockaddr *dst = SA(&remote_addr.sa);
7609 if (dst->sa_family == AF_INET6) {
7610 struct in6_addr *addrv6 = &(((struct sockaddr_in6 *)(void *)dst)->sin6_addr);
7611 if (NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
7612 ifnet_head_lock_shared();
7613 ifnet_t bound_interface = ifindex2ifnet[bound_interface_index];
7614 if (bound_interface != NULL && IFNET_IS_INTCOPROC(bound_interface)) {
7615 bypass_type = NECP_BYPASS_TYPE_INTCOPROC;
7616 }
7617 ifnet_head_done();
7618 }
7619 }
7620 }
7621
7622 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
7623 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7624 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7625 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7626 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK) {
7627 returned_result->routed_interface_index = lo_ifp->if_index;
7628 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7629 } else {
7630 returned_result->routed_interface_index = bound_interface_index;
7631 }
7632 if (cred != NULL) {
7633 kauth_cred_unref(&cred);
7634 }
7635 return 0;
7636 }
7637
7638 if (drop_order != 0) {
7639 if (remote_endpoint_type == NECP_CLIENT_ENDPOINT_TYPE_APPLICATION_SERVICE ||
7640 client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER ||
7641 ((client_flags & NECP_CLIENT_PARAMETER_FLAG_INBOUND) && remote_address_is_empty)) {
7642 // Allow listeners, inbound connections without remote addresses, and
7643 // application service connections to bypass the unentitled drop order,
7644 // to allow them to connect to application services (not directly over
7645 // physical networking interfaces)
7646 drop_order = 0;
7647 }
7648 }
7649
7650 if (proc_pid(effective_proc) != pid) {
7651 proc_t found_proc = proc_find(pid);
7652 if (found_proc != PROC_NULL) {
7653 effective_proc = found_proc;
7654 pid_version = proc_pidversion(effective_proc);
7655 release_eproc = true;
7656 }
7657 }
7658#if defined(XNU_TARGET_OS_OSX)
7659 if (effective_proc->p_responsible_pid > 0 && effective_proc->p_responsible_pid != pid) {
7660 proc_getresponsibleuuid(effective_proc, responsible_application_uuid, sizeof(responsible_application_uuid));
7661 responsible_proc = proc_find(pid: effective_proc->p_responsible_pid);
7662 }
7663#endif /* defined(XNU_TARGET_OS_OSX) */
7664
7665 // Lock
7666 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
7667
7668 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
7669 size_t route_rule_id_array_count = 0;
7670 necp_application_fillout_info_locked(task, application_uuid, real_application_uuid, responsible_application_uuid, account, domain, url, pid, pid_version, uid, real_uid, protocol, bound_interface_index, traffic_class, local_addr: &local_addr, remote_addr: &remote_addr, local_port, remote_port, has_client, has_system_signed_result, real_proc: proc, proc: effective_proc, responsible_proc, drop_order, client_flags, scheme_port, info: &info, is_loopback: (bypass_type == NECP_BYPASS_TYPE_LOOPBACK), is_delegated);
7671
7672 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
7673 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "START", 0, 0);
7674
7675 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
7676 matched_policy = necp_socket_find_policy_match_with_info_locked(policy_search_array: necp_kernel_socket_policies_app_layer_map, info: &info, return_filter: &filter_control_unit, return_route_rule_id_array: route_rule_id_array, return_route_rule_id_array_count: &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, return_service_action: &service_action, return_service: &service, return_netagent_array: netagent_ids, return_netagent_use_flags_array: netagent_use_flags, NECP_MAX_NETAGENTS, required_agent_types, num_required_agent_types, proc: info.used_responsible_pid ? responsible_proc : effective_proc, pf_tag: 0, skip_policy_id: &skip_policy_id, NULL, return_drop_dest_policy_result: &drop_dest_policy_result, return_drop_all_bypass: &drop_all_bypass, return_flow_divert_aggregate_unit: &flow_divert_aggregate_unit, NULL, debug);
7677
7678 // Check for loopback exception again after the policy match
7679 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
7680 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
7681 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
7682 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7683 returned_result->filter_control_unit = 0;
7684 } else {
7685 returned_result->filter_control_unit = filter_control_unit;
7686 }
7687
7688 if (flow_divert_aggregate_unit > 0) {
7689 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7690 }
7691
7692 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7693 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7694 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_PASS;
7695 returned_result->routed_interface_index = lo_ifp->if_index;
7696 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7697 error = 0;
7698 goto done;
7699 }
7700
7701 if (matched_policy) {
7702 returned_result->policy_id = matched_policy->id;
7703 returned_result->skip_policy_id = skip_policy_id;
7704 returned_result->routing_result = matched_policy->result;
7705 memcpy(dst: &returned_result->routing_result_parameter, src: &matched_policy->result_parameter, n: sizeof(returned_result->routing_result_parameter));
7706 if (returned_override_euuid != NULL && info.used_responsible_pid && !(matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
7707 uuid_copy(dst: *returned_override_euuid, src: responsible_application_uuid);
7708 }
7709 } else {
7710 bool drop_all = false;
7711 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
7712 // Mark socket as a drop if drop_all is set
7713 drop_all = true;
7714 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
7715 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
7716 }
7717 }
7718 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
7719 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7720 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7721 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7722 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO MATCH>", 0, 0);
7723 } else {
7724 returned_result->policy_id = 0;
7725 returned_result->skip_policy_id = 0;
7726 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_NONE;
7727 }
7728 }
7729 if (necp_check_missing_client_drop(proc, info: &info) ||
7730 necp_check_restricted_multicast_drop(proc, info: &info, false)) {
7731 // Mark as drop
7732 returned_result->policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7733 returned_result->skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
7734 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7735 NECP_DATA_TRACE_LOG_APP_LEVEL(debug, "APPLICATION", "RESULT - DROP <NO CLIENT / MULTICAST>", 0, 0);
7736 }
7737 if (filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
7738 returned_result->filter_control_unit = 0;
7739 } else {
7740 returned_result->filter_control_unit = filter_control_unit;
7741 }
7742
7743 if (flow_divert_aggregate_unit > 0) {
7744 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
7745 }
7746
7747 returned_result->service_action = service_action;
7748
7749 // Fetch service registration
7750 if (service.identifier != 0) {
7751 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: service.identifier);
7752 if (mapping != NULL) {
7753 struct necp_service_registration *service_registration = NULL;
7754 uuid_copy(dst: returned_result->service_uuid, src: mapping->uuid);
7755 returned_result->service_data = service.data;
7756 if (service.identifier == NECP_NULL_SERVICE_ID) {
7757 // NULL service is always 'registered'
7758 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
7759 } else {
7760 LIST_FOREACH(service_registration, &necp_registered_service_list, kernel_chain) {
7761 if (service.identifier == service_registration->service_id) {
7762 returned_result->service_flags |= NECP_SERVICE_FLAGS_REGISTERED;
7763 break;
7764 }
7765 }
7766 }
7767 }
7768 }
7769
7770 // Handle netagents
7771 size_t netagent_i = 0;
7772 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
7773 struct necp_uuid_id_mapping *mapping = NULL;
7774 u_int32_t netagent_id = netagent_ids[netagent_cursor];
7775 if (netagent_id == 0) {
7776 continue;
7777 }
7778 mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: netagent_id);
7779 if (mapping != NULL) {
7780 uuid_copy(dst: returned_result->netagents[netagent_i], src: mapping->uuid);
7781 returned_result->netagent_use_flags[netagent_i] = netagent_use_flags[netagent_cursor];
7782 netagent_i++;
7783 }
7784
7785 // If the flags say to remove, clear the local copy
7786 if (netagent_use_flags[netagent_cursor] & NECP_AGENT_USE_FLAG_REMOVE) {
7787 netagent_ids[netagent_cursor] = 0;
7788 }
7789 }
7790
7791 // Do routing evaluation
7792 u_int output_bound_interface = bound_interface_index;
7793 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
7794 output_bound_interface = returned_result->routing_result_parameter.scoped_interface_index;
7795 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
7796 output_bound_interface = returned_result->routing_result_parameter.tunnel_interface_index;
7797 } else if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
7798 output_bound_interface = necp_get_primary_direct_interface_index();
7799 if (output_bound_interface == IFSCOPE_NONE) {
7800 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
7801 } else {
7802 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED;
7803 returned_result->routing_result_parameter.scoped_interface_index = output_bound_interface;
7804 }
7805 }
7806
7807 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_DROP &&
7808 returned_result->routing_result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK) {
7809 if (!(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
7810 // Trigger the event that we dropped due to a local network policy
7811 necp_send_network_denied_event(pid, proc_uuid: application_uuid, NETPOLICY_NETWORKTYPE_LOCAL);
7812 }
7813 if (reason != NULL) {
7814 *reason = NECP_CLIENT_RESULT_REASON_LOCAL_NETWORK_PROHIBITED;
7815 }
7816 }
7817
7818 if (local_addr.sa.sa_len == 0 ||
7819 (local_addr.sa.sa_family == AF_INET && local_addr.sin.sin_addr.s_addr == 0) ||
7820 (local_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&local_addr.sin6.sin6_addr))) {
7821 no_local_addr = TRUE;
7822 }
7823
7824 if (remote_addr.sa.sa_len == 0 ||
7825 (remote_addr.sa.sa_family == AF_INET && remote_addr.sin.sin_addr.s_addr == 0) ||
7826 (remote_addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr.sin6.sin6_addr))) {
7827 no_remote_addr = TRUE;
7828 remote_family = remote_addr.sa.sa_family;
7829 }
7830
7831 returned_result->routed_interface_index = 0;
7832 struct rtentry *rt = NULL;
7833 if (!no_local_addr && (client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0) {
7834 // Treat the output bound interface as the routed interface for local address
7835 // validation later.
7836 returned_result->routed_interface_index = output_bound_interface;
7837 } else {
7838 if (no_remote_addr) {
7839 memset(s: &remote_addr, c: 0, n: sizeof(remote_addr));
7840 if (remote_family == AF_INET6) {
7841 // Reset address to ::
7842 remote_addr.sa.sa_family = AF_INET6;
7843 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
7844 } else {
7845 // Reset address to 0.0.0.0
7846 remote_addr.sa.sa_family = AF_INET;
7847 remote_addr.sa.sa_len = sizeof(struct sockaddr_in);
7848 }
7849 }
7850
7851 rt = rtalloc1_scoped((struct sockaddr *)&remote_addr, 0, 0,
7852 output_bound_interface);
7853
7854 if (remote_addr.sa.sa_family == AF_INET && rt != NULL &&
7855 IS_INTF_CLAT46(rt->rt_ifp)) {
7856 rtfree(rt);
7857 rt = NULL;
7858 returned_result->routed_interface_index = 0;
7859 }
7860
7861 if (no_remote_addr && remote_family == AF_UNSPEC &&
7862 (rt == NULL || rt->rt_ifp == NULL)) {
7863 // Route lookup for default IPv4 failed, try IPv6
7864
7865 // Cleanup old route if necessary
7866 if (rt != NULL) {
7867 rtfree(rt);
7868 rt = NULL;
7869 }
7870
7871 // Reset address to ::
7872 memset(s: &remote_addr, c: 0, n: sizeof(remote_addr));
7873 remote_addr.sa.sa_family = AF_INET6;
7874 remote_addr.sa.sa_len = sizeof(struct sockaddr_in6);
7875
7876 // Get route
7877 rt = rtalloc1_scoped((struct sockaddr *)&remote_addr, 0, 0,
7878 output_bound_interface);
7879 }
7880
7881 if (rt != NULL &&
7882 rt->rt_ifp != NULL) {
7883 returned_result->routed_interface_index = rt->rt_ifp->if_index;
7884 /*
7885 * For local addresses, we allow the interface scope to be
7886 * either the loopback interface or the interface hosting the
7887 * local address.
7888 */
7889 if (bound_interface_index != IFSCOPE_NONE &&
7890 rt->rt_ifa != NULL && rt->rt_ifa->ifa_ifp &&
7891 (output_bound_interface == lo_ifp->if_index ||
7892 rt->rt_ifp->if_index == lo_ifp->if_index ||
7893 rt->rt_ifa->ifa_ifp->if_index == bound_interface_index)) {
7894 struct sockaddr_storage dst;
7895 unsigned int ifscope = bound_interface_index;
7896
7897 /*
7898 * Transform dst into the internal routing table form
7899 */
7900 (void) sa_copy((struct sockaddr *)&remote_addr,
7901 &dst, &ifscope);
7902
7903 if ((rt->rt_ifp->if_index == lo_ifp->if_index) ||
7904 rt_ifa_is_dst((struct sockaddr *)&dst, rt->rt_ifa)) {
7905 returned_result->routed_interface_index =
7906 bound_interface_index;
7907 }
7908 }
7909 }
7910 }
7911
7912 if (returned_result->routed_interface_index != 0 &&
7913 returned_result->routed_interface_index != lo_ifp->if_index && // Loopback can accept any local address
7914 !no_local_addr) {
7915 // Transform local_addr into the ifaddr form
7916 // IPv6 Scope IDs are always embedded in the ifaddr list
7917 struct sockaddr_storage local_address_sanitized;
7918 u_int ifscope = IFSCOPE_NONE;
7919 (void)sa_copy(SA(&local_addr.sa), &local_address_sanitized, &ifscope);
7920 SIN(&local_address_sanitized)->sin_port = 0;
7921 if (local_address_sanitized.ss_family == AF_INET6) {
7922 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&local_address_sanitized)->sin6_addr)) {
7923 SIN6(&local_address_sanitized)->sin6_scope_id = 0;
7924 }
7925 }
7926
7927 // Validate local address on routed interface
7928 struct ifaddr *ifa = ifa_ifwithaddr_scoped((struct sockaddr *)&local_address_sanitized, returned_result->routed_interface_index);
7929 if (ifa == NULL) {
7930 // Interface address not found, reject route
7931 returned_result->routed_interface_index = 0;
7932 if (rt != NULL) {
7933 rtfree(rt);
7934 rt = NULL;
7935 }
7936 } else {
7937 ifaddr_release(ifaddr: ifa);
7938 ifa = NULL;
7939 }
7940 }
7941
7942 if (flags != NULL) {
7943#if SKYWALK && defined(XNU_TARGET_OS_OSX)
7944 enum net_filter_event_subsystems filters = net_filter_event_get_state();
7945
7946 if (filters & (NET_FILTER_EVENT_SOCKET | NET_FILTER_EVENT_INTERFACE | NET_FILTER_EVENT_IP)) {
7947 *flags |= NECP_CLIENT_RESULT_FLAG_KEXT_FILTER_PRESENT;
7948 }
7949 if (filters & NET_FILTER_EVENT_PF_PRIVATE_PROXY) {
7950 *flags |= NECP_CLIENT_RESULT_FLAG_PF_RULES_PRESENT;
7951 }
7952 if (filters & NET_FILTER_EVENT_ALF) {
7953 *flags |= NECP_CLIENT_RESULT_FLAG_ALF_PRESENT;
7954 }
7955 if (filters & NET_FILTER_EVENT_PARENTAL_CONTROLS) {
7956 *flags |= NECP_CLIENT_RESULT_FLAG_PARENTAL_CONTROLS_PRESENT;
7957 }
7958#endif /* SKYWALK && defined(XNU_TARGET_OS_OSX) */
7959 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) == 0) {
7960 // Check for local/direct
7961 bool is_local = FALSE;
7962 if (rt != NULL && (rt->rt_flags & RTF_LOCAL)) {
7963 is_local = TRUE;
7964 } else if (returned_result->routed_interface_index != 0 &&
7965 !no_remote_addr) {
7966 // Clean up the address before comparison with interface addresses
7967
7968 // Transform remote_addr into the ifaddr form
7969 // IPv6 Scope IDs are always embedded in the ifaddr list
7970 struct sockaddr_storage remote_address_sanitized;
7971 u_int ifscope = IFSCOPE_NONE;
7972 (void)sa_copy(SA(&remote_addr.sa), &remote_address_sanitized, &ifscope);
7973 SIN(&remote_address_sanitized)->sin_port = 0;
7974 if (remote_address_sanitized.ss_family == AF_INET6) {
7975 if (in6_embedded_scope || !IN6_IS_SCOPE_EMBED(&SIN6(&remote_address_sanitized)->sin6_addr)) {
7976 SIN6(&remote_address_sanitized)->sin6_scope_id = 0;
7977 }
7978 }
7979
7980 // Check if remote address is an interface address
7981 struct ifaddr *ifa = ifa_ifwithaddr((struct sockaddr *)&remote_address_sanitized);
7982 if (ifa != NULL && ifa->ifa_ifp != NULL) {
7983 u_int if_index_for_remote_addr = ifa->ifa_ifp->if_index;
7984 if (if_index_for_remote_addr == returned_result->routed_interface_index ||
7985 if_index_for_remote_addr == lo_ifp->if_index) {
7986 is_local = TRUE;
7987 }
7988 }
7989 if (ifa != NULL) {
7990 ifaddr_release(ifaddr: ifa);
7991 ifa = NULL;
7992 }
7993 }
7994
7995 if (is_local) {
7996 *flags |= (NECP_CLIENT_RESULT_FLAG_IS_LOCAL | NECP_CLIENT_RESULT_FLAG_IS_DIRECT);
7997 } else if (rt != NULL) {
7998 if (rt->rt_flags & RTF_GLOBAL) {
7999 *flags |= NECP_CLIENT_RESULT_FLAG_IS_GLOBAL_INTERNET;
8000 } else if (!(rt->rt_flags & RTF_GATEWAY) &&
8001 (rt->rt_ifa && rt->rt_ifa->ifa_ifp && !(rt->rt_ifa->ifa_ifp->if_flags & IFF_POINTOPOINT))) {
8002 // Route is directly accessible
8003 *flags |= NECP_CLIENT_RESULT_FLAG_IS_DIRECT;
8004 }
8005 }
8006
8007 if (rt != NULL &&
8008 rt->rt_ifp != NULL) {
8009 // Check probe status
8010 if (rt->rt_ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
8011 *flags |= NECP_CLIENT_RESULT_FLAG_PROBE_CONNECTIVITY;
8012 }
8013
8014 if (rt->rt_ifp->if_type == IFT_CELLULAR) {
8015 struct if_cellular_status_v1 *ifsr;
8016
8017 ifnet_lock_shared(ifp: rt->rt_ifp);
8018 lck_rw_lock_exclusive(lck: &rt->rt_ifp->if_link_status_lock);
8019
8020 if (rt->rt_ifp->if_link_status != NULL) {
8021 ifsr = &rt->rt_ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
8022
8023 if (ifsr->valid_bitmask & IF_CELL_UL_MSS_RECOMMENDED_VALID) {
8024 if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_NONE) {
8025 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_NONE;
8026 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_MEDIUM) {
8027 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_MEDIUM;
8028 } else if (ifsr->mss_recommended == IF_CELL_UL_MSS_RECOMMENDED_LOW) {
8029 returned_result->mss_recommended = NECP_CLIENT_RESULT_RECOMMENDED_MSS_LOW;
8030 }
8031 }
8032 }
8033 lck_rw_done(lck: &rt->rt_ifp->if_link_status_lock);
8034 ifnet_lock_done(ifp: rt->rt_ifp);
8035 }
8036
8037 // Check link quality
8038 if ((client_flags & NECP_CLIENT_PARAMETER_FLAG_DISCRETIONARY) &&
8039 (rt->rt_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
8040 rt->rt_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
8041 *flags |= NECP_CLIENT_RESULT_FLAG_LINK_QUALITY_ABORT;
8042 }
8043
8044 // Check QoS marking (fastlane)
8045 for (size_t route_rule_index = 0; route_rule_index < route_rule_id_array_count; route_rule_index++) {
8046 if (necp_update_qos_marking(ifp: rt->rt_ifp, netagent_array: netagent_ids, NECP_MAX_NETAGENTS, route_rule_id: route_rule_id_array[route_rule_index])) {
8047 *flags |= NECP_CLIENT_RESULT_FLAG_ALLOW_QOS_MARKING;
8048 // If the route can use QoS markings, stop iterating route rules
8049 break;
8050 }
8051 }
8052
8053 if (IFNET_IS_LOW_POWER(rt->rt_ifp)) {
8054 *flags |= NECP_CLIENT_RESULT_FLAG_INTERFACE_LOW_POWER;
8055 }
8056
8057 if (traffic_class == SO_TC_BK_SYS) {
8058 // Block BK_SYS traffic if interface is throttled
8059 u_int32_t throttle_level = 0;
8060 if (ifnet_get_throttle(rt->rt_ifp, &throttle_level) == 0) {
8061 if (throttle_level == IFNET_THROTTLE_OPPORTUNISTIC) {
8062 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8063 memset(s: &returned_result->routing_result_parameter, c: 0, n: sizeof(returned_result->routing_result_parameter));
8064 }
8065 }
8066 }
8067 }
8068 }
8069
8070 u_int interface_to_check = returned_result->routed_interface_index;
8071 if (interface_to_check == 0) {
8072 interface_to_check = output_bound_interface;
8073 }
8074 union necp_sockaddr_union default_address;
8075 struct rtentry *v4Route = NULL;
8076 struct rtentry *v6Route = NULL;
8077
8078 memset(s: &default_address, c: 0, n: sizeof(default_address));
8079
8080 // Reset address to 0.0.0.0
8081 default_address.sa.sa_family = AF_INET;
8082 default_address.sa.sa_len = sizeof(struct sockaddr_in);
8083 v4Route = rtalloc1_scoped((struct sockaddr *)&default_address, 0, 0,
8084 returned_result->routed_interface_index);
8085
8086 // Reset address to ::
8087 default_address.sa.sa_family = AF_INET6;
8088 default_address.sa.sa_len = sizeof(struct sockaddr_in6);
8089 v6Route = rtalloc1_scoped((struct sockaddr *)&default_address, 0, 0,
8090 returned_result->routed_interface_index);
8091
8092 if (v4Route != NULL) {
8093 if (v4Route->rt_ifp != NULL && !IS_INTF_CLAT46(v4Route->rt_ifp)) {
8094 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV4;
8095 }
8096 if (returned_v4_gateway != NULL &&
8097 v4Route->rt_gateway != NULL &&
8098 v4Route->rt_gateway->sa_len == sizeof(returned_v4_gateway->u.sin)) {
8099 memcpy(dst: &returned_v4_gateway->u.sin, src: v4Route->rt_gateway, n: sizeof(returned_v4_gateway->u.sin));
8100 memset(s: &returned_v4_gateway->u.sin.sin_zero, c: 0, n: sizeof(returned_v4_gateway->u.sin.sin_zero));
8101 }
8102 rtfree(v4Route);
8103 v4Route = NULL;
8104 }
8105
8106 if (v6Route != NULL) {
8107 if (v6Route->rt_ifp != NULL) {
8108 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_IPV6;
8109
8110 if (ifnet_get_nat64prefix(v6Route->rt_ifp, returned_result->nat64_prefixes) == 0) {
8111 *flags |= NECP_CLIENT_RESULT_FLAG_HAS_NAT64;
8112 }
8113 }
8114 if (returned_v6_gateway != NULL &&
8115 v6Route->rt_gateway != NULL &&
8116 v6Route->rt_gateway->sa_len == sizeof(returned_v6_gateway->u.sin6)) {
8117 memcpy(dst: &returned_v6_gateway->u.sin6, src: v6Route->rt_gateway, n: sizeof(returned_v6_gateway->u.sin6));
8118 }
8119 rtfree(v6Route);
8120 v6Route = NULL;
8121 }
8122 }
8123
8124 // Take two passes through the rule list: first for rules that don't match based on agents,
8125 // second for rules that match based on agents. Since rules can modify the agent list itself,
8126 // this makes the logic more deterministic. This allows a non-agent matching rule to remove
8127 // an agent before it is used for matching later.
8128 size_t route_rule_index = 0;
8129 bool second_pass = false;
8130 while (route_rule_index < route_rule_id_array_count) {
8131 bool rule_matches_agents = necp_route_rule_matches_agents(route_rule_id: route_rule_id_array[route_rule_index]);
8132 if (rule_matches_agents != second_pass) {
8133 // Process rules that match based on agents only in the second pass
8134 route_rule_index++;
8135 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8136 route_rule_index = 0;
8137 second_pass = true;
8138 }
8139 continue;
8140 }
8141
8142 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
8143 bool route_is_allowed = necp_route_is_allowed(route: rt, NULL, netagent_array: netagent_ids, NECP_MAX_NETAGENTS, route_rule_id: route_rule_id_array[route_rule_index], interface_type_denied: &interface_type_denied);
8144 if (!route_is_allowed) {
8145 // If the route is blocked, treat the lookup as a drop
8146 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8147 memset(s: &returned_result->routing_result_parameter, c: 0, n: sizeof(returned_result->routing_result_parameter));
8148
8149 if (interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
8150 if (reason != NULL) {
8151 if (interface_type_denied == IFRTYPE_FUNCTIONAL_CELLULAR) {
8152 *reason = NECP_CLIENT_RESULT_REASON_CELLULAR_DENIED;
8153 } else if (interface_type_denied == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
8154 *reason = NECP_CLIENT_RESULT_REASON_WIFI_DENIED;
8155 }
8156 }
8157 necp_send_application_interface_denied_event(pid, proc_uuid: application_uuid, if_functional_type: interface_type_denied);
8158 }
8159 // If the route gets denied, stop matching rules
8160 break;
8161 }
8162
8163 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
8164 if (returned_result->routing_result == NECP_KERNEL_POLICY_RESULT_NONE) {
8165 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(route: rt, netagent_array: netagent_ids, NECP_MAX_NETAGENTS,
8166 route_rule_id: route_rule_id_array[route_rule_index], flow_divert_aggregate_unit: &flow_divert_aggregate_unit);
8167 if (flow_divert_control_unit != 0) {
8168 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
8169 returned_result->routing_result_parameter.flow_divert_control_unit = flow_divert_control_unit;
8170 }
8171 if (flow_divert_aggregate_unit != 0) {
8172 returned_result->flow_divert_aggregate_unit = flow_divert_aggregate_unit;
8173 }
8174 }
8175
8176 // Check if there is a route rule that adds or removes an agent
8177 bool remove = false;
8178 u_int32_t netagent_id = necp_route_get_netagent(route: rt, netagent_array: netagent_ids, NECP_MAX_NETAGENTS, route_rule_id: route_rule_id_array[route_rule_index], remove: &remove);
8179 if (netagent_id != 0) {
8180 struct necp_uuid_id_mapping *mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: netagent_id);
8181 if (mapping != NULL) {
8182 bool agent_already_present = false;
8183 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8184 if (uuid_compare(uu1: returned_result->netagents[netagent_cursor], uu2: mapping->uuid) == 0) {
8185 // Found the agent already present
8186 agent_already_present = true;
8187 if (remove) {
8188 // Mark as remove if necessary
8189 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8190 }
8191 } else if (uuid_is_null(uu: returned_result->netagents[netagent_cursor])) {
8192 // Found open slot
8193 if (!agent_already_present) {
8194 uuid_copy(dst: returned_result->netagents[netagent_cursor], src: mapping->uuid);
8195 if (remove) {
8196 returned_result->netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
8197 } else {
8198 returned_result->netagent_use_flags[netagent_cursor] = 0;
8199 }
8200 }
8201 break;
8202 }
8203 }
8204 }
8205
8206 // Update the local netagent_ids array for future evaluations
8207 if (remove) {
8208 // Check if the agent ID is in the array, and remove it
8209 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8210 if (netagent_id == netagent_ids[netagent_cursor]) {
8211 netagent_ids[netagent_cursor] = 0;
8212 }
8213 }
8214 } else {
8215 // Check if the agent ID is not yet in the array, and add it
8216 bool found = false;
8217 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8218 if (netagent_id == netagent_ids[netagent_cursor]) {
8219 found = true;
8220 break;
8221 }
8222 }
8223 if (!found) {
8224 for (netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
8225 if (netagent_ids[netagent_cursor] == 0) {
8226 // Empty slot, add the agent
8227 netagent_ids[netagent_cursor] = netagent_id;
8228 break;
8229 }
8230 }
8231 }
8232 }
8233 }
8234
8235 route_rule_index++;
8236 if (route_rule_index == route_rule_id_array_count && !second_pass) {
8237 route_rule_index = 0;
8238 second_pass = true;
8239 }
8240 }
8241
8242 if (rt != NULL && rt->rt_ifp != NULL) {
8243 const bool is_listener = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER) != 0);
8244 const bool is_browser = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_BROWSE) != 0);
8245 const bool expensive_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE) &&
8246 IFNET_IS_EXPENSIVE(rt->rt_ifp));
8247 const bool constrained_prohibited = ((client_flags & NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED) &&
8248 IFNET_IS_CONSTRAINED(rt->rt_ifp));
8249 const bool interface_type_blocked = !necp_route_is_interface_type_allowed(route: rt, NULL, proc, NULL);
8250 if (!is_listener && !is_browser) {
8251 if (reason != NULL) {
8252 if (expensive_prohibited) {
8253 *reason = NECP_CLIENT_RESULT_REASON_EXPENSIVE_PROHIBITED;
8254 } else if (constrained_prohibited) {
8255 *reason = NECP_CLIENT_RESULT_REASON_CONSTRAINED_PROHIBITED;
8256 }
8257 }
8258 if (expensive_prohibited || constrained_prohibited || interface_type_blocked) {
8259 // If a property of the interface was not allowed, treat it as a drop
8260 returned_result->routing_result = NECP_KERNEL_POLICY_RESULT_DROP;
8261 memset(s: &returned_result->routing_result_parameter, c: 0, n: sizeof(returned_result->routing_result_parameter));
8262 }
8263 }
8264 }
8265
8266 if (rt != NULL) {
8267 if (returned_route != NULL) {
8268 *returned_route = rt;
8269 } else {
8270 rtfree(rt);
8271 }
8272 rt = NULL;
8273 }
8274
8275done:
8276 // Unlock
8277 lck_rw_done(lck: &necp_kernel_policy_lock);
8278
8279 if (release_eproc && effective_proc != PROC_NULL) {
8280 proc_rele(p: effective_proc);
8281 }
8282#if defined(XNU_TARGET_OS_OSX)
8283 if (responsible_proc != PROC_NULL) {
8284 proc_rele(p: responsible_proc);
8285 }
8286#endif
8287
8288 if (cred != NULL) {
8289 kauth_cred_unref(&cred);
8290 }
8291
8292 return error;
8293}
8294
8295static bool
8296necp_is_route_local(union necp_sockaddr_union *remote_addr)
8297{
8298 struct rtentry *rt = NULL;
8299 bool is_local = FALSE;
8300
8301 if (remote_addr == NULL) {
8302 return NULL;
8303 }
8304
8305 if (remote_addr->sa.sa_len == 0 ||
8306 (remote_addr->sa.sa_family == AF_INET && remote_addr->sin.sin_addr.s_addr == 0) ||
8307 (remote_addr->sa.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&remote_addr->sin6.sin6_addr))) {
8308 return FALSE;
8309 }
8310
8311 // Lookup route regardless of the scoped interface to check if
8312 // remote address is in a local network.
8313 rt = rtalloc1_scoped((struct sockaddr *)remote_addr, 0, 0, 0);
8314
8315 if (rt == NULL) {
8316 goto done;
8317 }
8318 if (remote_addr->sa.sa_family == AF_INET && IS_INTF_CLAT46(rt->rt_ifp)) {
8319 goto free_rt;
8320 }
8321 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
8322
8323free_rt:
8324 rtfree(rt);
8325
8326done:
8327 return is_local;
8328}
8329
8330static bool
8331necp_socket_check_policy(struct necp_kernel_socket_policy *kernel_policy, necp_app_id app_id, necp_app_id real_app_id, uint8_t is_entitled, u_int32_t account_id, struct substring domain, u_int8_t domain_dot_count, const char *url, pid_t pid, int32_t pid_version, uid_t uid, uid_t real_uid, u_int32_t bound_interface_index, u_int32_t traffic_class, u_int16_t protocol, union necp_sockaddr_union *local, union necp_sockaddr_union *remote, struct necp_client_parameter_netagent_type *required_agent_types, u_int32_t num_required_agent_types, bool has_client, uint32_t client_flags, int is_platform_binary, bool has_signed_result, proc_t proc, u_int16_t pf_tag, u_int16_t scheme_port, struct rtentry *rt, bool is_loopback, int debug, bool real_is_platform_binary, u_int32_t bound_interface_flags, u_int32_t bound_interface_eflags, u_int32_t bound_interface_xflags, struct necp_socket_info *info, bool is_delegated)
8332{
8333 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
8334 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8335 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
8336 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
8337 "NECP_KERNEL_CONDITION_BOUND_INTERFACE", cond_bound_interface_index, bound_interface_index);
8338 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
8339 if (bound_interface_index == cond_bound_interface_index) {
8340 // No match, matches forbidden interface
8341 return FALSE;
8342 }
8343 } else {
8344 if (bound_interface_index != cond_bound_interface_index) {
8345 // No match, does not match required interface
8346 return FALSE;
8347 }
8348 }
8349 }
8350 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8351 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8352 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
8353 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8354 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
8355 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
8356 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
8357 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
8358 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8359 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8360 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8361 // No match, matches some forbidden interface flags
8362 return FALSE;
8363 }
8364 } else {
8365 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
8366 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
8367 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
8368 // No match, does not match some required interface xflags
8369 return FALSE;
8370 }
8371 }
8372 }
8373 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
8374 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
8375 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "Requiring no bound interface", 0, bound_interface_index);
8376 if (bound_interface_index != 0) {
8377 // No match, requires a non-bound packet
8378 return FALSE;
8379 }
8380 }
8381 }
8382
8383 if (kernel_policy->condition_mask == 0) {
8384 return TRUE;
8385 }
8386
8387 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8388 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID,
8389 "NECP_KERNEL_CONDITION_APP_ID", kernel_policy->cond_app_id, app_id);
8390 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_APP_ID) {
8391 if (app_id == kernel_policy->cond_app_id) {
8392 // No match, matches forbidden application
8393 return FALSE;
8394 }
8395 } else {
8396 if (app_id != kernel_policy->cond_app_id) {
8397 // No match, does not match required application
8398 return FALSE;
8399 }
8400 }
8401
8402 // Check signing identifier only after APP ID matched
8403 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER ||
8404 kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8405 u_int8_t matched = necp_boolean_state_false;
8406 const char *signing_id = cs_identity_get(proc ? proc : current_proc());
8407 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER,
8408 "NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER",
8409 kernel_policy->cond_signing_identifier ? kernel_policy->cond_signing_identifier : "<n/a>",
8410 signing_id ? signing_id : "<n/a>");
8411 if (signing_id != NULL) {
8412 size_t signing_id_size = strlen(s: signing_id) + 1;
8413 if (memcmp(s1: signing_id, s2: kernel_policy->cond_signing_identifier, n: signing_id_size) == 0) {
8414 matched = necp_boolean_state_true;
8415 }
8416 }
8417
8418 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SIGNING_IDENTIFIER) {
8419 if (matched == necp_boolean_state_true) {
8420 return FALSE;
8421 }
8422 } else {
8423 if (matched != necp_boolean_state_true) {
8424 return FALSE;
8425 }
8426 }
8427 }
8428 }
8429
8430 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8431 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID,
8432 "NECP_KERNEL_CONDITION_REAL_APP_ID",
8433 kernel_policy->cond_real_app_id, real_app_id);
8434 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
8435 if (real_app_id == kernel_policy->cond_real_app_id) {
8436 // No match, matches forbidden application
8437 return FALSE;
8438 }
8439 } else {
8440 if (real_app_id != kernel_policy->cond_real_app_id) {
8441 // No match, does not match required application
8442 return FALSE;
8443 }
8444 }
8445 }
8446
8447 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8448 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_HAS_CLIENT", 0, has_client);
8449 if (!has_client) {
8450 return FALSE;
8451 }
8452 }
8453
8454 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
8455 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_ENTITLEMENT", 0, is_entitled);
8456 if (!is_entitled) {
8457 // Process is missing entitlement
8458 return FALSE;
8459 }
8460 }
8461
8462 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
8463 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_PLATFORM_BINARY", 0, is_platform_binary);
8464 if (is_platform_binary == 0) {
8465 // Process is not platform binary
8466 return FALSE;
8467 }
8468 }
8469
8470 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
8471 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT", 0, is_platform_binary);
8472 if (has_signed_result == 0) {
8473 // Client did not have a system-signed result
8474 return FALSE;
8475 }
8476 }
8477
8478 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SDK_VERSION) {
8479 if (proc != NULL) {
8480 NECP_DATA_TRACE_LOG_CONDITION3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_SDK_VERSION",
8481 kernel_policy->cond_sdk_version.platform,
8482 kernel_policy->cond_sdk_version.min_version,
8483 kernel_policy->cond_sdk_version.version,
8484 proc_platform(proc),
8485 proc_min_sdk(proc),
8486 proc_sdk(proc));
8487 if (kernel_policy->cond_sdk_version.platform != 0) {
8488 if (kernel_policy->cond_sdk_version.platform != proc_platform(proc)) {
8489 // Process does not match platform
8490 return FALSE;
8491 }
8492 }
8493
8494 if (kernel_policy->cond_sdk_version.min_version != 0) {
8495 if (kernel_policy->cond_sdk_version.min_version > proc_min_sdk(proc)) {
8496 // Process min version is older than required min version
8497 return FALSE;
8498 }
8499 }
8500
8501 if (kernel_policy->cond_sdk_version.version != 0) {
8502 if (kernel_policy->cond_sdk_version.version > proc_sdk(proc)) {
8503 // Process SDK version is older than required version
8504 return FALSE;
8505 }
8506 }
8507 }
8508 }
8509
8510 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT) {
8511 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_CUSTOM_ENTITLEMENT", "n/a", kernel_policy->cond_custom_entitlement);
8512 if (kernel_policy->cond_custom_entitlement != NULL) {
8513 if (proc == NULL) {
8514 // No process found, cannot check entitlement
8515 return FALSE;
8516 }
8517 task_t task = proc_task(proc);
8518 if (task == NULL ||
8519 !IOTaskHasEntitlement(task, entitlement: kernel_policy->cond_custom_entitlement)) {
8520 // Process is missing custom entitlement
8521 return FALSE;
8522 }
8523 }
8524 }
8525
8526 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8527 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN,
8528 "NECP_KERNEL_CONDITION_EXACT_DOMAIN", kernel_policy->cond_domain, domain.string);
8529 // Exact match requires the number of dots to match (no suffix matching allowed)
8530 bool domain_matches = (domain_dot_count == kernel_policy->cond_domain_dot_count &&
8531 necp_hostname_matches_domain(hostname_substring: domain, hostname_dot_count: domain_dot_count, domain: kernel_policy->cond_domain, domain_dot_count: kernel_policy->cond_domain_dot_count));
8532 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) {
8533 if (domain_matches) {
8534 // No match, matches forbidden domain
8535 return FALSE;
8536 }
8537 } else {
8538 if (!domain_matches) {
8539 // No match, does not match required domain
8540 return FALSE;
8541 }
8542 }
8543 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8544 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN,
8545 "NECP_KERNEL_CONDITION_DOMAIN", kernel_policy->cond_domain, domain.string);
8546 bool domain_matches = necp_hostname_matches_domain(hostname_substring: domain, hostname_dot_count: domain_dot_count, domain: kernel_policy->cond_domain, domain_dot_count: kernel_policy->cond_domain_dot_count);
8547 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN) {
8548 if (domain_matches) {
8549 // No match, matches forbidden domain
8550 return FALSE;
8551 }
8552 } else {
8553 if (!domain_matches) {
8554 // No match, does not match required domain
8555 return FALSE;
8556 }
8557 }
8558 }
8559
8560 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8561 struct necp_domain_filter *filter = necp_lookup_domain_filter(list: &necp_global_domain_filter_list, filter_id: kernel_policy->cond_domain_filter);
8562 if (filter != NULL && filter->filter != NULL) {
8563 bool domain_matches = net_bloom_filter_contains(filter: filter->filter, buffer: domain.string, length: domain.length);
8564 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER) {
8565 if (domain_matches) {
8566 // No match, matches forbidden domain
8567 return FALSE;
8568 }
8569 } else {
8570 if (!domain_matches) {
8571 // No match, does not match required domain
8572 return FALSE;
8573 }
8574 }
8575 }
8576 }
8577
8578 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_URL) {
8579 NECP_DATA_TRACE_LOG_CONDITION_STR(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL,
8580 "NECP_KERNEL_CONDITION_URL", kernel_policy->cond_url, url);
8581 bool url_matches = (url ? strncasecmp(s1: kernel_policy->cond_url, s2: url, n: strlen(s: kernel_policy->cond_url)) == 0 : false);
8582 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_URL) {
8583 if (url_matches) {
8584 // No match, matches forbidden url
8585 return FALSE;
8586 }
8587 } else {
8588 if (!url_matches) {
8589 // No match, does not match required url
8590 return FALSE;
8591 }
8592 }
8593 }
8594
8595 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8596 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID,
8597 "NECP_KERNEL_CONDITION_ACCOUNT_ID",
8598 kernel_policy->cond_account_id, account_id);
8599 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID) {
8600 if (account_id == kernel_policy->cond_account_id) {
8601 // No match, matches forbidden account
8602 return FALSE;
8603 }
8604 } else {
8605 if (account_id != kernel_policy->cond_account_id) {
8606 // No match, does not match required account
8607 return FALSE;
8608 }
8609 }
8610 }
8611
8612 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PID) {
8613 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID,
8614 "NECP_KERNEL_CONDITION_PID",
8615 kernel_policy->cond_pid, pid);
8616 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PID) {
8617 if (pid == kernel_policy->cond_pid) {
8618 // No match, matches forbidden pid
8619 return FALSE;
8620 }
8621 if (kernel_policy->cond_pid_version != 0 && pid_version == kernel_policy->cond_pid_version) {
8622 return FALSE;
8623 }
8624 } else {
8625 if (pid != kernel_policy->cond_pid) {
8626 // No match, does not match required pid
8627 return FALSE;
8628 }
8629 if (kernel_policy->cond_pid_version != 0 && pid_version != kernel_policy->cond_pid_version) {
8630 return FALSE;
8631 }
8632 }
8633 }
8634
8635 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_UID) {
8636 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID,
8637 "NECP_KERNEL_CONDITION_UID",
8638 kernel_policy->cond_uid, uid);
8639 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_UID) {
8640 if (uid == kernel_policy->cond_uid) {
8641 // No match, matches forbidden uid
8642 return FALSE;
8643 }
8644 } else {
8645 if (uid != kernel_policy->cond_uid) {
8646 // No match, does not match required uid
8647 return FALSE;
8648 }
8649 }
8650 }
8651
8652 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
8653 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID,
8654 "NECP_KERNEL_CONDITION_REAL_UID",
8655 kernel_policy->cond_real_uid, real_uid);
8656 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REAL_UID) {
8657 if (real_uid == kernel_policy->cond_real_uid) {
8658 // No match, matches forbidden uid
8659 return FALSE;
8660 }
8661 } else {
8662 if (real_uid != kernel_policy->cond_real_uid) {
8663 // No match, does not match required uid
8664 return FALSE;
8665 }
8666 }
8667 }
8668
8669 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8670 NECP_DATA_TRACE_LOG_CONDITION3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_TRAFFIC_CLASS",
8671 kernel_policy->cond_traffic_class.start_tc, kernel_policy->cond_traffic_class.end_tc, 0,
8672 traffic_class, 0, 0);
8673 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8674 if (traffic_class >= kernel_policy->cond_traffic_class.start_tc &&
8675 traffic_class <= kernel_policy->cond_traffic_class.end_tc) {
8676 // No match, matches forbidden traffic class
8677 return FALSE;
8678 }
8679 } else {
8680 if (traffic_class < kernel_policy->cond_traffic_class.start_tc ||
8681 traffic_class > kernel_policy->cond_traffic_class.end_tc) {
8682 // No match, does not match required traffic class
8683 return FALSE;
8684 }
8685 }
8686 }
8687
8688 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8689 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
8690 "NECP_KERNEL_CONDITION_PROTOCOL",
8691 kernel_policy->cond_protocol, protocol);
8692 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8693 if (protocol == kernel_policy->cond_protocol) {
8694 // No match, matches forbidden protocol
8695 return FALSE;
8696 }
8697 } else {
8698 if (protocol != kernel_policy->cond_protocol) {
8699 // No match, does not match required protocol
8700 return FALSE;
8701 }
8702 }
8703 }
8704
8705 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_AGENT_TYPE) {
8706 NECP_DATA_TRACE_LOG_CONDITION_STR3(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_AGENT_TYPE",
8707 kernel_policy->cond_agent_type.agent_domain, kernel_policy->cond_agent_type.agent_type, "n/a",
8708 "n/a", "n/a", "n/a");
8709 bool matches_agent_type = FALSE;
8710 for (u_int32_t i = 0; i < num_required_agent_types; i++) {
8711 struct necp_client_parameter_netagent_type *required_agent_type = &required_agent_types[i];
8712 if ((strlen(s: kernel_policy->cond_agent_type.agent_domain) == 0 ||
8713 strncmp(s1: required_agent_type->netagent_domain, s2: kernel_policy->cond_agent_type.agent_domain, NETAGENT_DOMAINSIZE) == 0) &&
8714 (strlen(s: kernel_policy->cond_agent_type.agent_type) == 0 ||
8715 strncmp(s1: required_agent_type->netagent_type, s2: kernel_policy->cond_agent_type.agent_type, NETAGENT_TYPESIZE) == 0)) {
8716 // Found a required agent that matches
8717 matches_agent_type = TRUE;
8718 break;
8719 }
8720 }
8721 if (!matches_agent_type) {
8722 return FALSE;
8723 }
8724 }
8725
8726 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
8727 bool is_local = FALSE;
8728
8729 if (rt != NULL) {
8730 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
8731 } else {
8732 is_local = necp_is_route_local(remote_addr: remote);
8733 }
8734 if (info != NULL) {
8735 info->is_local = is_local;
8736 }
8737 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", false, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
8738 if (!is_local) {
8739 // Either no route to validate or no match for local networks
8740 return FALSE;
8741 }
8742 }
8743
8744 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
8745 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
8746 bool inRange = necp_is_addr_in_range(addr: (struct sockaddr *)local, range_start: (struct sockaddr *)&kernel_policy->cond_local_start, range_end: (struct sockaddr *)&kernel_policy->cond_local_end);
8747 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
8748 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
8749 if (inRange) {
8750 return FALSE;
8751 }
8752 } else {
8753 if (!inRange) {
8754 return FALSE;
8755 }
8756 }
8757 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
8758 bool inSubnet = necp_is_addr_in_subnet(addr: (struct sockaddr *)local, subnet_addr: (struct sockaddr *)&kernel_policy->cond_local_start, subnet_prefix: kernel_policy->cond_local_prefix);
8759 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
8760 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
8761 if (inSubnet) {
8762 return FALSE;
8763 }
8764 } else {
8765 if (!inSubnet) {
8766 return FALSE;
8767 }
8768 }
8769 }
8770 }
8771
8772 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
8773 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
8774 bool inRange = necp_is_addr_in_range(addr: (struct sockaddr *)remote, range_start: (struct sockaddr *)&kernel_policy->cond_remote_start, range_end: (struct sockaddr *)&kernel_policy->cond_remote_end);
8775 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
8776 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
8777 if (inRange) {
8778 return FALSE;
8779 }
8780 } else {
8781 if (!inRange) {
8782 return FALSE;
8783 }
8784 }
8785 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
8786 bool inSubnet = necp_is_addr_in_subnet(addr: (struct sockaddr *)remote, subnet_addr: (struct sockaddr *)&kernel_policy->cond_remote_start, subnet_prefix: kernel_policy->cond_remote_prefix);
8787 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
8788 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
8789 if (inSubnet) {
8790 return FALSE;
8791 }
8792 } else {
8793 if (!inSubnet) {
8794 return FALSE;
8795 }
8796 }
8797 }
8798 }
8799
8800 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8801 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS,
8802 "NECP_KERNEL_CONDITION_CLIENT_FLAGS",
8803 kernel_policy->cond_client_flags, client_flags);
8804 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8805 if ((client_flags & kernel_policy->cond_client_flags) == kernel_policy->cond_client_flags) {
8806 // Flags do match, and condition is negative, fail.
8807 return FALSE;
8808 }
8809 } else {
8810 if ((client_flags & kernel_policy->cond_client_flags) != kernel_policy->cond_client_flags) {
8811 // Flags do not match, fail.
8812 return FALSE;
8813 }
8814 }
8815 }
8816
8817 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
8818 bool isEmpty = necp_addr_is_empty(addr: (struct sockaddr *)local);
8819 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY,
8820 "NECP_KERNEL_CONDITION_LOCAL_EMPTY",
8821 0, isEmpty);
8822 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_EMPTY) {
8823 if (isEmpty) {
8824 return FALSE;
8825 }
8826 } else {
8827 if (!isEmpty) {
8828 return FALSE;
8829 }
8830 }
8831 }
8832
8833 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
8834 bool isEmpty = necp_addr_is_empty(addr: (struct sockaddr *)remote);
8835 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY,
8836 "NECP_KERNEL_CONDITION_REMOTE_EMPTY",
8837 0, isEmpty);
8838 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_EMPTY) {
8839 if (isEmpty) {
8840 return FALSE;
8841 }
8842 } else {
8843 if (!isEmpty) {
8844 return FALSE;
8845 }
8846 }
8847 }
8848
8849 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
8850 u_int16_t remote_port = 0;
8851 if (((struct sockaddr *)remote)->sa_family == AF_INET || ((struct sockaddr *)remote)->sa_family == AF_INET6) {
8852 remote_port = ((struct sockaddr_in *)remote)->sin_port;
8853 }
8854 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
8855 "NECP_KERNEL_CONDITION_SCHEME_PORT",
8856 scheme_port, remote_port);
8857 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
8858 if (kernel_policy->cond_scheme_port == scheme_port ||
8859 kernel_policy->cond_scheme_port == remote_port) {
8860 return FALSE;
8861 }
8862 } else {
8863 if (kernel_policy->cond_scheme_port != scheme_port &&
8864 kernel_policy->cond_scheme_port != remote_port) {
8865 return FALSE;
8866 }
8867 }
8868 }
8869
8870 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
8871 NECP_DATA_TRACE_LOG_CONDITION(debug, "SOCKET", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
8872 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
8873 kernel_policy->cond_packet_filter_tags,
8874 pf_tag);
8875 bool tags_matched = false;
8876 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
8877 if (pf_tag == PF_TAG_ID_STACK_DROP) {
8878 tags_matched = true;
8879 }
8880 }
8881
8882 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
8883 if (tags_matched) {
8884 return FALSE;
8885 }
8886 } else {
8887 if (!tags_matched) {
8888 return FALSE;
8889 }
8890 }
8891 }
8892
8893 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
8894 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_IS_LOOPBACK) {
8895 if (is_loopback) {
8896 return FALSE;
8897 }
8898 } else {
8899 if (!is_loopback) {
8900 return FALSE;
8901 }
8902 }
8903 }
8904
8905 if (is_delegated && (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY)) {
8906 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
8907 if (real_is_platform_binary) {
8908 return FALSE;
8909 }
8910 } else {
8911 if (!real_is_platform_binary) {
8912 return FALSE;
8913 }
8914 }
8915 }
8916
8917 return TRUE;
8918}
8919
8920static inline u_int32_t
8921necp_socket_calc_flowhash_locked(struct necp_socket_info *info)
8922{
8923 return net_flowhash(info, sizeof(*info), necp_kernel_socket_policies_gencount);
8924}
8925
8926static void
8927necp_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)
8928{
8929 struct socket *so = NULL;
8930 proc_t sock_proc = NULL;
8931 proc_t curr_proc = current_proc();
8932
8933 memset(s: info, c: 0, n: sizeof(struct necp_socket_info));
8934
8935 so = inp->inp_socket;
8936
8937 info->drop_order = drop_order;
8938 info->is_loopback = is_loopback;
8939 info->is_delegated = ((so->so_flags & SOF_DELEGATED) ? true : false);
8940
8941 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_UID ||
8942 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_UID) {
8943 info->uid = kauth_cred_getuid(cred: so->so_cred);
8944 info->real_uid = info->uid;
8945 }
8946
8947 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_TRAFFIC_CLASS) {
8948 info->traffic_class = so->so_traffic_class;
8949 }
8950
8951 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_HAS_CLIENT) {
8952 info->has_client = !uuid_is_null(uu: inp->necp_client_uuid);
8953 }
8954
8955 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_CLIENT_FLAGS) {
8956 info->client_flags = 0;
8957 if (INP_NO_CONSTRAINED(inp)) {
8958 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_CONSTRAINED;
8959 }
8960 if (INP_NO_EXPENSIVE(inp)) {
8961 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_PROHIBIT_EXPENSIVE;
8962 }
8963 if (inp->inp_socket->so_flags1 & SOF1_CELLFALLBACK) {
8964 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_FALLBACK_TRAFFIC;
8965 }
8966 if (inp->inp_socket->so_flags1 & SOF1_KNOWN_TRACKER) {
8967 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_KNOWN_TRACKER;
8968 }
8969 if (inp->inp_socket->so_flags1 & SOF1_APPROVED_APP_DOMAIN) {
8970 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_APPROVED_APP_DOMAIN;
8971 }
8972 if (inp->inp_socket->so_flags1 & SOF1_INBOUND || override_is_inbound) {
8973 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_INBOUND;
8974 }
8975 if (inp->inp_socket->so_options & SO_ACCEPTCONN ||
8976 inp->inp_flags2 & INP2_EXTERNAL_PORT) {
8977 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_LISTENER;
8978 }
8979 if (inp->inp_socket->so_options & SO_NOWAKEFROMSLEEP) {
8980 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_NO_WAKE_FROM_SLEEP;
8981 }
8982 if (inp->inp_socket->so_options & SO_REUSEPORT) {
8983 info->client_flags |= NECP_CLIENT_PARAMETER_FLAG_REUSE_LOCAL;
8984 }
8985 }
8986
8987 if ((necp_data_tracing_level && necp_data_tracing_proto) ||
8988 necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
8989 if (inp->inp_ip_p) {
8990 info->protocol = inp->inp_ip_p;
8991 } else {
8992 info->protocol = SOCK_PROTO(so);
8993 }
8994 }
8995
8996 if (inp->inp_flags2 & INP2_WANT_APP_POLICY && necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_APP_ID) {
8997 u_int32_t responsible_application_id = 0;
8998
8999 struct necp_uuid_id_mapping *existing_mapping = necp_uuid_lookup_app_id_locked(uuid: ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid));
9000 if (existing_mapping) {
9001 info->application_id = existing_mapping->id;
9002 }
9003
9004#if defined(XNU_TARGET_OS_OSX)
9005 if (so->so_rpid > 0) {
9006 existing_mapping = necp_uuid_lookup_app_id_locked(uuid: so->so_ruuid);
9007 if (existing_mapping != NULL) {
9008 responsible_application_id = existing_mapping->id;
9009 }
9010 }
9011#endif
9012
9013 if (responsible_application_id > 0) {
9014 info->real_application_id = info->application_id;
9015 info->application_id = responsible_application_id;
9016 info->used_responsible_pid = true;
9017 } else if (!(so->so_flags & SOF_DELEGATED)) {
9018 info->real_application_id = info->application_id;
9019 } else if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID) {
9020 struct necp_uuid_id_mapping *real_existing_mapping = necp_uuid_lookup_app_id_locked(uuid: so->last_uuid);
9021 if (real_existing_mapping) {
9022 info->real_application_id = real_existing_mapping->id;
9023 }
9024 }
9025 }
9026
9027 pid_t socket_pid =
9028#if defined(XNU_TARGET_OS_OSX)
9029 info->used_responsible_pid ? so->so_rpid :
9030#endif
9031 ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid);
9032 if (socket_pid && (socket_pid != proc_pid(curr_proc))) {
9033 sock_proc = proc_find(pid: socket_pid);
9034 if (socket_proc) {
9035 *socket_proc = sock_proc;
9036 }
9037 }
9038
9039 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ENTITLEMENT) {
9040 const task_t task = proc_task(sock_proc != NULL ? sock_proc : curr_proc);
9041 info->is_entitled = necp_task_has_match_entitlement(task);
9042 if (!info->is_entitled) {
9043 // Task does not have entitlement, check the parent task
9044 necp_get_parent_is_entitled(task, info);
9045 }
9046 }
9047
9048 if ((necp_data_tracing_level && necp_data_tracing_pid) ||
9049 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PID)) {
9050 info->pid = socket_pid;
9051 info->pid_version = proc_pidversion(sock_proc != NULL ? sock_proc : curr_proc);
9052 }
9053
9054 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_PLATFORM_BINARY) {
9055 info->is_platform_binary = necp_is_platform_binary(proc: sock_proc ? sock_proc : curr_proc) ? true : false;
9056 }
9057
9058 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DELEGATE_IS_PLATFORM_BINARY) {
9059 proc_t real_proc = curr_proc;
9060 bool release_real_proc = false;
9061 if (so->last_pid != proc_pid(real_proc)) {
9062 if (so->last_pid == socket_pid && sock_proc != NULL) {
9063 real_proc = sock_proc;
9064 } else {
9065 proc_t last_proc = proc_find(pid: so->last_pid);
9066 if (last_proc != NULL) {
9067 real_proc = last_proc;
9068 release_real_proc = true;
9069 }
9070 }
9071 }
9072 if (real_proc != NULL) {
9073 info->real_is_platform_binary = (necp_is_platform_binary(proc: real_proc) ? true : false);
9074 if (release_real_proc) {
9075 proc_rele(p: real_proc);
9076 }
9077 }
9078 }
9079
9080 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_ACCOUNT_ID && inp->inp_necp_attributes.inp_account != NULL) {
9081 struct necp_string_id_mapping *existing_mapping = necp_lookup_string_to_id_locked(list: &necp_account_id_list, string: inp->inp_necp_attributes.inp_account);
9082 if (existing_mapping) {
9083 info->account_id = existing_mapping->id;
9084 }
9085 }
9086
9087 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN) ||
9088 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_EXACT_DOMAIN) ||
9089 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_DOMAIN_FILTER)) {
9090 info->domain = inp->inp_necp_attributes.inp_domain;
9091 }
9092
9093 if (override_bound_interface) {
9094 info->bound_interface_index = override_bound_interface;
9095 } else {
9096 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp) {
9097 info->bound_interface_index = inp->inp_boundifp->if_index;
9098 }
9099 }
9100
9101 if ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) &&
9102 info->bound_interface_index != IFSCOPE_NONE) {
9103 ifnet_head_lock_shared();
9104 ifnet_t interface = ifindex2ifnet[info->bound_interface_index];
9105 if (interface != NULL) {
9106 info->bound_interface_flags = interface->if_flags;
9107 info->bound_interface_eflags = interface->if_eflags;
9108 info->bound_interface_xflags = interface->if_xflags;
9109 }
9110 ifnet_head_done();
9111 }
9112
9113 bool needs_address_for_signature = ((necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) &&
9114 uuid_is_null(uu: inp->necp_client_uuid) &&
9115 necp_socket_has_resolver_signature(inp));
9116 if ((necp_data_tracing_level && necp_data_tracing_port) ||
9117 necp_restrict_multicast ||
9118 needs_address_for_signature ||
9119 (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_ADDRESS_TYPE_CONDITIONS)) {
9120 if (override_local_addr != NULL) {
9121 if (override_local_addr->sa_family == AF_INET6 && override_local_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9122 memcpy(dst: &info->local_addr, src: override_local_addr, n: override_local_addr->sa_len);
9123 if (IN6_IS_ADDR_V4MAPPED(&(info->local_addr.sin6.sin6_addr))) {
9124 struct sockaddr_in sin;
9125 in6_sin6_2_sin(sin: &sin, sin6: &(info->local_addr.sin6));
9126 memset(s: &info->local_addr, c: 0, n: sizeof(union necp_sockaddr_union));
9127 memcpy(dst: &info->local_addr, src: &sin, n: sin.sin_len);
9128 }
9129 } else if (override_local_addr->sa_family == AF_INET && override_local_addr->sa_len <= sizeof(struct sockaddr_in)) {
9130 memcpy(dst: &info->local_addr, src: override_local_addr, n: override_local_addr->sa_len);
9131 }
9132 } else {
9133 if (inp->inp_vflag & INP_IPV6) {
9134 ((struct sockaddr_in6 *)&info->local_addr)->sin6_family = AF_INET6;
9135 ((struct sockaddr_in6 *)&info->local_addr)->sin6_len = sizeof(struct sockaddr_in6);
9136 ((struct sockaddr_in6 *)&info->local_addr)->sin6_port = inp->inp_lport;
9137 memcpy(dst: &((struct sockaddr_in6 *)&info->local_addr)->sin6_addr, src: &inp->in6p_laddr, n: sizeof(struct in6_addr));
9138 } else if (inp->inp_vflag & INP_IPV4) {
9139 ((struct sockaddr_in *)&info->local_addr)->sin_family = AF_INET;
9140 ((struct sockaddr_in *)&info->local_addr)->sin_len = sizeof(struct sockaddr_in);
9141 ((struct sockaddr_in *)&info->local_addr)->sin_port = inp->inp_lport;
9142 memcpy(dst: &((struct sockaddr_in *)&info->local_addr)->sin_addr, src: &inp->inp_laddr, n: sizeof(struct in_addr));
9143 }
9144 }
9145
9146 if (override_remote_addr != NULL) {
9147 if (override_remote_addr->sa_family == AF_INET6 && override_remote_addr->sa_len <= sizeof(struct sockaddr_in6)) {
9148 memcpy(dst: &info->remote_addr, src: override_remote_addr, n: override_remote_addr->sa_len);
9149 if (IN6_IS_ADDR_V4MAPPED(&(info->remote_addr.sin6.sin6_addr))) {
9150 struct sockaddr_in sin;
9151 in6_sin6_2_sin(sin: &sin, sin6: &(info->remote_addr.sin6));
9152 memset(s: &info->remote_addr, c: 0, n: sizeof(union necp_sockaddr_union));
9153 memcpy(dst: &info->remote_addr, src: &sin, n: sin.sin_len);
9154 }
9155 } else if (override_remote_addr->sa_family == AF_INET && override_remote_addr->sa_len <= sizeof(struct sockaddr_in)) {
9156 memcpy(dst: &info->remote_addr, src: override_remote_addr, n: override_remote_addr->sa_len);
9157 }
9158 } else {
9159 if (inp->inp_vflag & INP_IPV6) {
9160 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_family = AF_INET6;
9161 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
9162 ((struct sockaddr_in6 *)&info->remote_addr)->sin6_port = inp->inp_fport;
9163 memcpy(dst: &((struct sockaddr_in6 *)&info->remote_addr)->sin6_addr, src: &inp->in6p_faddr, n: sizeof(struct in6_addr));
9164 } else if (inp->inp_vflag & INP_IPV4) {
9165 ((struct sockaddr_in *)&info->remote_addr)->sin_family = AF_INET;
9166 ((struct sockaddr_in *)&info->remote_addr)->sin_len = sizeof(struct sockaddr_in);
9167 ((struct sockaddr_in *)&info->remote_addr)->sin_port = inp->inp_fport;
9168 memcpy(dst: &((struct sockaddr_in *)&info->remote_addr)->sin_addr, src: &inp->inp_faddr, n: sizeof(struct in_addr));
9169 }
9170 }
9171 // Clear the embedded scope id from v6 addresses
9172 if (info->local_addr.sa.sa_family == AF_INET6) {
9173 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&info->local_addr;
9174 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9175 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9176 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9177 sin6->sin6_addr.s6_addr16[1] = 0;
9178 }
9179 }
9180 }
9181 if (info->remote_addr.sa.sa_family == AF_INET6) {
9182 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&info->remote_addr;
9183 if (IN6_IS_SCOPE_EMBED(&sin6->sin6_addr) && in6_embedded_scope) {
9184 if (sin6->sin6_addr.s6_addr16[1] != 0) {
9185 sin6->sin6_scope_id = ntohs(sin6->sin6_addr.s6_addr16[1]);
9186 sin6->sin6_addr.s6_addr16[1] = 0;
9187 }
9188 }
9189 }
9190 }
9191
9192 if (necp_kernel_socket_policies_condition_mask & NECP_KERNEL_CONDITION_SYSTEM_SIGNED_RESULT) {
9193 // For checking sockets, only validate that there is an NECP client present. It will have
9194 // already checked for the signature.
9195 if (!uuid_is_null(uu: inp->necp_client_uuid)) {
9196 info->has_system_signed_result = true;
9197 } else {
9198 info->has_system_signed_result = necp_socket_resolver_signature_matches_address(inp, address: &info->remote_addr);
9199 }
9200 }
9201}
9202
9203#define IS_NECP_KERNEL_POLICY_IP_RESULT(result) (result == NECP_KERNEL_POLICY_RESULT_PASS || result == NECP_KERNEL_POLICY_RESULT_DROP || result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL || result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES)
9204
9205static inline struct necp_kernel_socket_policy *
9206necp_socket_find_policy_match_with_info_locked(struct necp_kernel_socket_policy **policy_search_array, struct necp_socket_info *info,
9207 necp_kernel_policy_filter *return_filter,
9208 u_int32_t *return_route_rule_id_array, size_t *return_route_rule_id_array_count, size_t route_rule_id_array_count,
9209 necp_kernel_policy_result *return_service_action, necp_kernel_policy_service *return_service,
9210 u_int32_t *return_netagent_array, u_int32_t *return_netagent_use_flags_array, size_t netagent_array_count,
9211 struct necp_client_parameter_netagent_type *required_agent_types,
9212 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,
9213 necp_kernel_policy_result *return_drop_dest_policy_result, necp_drop_all_bypass_check_result_t *return_drop_all_bypass,
9214 u_int32_t *return_flow_divert_aggregate_unit, struct socket *so, int debug)
9215{
9216 struct necp_kernel_socket_policy *matched_policy = NULL;
9217 u_int32_t skip_order = 0;
9218 u_int32_t skip_session_order = 0;
9219 bool skipped_ip_result = false;
9220 size_t route_rule_id_count = 0;
9221 int i;
9222 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9223 u_int32_t netagent_use_flags[NECP_MAX_NETAGENTS];
9224 memset(s: &netagent_ids, c: 0, n: sizeof(netagent_ids));
9225 memset(s: &netagent_use_flags, c: 0, n: sizeof(netagent_use_flags));
9226 size_t netagent_cursor = 0;
9227 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9228 if (return_drop_all_bypass != NULL) {
9229 *return_drop_all_bypass = drop_all_bypass;
9230 }
9231
9232 if (netagent_array_count > NECP_MAX_NETAGENTS) {
9233 netagent_array_count = NECP_MAX_NETAGENTS;
9234 }
9235
9236 // Pre-process domain for quick matching
9237 struct substring domain_substring = necp_trim_dots_and_stars(string: info->domain, length: info->domain ? strlen(s: info->domain) : 0);
9238 u_int8_t domain_dot_count = necp_count_dots(string: domain_substring.string, length: domain_substring.length);
9239
9240 if (return_filter != NULL) {
9241 *return_filter = 0;
9242 }
9243
9244 if (return_route_rule_id_array_count != NULL) {
9245 *return_route_rule_id_array_count = 0;
9246 }
9247
9248 if (return_service_action != NULL) {
9249 *return_service_action = 0;
9250 }
9251
9252 if (return_service != NULL) {
9253 return_service->identifier = 0;
9254 return_service->data = 0;
9255 }
9256
9257 // Do not subject layer-2 filter to NECP policies, return a PASS policy
9258 if (necp_pass_interpose > 0 && info->client_flags & NECP_CLIENT_PARAMETER_FLAG_INTERPOSE) {
9259 return &pass_policy;
9260 }
9261
9262 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9263
9264 if (policy_search_array != NULL) {
9265 for (i = 0; policy_search_array[i] != NULL; i++) {
9266 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "EXAMINING");
9267
9268 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
9269 // We've hit a drop all rule
9270 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9271 drop_all_bypass = necp_check_drop_all_bypass_result(proc);
9272 if (return_drop_all_bypass != NULL) {
9273 *return_drop_all_bypass = drop_all_bypass;
9274 }
9275 }
9276 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9277 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - DROP - (session order > drop-all order)");
9278 break;
9279 }
9280 }
9281 if (necp_drop_dest_policy.entry_count != 0 &&
9282 necp_address_matches_drop_dest_policy(&info->remote_addr, policy_search_array[i]->session_order)) {
9283 // We've hit a drop by destination address rule
9284 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
9285 break;
9286 }
9287 if (info->drop_order != 0 && policy_search_array[i]->session_order >= info->drop_order) {
9288 // We've hit a drop order for this socket
9289 break;
9290 }
9291 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
9292 // Done skipping
9293 skip_order = 0;
9294 skip_session_order = 0;
9295 // If we didn't skip any policy with IP result, no need to save the skip for IP evaluation.
9296 if (skip_policy_id && *skip_policy_id != NECP_KERNEL_POLICY_ID_NONE && !skipped_ip_result) {
9297 *skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9298 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (cleared saved skip)");
9299 }
9300 }
9301 if (skip_order) {
9302 if (policy_search_array[i]->order < skip_order) {
9303 // Skip this policy
9304 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9305 // didn't, clear out the return value for skip ID when we are done with each session.'
9306 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9307 skipped_ip_result = true;
9308 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIPPING IP RESULT");
9309 }
9310 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (session order < skip-order)");
9311 continue;
9312 } else {
9313 // Done skipping
9314 skip_order = 0;
9315 skip_session_order = 0;
9316 }
9317 } else if (skip_session_order) {
9318 // Skip this policy
9319 // Remember if we skipped an interesting PASS/DROP/IP_TUNNEL/ROUTE_RULES policy. If we
9320 // didn't, clear out the return value for skip ID when we are done with each session.'
9321 if (IS_NECP_KERNEL_POLICY_IP_RESULT(policy_search_array[i]->result)) {
9322 skipped_ip_result = true;
9323 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIPPING IP RESULT");
9324 }
9325 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "SKIP (skip-session-order)");
9326 continue;
9327 }
9328
9329 if (necp_socket_check_policy(kernel_policy: policy_search_array[i], app_id: info->application_id, real_app_id: info->real_application_id, is_entitled: info->is_entitled, account_id: info->account_id, domain: domain_substring, domain_dot_count, url: info->url, pid: info->pid, pid_version: info->pid_version, uid: info->uid, real_uid: info->real_uid, bound_interface_index: info->bound_interface_index, traffic_class: info->traffic_class, protocol: info->protocol, local: &info->local_addr, remote: &info->remote_addr, required_agent_types, num_required_agent_types, has_client: info->has_client, client_flags: info->client_flags, is_platform_binary: info->is_platform_binary, has_signed_result: info->has_system_signed_result, proc, pf_tag, scheme_port: info->scheme_port, rt, is_loopback: info->is_loopback, debug, real_is_platform_binary: info->real_is_platform_binary, bound_interface_flags: info->bound_interface_flags, bound_interface_eflags: info->bound_interface_eflags, bound_interface_xflags: info->bound_interface_xflags, info, is_delegated: info->is_delegated)) {
9330 if (!debug && necp_data_tracing_session_order) {
9331 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
9332 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
9333 NECP_DATA_TRACE_LOG_SOCKET_RESULT(true, so, "SOCKET", "DEBUG - MATCHED POLICY");
9334 }
9335 }
9336
9337 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_FILTER) {
9338 if (return_filter && *return_filter != NECP_FILTER_UNIT_NO_FILTER) {
9339 necp_kernel_policy_filter control_unit = policy_search_array[i]->result_parameter.filter_control_unit;
9340 if (control_unit == NECP_FILTER_UNIT_NO_FILTER) {
9341 *return_filter = control_unit;
9342 } else {
9343 // Preserve pre-existing connections only if all filters preserve.
9344 bool preserve_bit_off = false;
9345 if ((*return_filter && !(*return_filter & NECP_MASK_PRESERVE_CONNECTIONS)) ||
9346 (control_unit && !(control_unit & NECP_MASK_PRESERVE_CONNECTIONS))) {
9347 preserve_bit_off = true;
9348 }
9349 *return_filter |= control_unit;
9350 if (preserve_bit_off == true) {
9351 *return_filter &= ~NECP_MASK_PRESERVE_CONNECTIONS;
9352 }
9353 }
9354 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9355 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Filter %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.filter_control_unit);
9356 }
9357 }
9358 continue;
9359 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
9360 if (return_route_rule_id_array && route_rule_id_count < route_rule_id_array_count) {
9361 return_route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
9362 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9363 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Route Rule %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, policy_search_array[i]->result_parameter.route_rule_id);
9364 }
9365 }
9366 continue;
9367 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ||
9368 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9369 if (netagent_cursor < netagent_array_count) {
9370 bool agent_already_present = false;
9371 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9372 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9373 // Already present. Mark the "SCOPED" flag if flags are necessary.
9374 agent_already_present = true;
9375 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE) &&
9376 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9377 netagent_use_flags[netagent_i] |= NECP_AGENT_USE_FLAG_SCOPE;
9378 }
9379 }
9380 }
9381
9382 if (!agent_already_present) {
9383 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9384 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_NETAGENT_SCOPED) {
9385 netagent_use_flags[netagent_cursor] |= NECP_AGENT_USE_FLAG_SCOPE;
9386 }
9387 netagent_cursor++;
9388 }
9389 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9390 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) %s Netagent %d",
9391 info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9392 policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_USE_NETAGENT ? "Use" : "Scope",
9393 policy_search_array[i]->result_parameter.netagent_id);
9394 }
9395 }
9396 continue;
9397 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_REMOVE_NETAGENT) {
9398 bool agent_already_present = false;
9399 for (size_t netagent_i = 0; netagent_i < netagent_cursor; netagent_i++) {
9400 if (netagent_ids[netagent_i] == policy_search_array[i]->result_parameter.netagent_id) {
9401 // Already present. Mark the "REMOVE" flag if flags are supported, or just clear the entry
9402 agent_already_present = true;
9403 netagent_use_flags[netagent_i] = NECP_AGENT_USE_FLAG_REMOVE;
9404 }
9405 }
9406 if (!agent_already_present && netagent_cursor < netagent_array_count) {
9407 // If not present, and flags are supported, add an entry with the "REMOVE" flag
9408 netagent_ids[netagent_cursor] = policy_search_array[i]->result_parameter.netagent_id;
9409 netagent_use_flags[netagent_cursor] = NECP_AGENT_USE_FLAG_REMOVE;
9410 netagent_cursor++;
9411 }
9412 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9413 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) Remove Netagent %d",
9414 info->application_id, info->real_application_id, info->bound_interface_index, info->protocol,
9415 policy_search_array[i]->result_parameter.netagent_id);
9416 }
9417 continue;
9418 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
9419 u_int32_t control_unit = policy_search_array[i]->result_parameter.flow_divert_control_unit;
9420 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
9421 /* For transparent proxies, accumulate the control unit and continue to the next policy */
9422 if (return_flow_divert_aggregate_unit != NULL) {
9423 *return_flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
9424 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9425 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: (Application %d Real Application %d BoundInterface %d Proto %d) flow divert %u", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, control_unit);
9426 }
9427 }
9428 continue;
9429 }
9430 }
9431
9432 // Matched policy is a skip. Do skip and continue.
9433 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
9434 NECP_DATA_TRACE_LOG_POLICY(debug, "SOCKET", "MATCHED SKIP POLICY");
9435 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
9436 skip_session_order = policy_search_array[i]->session_order + 1;
9437 if (skip_policy_id && *skip_policy_id == NECP_KERNEL_POLICY_ID_NONE) {
9438 *skip_policy_id = policy_search_array[i]->id;
9439 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9440 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: MATCHED SKIP POLICY (Application %d Real Application %d BoundInterface %d Proto %d) set skip_policy_id %d", info->application_id, info->real_application_id, info->bound_interface_index, info->protocol, *skip_policy_id);
9441 }
9442 }
9443 continue;
9444 }
9445
9446 // Matched an allow unentitled, which clears any drop order
9447 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ALLOW_UNENTITLED) {
9448 info->drop_order = 0;
9449 continue;
9450 }
9451
9452 // Passed all tests, found a match
9453 matched_policy = policy_search_array[i];
9454 NECP_DATA_TRACE_LOG_SOCKET_RESULT(debug, so, "SOCKET", "RESULT - MATCHED POLICY");
9455 break;
9456 }
9457 }
9458 }
9459
9460 if (return_netagent_array != NULL) {
9461 if (return_netagent_use_flags_array != NULL) {
9462 memcpy(dst: return_netagent_array, src: &netagent_ids, n: sizeof(u_int32_t) * netagent_array_count);
9463 memcpy(dst: return_netagent_use_flags_array, src: &netagent_use_flags, n: sizeof(u_int32_t) * netagent_array_count);
9464 } else {
9465 for (size_t netagent_i = 0; netagent_i < netagent_array_count; netagent_i++) {
9466 if (!(netagent_use_flags[netagent_i] & NECP_AGENT_USE_FLAG_REMOVE)) {
9467 return_netagent_array[netagent_i] = netagent_ids[netagent_i];
9468 } else {
9469 return_netagent_array[netagent_i] = 0;
9470 }
9471 }
9472 }
9473 }
9474
9475 if (return_route_rule_id_array_count != NULL) {
9476 *return_route_rule_id_array_count = route_rule_id_count;
9477 }
9478 return matched_policy;
9479}
9480
9481static bool
9482necp_socket_uses_interface(struct inpcb *inp, u_int32_t interface_index)
9483{
9484 bool found_match = FALSE;
9485 ifaddr_t ifa;
9486 union necp_sockaddr_union address_storage;
9487 int family = AF_INET;
9488
9489 ifnet_head_lock_shared();
9490 ifnet_t interface = ifindex2ifnet[interface_index];
9491 ifnet_head_done();
9492
9493 if (inp == NULL || interface == NULL) {
9494 return FALSE;
9495 }
9496
9497 if (inp->inp_vflag & INP_IPV4) {
9498 family = AF_INET;
9499 } else if (inp->inp_vflag & INP_IPV6) {
9500 family = AF_INET6;
9501 } else {
9502 return FALSE;
9503 }
9504
9505 // Match socket address against interface addresses
9506 ifnet_lock_shared(ifp: interface);
9507 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
9508 if (ifaddr_address(ifaddr: ifa, SA(&address_storage.sa), addr_size: sizeof(address_storage)) == 0) {
9509 if (address_storage.sa.sa_family != family) {
9510 continue;
9511 }
9512
9513 if (family == AF_INET) {
9514 if (memcmp(s1: &address_storage.sin.sin_addr, s2: &inp->inp_laddr, n: sizeof(inp->inp_laddr)) == 0) {
9515 found_match = TRUE;
9516 break;
9517 }
9518 } else if (family == AF_INET6) {
9519 if (memcmp(s1: &address_storage.sin6.sin6_addr, s2: &inp->in6p_laddr, n: sizeof(inp->in6p_laddr)) == 0) {
9520 found_match = TRUE;
9521 break;
9522 }
9523 }
9524 }
9525 }
9526 ifnet_lock_done(ifp: interface);
9527
9528 return found_match;
9529}
9530
9531static inline bool
9532necp_socket_is_connected(struct inpcb *inp)
9533{
9534 return inp->inp_socket->so_state & (SS_ISCONNECTING | SS_ISCONNECTED | SS_ISDISCONNECTING);
9535}
9536
9537static inline necp_socket_bypass_type_t
9538necp_socket_bypass(struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, struct inpcb *inp)
9539{
9540 if (necp_pass_loopback > 0 && necp_is_loopback(local_addr: override_local_addr, remote_addr: override_remote_addr, inp, NULL, IFSCOPE_NONE)) {
9541 return NECP_BYPASS_TYPE_LOOPBACK;
9542 } else if (necp_is_intcoproc(inp, NULL)) {
9543 return NECP_BYPASS_TYPE_INTCOPROC;
9544 }
9545
9546 return NECP_BYPASS_TYPE_NONE;
9547}
9548
9549static inline void
9550necp_socket_ip_tunnel_tso(struct inpcb *inp)
9551{
9552 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
9553 ifnet_t tunnel_interface = NULL;
9554
9555 ifnet_head_lock_shared();
9556 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
9557 ifnet_head_done();
9558
9559 if (tunnel_interface != NULL) {
9560 tcp_set_tso(intotcpcb(inp), ifp: tunnel_interface);
9561 }
9562}
9563
9564static inline void
9565necp_unscope(struct inpcb *inp)
9566{
9567 // If the current policy result is "socket scoped" and the pcb was actually re-scoped as a result, then un-bind the pcb
9568 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED && (inp->inp_flags2 & INP2_SCOPED_BY_NECP)) {
9569 inp->inp_flags &= ~INP_BOUND_IF;
9570 inp->inp_boundifp = NULL;
9571 }
9572}
9573
9574static inline void
9575necp_clear_tunnel(struct inpcb *inp)
9576{
9577 if (inp->inp_boundifp != NULL && inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
9578 inp->inp_flags &= ~INP_BOUND_IF;
9579 inp->inp_boundifp = NULL;
9580 }
9581}
9582
9583static inline bool
9584necp_socket_verify_netagents(u_int32_t *netagent_ids, int debug, struct socket *so)
9585{
9586 // Verify netagents
9587 for (int netagent_cursor = 0; netagent_cursor < NECP_MAX_NETAGENTS; netagent_cursor++) {
9588 struct necp_uuid_id_mapping *mapping = NULL;
9589 u_int32_t netagent_id = netagent_ids[netagent_cursor];
9590 if (netagent_id == 0) {
9591 continue;
9592 }
9593 mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: netagent_id);
9594 if (mapping != NULL) {
9595 u_int32_t agent_flags = 0;
9596 agent_flags = netagent_get_flags(uuid: mapping->uuid);
9597 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
9598 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
9599 continue;
9600 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
9601 if (agent_flags & NETAGENT_FLAG_KERNEL_ACTIVATED) {
9602 int trigger_error = 0;
9603 trigger_error = netagent_kernel_trigger(uuid: mapping->uuid);
9604 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9605 NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> Triggering inactive agent (%d), error %d", (unsigned long long)so, netagent_id, trigger_error);
9606 }
9607 }
9608 return false;
9609 }
9610 }
9611 }
9612 }
9613 return true;
9614}
9615
9616necp_kernel_policy_id
9617necp_socket_find_policy_match(struct inpcb *inp, struct sockaddr *override_local_addr, struct sockaddr *override_remote_addr, u_int32_t override_bound_interface)
9618{
9619 struct socket *so = NULL;
9620 necp_kernel_policy_filter filter_control_unit = 0;
9621 struct necp_kernel_socket_policy *matched_policy = NULL;
9622 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9623 necp_kernel_policy_result service_action = 0;
9624 necp_kernel_policy_service service = { 0, 0 };
9625 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
9626 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
9627 proc_t socket_proc = NULL;
9628 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
9629
9630 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
9631 memset(s: &netagent_ids, c: 0, n: sizeof(netagent_ids));
9632
9633 struct necp_socket_info info = {};
9634
9635 u_int32_t flow_divert_aggregate_unit = 0;
9636
9637 if (inp == NULL) {
9638 return NECP_KERNEL_POLICY_ID_NONE;
9639 }
9640
9641 // Ignore invalid addresses
9642 if (override_local_addr != NULL &&
9643 !necp_address_is_valid(override_local_addr)) {
9644 override_local_addr = NULL;
9645 }
9646 if (override_remote_addr != NULL &&
9647 !necp_address_is_valid(override_remote_addr)) {
9648 override_remote_addr = NULL;
9649 }
9650
9651 so = inp->inp_socket;
9652
9653 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
9654
9655 // Don't lock. Possible race condition, but we don't want the performance hit.
9656 if (necp_drop_management_order == 0 &&
9657 (necp_kernel_socket_policies_count == 0 ||
9658 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
9659 if (necp_drop_all_order > 0 || drop_order > 0) {
9660 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9661 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9662 inp->inp_policyresult.policy_gencount = 0;
9663 inp->inp_policyresult.app_id = 0;
9664 inp->inp_policyresult.flowhash = 0;
9665 inp->inp_policyresult.results.filter_control_unit = 0;
9666 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9667 inp->inp_policyresult.results.route_rule_id = 0;
9668 if (necp_socket_bypass(override_local_addr, override_remote_addr, inp) != NECP_BYPASS_TYPE_NONE) {
9669 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9670 } else {
9671 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9672 }
9673 }
9674 return NECP_KERNEL_POLICY_ID_NONE;
9675 }
9676
9677 // Check for loopback exception
9678 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
9679 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
9680 // Mark socket as a pass
9681 necp_unscope(inp);
9682 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9683 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9684 inp->inp_policyresult.policy_gencount = 0;
9685 inp->inp_policyresult.app_id = 0;
9686 inp->inp_policyresult.flowhash = 0;
9687 inp->inp_policyresult.results.filter_control_unit = 0;
9688 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9689 inp->inp_policyresult.results.route_rule_id = 0;
9690 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9691 return NECP_KERNEL_POLICY_ID_NONE;
9692 }
9693
9694 // Lock
9695 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
9696 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface, false, drop_order, socket_proc: &socket_proc, info: &info, is_loopback: (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
9697
9698 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
9699 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "START", 0, 0);
9700
9701 // Check info
9702 u_int32_t flowhash = necp_socket_calc_flowhash_locked(info: &info);
9703 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
9704 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
9705 inp->inp_policyresult.flowhash == flowhash) {
9706 // If already matched this socket on this generation of table, skip
9707
9708 // Unlock
9709 lck_rw_done(lck: &necp_kernel_policy_lock);
9710
9711 if (socket_proc) {
9712 proc_rele(p: socket_proc);
9713 }
9714
9715 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9716 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - INP UPDATE - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d",
9717 inp->inp_socket, info.bound_interface_index, info.protocol,
9718 inp->inp_policyresult.policy_id,
9719 inp->inp_policyresult.results.result,
9720 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
9721 }
9722 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - CACHED <MATCHED>", inp->inp_policyresult.policy_id, 0);
9723 return inp->inp_policyresult.policy_id;
9724 }
9725
9726 inp->inp_policyresult.app_id = info.application_id;
9727
9728 // Match socket to policy
9729 necp_kernel_policy_id skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
9730 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES] = {};
9731 size_t route_rule_id_array_count = 0;
9732
9733 matched_policy = necp_socket_find_policy_match_with_info_locked(policy_search_array: necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], info: &info, return_filter: &filter_control_unit, return_route_rule_id_array: route_rule_id_array, return_route_rule_id_array_count: &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, return_service_action: &service_action, return_service: &service, return_netagent_array: netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, num_required_agent_types: 0, proc: socket_proc ? socket_proc : current_proc(), pf_tag: 0, skip_policy_id: &skip_policy_id, rt: inp->inp_route.ro_rt, return_drop_dest_policy_result: &drop_dest_policy_result, return_drop_all_bypass: &drop_all_bypass, return_flow_divert_aggregate_unit: &flow_divert_aggregate_unit, so, debug);
9734
9735 // Check for loopback exception again after the policy match
9736 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
9737 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
9738 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
9739 // Mark socket as a pass
9740 necp_unscope(inp);
9741 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9742 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9743 inp->inp_policyresult.policy_gencount = 0;
9744 inp->inp_policyresult.app_id = 0;
9745 inp->inp_policyresult.flowhash = 0;
9746 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9747 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9748 inp->inp_policyresult.results.route_rule_id = 0;
9749 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_PASS;
9750
9751 // Unlock
9752 lck_rw_done(lck: &necp_kernel_policy_lock);
9753
9754 if (socket_proc) {
9755 proc_rele(p: socket_proc);
9756 }
9757
9758 return NECP_KERNEL_POLICY_ID_NONE;
9759 }
9760
9761 // Verify netagents
9762 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
9763 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9764 NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (unsigned long long)so, info.bound_interface_index, info.protocol);
9765 }
9766
9767 // Mark socket as a drop if required agent is not active
9768 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9769 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9770 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9771 inp->inp_policyresult.flowhash = flowhash;
9772 inp->inp_policyresult.results.filter_control_unit = 0;
9773 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9774 inp->inp_policyresult.results.route_rule_id = 0;
9775 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9776
9777 // Unlock
9778 lck_rw_done(lck: &necp_kernel_policy_lock);
9779
9780 if (socket_proc) {
9781 proc_rele(p: socket_proc);
9782 }
9783
9784 return NECP_KERNEL_POLICY_ID_NONE;
9785 }
9786
9787 u_int32_t route_rule_id = 0;
9788 if (route_rule_id_array_count == 1) {
9789 route_rule_id = route_rule_id_array[0];
9790 } else if (route_rule_id_array_count > 1) {
9791 route_rule_id = necp_create_aggregate_route_rule(rule_ids: route_rule_id_array);
9792 }
9793
9794 bool reset_tcp_tunnel_interface = false;
9795 bool send_local_network_denied_event = false;
9796 if (matched_policy) {
9797 // For PASS policy result, clear previous rescope / tunnel inteface
9798 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS &&
9799 (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local)) {
9800 necp_unscope(inp);
9801 necp_clear_tunnel(inp);
9802 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9803 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for PASS result", inp->inp_policyresult.policy_id, 0);
9804 }
9805 }
9806 matched_policy_id = matched_policy->id;
9807 inp->inp_policyresult.policy_id = matched_policy->id;
9808 inp->inp_policyresult.skip_policy_id = skip_policy_id;
9809 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9810 inp->inp_policyresult.flowhash = flowhash;
9811 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9812 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9813 inp->inp_policyresult.results.route_rule_id = route_rule_id;
9814 inp->inp_policyresult.results.result = matched_policy->result;
9815 memcpy(dst: &inp->inp_policyresult.results.result_parameter, src: &matched_policy->result_parameter, n: sizeof(matched_policy->result_parameter));
9816
9817 if (info.used_responsible_pid && (matched_policy->condition_mask & NECP_KERNEL_CONDITION_REAL_APP_ID)) {
9818 inp->inp_policyresult.app_id = info.real_application_id;
9819 }
9820
9821 if (necp_socket_is_connected(inp) &&
9822 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
9823 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && !necp_socket_uses_interface(inp, interface_index: matched_policy->result_parameter.tunnel_interface_index)))) {
9824 NECPLOG(LOG_ERR, "Marking socket in state %d as defunct", so->so_state);
9825 sosetdefunct(current_proc(), so, SHUTDOWN_SOCKET_LEVEL_NECP | SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL, TRUE);
9826 } else if (necp_socket_is_connected(inp) &&
9827 matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
9828 info.protocol == IPPROTO_TCP) {
9829 // Reset TCP socket interface based parameters if tunnel policy changes
9830 reset_tcp_tunnel_interface = true;
9831 }
9832
9833 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9834 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy: %p (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d", inp->inp_socket, info.bound_interface_index, info.protocol, matched_policy->id, skip_policy_id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index);
9835 }
9836
9837 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
9838 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
9839 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
9840 // Trigger the event that we dropped due to a local network policy
9841 send_local_network_denied_event = true;
9842 }
9843 } else {
9844 bool drop_all = false;
9845 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
9846 // Mark socket as a drop if set
9847 drop_all = true;
9848 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
9849 drop_all_bypass = necp_check_drop_all_bypass_result(proc: socket_proc ? socket_proc : current_proc());
9850 }
9851 }
9852
9853 // Check if there is a route rule that adds flow divert, if we don't already have a terminal policy result
9854 u_int32_t flow_divert_control_unit = necp_route_get_flow_divert(NULL, netagent_array: netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, flow_divert_aggregate_unit: &flow_divert_aggregate_unit);
9855 if (flow_divert_control_unit != 0) {
9856 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9857 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9858 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9859 inp->inp_policyresult.flowhash = flowhash;
9860 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
9861 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9862 inp->inp_policyresult.results.route_rule_id = route_rule_id;
9863 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT;
9864 inp->inp_policyresult.results.result_parameter.flow_divert_control_unit = flow_divert_control_unit;
9865 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "FLOW DIVERT <ROUTE RULE>", 0, 0);
9866 } else if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
9867 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9868 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9869 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9870 inp->inp_policyresult.flowhash = flowhash;
9871 inp->inp_policyresult.results.filter_control_unit = 0;
9872 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9873 inp->inp_policyresult.results.route_rule_id = 0;
9874 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9875 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "RESULT - DROP <NO MATCH>", 0, 0);
9876 } else {
9877 // Mark non-matching socket so we don't re-check it
9878 necp_unscope(inp);
9879 if (info.client_flags & NECP_CLIENT_PARAMETER_FLAG_LISTENER || info.is_local) {
9880 necp_clear_tunnel(inp);
9881 }
9882 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
9883 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - INP UPDATE", "socket unscoped for <NO MATCH>", inp->inp_policyresult.policy_id, 0);
9884 }
9885 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9886 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9887 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9888 inp->inp_policyresult.flowhash = flowhash;
9889 inp->inp_policyresult.results.filter_control_unit = filter_control_unit; // We may have matched a filter, so mark it!
9890 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
9891 inp->inp_policyresult.results.route_rule_id = route_rule_id; // We may have matched a route rule, so mark it!
9892 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_NONE;
9893 }
9894 }
9895
9896 if (necp_check_missing_client_drop(proc: socket_proc ? socket_proc : current_proc(), info: &info) ||
9897 necp_check_restricted_multicast_drop(proc: socket_proc ? socket_proc : current_proc(), info: &info, false)) {
9898 // Mark as drop
9899 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9900 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
9901 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
9902 inp->inp_policyresult.flowhash = flowhash;
9903 inp->inp_policyresult.results.filter_control_unit = 0;
9904 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
9905 inp->inp_policyresult.results.route_rule_id = 0;
9906 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
9907 }
9908
9909 // Unlock
9910 lck_rw_done(lck: &necp_kernel_policy_lock);
9911
9912 if (reset_tcp_tunnel_interface) {
9913 // Update MSS when not holding the policy lock to avoid recursive locking
9914 tcp_mtudisc(inp, 0);
9915
9916 // Update TSO flag based on the tunnel interface
9917 necp_socket_ip_tunnel_tso(inp);
9918 }
9919
9920 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
9921 inp->inp_policyresult.network_denied_notifies++;
9922 necp_send_network_denied_event(pid: ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
9923 proc_uuid: ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
9924 NETPOLICY_NETWORKTYPE_LOCAL);
9925 }
9926
9927 if (socket_proc) {
9928 proc_rele(p: socket_proc);
9929 }
9930
9931 return matched_policy_id;
9932}
9933
9934static bool
9935necp_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)
9936{
9937 u_int32_t bound_interface_flags = 0;
9938 u_int32_t bound_interface_eflags = 0;
9939 u_int32_t bound_interface_xflags = 0;
9940
9941 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_ALL_INTERFACES)) {
9942 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9943 u_int32_t cond_bound_interface_index = kernel_policy->cond_bound_interface ? kernel_policy->cond_bound_interface->if_index : 0;
9944 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE,
9945 "NECP_KERNEL_CONDITION_BOUND_INTERFACE",
9946 cond_bound_interface_index, bound_interface_index);
9947 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) {
9948 if (bound_interface_index == cond_bound_interface_index) {
9949 // No match, matches forbidden interface
9950 return FALSE;
9951 }
9952 } else {
9953 if (bound_interface_index != cond_bound_interface_index) {
9954 // No match, does not match required interface
9955 return FALSE;
9956 }
9957 }
9958 }
9959 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9960 if (bound_interface_index != IFSCOPE_NONE) {
9961 ifnet_head_lock_shared();
9962 ifnet_t interface = ifindex2ifnet[bound_interface_index];
9963 if (interface != NULL) {
9964 bound_interface_flags = interface->if_flags;
9965 bound_interface_eflags = interface->if_eflags;
9966 bound_interface_xflags = interface->if_xflags;
9967 }
9968 ifnet_head_done();
9969 }
9970
9971 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9972 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - flags", kernel_policy->cond_bound_interface_flags, bound_interface_flags);
9973 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9974 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - eflags", kernel_policy->cond_bound_interface_eflags, bound_interface_eflags);
9975 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS,
9976 "NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS - xflags", kernel_policy->cond_bound_interface_xflags, bound_interface_xflags);
9977 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS) {
9978 if ((kernel_policy->cond_bound_interface_flags && (bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9979 (kernel_policy->cond_bound_interface_eflags && (bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9980 (kernel_policy->cond_bound_interface_xflags && (bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9981 // No match, matches some forbidden interface flags
9982 return FALSE;
9983 }
9984 } else {
9985 if ((kernel_policy->cond_bound_interface_flags && !(bound_interface_flags & kernel_policy->cond_bound_interface_flags)) ||
9986 (kernel_policy->cond_bound_interface_eflags && !(bound_interface_eflags & kernel_policy->cond_bound_interface_eflags)) ||
9987 (kernel_policy->cond_bound_interface_xflags && !(bound_interface_xflags & kernel_policy->cond_bound_interface_xflags))) {
9988 // No match, does not match some required interface xflags
9989 return FALSE;
9990 }
9991 }
9992 }
9993 if (!(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE) &&
9994 !(kernel_policy->condition_mask & NECP_KERNEL_CONDITION_BOUND_INTERFACE_FLAGS)) {
9995 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false, "Requiring no bound interface", 0, bound_interface_index);
9996 if (bound_interface_index != 0) {
9997 // No match, requires a non-bound packet
9998 return FALSE;
9999 }
10000 }
10001 }
10002
10003 if (kernel_policy->condition_mask == 0) {
10004 return TRUE;
10005 }
10006
10007 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_POLICY_ID) {
10008 necp_kernel_policy_id matched_policy_id =
10009 kernel_policy->result == NECP_KERNEL_POLICY_RESULT_SKIP ? socket_skip_policy_id : socket_policy_id;
10010 NECP_DATA_TRACE_LOG_CONDITION3(debug, "IP", false,
10011 "NECP_KERNEL_CONDITION_POLICY_ID",
10012 kernel_policy->cond_policy_id, 0, 0,
10013 matched_policy_id, socket_policy_id, socket_skip_policy_id);
10014 if (matched_policy_id != kernel_policy->cond_policy_id) {
10015 // No match, does not match required id
10016 return FALSE;
10017 }
10018 }
10019
10020 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LAST_INTERFACE) {
10021 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false,
10022 "NECP_KERNEL_CONDITION_LAST_INTERFACE",
10023 kernel_policy->cond_last_interface_index, last_interface_index);
10024 if (last_interface_index != kernel_policy->cond_last_interface_index) {
10025 return FALSE;
10026 }
10027 }
10028
10029 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10030 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL,
10031 "NECP_KERNEL_CONDITION_PROTOCOL",
10032 kernel_policy->cond_protocol, protocol);
10033 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PROTOCOL) {
10034 if (protocol == kernel_policy->cond_protocol) {
10035 // No match, matches forbidden protocol
10036 return FALSE;
10037 }
10038 } else {
10039 if (protocol != kernel_policy->cond_protocol) {
10040 // No match, does not match required protocol
10041 return FALSE;
10042 }
10043 }
10044 }
10045
10046 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_NETWORKS) {
10047 bool is_local = FALSE;
10048
10049 if (rt != NULL) {
10050 is_local = IS_NECP_DEST_IN_LOCAL_NETWORKS(rt);
10051 } else {
10052 is_local = necp_is_route_local(remote_addr: remote);
10053 }
10054 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", false, "NECP_KERNEL_CONDITION_LOCAL_NETWORKS", 0, is_local);
10055 if (!is_local) {
10056 // Either no route to validate or no match for local networks
10057 return FALSE;
10058 }
10059 }
10060
10061 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_START) {
10062 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10063 bool inRange = necp_is_addr_in_range(addr: (struct sockaddr *)local, range_start: (struct sockaddr *)&kernel_policy->cond_local_start, range_end: (struct sockaddr *)&kernel_policy->cond_local_end);
10064 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END, "local address range", 0, 0);
10065 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_END) {
10066 if (inRange) {
10067 return FALSE;
10068 }
10069 } else {
10070 if (!inRange) {
10071 return FALSE;
10072 }
10073 }
10074 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10075 bool inSubnet = necp_is_addr_in_subnet(addr: (struct sockaddr *)local, subnet_addr: (struct sockaddr *)&kernel_policy->cond_local_start, subnet_prefix: kernel_policy->cond_local_prefix);
10076 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX, "local address with prefix", 0, 0);
10077 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_LOCAL_PREFIX) {
10078 if (inSubnet) {
10079 return FALSE;
10080 }
10081 } else {
10082 if (!inSubnet) {
10083 return FALSE;
10084 }
10085 }
10086 }
10087 }
10088
10089 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_START) {
10090 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10091 bool inRange = necp_is_addr_in_range(addr: (struct sockaddr *)remote, range_start: (struct sockaddr *)&kernel_policy->cond_remote_start, range_end: (struct sockaddr *)&kernel_policy->cond_remote_end);
10092 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END, "remote address range", 0, 0);
10093 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_END) {
10094 if (inRange) {
10095 return FALSE;
10096 }
10097 } else {
10098 if (!inRange) {
10099 return FALSE;
10100 }
10101 }
10102 } else if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10103 bool inSubnet = necp_is_addr_in_subnet(addr: (struct sockaddr *)remote, subnet_addr: (struct sockaddr *)&kernel_policy->cond_remote_start, subnet_prefix: kernel_policy->cond_remote_prefix);
10104 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX, "remote address with prefix", 0, 0);
10105 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_REMOTE_PREFIX) {
10106 if (inSubnet) {
10107 return FALSE;
10108 }
10109 } else {
10110 if (!inSubnet) {
10111 return FALSE;
10112 }
10113 }
10114 }
10115 }
10116
10117 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10118 u_int16_t remote_port = 0;
10119 if (((struct sockaddr *)remote)->sa_family == AF_INET || ((struct sockaddr *)remote)->sa_family == AF_INET6) {
10120 remote_port = ((struct sockaddr_in *)remote)->sin_port;
10121 }
10122 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT,
10123 "NECP_KERNEL_CONDITION_SCHEME_PORT",
10124 0, remote_port);
10125 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_SCHEME_PORT) {
10126 if (kernel_policy->cond_scheme_port == remote_port) {
10127 return FALSE;
10128 }
10129 } else {
10130 if (kernel_policy->cond_scheme_port != remote_port) {
10131 return FALSE;
10132 }
10133 }
10134 }
10135
10136 if (kernel_policy->condition_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10137 bool tags_matched = false;
10138 NECP_DATA_TRACE_LOG_CONDITION(debug, "IP", kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS,
10139 "NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS",
10140 kernel_policy->cond_packet_filter_tags, pf_tag);
10141 if (kernel_policy->cond_packet_filter_tags & NECP_POLICY_CONDITION_PACKET_FILTER_TAG_STACK_DROP) {
10142 if ((pf_tag & PF_TAG_ID_STACK_DROP) == PF_TAG_ID_STACK_DROP) {
10143 tags_matched = true;
10144 }
10145
10146 if (kernel_policy->condition_negated_mask & NECP_KERNEL_CONDITION_PACKET_FILTER_TAGS) {
10147 if (tags_matched) {
10148 return FALSE;
10149 }
10150 } else {
10151 if (!tags_matched) {
10152 return FALSE;
10153 }
10154 }
10155 }
10156 }
10157
10158 return TRUE;
10159}
10160
10161static inline struct necp_kernel_ip_output_policy *
10162necp_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)
10163{
10164 u_int32_t skip_order = 0;
10165 u_int32_t skip_session_order = 0;
10166 struct necp_kernel_ip_output_policy *matched_policy = NULL;
10167 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)];
10168 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
10169 size_t route_rule_id_count = 0;
10170 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10171 if (return_drop_all_bypass != NULL) {
10172 *return_drop_all_bypass = drop_all_bypass;
10173 }
10174
10175 if (return_route_rule_id != NULL) {
10176 *return_route_rule_id = 0;
10177 }
10178
10179 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10180
10181 if (policy_search_array != NULL) {
10182 for (int i = 0; policy_search_array[i] != NULL; i++) {
10183 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "EXAMINING");
10184 if (necp_drop_all_order != 0 && policy_search_array[i]->session_order >= necp_drop_all_order) {
10185 // We've hit a drop all rule
10186 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10187 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10188 if (return_drop_all_bypass != NULL) {
10189 *return_drop_all_bypass = drop_all_bypass;
10190 }
10191 }
10192 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10193 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (session order > drop-all order)");
10194 break;
10195 }
10196 }
10197 if (necp_drop_dest_policy.entry_count > 0 &&
10198 necp_address_matches_drop_dest_policy(remote_addr, policy_search_array[i]->session_order)) {
10199 // We've hit a drop by destination address rule
10200 *return_drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_DROP;
10201 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - DROP (destination address rule)");
10202 break;
10203 }
10204 if (skip_session_order && policy_search_array[i]->session_order >= skip_session_order) {
10205 // Done skipping
10206 skip_order = 0;
10207 skip_session_order = 0;
10208 }
10209 if (skip_order) {
10210 if (policy_search_array[i]->order < skip_order) {
10211 // Skip this policy
10212 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "SKIP (session order < skip-order)");
10213 continue;
10214 } else {
10215 // Done skipping
10216 skip_order = 0;
10217 skip_session_order = 0;
10218 }
10219 } else if (skip_session_order) {
10220 // Skip this policy
10221 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "SKIP (skip-session-order)");
10222 continue;
10223 }
10224
10225 if (necp_ip_output_check_policy(kernel_policy: policy_search_array[i], socket_policy_id, socket_skip_policy_id, bound_interface_index, last_interface_index, protocol, local: local_addr, remote: remote_addr, rt, pf_tag, debug)) {
10226 if (!debug && necp_data_tracing_session_order) {
10227 if ((necp_data_tracing_session_order == policy_search_array[i]->session_order) &&
10228 (!necp_data_tracing_policy_order || (necp_data_tracing_policy_order == policy_search_array[i]->order))) {
10229 NECP_DATA_TRACE_LOG_IP_RESULT(true, "IP", "DEBUG - MATCHED POLICY");
10230 }
10231 }
10232
10233 if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_ROUTE_RULES) {
10234 if (return_route_rule_id != NULL && route_rule_id_count < MAX_AGGREGATE_ROUTE_RULES) {
10235 route_rule_id_array[route_rule_id_count++] = policy_search_array[i]->result_parameter.route_rule_id;
10236 }
10237 continue;
10238 } else if (policy_search_array[i]->result == NECP_KERNEL_POLICY_RESULT_SKIP) {
10239 skip_order = policy_search_array[i]->result_parameter.skip_policy_order;
10240 skip_session_order = policy_search_array[i]->session_order + 1;
10241 NECP_DATA_TRACE_LOG_POLICY(debug, "IP", "MATCHED SKIP POLICY");
10242 continue;
10243 }
10244
10245 // Passed all tests, found a match
10246 matched_policy = policy_search_array[i];
10247 NECP_DATA_TRACE_LOG_IP_RESULT(debug, "IP", "RESULT - MATCHED POLICY");
10248 break;
10249 }
10250 }
10251 }
10252
10253 if (route_rule_id_count == 1) {
10254 *return_route_rule_id = route_rule_id_array[0];
10255 } else if (route_rule_id_count > 1) {
10256 *return_route_rule_id = necp_create_aggregate_route_rule(rule_ids: route_rule_id_array);
10257 }
10258
10259 return matched_policy;
10260}
10261
10262static inline bool
10263necp_output_bypass(struct mbuf *packet)
10264{
10265 if (necp_pass_loopback > 0 && necp_is_loopback(NULL, NULL, NULL, packet, IFSCOPE_NONE)) {
10266 return true;
10267 }
10268 if (necp_pass_keepalives > 0 && necp_get_is_keepalive_from_packet(packet)) {
10269 return true;
10270 }
10271 if (necp_is_intcoproc(NULL, packet)) {
10272 return true;
10273 }
10274 return false;
10275}
10276
10277necp_kernel_policy_id
10278necp_ip_output_find_policy_match(struct mbuf *packet, int flags, struct ip_out_args *ipoa, struct rtentry *rt,
10279 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
10280{
10281 struct ip *ip = NULL;
10282 int hlen = sizeof(struct ip);
10283 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10284 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10285 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10286 struct necp_kernel_ip_output_policy *matched_policy = NULL;
10287 u_int16_t protocol = 0;
10288 u_int32_t bound_interface_index = 0;
10289 u_int32_t last_interface_index = 0;
10290 union necp_sockaddr_union local_addr = { };
10291 union necp_sockaddr_union remote_addr = { };
10292 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10293 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10294 u_int16_t pf_tag = 0;
10295
10296 if (result) {
10297 *result = 0;
10298 }
10299
10300 if (result_parameter) {
10301 memset(s: result_parameter, c: 0, n: sizeof(*result_parameter));
10302 }
10303
10304 if (packet == NULL) {
10305 return NECP_KERNEL_POLICY_ID_NONE;
10306 }
10307
10308 socket_policy_id = necp_get_policy_id_from_packet(packet);
10309 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
10310 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
10311
10312 // Exit early for an empty list
10313 // Don't lock. Possible race condition, but we don't want the performance hit.
10314 if (necp_kernel_ip_output_policies_count == 0 ||
10315 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0)) {
10316 if (necp_drop_all_order > 0) {
10317 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10318 if (result) {
10319 if (necp_output_bypass(packet)) {
10320 *result = NECP_KERNEL_POLICY_RESULT_PASS;
10321 } else {
10322 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10323 }
10324 }
10325 }
10326
10327 return matched_policy_id;
10328 }
10329
10330 // Check for loopback exception
10331 if (necp_output_bypass(packet)) {
10332 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10333 if (result) {
10334 *result = NECP_KERNEL_POLICY_RESULT_PASS;
10335 }
10336 return matched_policy_id;
10337 }
10338
10339 last_interface_index = necp_get_last_interface_index_from_packet(packet);
10340
10341 // Process packet to get relevant fields
10342 ip = mtod(packet, struct ip *);
10343#ifdef _IP_VHL
10344 hlen = _IP_VHL_HL(ip->ip_vhl) << 2;
10345#else
10346 hlen = ip->ip_hl << 2;
10347#endif
10348
10349 protocol = ip->ip_p;
10350
10351 if ((flags & IP_OUTARGS) && (ipoa != NULL) &&
10352 (ipoa->ipoa_flags & IPOAF_BOUND_IF) &&
10353 ipoa->ipoa_boundif != IFSCOPE_NONE) {
10354 bound_interface_index = ipoa->ipoa_boundif;
10355 }
10356
10357 local_addr.sin.sin_family = AF_INET;
10358 local_addr.sin.sin_len = sizeof(struct sockaddr_in);
10359 memcpy(dst: &local_addr.sin.sin_addr, src: &ip->ip_src, n: sizeof(ip->ip_src));
10360
10361 remote_addr.sin.sin_family = AF_INET;
10362 remote_addr.sin.sin_len = sizeof(struct sockaddr_in);
10363 memcpy(dst: &((struct sockaddr_in *)&remote_addr)->sin_addr, src: &ip->ip_dst, n: sizeof(ip->ip_dst));
10364
10365 switch (protocol) {
10366 case IPPROTO_TCP: {
10367 struct tcphdr th;
10368 if ((int)(hlen + sizeof(th)) <= packet->m_pkthdr.len) {
10369 m_copydata(packet, hlen, sizeof(th), (u_int8_t *)&th);
10370 ((struct sockaddr_in *)&local_addr)->sin_port = th.th_sport;
10371 ((struct sockaddr_in *)&remote_addr)->sin_port = th.th_dport;
10372 }
10373 break;
10374 }
10375 case IPPROTO_UDP: {
10376 struct udphdr uh;
10377 if ((int)(hlen + sizeof(uh)) <= packet->m_pkthdr.len) {
10378 m_copydata(packet, hlen, sizeof(uh), (u_int8_t *)&uh);
10379 ((struct sockaddr_in *)&local_addr)->sin_port = uh.uh_sport;
10380 ((struct sockaddr_in *)&remote_addr)->sin_port = uh.uh_dport;
10381 }
10382 break;
10383 }
10384 default: {
10385 ((struct sockaddr_in *)&local_addr)->sin_port = 0;
10386 ((struct sockaddr_in *)&remote_addr)->sin_port = 0;
10387 break;
10388 }
10389 }
10390
10391 // Match packet to policy
10392 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
10393 u_int32_t route_rule_id = 0;
10394
10395 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
10396 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "START");
10397
10398 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: &local_addr, remote_addr: &remote_addr, rt, pf_tag, return_route_rule_id: &route_rule_id, return_drop_dest_policy_result: &drop_dest_policy_result, return_drop_all_bypass: &drop_all_bypass, debug);
10399 if (matched_policy) {
10400 matched_policy_id = matched_policy->id;
10401 if (result) {
10402 *result = matched_policy->result;
10403 }
10404
10405 if (result_parameter) {
10406 memcpy(dst: result_parameter, src: &matched_policy->result_parameter, n: sizeof(matched_policy->result_parameter));
10407 }
10408
10409 if (route_rule_id != 0 &&
10410 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10411 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10412 }
10413
10414 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10415 NECPLOG(LOG_DEBUG, "DATA-TRACE: IP Output: RESULT - MATCHED (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d Route Rule %u", socket_policy_id, bound_interface_index, last_interface_index, protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index, route_rule_id);
10416 }
10417 } else {
10418 bool drop_all = false;
10419 /*
10420 * Apply drop-all only to packets which have never matched a primary policy (check
10421 * if the packet saved policy id is none or falls within the socket policy id range).
10422 */
10423 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10424 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10425 drop_all = true;
10426 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10427 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10428 }
10429 }
10430 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10431 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10432 if (result) {
10433 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10434 NECP_DATA_TRACE_LOG_IP4(debug, "IP4", "RESULT - DROP <NO MATCH>");
10435 }
10436 } else if (route_rule_id != 0 &&
10437 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10438 // If we matched a route rule, mark it
10439 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10440 }
10441 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10442 NECPLOG(LOG_DEBUG, "DATA-TRACE: IP Output: RESULT - NO MATCH (ID %d BoundInterface %d LastInterface %d Proto %d)", socket_policy_id, bound_interface_index, last_interface_index, protocol);
10443 }
10444 }
10445
10446 lck_rw_done(lck: &necp_kernel_policy_lock);
10447
10448 return matched_policy_id;
10449}
10450
10451necp_kernel_policy_id
10452necp_ip6_output_find_policy_match(struct mbuf *packet, int flags, struct ip6_out_args *ip6oa, struct rtentry *rt,
10453 necp_kernel_policy_result *result, necp_kernel_policy_result_parameter *result_parameter)
10454{
10455 struct ip6_hdr *ip6 = NULL;
10456 int next = -1;
10457 int offset = 0;
10458 necp_kernel_policy_id socket_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10459 necp_kernel_policy_id socket_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10460 necp_kernel_policy_id matched_policy_id = NECP_KERNEL_POLICY_ID_NONE;
10461 struct necp_kernel_ip_output_policy *matched_policy = NULL;
10462 u_int16_t protocol = 0;
10463 u_int32_t bound_interface_index = 0;
10464 u_int32_t last_interface_index = 0;
10465 union necp_sockaddr_union local_addr = { };
10466 union necp_sockaddr_union remote_addr = { };
10467 u_int32_t drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
10468 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
10469 u_int16_t pf_tag = 0;
10470
10471 if (result) {
10472 *result = 0;
10473 }
10474
10475 if (result_parameter) {
10476 memset(s: result_parameter, c: 0, n: sizeof(*result_parameter));
10477 }
10478
10479 if (packet == NULL) {
10480 return NECP_KERNEL_POLICY_ID_NONE;
10481 }
10482
10483 socket_policy_id = necp_get_policy_id_from_packet(packet);
10484 socket_skip_policy_id = necp_get_skip_policy_id_from_packet(packet);
10485 pf_tag = necp_get_packet_filter_tags_from_packet(packet);
10486
10487 // Exit early for an empty list
10488 // Don't lock. Possible race condition, but we don't want the performance hit.
10489 if (necp_drop_management_order == 0 &&
10490 (necp_kernel_ip_output_policies_count == 0 ||
10491 (socket_policy_id == NECP_KERNEL_POLICY_ID_NONE && necp_kernel_ip_output_policies_non_id_count == 0 && necp_drop_dest_policy.entry_count == 0))) {
10492 if (necp_drop_all_order > 0) {
10493 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10494 if (result) {
10495 if (necp_output_bypass(packet)) {
10496 *result = NECP_KERNEL_POLICY_RESULT_PASS;
10497 } else {
10498 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10499 }
10500 }
10501 }
10502
10503 return matched_policy_id;
10504 }
10505
10506 // Check for loopback exception
10507 if (necp_output_bypass(packet)) {
10508 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10509 if (result) {
10510 *result = NECP_KERNEL_POLICY_RESULT_PASS;
10511 }
10512 return matched_policy_id;
10513 }
10514
10515 last_interface_index = necp_get_last_interface_index_from_packet(packet);
10516
10517 // Process packet to get relevant fields
10518 ip6 = mtod(packet, struct ip6_hdr *);
10519
10520 if ((flags & IPV6_OUTARGS) && (ip6oa != NULL) &&
10521 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
10522 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
10523 bound_interface_index = ip6oa->ip6oa_boundif;
10524 }
10525
10526 ((struct sockaddr_in6 *)&local_addr)->sin6_family = AF_INET6;
10527 ((struct sockaddr_in6 *)&local_addr)->sin6_len = sizeof(struct sockaddr_in6);
10528 memcpy(dst: &((struct sockaddr_in6 *)&local_addr)->sin6_addr, src: &ip6->ip6_src, n: sizeof(ip6->ip6_src));
10529
10530 ((struct sockaddr_in6 *)&remote_addr)->sin6_family = AF_INET6;
10531 ((struct sockaddr_in6 *)&remote_addr)->sin6_len = sizeof(struct sockaddr_in6);
10532 memcpy(dst: &((struct sockaddr_in6 *)&remote_addr)->sin6_addr, src: &ip6->ip6_dst, n: sizeof(ip6->ip6_dst));
10533
10534 offset = ip6_lasthdr(packet, 0, IPPROTO_IPV6, &next);
10535 if (offset >= 0 && packet->m_pkthdr.len >= offset) {
10536 protocol = next;
10537 switch (protocol) {
10538 case IPPROTO_TCP: {
10539 struct tcphdr th;
10540 if ((int)(offset + sizeof(th)) <= packet->m_pkthdr.len) {
10541 m_copydata(packet, offset, sizeof(th), (u_int8_t *)&th);
10542 ((struct sockaddr_in6 *)&local_addr)->sin6_port = th.th_sport;
10543 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = th.th_dport;
10544 }
10545 break;
10546 }
10547 case IPPROTO_UDP: {
10548 struct udphdr uh;
10549 if ((int)(offset + sizeof(uh)) <= packet->m_pkthdr.len) {
10550 m_copydata(packet, offset, sizeof(uh), (u_int8_t *)&uh);
10551 ((struct sockaddr_in6 *)&local_addr)->sin6_port = uh.uh_sport;
10552 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = uh.uh_dport;
10553 }
10554 break;
10555 }
10556 default: {
10557 ((struct sockaddr_in6 *)&local_addr)->sin6_port = 0;
10558 ((struct sockaddr_in6 *)&remote_addr)->sin6_port = 0;
10559 break;
10560 }
10561 }
10562 }
10563
10564 // Match packet to policy
10565 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
10566 u_int32_t route_rule_id = 0;
10567
10568 int debug = NECP_ENABLE_DATA_TRACE((&local_addr), (&remote_addr), protocol, 0, bound_interface_index);
10569 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "START");
10570
10571 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: &local_addr, remote_addr: &remote_addr, rt, pf_tag, return_route_rule_id: &route_rule_id, return_drop_dest_policy_result: &drop_dest_policy_result, return_drop_all_bypass: &drop_all_bypass, debug);
10572 if (matched_policy) {
10573 matched_policy_id = matched_policy->id;
10574 if (result) {
10575 *result = matched_policy->result;
10576 }
10577
10578 if (result_parameter) {
10579 memcpy(dst: result_parameter, src: &matched_policy->result_parameter, n: sizeof(matched_policy->result_parameter));
10580 }
10581
10582 if (route_rule_id != 0 &&
10583 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10584 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10585 }
10586
10587 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10588 NECPLOG(LOG_DEBUG, "DATA-TRACE: IP6 Output: RESULT - MATCHED (ID %d BoundInterface %d LastInterface %d Proto %d) Policy %d Result %d Parameter %d Route Rule %u", socket_policy_id, bound_interface_index, last_interface_index, protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index, route_rule_id);
10589 }
10590 } else {
10591 bool drop_all = false;
10592 /*
10593 * Apply drop-all only to packets which have never matched a primary policy (check
10594 * if the packet saved policy id is none or falls within the socket policy id range).
10595 */
10596 if (socket_policy_id < NECP_KERNEL_POLICY_ID_FIRST_VALID_IP &&
10597 (necp_drop_all_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP)) {
10598 drop_all = true;
10599 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
10600 drop_all_bypass = necp_check_drop_all_bypass_result(NULL);
10601 }
10602 }
10603 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
10604 matched_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
10605 if (result) {
10606 *result = NECP_KERNEL_POLICY_RESULT_DROP;
10607 NECP_DATA_TRACE_LOG_IP6(debug, "IP6", "RESULT - DROP <NO MATCH>");
10608 }
10609 } else if (route_rule_id != 0 &&
10610 packet->m_pkthdr.necp_mtag.necp_route_rule_id == 0) {
10611 // If we matched a route rule, mark it
10612 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
10613 }
10614 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
10615 NECPLOG(LOG_DEBUG, "DATA-TRACE: IP6 Output: RESULT - NO MATCH (ID %d BoundInterface %d LastInterface %d Proto %d)", socket_policy_id, bound_interface_index, last_interface_index, protocol);
10616 }
10617 }
10618
10619 lck_rw_done(lck: &necp_kernel_policy_lock);
10620
10621 return matched_policy_id;
10622}
10623
10624// Utilities
10625static bool
10626necp_is_addr_in_range(struct sockaddr *addr, struct sockaddr *range_start, struct sockaddr *range_end)
10627{
10628 int cmp = 0;
10629
10630 if (addr == NULL || range_start == NULL || range_end == NULL) {
10631 return FALSE;
10632 }
10633
10634 /* Must be greater than or equal to start */
10635 cmp = necp_addr_compare(sa1: addr, sa2: range_start, check_port: 1);
10636 if (cmp != 0 && cmp != 1) {
10637 return FALSE;
10638 }
10639
10640 /* Must be less than or equal to end */
10641 cmp = necp_addr_compare(sa1: addr, sa2: range_end, check_port: 1);
10642 if (cmp != 0 && cmp != -1) {
10643 return FALSE;
10644 }
10645
10646 return TRUE;
10647}
10648
10649static bool
10650necp_is_range_in_range(struct sockaddr *inner_range_start, struct sockaddr *inner_range_end, struct sockaddr *range_start, struct sockaddr *range_end)
10651{
10652 int cmp = 0;
10653
10654 if (inner_range_start == NULL || inner_range_end == NULL || range_start == NULL || range_end == NULL) {
10655 return FALSE;
10656 }
10657
10658 /* Must be greater than or equal to start */
10659 cmp = necp_addr_compare(sa1: inner_range_start, sa2: range_start, check_port: 1);
10660 if (cmp != 0 && cmp != 1) {
10661 return FALSE;
10662 }
10663
10664 /* Must be less than or equal to end */
10665 cmp = necp_addr_compare(sa1: inner_range_end, sa2: range_end, check_port: 1);
10666 if (cmp != 0 && cmp != -1) {
10667 return FALSE;
10668 }
10669
10670 return TRUE;
10671}
10672
10673static bool
10674necp_is_addr_in_subnet(struct sockaddr *addr, struct sockaddr *subnet_addr, u_int8_t subnet_prefix)
10675{
10676 if (addr == NULL || subnet_addr == NULL) {
10677 return FALSE;
10678 }
10679
10680 if (addr->sa_family != subnet_addr->sa_family || addr->sa_len != subnet_addr->sa_len) {
10681 return FALSE;
10682 }
10683
10684 switch (addr->sa_family) {
10685 case AF_INET: {
10686 if (satosin(subnet_addr)->sin_port != 0 &&
10687 satosin(addr)->sin_port != satosin(subnet_addr)->sin_port) {
10688 return FALSE;
10689 }
10690 return necp_buffer_compare_with_bit_prefix(p1: (u_int8_t *)&satosin(addr)->sin_addr, p2: (u_int8_t *)&satosin(subnet_addr)->sin_addr, bits: subnet_prefix);
10691 }
10692 case AF_INET6: {
10693 if (satosin6(subnet_addr)->sin6_port != 0 &&
10694 satosin6(addr)->sin6_port != satosin6(subnet_addr)->sin6_port) {
10695 return FALSE;
10696 }
10697 if (satosin6(addr)->sin6_scope_id &&
10698 satosin6(subnet_addr)->sin6_scope_id &&
10699 satosin6(addr)->sin6_scope_id != satosin6(subnet_addr)->sin6_scope_id) {
10700 return FALSE;
10701 }
10702 return necp_buffer_compare_with_bit_prefix(p1: (u_int8_t *)&satosin6(addr)->sin6_addr, p2: (u_int8_t *)&satosin6(subnet_addr)->sin6_addr, bits: subnet_prefix);
10703 }
10704 default: {
10705 return FALSE;
10706 }
10707 }
10708
10709 return FALSE;
10710}
10711
10712/*
10713 * Return values:
10714 * -1: sa1 < sa2
10715 * 0: sa1 == sa2
10716 * 1: sa1 > sa2
10717 * 2: Not comparable or error
10718 */
10719static int
10720necp_addr_compare(struct sockaddr *sa1, struct sockaddr *sa2, int check_port)
10721{
10722 int result = 0;
10723 int port_result = 0;
10724
10725 if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) {
10726 return 2;
10727 }
10728
10729 if (sa1->sa_len == 0) {
10730 return 0;
10731 }
10732
10733 switch (sa1->sa_family) {
10734 case AF_INET: {
10735 if (sa1->sa_len != sizeof(struct sockaddr_in)) {
10736 return 2;
10737 }
10738
10739 result = memcmp(s1: &satosin(sa1)->sin_addr.s_addr, s2: &satosin(sa2)->sin_addr.s_addr, n: sizeof(satosin(sa1)->sin_addr.s_addr));
10740
10741 if (check_port) {
10742 if (satosin(sa1)->sin_port < satosin(sa2)->sin_port) {
10743 port_result = -1;
10744 } else if (satosin(sa1)->sin_port > satosin(sa2)->sin_port) {
10745 port_result = 1;
10746 }
10747
10748 if (result == 0) {
10749 result = port_result;
10750 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
10751 return 2;
10752 }
10753 }
10754
10755 break;
10756 }
10757 case AF_INET6: {
10758 if (sa1->sa_len != sizeof(struct sockaddr_in6)) {
10759 return 2;
10760 }
10761
10762 if (satosin6(sa1)->sin6_scope_id != satosin6(sa2)->sin6_scope_id) {
10763 return 2;
10764 }
10765
10766 result = memcmp(s1: &satosin6(sa1)->sin6_addr.s6_addr[0], s2: &satosin6(sa2)->sin6_addr.s6_addr[0], n: sizeof(struct in6_addr));
10767
10768 if (check_port) {
10769 if (satosin6(sa1)->sin6_port < satosin6(sa2)->sin6_port) {
10770 port_result = -1;
10771 } else if (satosin6(sa1)->sin6_port > satosin6(sa2)->sin6_port) {
10772 port_result = 1;
10773 }
10774
10775 if (result == 0) {
10776 result = port_result;
10777 } else if ((result > 0 && port_result < 0) || (result < 0 && port_result > 0)) {
10778 return 2;
10779 }
10780 }
10781
10782 break;
10783 }
10784 default: {
10785 result = memcmp(s1: sa1, s2: sa2, n: sa1->sa_len);
10786 break;
10787 }
10788 }
10789
10790 if (result < 0) {
10791 result = (-1);
10792 } else if (result > 0) {
10793 result = (1);
10794 }
10795
10796 return result;
10797}
10798
10799static bool
10800necp_buffer_compare_with_bit_prefix(u_int8_t *p1, u_int8_t *p2, u_int32_t bits)
10801{
10802 u_int8_t mask;
10803
10804 /* Handle null pointers */
10805 if (p1 == NULL || p2 == NULL) {
10806 return p1 == p2;
10807 }
10808
10809 while (bits >= 8) {
10810 if (*p1++ != *p2++) {
10811 return FALSE;
10812 }
10813 bits -= 8;
10814 }
10815
10816 if (bits > 0) {
10817 mask = ~((1 << (8 - bits)) - 1);
10818 if ((*p1 & mask) != (*p2 & mask)) {
10819 return FALSE;
10820 }
10821 }
10822 return TRUE;
10823}
10824
10825static bool
10826necp_addr_is_empty(struct sockaddr *addr)
10827{
10828 if (addr == NULL) {
10829 return TRUE;
10830 }
10831
10832 if (addr->sa_len == 0) {
10833 return TRUE;
10834 }
10835
10836 switch (addr->sa_family) {
10837 case AF_INET: {
10838 static struct sockaddr_in ipv4_empty_address = {
10839 .sin_len = sizeof(struct sockaddr_in),
10840 .sin_family = AF_INET,
10841 .sin_port = 0,
10842 .sin_addr = { .s_addr = 0 }, // 0.0.0.0
10843 .sin_zero = {0},
10844 };
10845 if (necp_addr_compare(sa1: addr, sa2: (struct sockaddr *)&ipv4_empty_address, check_port: 0) == 0) {
10846 return TRUE;
10847 } else {
10848 return FALSE;
10849 }
10850 }
10851 case AF_INET6: {
10852 static struct sockaddr_in6 ipv6_empty_address = {
10853 .sin6_len = sizeof(struct sockaddr_in6),
10854 .sin6_family = AF_INET6,
10855 .sin6_port = 0,
10856 .sin6_flowinfo = 0,
10857 .sin6_addr = IN6ADDR_ANY_INIT, // ::
10858 .sin6_scope_id = 0,
10859 };
10860 if (necp_addr_compare(sa1: addr, sa2: (struct sockaddr *)&ipv6_empty_address, check_port: 0) == 0) {
10861 return TRUE;
10862 } else {
10863 return FALSE;
10864 }
10865 }
10866 default:
10867 return FALSE;
10868 }
10869
10870 return FALSE;
10871}
10872
10873static bool
10874necp_update_qos_marking(struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
10875{
10876 bool qos_marking = FALSE;
10877 int exception_index = 0;
10878 struct necp_route_rule *route_rule = NULL;
10879
10880 route_rule = necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id);
10881 if (route_rule == NULL) {
10882 qos_marking = FALSE;
10883 goto done;
10884 }
10885
10886 if (route_rule->match_netagent_id != 0) {
10887 if (netagent_array == NULL || netagent_array_count == 0) {
10888 // No agents, ignore rule
10889 goto done;
10890 }
10891 bool found_match = FALSE;
10892 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
10893 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
10894 found_match = TRUE;
10895 break;
10896 }
10897 }
10898 if (!found_match) {
10899 // Agents don't match, ignore rule
10900 goto done;
10901 }
10902 }
10903
10904 qos_marking = (route_rule->default_action == NECP_ROUTE_RULE_QOS_MARKING) ? TRUE : FALSE;
10905
10906 if (ifp == NULL) {
10907 goto done;
10908 }
10909
10910 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
10911 if (route_rule->exception_if_indices[exception_index] == 0) {
10912 break;
10913 }
10914 if (route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_QOS_MARKING) {
10915 continue;
10916 }
10917 if (route_rule->exception_if_indices[exception_index] == ifp->if_index) {
10918 qos_marking = TRUE;
10919 if (necp_debug > 2) {
10920 NECPLOG(LOG_DEBUG, "QoS Marking : Interface match %d for Rule %d Allowed %d",
10921 route_rule->exception_if_indices[exception_index], route_rule_id, qos_marking);
10922 }
10923 goto done;
10924 }
10925 }
10926
10927 if ((route_rule->cellular_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CELLULAR(ifp)) ||
10928 (route_rule->wifi_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIFI(ifp)) ||
10929 (route_rule->wired_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_WIRED(ifp)) ||
10930 (route_rule->expensive_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_EXPENSIVE(ifp)) ||
10931 (route_rule->constrained_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_CONSTRAINED(ifp)) ||
10932 (route_rule->companion_action == NECP_ROUTE_RULE_QOS_MARKING && IFNET_IS_COMPANION_LINK(ifp))) {
10933 qos_marking = TRUE;
10934 if (necp_debug > 2) {
10935 NECPLOG(LOG_DEBUG, "QoS Marking: C:%d WF:%d W:%d E:%d Cn:%d Cmpn:%d for Rule %d Allowed %d",
10936 route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action,
10937 route_rule->expensive_action, route_rule->constrained_action, route_rule->companion_action, route_rule_id, qos_marking);
10938 }
10939 goto done;
10940 }
10941done:
10942 if (necp_debug > 1) {
10943 NECPLOG(LOG_DEBUG, "QoS Marking: Rule %d ifp %s Allowed %d",
10944 route_rule_id, ifp ? ifp->if_xname : "", qos_marking);
10945 }
10946 return qos_marking;
10947}
10948
10949bool
10950necp_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)
10951{
10952 bool new_qos_marking = old_qos_marking;
10953 struct ifnet *ifp = interface;
10954
10955 if (net_qos_policy_restricted == 0) {
10956 return new_qos_marking;
10957 }
10958
10959 /*
10960 * This is racy but we do not need the performance hit of taking necp_kernel_policy_lock
10961 */
10962 if (*qos_marking_gencount == necp_kernel_socket_policies_gencount) {
10963 return new_qos_marking;
10964 }
10965
10966 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
10967
10968 if (ifp == NULL && route != NULL) {
10969 ifp = route->rt_ifp;
10970 }
10971 /*
10972 * By default, until we have a interface, do not mark and reevaluate the Qos marking policy
10973 */
10974 if (ifp == NULL || route_rule_id == 0) {
10975 new_qos_marking = FALSE;
10976 goto done;
10977 }
10978
10979 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
10980 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
10981 if (aggregate_route_rule != NULL) {
10982 int index = 0;
10983 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
10984 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
10985 if (sub_route_rule_id == 0) {
10986 break;
10987 }
10988 new_qos_marking = necp_update_qos_marking(ifp, NULL, netagent_array_count: 0, route_rule_id: sub_route_rule_id);
10989 if (new_qos_marking == TRUE) {
10990 break;
10991 }
10992 }
10993 }
10994 } else {
10995 new_qos_marking = necp_update_qos_marking(ifp, NULL, netagent_array_count: 0, route_rule_id);
10996 }
10997 /*
10998 * Now that we have an interface we remember the gencount
10999 */
11000 *qos_marking_gencount = necp_kernel_socket_policies_gencount;
11001
11002done:
11003 lck_rw_done(lck: &necp_kernel_policy_lock);
11004 return new_qos_marking;
11005}
11006
11007void
11008necp_socket_update_qos_marking(struct inpcb *inp, struct rtentry *route, u_int32_t route_rule_id)
11009{
11010 bool qos_marking = inp->inp_socket->so_flags1 & SOF1_QOSMARKING_ALLOWED ? TRUE : FALSE;
11011
11012 if (net_qos_policy_restricted == 0) {
11013 return;
11014 }
11015 if (inp->inp_socket == NULL) {
11016 return;
11017 }
11018 if ((inp->inp_socket->so_flags1 & SOF1_QOSMARKING_POLICY_OVERRIDE)) {
11019 return;
11020 }
11021
11022 qos_marking = necp_lookup_current_qos_marking(qos_marking_gencount: &(inp->inp_policyresult.results.qos_marking_gencount), route, NULL, route_rule_id, old_qos_marking: qos_marking);
11023
11024 if (qos_marking == TRUE) {
11025 inp->inp_socket->so_flags1 |= SOF1_QOSMARKING_ALLOWED;
11026 } else {
11027 inp->inp_socket->so_flags1 &= ~SOF1_QOSMARKING_ALLOWED;
11028 }
11029}
11030
11031static bool
11032necp_route_is_lqm_abort(struct ifnet *ifp, struct ifnet *delegated_ifp)
11033{
11034 if (ifp != NULL &&
11035 (ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11036 ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11037 return true;
11038 }
11039 if (delegated_ifp != NULL &&
11040 (delegated_ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID) &&
11041 delegated_ifp->if_interface_state.lqm_state == IFNET_LQM_THRESH_ABORT) {
11042 return true;
11043 }
11044 return false;
11045}
11046
11047static bool
11048necp_route_is_allowed_inner(struct rtentry *route, struct ifnet *ifp, u_int32_t *netagent_array, size_t netagent_array_count,
11049 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11050{
11051 bool default_is_allowed = TRUE;
11052 u_int8_t type_aggregate_action = NECP_ROUTE_RULE_NONE;
11053 int exception_index = 0;
11054 struct ifnet *delegated_ifp = NULL;
11055 struct necp_route_rule *route_rule = NULL;
11056
11057 route_rule = necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id);
11058 if (route_rule == NULL) {
11059 return TRUE;
11060 }
11061
11062 if (route_rule->match_netagent_id != 0) {
11063 if (netagent_array == NULL || netagent_array_count == 0) {
11064 // No agents, ignore rule
11065 return TRUE;
11066 }
11067 bool found_match = FALSE;
11068 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11069 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11070 found_match = TRUE;
11071 break;
11072 }
11073 }
11074 if (!found_match) {
11075 // Agents don't match, ignore rule
11076 return TRUE;
11077 }
11078 }
11079
11080 default_is_allowed = IS_NECP_ROUTE_RULE_DENY(route_rule->default_action) ? FALSE : TRUE;
11081 if (ifp == NULL && route != NULL) {
11082 ifp = route->rt_ifp;
11083 }
11084 if (ifp == NULL) {
11085 if (necp_debug > 1 && !default_is_allowed) {
11086 NECPLOG(LOG_DEBUG, "Route Allowed: No interface for route, using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11087 }
11088 return default_is_allowed;
11089 }
11090
11091 delegated_ifp = ifp->if_delegated.ifp;
11092 for (exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11093 if (route_rule->exception_if_indices[exception_index] == 0) {
11094 break;
11095 }
11096 if (route_rule->exception_if_indices[exception_index] == ifp->if_index ||
11097 (delegated_ifp != NULL && route_rule->exception_if_indices[exception_index] == delegated_ifp->if_index)) {
11098 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11099 const bool lqm_abort = necp_route_is_lqm_abort(ifp, delegated_ifp);
11100 if (necp_debug > 1 && lqm_abort) {
11101 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Deny LQM Abort",
11102 route_rule->exception_if_indices[exception_index], route_rule_id);
11103 }
11104 return false;
11105 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->exception_if_actions[exception_index])) {
11106 if (necp_debug > 1) {
11107 NECPLOG(LOG_DEBUG, "Route Allowed: Interface match %d for Rule %d Allowed %d", route_rule->exception_if_indices[exception_index], route_rule_id, (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE));
11108 }
11109 if (IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) && route_rule->effective_type != 0 && interface_type_denied != NULL) {
11110 *interface_type_denied = route_rule->effective_type;
11111 }
11112 return IS_NECP_ROUTE_RULE_DENY(route_rule->exception_if_actions[exception_index]) ? FALSE : TRUE;
11113 }
11114 }
11115 }
11116
11117 if (IFNET_IS_CELLULAR(ifp)) {
11118 if (route_rule->cellular_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11119 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11120 if (interface_type_denied != NULL) {
11121 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11122 if (route_rule->effective_type != 0) {
11123 *interface_type_denied = route_rule->effective_type;
11124 }
11125 }
11126 // Mark aggregate action as deny
11127 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11128 }
11129 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->cellular_action)) {
11130 if (interface_type_denied != NULL) {
11131 *interface_type_denied = IFRTYPE_FUNCTIONAL_CELLULAR;
11132 if (route_rule->effective_type != 0) {
11133 *interface_type_denied = route_rule->effective_type;
11134 }
11135 }
11136 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11137 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11138 IS_NECP_ROUTE_RULE_DENY(route_rule->cellular_action))) {
11139 // Deny wins if there is a conflict
11140 type_aggregate_action = route_rule->cellular_action;
11141 }
11142 }
11143 }
11144
11145 if (IFNET_IS_WIFI(ifp)) {
11146 if (route_rule->wifi_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11147 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11148 if (interface_type_denied != NULL) {
11149 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11150 if (route_rule->effective_type != 0) {
11151 *interface_type_denied = route_rule->effective_type;
11152 }
11153 }
11154 // Mark aggregate action as deny
11155 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11156 }
11157 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wifi_action)) {
11158 if (interface_type_denied != NULL) {
11159 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
11160 if (route_rule->effective_type != 0) {
11161 *interface_type_denied = route_rule->effective_type;
11162 }
11163 }
11164 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11165 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11166 IS_NECP_ROUTE_RULE_DENY(route_rule->wifi_action))) {
11167 // Deny wins if there is a conflict
11168 type_aggregate_action = route_rule->wifi_action;
11169 }
11170 }
11171 }
11172
11173 if (IFNET_IS_COMPANION_LINK(ifp) ||
11174 (ifp->if_delegated.ifp != NULL && IFNET_IS_COMPANION_LINK(ifp->if_delegated.ifp))) {
11175 if (route_rule->companion_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11176 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11177 if (interface_type_denied != NULL) {
11178 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11179 if (route_rule->effective_type != 0) {
11180 *interface_type_denied = route_rule->effective_type;
11181 }
11182 }
11183 // Mark aggregate action as deny
11184 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11185 }
11186 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->companion_action)) {
11187 if (interface_type_denied != NULL) {
11188 *interface_type_denied = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
11189 if (route_rule->effective_type != 0) {
11190 *interface_type_denied = route_rule->effective_type;
11191 }
11192 }
11193 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11194 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11195 IS_NECP_ROUTE_RULE_DENY(route_rule->companion_action))) {
11196 // Deny wins if there is a conflict
11197 type_aggregate_action = route_rule->companion_action;
11198 }
11199 }
11200 }
11201
11202 if (IFNET_IS_WIRED(ifp)) {
11203 if (route_rule->wired_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11204 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11205 if (interface_type_denied != NULL) {
11206 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11207 if (route_rule->effective_type != 0) {
11208 *interface_type_denied = route_rule->effective_type;
11209 }
11210 }
11211 // Mark aggregate action as deny
11212 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11213 }
11214 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->wired_action)) {
11215 if (interface_type_denied != NULL) {
11216 *interface_type_denied = IFRTYPE_FUNCTIONAL_WIRED;
11217 if (route_rule->effective_type != 0) {
11218 *interface_type_denied = route_rule->effective_type;
11219 }
11220 }
11221 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11222 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11223 IS_NECP_ROUTE_RULE_DENY(route_rule->wired_action))) {
11224 // Deny wins if there is a conflict
11225 type_aggregate_action = route_rule->wired_action;
11226 }
11227 }
11228 }
11229
11230 if (IFNET_IS_EXPENSIVE(ifp)) {
11231 if (route_rule->expensive_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11232 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11233 // Mark aggregate action as deny
11234 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11235 }
11236 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->expensive_action)) {
11237 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11238 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11239 IS_NECP_ROUTE_RULE_DENY(route_rule->expensive_action))) {
11240 // Deny wins if there is a conflict
11241 type_aggregate_action = route_rule->expensive_action;
11242 }
11243 }
11244 }
11245
11246 if (IFNET_IS_CONSTRAINED(ifp)) {
11247 if (route_rule->constrained_action == NECP_ROUTE_RULE_DENY_LQM_ABORT) {
11248 if (necp_route_is_lqm_abort(ifp, delegated_ifp)) {
11249 // Mark aggregate action as deny
11250 type_aggregate_action = NECP_ROUTE_RULE_DENY_INTERFACE;
11251 }
11252 } else if (IS_NECP_ROUTE_RULE_ALLOW_OR_DENY(route_rule->constrained_action)) {
11253 if (type_aggregate_action == NECP_ROUTE_RULE_NONE ||
11254 (type_aggregate_action == NECP_ROUTE_RULE_ALLOW_INTERFACE &&
11255 IS_NECP_ROUTE_RULE_DENY(route_rule->constrained_action))) {
11256 // Deny wins if there is a conflict
11257 type_aggregate_action = route_rule->constrained_action;
11258 }
11259 }
11260 }
11261
11262 if (type_aggregate_action != NECP_ROUTE_RULE_NONE) {
11263 if (necp_debug > 1) {
11264 NECPLOG(LOG_DEBUG, "Route Allowed: C:%d WF:%d W:%d E:%d Cmpn:%d for Rule %d Allowed %d", route_rule->cellular_action, route_rule->wifi_action, route_rule->wired_action, route_rule->expensive_action, route_rule->companion_action, route_rule_id, (IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE));
11265 }
11266 return IS_NECP_ROUTE_RULE_DENY(type_aggregate_action) ? FALSE : TRUE;
11267 }
11268
11269 if (necp_debug > 1 && !default_is_allowed) {
11270 NECPLOG(LOG_DEBUG, "Route Allowed: Using default for Rule %d Allowed %d", route_rule_id, default_is_allowed);
11271 }
11272 return default_is_allowed;
11273}
11274
11275static bool
11276necp_proc_is_allowed_on_management_interface(proc_t proc)
11277{
11278 bool allowed = false;
11279 const task_t task = proc_task(proc);
11280
11281 if (task != NULL) {
11282 if (IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT) == true
11283 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT) == true
11284#if DEBUG || DEVELOPMENT
11285 || IOTaskHasEntitlement(task, INTCOPROC_RESTRICTED_ENTITLEMENT_DEVELOPMENT) == true
11286 || IOTaskHasEntitlement(task, MANAGEMENT_DATA_ENTITLEMENT_DEVELOPMENT) == true
11287#endif /* DEBUG || DEVELOPMENT */
11288 ) {
11289 allowed = true;
11290 }
11291 }
11292 return allowed;
11293}
11294
11295__attribute__((noinline))
11296static void
11297necp_log_interface_not_allowed(struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11298{
11299 char buf[128];
11300
11301 if (inp != NULL) {
11302 inp_snprintf_tuple(inp, buf, sizeof(buf));
11303 } else {
11304 *buf = 0;
11305 }
11306 os_log(OS_LOG_DEFAULT,
11307 "necp_route_is_interface_type_allowed %s:%d %s not allowed on management interface %s",
11308 proc != NULL ? proc_best_name(proc) : proc_best_name(current_proc()),
11309 proc != NULL ? proc_getpid(proc) : proc_selfpid(),
11310 inp != NULL ? buf : "",
11311 ifp->if_xname);
11312}
11313
11314static bool
11315necp_route_is_interface_type_allowed(struct rtentry *route, struct ifnet *ifp, proc_t proc, struct inpcb *inp)
11316{
11317 if (if_management_interface_check_needed == false) {
11318 return true;
11319 }
11320 if (necp_drop_management_order == 0) {
11321 return true;
11322 }
11323 if (ifp == NULL && route != NULL) {
11324 ifp = route->rt_ifp;
11325 }
11326 if (ifp == NULL) {
11327 return true;
11328 }
11329
11330 if (IFNET_IS_MANAGEMENT(ifp)) {
11331 bool allowed = true;
11332
11333 if (inp != NULL) {
11334 /*
11335 * The entitlement check is already performed for socket flows
11336 */
11337 allowed = INP_MANAGEMENT_ALLOWED(inp);
11338 } else if (proc != NULL) {
11339 allowed = necp_proc_is_allowed_on_management_interface(proc);
11340 }
11341 if (__improbable(if_management_verbose > 1 && allowed == false)) {
11342 necp_log_interface_not_allowed(ifp, proc, inp);
11343 }
11344 return allowed;
11345 }
11346 return true;
11347}
11348
11349static bool
11350necp_route_is_allowed(struct rtentry *route, struct ifnet *interface, u_int32_t *netagent_array, size_t netagent_array_count,
11351 u_int32_t route_rule_id, u_int32_t *interface_type_denied)
11352{
11353 if ((route == NULL && interface == NULL && netagent_array == NULL) || route_rule_id == 0) {
11354 if (necp_debug > 1) {
11355 NECPLOG(LOG_DEBUG, "Route Allowed: no route or interface, Rule %d Allowed %d", route_rule_id, TRUE);
11356 }
11357 return TRUE;
11358 }
11359
11360 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11361 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11362 if (aggregate_route_rule != NULL) {
11363 int index = 0;
11364 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11365 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11366 if (sub_route_rule_id == 0) {
11367 break;
11368 }
11369 if (!necp_route_is_allowed_inner(route, ifp: interface, netagent_array, netagent_array_count, route_rule_id: sub_route_rule_id, interface_type_denied)) {
11370 return FALSE;
11371 }
11372 }
11373 }
11374 } else {
11375 return necp_route_is_allowed_inner(route, ifp: interface, netagent_array, netagent_array_count, route_rule_id, interface_type_denied);
11376 }
11377
11378 return TRUE;
11379}
11380
11381static bool
11382necp_route_rule_matches_agents(u_int32_t route_rule_id)
11383{
11384 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id);
11385 if (route_rule == NULL) {
11386 return false;
11387 }
11388
11389 return route_rule->match_netagent_id != 0;
11390}
11391
11392static uint32_t
11393necp_route_get_netagent(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id, bool *remove)
11394{
11395 if (remove == NULL) {
11396 return 0;
11397 }
11398
11399 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id);
11400 if (route_rule == NULL) {
11401 return 0;
11402 }
11403
11404 // No netagent, skip
11405 if (route_rule->netagent_id == 0) {
11406 return 0;
11407 }
11408
11409 if (route_rule->match_netagent_id != 0) {
11410 if (netagent_array == NULL || netagent_array_count == 0) {
11411 // No agents, ignore rule
11412 return 0;
11413 }
11414 bool found_match = FALSE;
11415 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11416 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11417 found_match = TRUE;
11418 break;
11419 }
11420 }
11421 if (!found_match) {
11422 // Agents don't match, ignore rule
11423 return 0;
11424 }
11425 }
11426
11427 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
11428 if (ifp == NULL) {
11429 // No interface, apply the default action
11430 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11431 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11432 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11433 return route_rule->netagent_id;
11434 }
11435 return 0;
11436 }
11437
11438 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11439 if (route_rule->exception_if_indices[exception_index] == 0) {
11440 break;
11441 }
11442 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
11443 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
11444 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_USE_NETAGENT ||
11445 route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11446 *remove = (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11447 return route_rule->netagent_id;
11448 }
11449 return 0;
11450 }
11451 }
11452
11453 if (ifp->if_type == IFT_CELLULAR &&
11454 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
11455 if (route_rule->cellular_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11456 route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11457 *remove = (route_rule->cellular_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11458 return route_rule->netagent_id;
11459 }
11460 return 0;
11461 }
11462
11463 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
11464 route_rule->wifi_action != NECP_ROUTE_RULE_NONE) {
11465 if ((route_rule->wifi_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11466 route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
11467 *remove = (route_rule->wifi_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11468 return route_rule->netagent_id;
11469 }
11470 return 0;
11471 }
11472
11473 if (IFNET_IS_COMPANION_LINK(ifp) &&
11474 route_rule->companion_action != NECP_ROUTE_RULE_NONE) {
11475 if ((route_rule->companion_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11476 route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
11477 *remove = (route_rule->companion_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11478 return route_rule->netagent_id;
11479 }
11480 return 0;
11481 }
11482
11483 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
11484 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
11485 if ((route_rule->wired_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11486 route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT)) {
11487 *remove = (route_rule->wired_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11488 return route_rule->netagent_id;
11489 }
11490 return 0;
11491 }
11492
11493 if (ifp->if_eflags & IFEF_EXPENSIVE &&
11494 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
11495 if (route_rule->expensive_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11496 route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11497 *remove = (route_rule->expensive_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11498 return route_rule->netagent_id;
11499 }
11500 return 0;
11501 }
11502
11503 if (ifp->if_xflags & IFXF_CONSTRAINED &&
11504 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
11505 if (route_rule->constrained_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11506 route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11507 *remove = (route_rule->constrained_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11508 return route_rule->netagent_id;
11509 }
11510 return 0;
11511 }
11512
11513 // No more specific case matched, apply the default action
11514 if (route_rule->default_action == NECP_ROUTE_RULE_USE_NETAGENT ||
11515 route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT) {
11516 *remove = (route_rule->default_action == NECP_ROUTE_RULE_REMOVE_NETAGENT);
11517 return route_rule->netagent_id;
11518 }
11519
11520 return 0;
11521}
11522
11523static uint32_t
11524necp_route_get_flow_divert_inner(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id)
11525{
11526 struct necp_route_rule *route_rule = necp_lookup_route_rule_locked(list: &necp_route_rules, route_rule_id);
11527 if (route_rule == NULL) {
11528 return 0;
11529 }
11530
11531 // No control unit, skip
11532 if (route_rule->control_unit == 0) {
11533 return 0;
11534 }
11535
11536 if (route_rule->match_netagent_id != 0) {
11537 if (netagent_array == NULL || netagent_array_count == 0) {
11538 // No agents, ignore rule
11539 return 0;
11540 }
11541 bool found_match = FALSE;
11542 for (size_t agent_index = 0; agent_index < netagent_array_count; agent_index++) {
11543 if (route_rule->match_netagent_id == netagent_array[agent_index]) {
11544 found_match = TRUE;
11545 break;
11546 }
11547 }
11548 if (!found_match) {
11549 // Agents don't match, ignore rule
11550 return 0;
11551 }
11552 }
11553
11554 struct ifnet *ifp = route != NULL ? route->rt_ifp : NULL;
11555 if (ifp == NULL) {
11556 // No interface, apply the default action
11557 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11558 return route_rule->control_unit;
11559 }
11560 return 0;
11561 }
11562
11563 for (int exception_index = 0; exception_index < MAX_ROUTE_RULE_INTERFACES; exception_index++) {
11564 if (route_rule->exception_if_indices[exception_index] == 0) {
11565 break;
11566 }
11567 if (route_rule->exception_if_indices[exception_index] == ifp->if_index &&
11568 route_rule->exception_if_actions[exception_index] != NECP_ROUTE_RULE_NONE) {
11569 if (route_rule->exception_if_actions[exception_index] == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11570 return route_rule->control_unit;
11571 }
11572 return 0;
11573 }
11574 }
11575
11576 if (ifp->if_type == IFT_CELLULAR &&
11577 route_rule->cellular_action != NECP_ROUTE_RULE_NONE) {
11578 if (route_rule->cellular_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11579 return route_rule->control_unit;
11580 }
11581 return 0;
11582 }
11583
11584 if (ifp->if_family == IFNET_FAMILY_ETHERNET && ifp->if_subfamily == IFNET_SUBFAMILY_WIFI &&
11585 route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11586 if (route_rule->wifi_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11587 return route_rule->control_unit;
11588 }
11589 return 0;
11590 }
11591
11592 if (IFNET_IS_COMPANION_LINK(ifp) &&
11593 route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11594 if (route_rule->companion_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11595 return route_rule->control_unit;
11596 }
11597 return 0;
11598 }
11599
11600 if ((ifp->if_family == IFNET_FAMILY_ETHERNET || ifp->if_family == IFNET_FAMILY_FIREWIRE) &&
11601 route_rule->wired_action != NECP_ROUTE_RULE_NONE) {
11602 if (route_rule->wired_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11603 return route_rule->control_unit;
11604 }
11605 return 0;
11606 }
11607
11608 if (ifp->if_eflags & IFEF_EXPENSIVE &&
11609 route_rule->expensive_action != NECP_ROUTE_RULE_NONE) {
11610 if (route_rule->expensive_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11611 return route_rule->control_unit;
11612 }
11613 return 0;
11614 }
11615
11616 if (ifp->if_xflags & IFXF_CONSTRAINED &&
11617 route_rule->constrained_action != NECP_ROUTE_RULE_NONE) {
11618 if (route_rule->constrained_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11619 return route_rule->control_unit;
11620 }
11621 return 0;
11622 }
11623
11624 // No more specific case matched, apply the default action
11625 if (route_rule->default_action == NECP_ROUTE_RULE_DIVERT_SOCKET) {
11626 return route_rule->control_unit;
11627 }
11628 return 0;
11629}
11630
11631static uint32_t
11632necp_route_get_flow_divert(struct rtentry *route, u_int32_t *netagent_array, size_t netagent_array_count, u_int32_t route_rule_id,
11633 u_int32_t *flow_divert_aggregate_unit)
11634{
11635 if ((route == NULL && netagent_array == NULL) || route_rule_id == 0 || flow_divert_aggregate_unit == NULL) {
11636 return 0;
11637 }
11638
11639 if (ROUTE_RULE_IS_AGGREGATE(route_rule_id)) {
11640 struct necp_aggregate_route_rule *aggregate_route_rule = necp_lookup_aggregate_route_rule_locked(route_rule_id);
11641 if (aggregate_route_rule != NULL) {
11642 int index = 0;
11643 for (index = 0; index < MAX_AGGREGATE_ROUTE_RULES; index++) {
11644 u_int32_t sub_route_rule_id = aggregate_route_rule->rule_ids[index];
11645 if (sub_route_rule_id == 0) {
11646 break;
11647 }
11648 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id: sub_route_rule_id);
11649 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
11650 // For transparent proxies, accumulate the control unit and continue to the next route rule
11651 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
11652 continue;
11653 }
11654
11655 if (control_unit != 0) {
11656 return control_unit;
11657 }
11658 }
11659 }
11660 } else {
11661 uint32_t control_unit = necp_route_get_flow_divert_inner(route, netagent_array, netagent_array_count, route_rule_id);
11662 if (control_unit & FLOW_DIVERT_IS_TRANSPARENT) {
11663 // For transparent proxies, accumulate the control unit and let the caller continue
11664 *flow_divert_aggregate_unit |= (control_unit & ~FLOW_DIVERT_IS_TRANSPARENT);
11665 return 0;
11666 }
11667 return control_unit;
11668 }
11669
11670 return 0;
11671}
11672
11673bool
11674necp_packet_is_allowed_over_interface(struct mbuf *packet, struct ifnet *interface)
11675{
11676 bool is_allowed = true;
11677 u_int32_t route_rule_id = necp_get_route_rule_id_from_packet(packet);
11678 if (route_rule_id != 0 &&
11679 interface != NULL) {
11680 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
11681 is_allowed = necp_route_is_allowed(NULL, interface, NULL, netagent_array_count: 0, route_rule_id: necp_get_route_rule_id_from_packet(packet), NULL);
11682 lck_rw_done(lck: &necp_kernel_policy_lock);
11683 }
11684 return is_allowed;
11685}
11686
11687static bool
11688necp_netagents_allow_traffic(u_int32_t *netagent_ids, size_t netagent_id_count)
11689{
11690 size_t netagent_cursor;
11691 for (netagent_cursor = 0; netagent_cursor < netagent_id_count; netagent_cursor++) {
11692 struct necp_uuid_id_mapping *mapping = NULL;
11693 u_int32_t netagent_id = netagent_ids[netagent_cursor];
11694 if (netagent_id == 0) {
11695 continue;
11696 }
11697 mapping = necp_uuid_lookup_uuid_with_service_id_locked(local_id: netagent_id);
11698 if (mapping != NULL) {
11699 u_int32_t agent_flags = 0;
11700 agent_flags = netagent_get_flags(uuid: mapping->uuid);
11701 if (agent_flags & NETAGENT_FLAG_REGISTERED) {
11702 if (agent_flags & NETAGENT_FLAG_ACTIVE) {
11703 continue;
11704 } else if ((agent_flags & NETAGENT_FLAG_VOLUNTARY) == 0) {
11705 return FALSE;
11706 }
11707 }
11708 }
11709 }
11710 return TRUE;
11711}
11712
11713static bool
11714necp_packet_filter_tags_receive(u_int16_t pf_tag, u_int32_t pass_flags)
11715{
11716 bool allowed_to_receive = TRUE;
11717
11718 if (pf_tag == PF_TAG_ID_STACK_DROP &&
11719 (pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) != NECP_KERNEL_POLICY_PASS_PF_TAG) {
11720 allowed_to_receive = FALSE;
11721 }
11722
11723 return allowed_to_receive;
11724}
11725
11726static bool
11727necp_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)
11728{
11729 u_int32_t verifyifindex = input_interface ? input_interface->if_index : 0;
11730 bool allowed_to_receive = TRUE;
11731 struct necp_socket_info info = {};
11732 u_int32_t flowhash = 0;
11733 necp_kernel_policy_result service_action = 0;
11734 necp_kernel_policy_service service = { 0, 0 };
11735 u_int32_t route_rule_id = 0;
11736 struct rtentry *route = NULL;
11737 u_int32_t interface_type_denied = IFRTYPE_FUNCTIONAL_UNKNOWN;
11738 necp_kernel_policy_result drop_dest_policy_result = NECP_KERNEL_POLICY_RESULT_NONE;
11739 necp_drop_all_bypass_check_result_t drop_all_bypass = NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE;
11740 u_int32_t netagent_ids[NECP_MAX_NETAGENTS];
11741 proc_t socket_proc = NULL;
11742 necp_kernel_policy_filter filter_control_unit = 0;
11743 u_int32_t pass_flags = 0;
11744 u_int32_t flow_divert_aggregate_unit = 0;
11745 necp_socket_bypass_type_t bypass_type = NECP_BYPASS_TYPE_NONE;
11746
11747 memset(s: &netagent_ids, c: 0, n: sizeof(netagent_ids));
11748
11749 if (return_policy_id) {
11750 *return_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11751 }
11752 if (return_skip_policy_id) {
11753 *return_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
11754 }
11755 if (return_route_rule_id) {
11756 *return_route_rule_id = 0;
11757 }
11758 if (return_pass_flags) {
11759 *return_pass_flags = 0;
11760 }
11761
11762 if (inp == NULL) {
11763 goto done;
11764 }
11765
11766 route = inp->inp_route.ro_rt;
11767
11768 struct socket *so = inp->inp_socket;
11769
11770 u_int32_t drop_order = necp_process_drop_order(so->so_cred);
11771
11772 // Don't lock. Possible race condition, but we don't want the performance hit.
11773 if (necp_drop_management_order == 0 &&
11774 (necp_kernel_socket_policies_count == 0 ||
11775 (!(inp->inp_flags2 & INP2_WANT_APP_POLICY) && necp_kernel_socket_policies_non_app_count == 0))) {
11776 if (necp_drop_all_order > 0 || drop_order > 0) {
11777 if (necp_socket_bypass(override_local_addr, override_remote_addr, inp) != NECP_BYPASS_TYPE_NONE) {
11778 allowed_to_receive = TRUE;
11779 } else {
11780 allowed_to_receive = FALSE;
11781 }
11782 }
11783 goto done;
11784 }
11785
11786 // If this socket is connected, or we are not taking addresses into account, try to reuse last result
11787 if ((necp_socket_is_connected(inp) || (override_local_addr == NULL && override_remote_addr == NULL)) && inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE) {
11788 bool policies_have_changed = FALSE;
11789 bool route_allowed = necp_route_is_interface_type_allowed(route, ifp: input_interface, NULL, inp);
11790 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount) {
11791 policies_have_changed = TRUE;
11792 } else {
11793 if (inp->inp_policyresult.results.route_rule_id != 0) {
11794 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
11795 if (!necp_route_is_allowed(route, interface: input_interface, NULL, netagent_array_count: 0, route_rule_id: inp->inp_policyresult.results.route_rule_id, interface_type_denied: &interface_type_denied)) {
11796 route_allowed = FALSE;
11797 }
11798 lck_rw_done(lck: &necp_kernel_policy_lock);
11799 }
11800 }
11801
11802 if (!policies_have_changed) {
11803 if (!route_allowed ||
11804 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
11805 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11806 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11807 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex)) {
11808 allowed_to_receive = FALSE;
11809 } else {
11810 if (return_policy_id) {
11811 *return_policy_id = inp->inp_policyresult.policy_id;
11812 }
11813 if (return_skip_policy_id) {
11814 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
11815 }
11816 if (return_route_rule_id) {
11817 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11818 }
11819 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
11820 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
11821 }
11822 }
11823 goto done;
11824 }
11825 }
11826
11827 // Check for loopback exception
11828 bypass_type = necp_socket_bypass(override_local_addr, override_remote_addr, inp);
11829 if (bypass_type == NECP_BYPASS_TYPE_INTCOPROC || (bypass_type == NECP_BYPASS_TYPE_LOOPBACK && necp_pass_loopback == NECP_LOOPBACK_PASS_ALL)) {
11830 allowed_to_receive = TRUE;
11831 goto done;
11832 }
11833
11834 // Actually calculate policy result
11835 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
11836 necp_socket_fillout_info_locked(inp, override_local_addr, override_remote_addr, override_bound_interface: 0, override_is_inbound: input_interface != NULL ? true : false, drop_order, socket_proc: &socket_proc, info: &info, is_loopback: (bypass_type == NECP_BYPASS_TYPE_LOOPBACK));
11837
11838 int debug = NECP_ENABLE_DATA_TRACE((&info.local_addr), (&info.remote_addr), info.protocol, info.pid, info.bound_interface_index);
11839 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "START", 0, 0);
11840
11841 flowhash = necp_socket_calc_flowhash_locked(info: &info);
11842 if (inp->inp_policyresult.policy_id != NECP_KERNEL_POLICY_ID_NONE &&
11843 inp->inp_policyresult.policy_gencount == necp_kernel_socket_policies_gencount &&
11844 inp->inp_policyresult.flowhash == flowhash) {
11845 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_DROP ||
11846 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11847 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11848 inp->inp_policyresult.results.result_parameter.tunnel_interface_index != verifyifindex) ||
11849 !necp_route_is_interface_type_allowed(route, ifp: input_interface, NULL, inp) ||
11850 (inp->inp_policyresult.results.route_rule_id != 0 &&
11851 !necp_route_is_allowed(route, interface: input_interface, NULL, netagent_array_count: 0, route_rule_id: inp->inp_policyresult.results.route_rule_id, interface_type_denied: &interface_type_denied))) {
11852 allowed_to_receive = FALSE;
11853 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <DROP>", 0, 0);
11854 } else {
11855 if (return_policy_id) {
11856 *return_policy_id = inp->inp_policyresult.policy_id;
11857 }
11858 if (return_route_rule_id) {
11859 *return_route_rule_id = inp->inp_policyresult.results.route_rule_id;
11860 }
11861 if (return_skip_policy_id) {
11862 *return_skip_policy_id = inp->inp_policyresult.skip_policy_id;
11863 }
11864 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS) {
11865 pass_flags = inp->inp_policyresult.results.result_parameter.pass_flags;
11866 }
11867 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11868 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - Send/Recv - RESULT - CACHED <MATCHED>: %p (BoundInterface %d Proto %d) Policy %d Skip %d Result %d Parameter %d",
11869 inp->inp_socket, info.bound_interface_index, info.protocol,
11870 inp->inp_policyresult.policy_id,
11871 inp->inp_policyresult.skip_policy_id,
11872 inp->inp_policyresult.results.result,
11873 inp->inp_policyresult.results.result_parameter.tunnel_interface_index);
11874 }
11875 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - CACHED <MATCHED>",
11876 return_policy_id ? *return_policy_id : 0, return_skip_policy_id ? *return_skip_policy_id : 0);
11877 }
11878 lck_rw_done(lck: &necp_kernel_policy_lock);
11879 goto done;
11880 }
11881
11882 u_int32_t route_rule_id_array[MAX_AGGREGATE_ROUTE_RULES];
11883 size_t route_rule_id_array_count = 0;
11884 struct necp_kernel_socket_policy *matched_policy = necp_socket_find_policy_match_with_info_locked(policy_search_array: necp_kernel_socket_policies_map[NECP_SOCKET_MAP_APP_ID_TO_BUCKET(info.application_id)], info: &info, return_filter: &filter_control_unit, return_route_rule_id_array: route_rule_id_array, return_route_rule_id_array_count: &route_rule_id_array_count, MAX_AGGREGATE_ROUTE_RULES, return_service_action: &service_action, return_service: &service, return_netagent_array: netagent_ids, NULL, NECP_MAX_NETAGENTS, NULL, num_required_agent_types: 0, proc: socket_proc ? socket_proc : current_proc(), pf_tag, skip_policy_id: return_skip_policy_id, rt: inp->inp_route.ro_rt, return_drop_dest_policy_result: &drop_dest_policy_result, return_drop_all_bypass: &drop_all_bypass, return_flow_divert_aggregate_unit: &flow_divert_aggregate_unit, so, debug);
11885
11886 // Check for loopback exception again after the policy match
11887 if (bypass_type == NECP_BYPASS_TYPE_LOOPBACK &&
11888 necp_pass_loopback == NECP_LOOPBACK_PASS_WITH_FILTER &&
11889 (matched_policy == NULL || matched_policy->result != NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT)) {
11890 // If policies haven't changed since last evaluation, do not update filter result in order to
11891 // preserve the very first filter result for the socket. Otherwise, update the filter result to
11892 // allow content filter to detect and drop pre-existing flows.
11893 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11894 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11895 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11896 }
11897 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11898 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11899 }
11900 allowed_to_receive = TRUE;
11901 lck_rw_done(lck: &necp_kernel_policy_lock);
11902 goto done;
11903 }
11904
11905 if (info.protocol != IPPROTO_UDP) {
11906 goto skip_agent_check;
11907 }
11908
11909 // Verify netagents
11910 if (necp_socket_verify_netagents(netagent_ids, debug, so) == false) {
11911 if (necp_debug > 1 || NECP_DATA_TRACE_POLICY_ON(debug)) {
11912 NECPLOG(LOG_ERR, "DATA-TRACE: Socket Policy: <so %llx> (BoundInterface %d Proto %d) Dropping packet because agent is not active", (unsigned long long)so, info.bound_interface_index, info.protocol);
11913 }
11914
11915 // Mark socket as a drop if required agent is not active
11916 inp->inp_policyresult.policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11917 inp->inp_policyresult.skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11918 inp->inp_policyresult.policy_gencount = necp_kernel_socket_policies_gencount;
11919 inp->inp_policyresult.flowhash = flowhash;
11920 inp->inp_policyresult.results.filter_control_unit = 0;
11921 inp->inp_policyresult.results.flow_divert_aggregate_unit = 0;
11922 inp->inp_policyresult.results.route_rule_id = 0;
11923 inp->inp_policyresult.results.result = NECP_KERNEL_POLICY_RESULT_DROP;
11924
11925 // Unlock
11926 allowed_to_receive = FALSE;
11927 lck_rw_done(lck: &necp_kernel_policy_lock);
11928 goto done;
11929 }
11930
11931skip_agent_check:
11932
11933 if (route_rule_id_array_count == 1) {
11934 route_rule_id = route_rule_id_array[0];
11935 } else if (route_rule_id_array_count > 1) {
11936 route_rule_id = necp_create_aggregate_route_rule(rule_ids: route_rule_id_array);
11937 }
11938
11939 bool send_local_network_denied_event = false;
11940 if (matched_policy != NULL) {
11941 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP &&
11942 matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_LOCAL_NETWORK &&
11943 !(matched_policy->result_parameter.drop_flags & NECP_KERNEL_POLICY_DROP_FLAG_SUPPRESS_ALERTS)) {
11944 // Trigger the event that we dropped due to a local network policy
11945 send_local_network_denied_event = true;
11946 }
11947
11948 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_DROP ||
11949 matched_policy->result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
11950 (matched_policy->result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL && input_interface &&
11951 matched_policy->result_parameter.tunnel_interface_index != verifyifindex) ||
11952 !necp_route_is_interface_type_allowed(route, ifp: input_interface, NULL, inp) ||
11953 (route_rule_id != 0 &&
11954 !necp_route_is_allowed(route, interface: input_interface, netagent_array: netagent_ids, NECP_MAX_NETAGENTS, route_rule_id, interface_type_denied: &interface_type_denied)) ||
11955 !necp_netagents_allow_traffic(netagent_ids, NECP_MAX_NETAGENTS)) {
11956 allowed_to_receive = FALSE;
11957 } else {
11958 if (return_policy_id) {
11959 *return_policy_id = matched_policy->id;
11960 }
11961 if (return_route_rule_id) {
11962 *return_route_rule_id = route_rule_id;
11963 }
11964 if (matched_policy->result == NECP_KERNEL_POLICY_RESULT_PASS) {
11965 pass_flags = matched_policy->result_parameter.pass_flags;
11966 }
11967 // If policies haven't changed since last evaluation, do not update filter result in order to
11968 // preserve the very first filter result for the socket. Otherwise, update the filter result to
11969 // allow content filter to detect and drop pre-existing flows.
11970 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
11971 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
11972 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
11973 }
11974 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
11975 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
11976 }
11977 }
11978
11979 if ((necp_debug > 1 && matched_policy->id != inp->inp_policyresult.policy_id) || NECP_DATA_TRACE_POLICY_ON(debug)) {
11980 NECPLOG(LOG_DEBUG, "DATA-TRACE: Socket Policy - Send/Recv: %p (BoundInterface %d Proto %d) Policy %d Result %d Parameter %d Allowed %d <filter_control_unit %d flow_divert_aggregate_unit %d>",
11981 inp->inp_socket, info.bound_interface_index, info.protocol, matched_policy->id, matched_policy->result, matched_policy->result_parameter.tunnel_interface_index, allowed_to_receive, filter_control_unit, flow_divert_aggregate_unit);
11982 }
11983 } else {
11984 bool drop_all = false;
11985 if (necp_drop_all_order > 0 || info.drop_order > 0 || drop_dest_policy_result == NECP_KERNEL_POLICY_RESULT_DROP) {
11986 drop_all = true;
11987 if (drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_NONE) {
11988 drop_all_bypass = necp_check_drop_all_bypass_result(proc: socket_proc ? socket_proc : current_proc());
11989 }
11990 }
11991 if (drop_all && drop_all_bypass == NECP_DROP_ALL_BYPASS_CHECK_RESULT_FALSE) {
11992 allowed_to_receive = FALSE;
11993 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - NO MATCH", 0, 0);
11994 } else {
11995 if (return_policy_id) {
11996 *return_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
11997 }
11998 if (return_route_rule_id) {
11999 *return_route_rule_id = route_rule_id;
12000 }
12001
12002 // If policies haven't changed since last evaluation, do not update filter result in order to
12003 // preserve the very first filter result for the socket. Otherwise, update the filter result to
12004 // allow content filter to detect and drop pre-existing flows.
12005 if (inp->inp_policyresult.policy_gencount != necp_kernel_socket_policies_gencount &&
12006 inp->inp_policyresult.results.filter_control_unit != filter_control_unit) {
12007 inp->inp_policyresult.results.filter_control_unit = filter_control_unit;
12008 }
12009 if (inp->inp_policyresult.results.flow_divert_aggregate_unit != flow_divert_aggregate_unit) {
12010 inp->inp_policyresult.results.flow_divert_aggregate_unit = flow_divert_aggregate_unit;
12011 }
12012 }
12013 }
12014
12015 if (necp_check_restricted_multicast_drop(proc: socket_proc ? socket_proc : current_proc(), info: &info, true)) {
12016 allowed_to_receive = FALSE;
12017 NECP_DATA_TRACE_LOG_SOCKET(debug, so, "SOCKET - DATA PATH", "RESULT - DROP - MULTICAST", 0, 0);
12018 }
12019
12020 lck_rw_done(lck: &necp_kernel_policy_lock);
12021
12022 if (send_local_network_denied_event && inp->inp_policyresult.network_denied_notifies == 0) {
12023 inp->inp_policyresult.network_denied_notifies++;
12024 necp_send_network_denied_event(pid: ((so->so_flags & SOF_DELEGATED) ? so->e_pid : so->last_pid),
12025 proc_uuid: ((so->so_flags & SOF_DELEGATED) ? so->e_uuid : so->last_uuid),
12026 NETPOLICY_NETWORKTYPE_LOCAL);
12027 }
12028
12029done:
12030 if (return_pass_flags != NULL) {
12031 *return_pass_flags = pass_flags;
12032 }
12033
12034 if (pf_tag != 0 && allowed_to_receive) {
12035 allowed_to_receive = necp_packet_filter_tags_receive(pf_tag, pass_flags);
12036 }
12037
12038 if (!allowed_to_receive && interface_type_denied != IFRTYPE_FUNCTIONAL_UNKNOWN) {
12039 soevent(so: inp->inp_socket, hint: (SO_FILT_HINT_LOCKED | SO_FILT_HINT_IFDENIED));
12040 }
12041
12042 if (socket_proc) {
12043 proc_rele(p: socket_proc);
12044 }
12045
12046 return allowed_to_receive;
12047}
12048
12049bool
12050necp_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)
12051{
12052 struct sockaddr_in local = {};
12053 struct sockaddr_in remote = {};
12054 local.sin_family = remote.sin_family = AF_INET;
12055 local.sin_len = remote.sin_len = sizeof(struct sockaddr_in);
12056 local.sin_port = local_port;
12057 remote.sin_port = remote_port;
12058 memcpy(dst: &local.sin_addr, src: local_addr, n: sizeof(local.sin_addr));
12059 memcpy(dst: &remote.sin_addr, src: remote_addr, n: sizeof(remote.sin_addr));
12060
12061 return necp_socket_is_allowed_to_send_recv_internal(inp, override_local_addr: (struct sockaddr *)&local, override_remote_addr: (struct sockaddr *)&remote, input_interface,
12062 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12063}
12064
12065bool
12066necp_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)
12067{
12068 struct sockaddr_in6 local = {};
12069 struct sockaddr_in6 remote = {};
12070 local.sin6_family = remote.sin6_family = AF_INET6;
12071 local.sin6_len = remote.sin6_len = sizeof(struct sockaddr_in6);
12072 local.sin6_port = local_port;
12073 remote.sin6_port = remote_port;
12074 memcpy(dst: &local.sin6_addr, src: local_addr, n: sizeof(local.sin6_addr));
12075 memcpy(dst: &remote.sin6_addr, src: remote_addr, n: sizeof(remote.sin6_addr));
12076
12077 return necp_socket_is_allowed_to_send_recv_internal(inp, override_local_addr: (struct sockaddr *)&local, override_remote_addr: (struct sockaddr *)&remote, input_interface,
12078 pf_tag, return_policy_id, return_route_rule_id, return_skip_policy_id, return_pass_flags);
12079}
12080
12081bool
12082necp_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,
12083 u_int32_t *return_route_rule_id, necp_kernel_policy_id *return_skip_policy_id, u_int32_t *return_pass_flags)
12084{
12085 return necp_socket_is_allowed_to_send_recv_internal(inp, NULL, NULL, input_interface, pf_tag,
12086 return_policy_id, return_route_rule_id,
12087 return_skip_policy_id, return_pass_flags);
12088}
12089
12090int
12091necp_mark_packet_from_socket(struct mbuf *packet, struct inpcb *inp, necp_kernel_policy_id policy_id, u_int32_t route_rule_id,
12092 necp_kernel_policy_id skip_policy_id, u_int32_t pass_flags)
12093{
12094 if (packet == NULL || inp == NULL || !(packet->m_flags & M_PKTHDR)) {
12095 return EINVAL;
12096 }
12097
12098 // Mark ID for Pass and IP Tunnel
12099 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12100 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12101 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_PASS ||
12102 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL) {
12103 packet->m_pkthdr.necp_mtag.necp_policy_id = inp->inp_policyresult.policy_id;
12104 } else {
12105 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12106 }
12107 packet->m_pkthdr.necp_mtag.necp_last_interface_index = 0;
12108 if (route_rule_id != 0) {
12109 packet->m_pkthdr.necp_mtag.necp_route_rule_id = route_rule_id;
12110 } else {
12111 packet->m_pkthdr.necp_mtag.necp_route_rule_id = inp->inp_policyresult.results.route_rule_id;
12112 }
12113 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);
12114
12115 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE &&
12116 skip_policy_id != NECP_KERNEL_POLICY_ID_NO_MATCH) {
12117 // Only mark the skip policy if it is a valid policy ID
12118 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12119 } else if (inp->inp_policyresult.results.filter_control_unit == NECP_FILTER_UNIT_NO_FILTER) {
12120 // Overload the meaning of "NECP_KERNEL_POLICY_ID_NO_MATCH"
12121 // to indicate that NECP_FILTER_UNIT_NO_FILTER was set
12122 // See necp_get_skip_policy_id_from_packet() and
12123 // necp_packet_should_skip_filters().
12124 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NO_MATCH;
12125 } else {
12126 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12127 }
12128
12129 if (((pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG) ||
12130 ((inp->inp_policyresult.results.result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_PF_TAG) == NECP_KERNEL_POLICY_PASS_PF_TAG)) {
12131 m_pftag(packet)->pftag_tag = PF_TAG_ID_SYSTEM_SERVICE;
12132 }
12133
12134 return 0;
12135}
12136
12137int
12138necp_mark_packet_from_ip(struct mbuf *packet, necp_kernel_policy_id policy_id)
12139{
12140 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12141 return EINVAL;
12142 }
12143
12144 // Mark ID for Pass and IP Tunnel
12145 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12146 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12147 } else {
12148 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12149 }
12150
12151 return 0;
12152}
12153
12154int
12155necp_mark_packet_from_ip_with_skip(struct mbuf *packet, necp_kernel_policy_id policy_id, necp_kernel_policy_id skip_policy_id)
12156{
12157 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12158 return EINVAL;
12159 }
12160
12161 // Mark ID for Pass and IP Tunnel
12162 if (policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12163 packet->m_pkthdr.necp_mtag.necp_policy_id = policy_id;
12164 } else {
12165 packet->m_pkthdr.necp_mtag.necp_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12166 }
12167
12168 if (skip_policy_id != NECP_KERNEL_POLICY_ID_NONE) {
12169 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = skip_policy_id;
12170 } else {
12171 packet->m_pkthdr.necp_mtag.necp_skip_policy_id = NECP_KERNEL_POLICY_ID_NONE;
12172 }
12173 return 0;
12174}
12175
12176int
12177necp_mark_packet_from_interface(struct mbuf *packet, ifnet_t interface)
12178{
12179 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12180 return EINVAL;
12181 }
12182
12183 // Mark ID for Pass and IP Tunnel
12184 if (interface != NULL) {
12185 packet->m_pkthdr.necp_mtag.necp_last_interface_index = interface->if_index;
12186 }
12187
12188 return 0;
12189}
12190
12191int
12192necp_mark_packet_as_keepalive(struct mbuf *packet, bool is_keepalive)
12193{
12194 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12195 return EINVAL;
12196 }
12197
12198 if (is_keepalive) {
12199 packet->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
12200 } else {
12201 packet->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
12202 }
12203
12204 return 0;
12205}
12206
12207necp_kernel_policy_id
12208necp_get_policy_id_from_packet(struct mbuf *packet)
12209{
12210 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12211 return NECP_KERNEL_POLICY_ID_NONE;
12212 }
12213
12214 return packet->m_pkthdr.necp_mtag.necp_policy_id;
12215}
12216
12217necp_kernel_policy_id
12218necp_get_skip_policy_id_from_packet(struct mbuf *packet)
12219{
12220 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12221 return NECP_KERNEL_POLICY_ID_NONE;
12222 }
12223
12224 // Check for overloaded value. See necp_mark_packet_from_socket().
12225 if (packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH) {
12226 return NECP_KERNEL_POLICY_ID_NONE;
12227 }
12228
12229 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id;
12230}
12231
12232u_int16_t
12233necp_get_packet_filter_tags_from_packet(struct mbuf *packet)
12234{
12235 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12236 return 0;
12237 }
12238
12239 return m_pftag(packet)->pftag_tag;
12240}
12241
12242bool
12243necp_packet_should_skip_filters(struct mbuf *packet)
12244{
12245 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12246 return false;
12247 }
12248
12249 // Check for overloaded value. See necp_mark_packet_from_socket().
12250 return packet->m_pkthdr.necp_mtag.necp_skip_policy_id == NECP_KERNEL_POLICY_ID_NO_MATCH;
12251}
12252
12253u_int32_t
12254necp_get_last_interface_index_from_packet(struct mbuf *packet)
12255{
12256 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12257 return 0;
12258 }
12259
12260 return packet->m_pkthdr.necp_mtag.necp_last_interface_index;
12261}
12262
12263u_int32_t
12264necp_get_route_rule_id_from_packet(struct mbuf *packet)
12265{
12266 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12267 return 0;
12268 }
12269
12270 return packet->m_pkthdr.necp_mtag.necp_route_rule_id;
12271}
12272
12273int
12274necp_get_app_uuid_from_packet(struct mbuf *packet,
12275 uuid_t app_uuid)
12276{
12277 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12278 return EINVAL;
12279 }
12280
12281 bool found_mapping = FALSE;
12282 if (packet->m_pkthdr.necp_mtag.necp_app_id != 0) {
12283 lck_rw_lock_shared(lck: &necp_kernel_policy_lock);
12284 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);
12285 struct necp_uuid_id_mapping *entry = necp_uuid_lookup_uuid_with_app_id_locked(local_id: app_id);
12286 if (entry != NULL) {
12287 uuid_copy(dst: app_uuid, src: entry->uuid);
12288 found_mapping = true;
12289 }
12290 lck_rw_done(lck: &necp_kernel_policy_lock);
12291 }
12292 if (!found_mapping) {
12293 uuid_clear(uu: app_uuid);
12294 }
12295 return 0;
12296}
12297
12298bool
12299necp_get_is_keepalive_from_packet(struct mbuf *packet)
12300{
12301 if (packet == NULL || !(packet->m_flags & M_PKTHDR)) {
12302 return FALSE;
12303 }
12304
12305 return packet->m_pkthdr.pkt_flags & PKTF_KEEPALIVE;
12306}
12307
12308u_int32_t
12309necp_socket_get_content_filter_control_unit(struct socket *so)
12310{
12311 struct inpcb *inp = sotoinpcb(so);
12312
12313 if (inp == NULL) {
12314 return 0;
12315 }
12316 return inp->inp_policyresult.results.filter_control_unit;
12317}
12318
12319bool
12320necp_socket_should_use_flow_divert(struct inpcb *inp)
12321{
12322 if (inp == NULL) {
12323 return FALSE;
12324 }
12325
12326 return !(inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) &&
12327 (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT ||
12328 (inp->inp_policyresult.results.flow_divert_aggregate_unit != 0));
12329}
12330
12331u_int32_t
12332necp_socket_get_flow_divert_control_unit(struct inpcb *inp, uint32_t *aggregate_unit)
12333{
12334 if (inp == NULL) {
12335 return 0;
12336 }
12337
12338 if (inp->inp_socket->so_flags1 & SOF1_FLOW_DIVERT_SKIP) {
12339 return 0;
12340 }
12341
12342 if (aggregate_unit != NULL &&
12343 inp->inp_policyresult.results.flow_divert_aggregate_unit != 0) {
12344 *aggregate_unit = inp->inp_policyresult.results.flow_divert_aggregate_unit;
12345 }
12346
12347 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT) {
12348 return inp->inp_policyresult.results.result_parameter.flow_divert_control_unit;
12349 }
12350
12351 return 0;
12352}
12353
12354bool
12355necp_socket_should_rescope(struct inpcb *inp)
12356{
12357 if (inp == NULL) {
12358 return FALSE;
12359 }
12360
12361 return inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED ||
12362 inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT;
12363}
12364
12365u_int
12366necp_socket_get_rescope_if_index(struct inpcb *inp)
12367{
12368 if (inp == NULL) {
12369 return 0;
12370 }
12371
12372 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SOCKET_SCOPED) {
12373 return inp->inp_policyresult.results.result_parameter.scoped_interface_index;
12374 } else if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_SCOPED_DIRECT) {
12375 return necp_get_primary_direct_interface_index();
12376 }
12377
12378 return 0;
12379}
12380
12381u_int32_t
12382necp_socket_get_effective_mtu(struct inpcb *inp, u_int32_t current_mtu)
12383{
12384 if (inp == NULL) {
12385 return current_mtu;
12386 }
12387
12388 if (inp->inp_policyresult.results.result == NECP_KERNEL_POLICY_RESULT_IP_TUNNEL &&
12389 (inp->inp_flags & INP_BOUND_IF) &&
12390 inp->inp_boundifp) {
12391 u_int bound_interface_index = inp->inp_boundifp->if_index;
12392 u_int tunnel_interface_index = inp->inp_policyresult.results.result_parameter.tunnel_interface_index;
12393
12394 // The result is IP Tunnel, and is rescoping from one interface to another. Recalculate MTU.
12395 if (bound_interface_index != tunnel_interface_index) {
12396 ifnet_t tunnel_interface = NULL;
12397
12398 ifnet_head_lock_shared();
12399 tunnel_interface = ifindex2ifnet[tunnel_interface_index];
12400 ifnet_head_done();
12401
12402 if (tunnel_interface != NULL) {
12403 u_int32_t direct_tunnel_mtu = tunnel_interface->if_mtu;
12404 u_int32_t delegate_tunnel_mtu = (tunnel_interface->if_delegated.ifp != NULL) ? tunnel_interface->if_delegated.ifp->if_mtu : 0;
12405 if (delegate_tunnel_mtu != 0 &&
12406 strncmp(s1: tunnel_interface->if_name, s2: "ipsec", n: strlen(s: "ipsec")) == 0) {
12407 // For ipsec interfaces, calculate the overhead from the delegate interface
12408 u_int32_t tunnel_overhead = (u_int32_t)(esp_hdrsiz(NULL) + sizeof(struct ip6_hdr));
12409 if (delegate_tunnel_mtu > tunnel_overhead) {
12410 delegate_tunnel_mtu -= tunnel_overhead;
12411 }
12412
12413 if (delegate_tunnel_mtu < direct_tunnel_mtu) {
12414 // If the (delegate - overhead) < direct, return (delegate - overhead)
12415 return delegate_tunnel_mtu;
12416 } else {
12417 // Otherwise return direct
12418 return direct_tunnel_mtu;
12419 }
12420 } else {
12421 // For non-ipsec interfaces, just return the tunnel MTU
12422 return direct_tunnel_mtu;
12423 }
12424 }
12425 }
12426 }
12427
12428 // By default, just return the MTU passed in
12429 return current_mtu;
12430}
12431
12432ifnet_t
12433necp_get_ifnet_from_result_parameter(necp_kernel_policy_result_parameter *result_parameter)
12434{
12435 if (result_parameter == NULL) {
12436 return NULL;
12437 }
12438
12439 return ifindex2ifnet[result_parameter->tunnel_interface_index];
12440}
12441
12442bool
12443necp_packet_can_rebind_to_ifnet(struct mbuf *packet, struct ifnet *interface, struct route *new_route, int family)
12444{
12445 bool found_match = FALSE;
12446 bool can_rebind = FALSE;
12447 ifaddr_t ifa;
12448 union necp_sockaddr_union address_storage;
12449
12450 if (packet == NULL || interface == NULL || new_route == NULL || (family != AF_INET && family != AF_INET6)) {
12451 return FALSE;
12452 }
12453
12454 // Match source address against interface addresses
12455 ifnet_lock_shared(ifp: interface);
12456 TAILQ_FOREACH(ifa, &interface->if_addrhead, ifa_link) {
12457 if (ifaddr_address(ifaddr: ifa, SA(&address_storage.sa), addr_size: sizeof(address_storage)) == 0) {
12458 if (address_storage.sa.sa_family != family) {
12459 continue;
12460 }
12461
12462 if (family == AF_INET) {
12463 struct ip *ip = mtod(packet, struct ip *);
12464 if (memcmp(s1: &address_storage.sin.sin_addr, s2: &ip->ip_src, n: sizeof(ip->ip_src)) == 0) {
12465 found_match = TRUE;
12466 break;
12467 }
12468 } else if (family == AF_INET6) {
12469 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12470 if (memcmp(s1: &address_storage.sin6.sin6_addr, s2: &ip6->ip6_src, n: sizeof(ip6->ip6_src)) == 0) {
12471 found_match = TRUE;
12472 break;
12473 }
12474 }
12475 }
12476 }
12477 const uint32_t if_idx = interface->if_index;
12478 ifnet_lock_done(ifp: interface);
12479
12480 // If source address matched, attempt to construct a route to the destination address
12481 if (found_match) {
12482 ROUTE_RELEASE(new_route);
12483
12484 if (family == AF_INET) {
12485 struct ip *ip = mtod(packet, struct ip *);
12486 struct sockaddr_in *dst4 = (struct sockaddr_in *)(void *)&new_route->ro_dst;
12487 dst4->sin_family = AF_INET;
12488 dst4->sin_len = sizeof(struct sockaddr_in);
12489 dst4->sin_addr = ip->ip_dst;
12490 rtalloc_scoped(new_route, if_idx);
12491 if (!ROUTE_UNUSABLE(new_route)) {
12492 can_rebind = TRUE;
12493 }
12494 } else if (family == AF_INET6) {
12495 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12496 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)(void *)&new_route->ro_dst;
12497 dst6->sin6_family = AF_INET6;
12498 dst6->sin6_len = sizeof(struct sockaddr_in6);
12499 dst6->sin6_addr = ip6->ip6_dst;
12500 rtalloc_scoped(new_route, if_idx);
12501 if (!ROUTE_UNUSABLE(new_route)) {
12502 can_rebind = TRUE;
12503 }
12504 }
12505 }
12506
12507 return can_rebind;
12508}
12509
12510static bool
12511necp_addr_is_loopback(struct sockaddr *address)
12512{
12513 if (address == NULL) {
12514 return FALSE;
12515 }
12516
12517 if (address->sa_family == AF_INET) {
12518 return ntohl(((struct sockaddr_in *)(void *)address)->sin_addr.s_addr) == INADDR_LOOPBACK;
12519 } else if (address->sa_family == AF_INET6) {
12520 if (!IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)address)->sin6_addr)) {
12521 return IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)address)->sin6_addr);
12522 } else {
12523 // Match ::ffff:127.0.0.1 loopback address
12524 in6_addr_t *in6_addr_ptr = &(((struct sockaddr_in6 *)(void *)address)->sin6_addr);
12525 return *(const __uint32_t *)(const void *)(&in6_addr_ptr->s6_addr[12]) == ntohl(INADDR_LOOPBACK);
12526 }
12527 }
12528
12529 return FALSE;
12530}
12531
12532static bool
12533necp_is_loopback(struct sockaddr *local_addr, struct sockaddr *remote_addr, struct inpcb *inp, struct mbuf *packet, u_int32_t bound_interface_index)
12534{
12535 // Note: This function only checks for the loopback addresses.
12536 // In the future, we may want to expand to also allow any traffic
12537 // going through the loopback interface, but until then, this
12538 // check is cheaper.
12539
12540 if (local_addr != NULL && necp_addr_is_loopback(address: local_addr)) {
12541 return TRUE;
12542 }
12543
12544 if (remote_addr != NULL && necp_addr_is_loopback(address: remote_addr)) {
12545 return TRUE;
12546 }
12547
12548 if (inp != NULL) {
12549 if ((inp->inp_flags & INP_BOUND_IF) && inp->inp_boundifp && (inp->inp_boundifp->if_flags & IFF_LOOPBACK)) {
12550 return TRUE;
12551 }
12552 if (inp->inp_vflag & INP_IPV4) {
12553 if (ntohl(inp->inp_laddr.s_addr) == INADDR_LOOPBACK ||
12554 ntohl(inp->inp_faddr.s_addr) == INADDR_LOOPBACK) {
12555 return TRUE;
12556 }
12557 } else if (inp->inp_vflag & INP_IPV6) {
12558 if (IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr) ||
12559 IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr)) {
12560 return TRUE;
12561 }
12562 }
12563 } else if (bound_interface_index != IFSCOPE_NONE && lo_ifp->if_index == bound_interface_index) {
12564 return TRUE;
12565 }
12566
12567 if (packet != NULL) {
12568 struct ip *ip = mtod(packet, struct ip *);
12569 if (ip->ip_v == 4) {
12570 if (ntohl(ip->ip_src.s_addr) == INADDR_LOOPBACK) {
12571 return TRUE;
12572 }
12573 if (ntohl(ip->ip_dst.s_addr) == INADDR_LOOPBACK) {
12574 return TRUE;
12575 }
12576 } else if (ip->ip_v == 6) {
12577 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12578 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src)) {
12579 return TRUE;
12580 }
12581 if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) {
12582 return TRUE;
12583 }
12584 }
12585 }
12586
12587 return FALSE;
12588}
12589
12590static bool
12591necp_is_intcoproc(struct inpcb *inp, struct mbuf *packet)
12592{
12593 if (inp != NULL) {
12594 if (!(inp->inp_vflag & INP_IPV6)) {
12595 return false;
12596 }
12597 if (INP_INTCOPROC_ALLOWED(inp)) {
12598 return true;
12599 }
12600 if ((inp->inp_flags & INP_BOUND_IF) &&
12601 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
12602 return true;
12603 }
12604 return false;
12605 }
12606 if (packet != NULL) {
12607 struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *);
12608 struct in6_addr *addrv6 = &ip6->ip6_dst;
12609 if ((ip6->ip6_vfc & IPV6_VERSION_MASK) == IPV6_VERSION &&
12610 NECP_IS_INTCOPROC_ADDRESS(addrv6)) {
12611 return true;
12612 }
12613 }
12614
12615 return false;
12616}
12617
12618static bool
12619necp_address_matches_drop_dest_policy(union necp_sockaddr_union *sau, u_int32_t session_order)
12620{
12621 char dest_str[MAX_IPv6_STR_LEN];
12622
12623 if (necp_drop_dest_debug > 0) {
12624 if (sau->sa.sa_family == AF_INET) {
12625 (void) inet_ntop(AF_INET, &sau->sin.sin_addr, dest_str, sizeof(dest_str));
12626 } else if (sau->sa.sa_family == AF_INET6) {
12627 (void) inet_ntop(AF_INET6, &sau->sin6.sin6_addr, dest_str, sizeof(dest_str));
12628 } else {
12629 dest_str[0] = 0;
12630 }
12631 }
12632 for (u_int32_t i = 0; i < necp_drop_dest_policy.entry_count; i++) {
12633 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
12634 struct necp_policy_condition_addr *npca = &necp_drop_dest_entry->cond_addr;
12635
12636 if (session_order >= necp_drop_dest_entry->order && necp_is_addr_in_subnet(SA(&sau->sa), SA(&npca->address.sa), subnet_prefix: npca->prefix)) {
12637 if (necp_drop_dest_debug > 0) {
12638 char subnet_str[MAX_IPv6_STR_LEN];
12639 struct proc *p = current_proc();
12640 pid_t pid = proc_pid(p);
12641
12642 if (sau->sa.sa_family == AF_INET) {
12643 (void) inet_ntop(AF_INET, &npca->address.sin, subnet_str, sizeof(subnet_str));
12644 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);
12645 } else if (sau->sa.sa_family == AF_INET6) {
12646 (void) inet_ntop(AF_INET6, &npca->address.sin6, subnet_str, sizeof(subnet_str));
12647 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);
12648 }
12649 }
12650 return true;
12651 }
12652 }
12653 if (necp_drop_dest_debug > 1) {
12654 struct proc *p = current_proc();
12655 pid_t pid = proc_pid(p);
12656
12657 os_log(OS_LOG_DEFAULT, "%s (process %s:%u) %s no match", __func__, proc_best_name(p), pid, dest_str);
12658 }
12659 return false;
12660}
12661
12662static int
12663sysctl_handle_necp_drop_dest_level SYSCTL_HANDLER_ARGS
12664{
12665#pragma unused(arg1, arg2, oidp)
12666 int changed = 0;
12667 int error = 0;
12668 struct necp_drop_dest_policy tmp_drop_dest_policy;
12669 struct proc *p = current_proc();
12670 pid_t pid = proc_pid(p);
12671
12672 if (req->newptr != USER_ADDR_NULL && proc_suser(p: current_proc()) != 0 &&
12673 priv_check_cred(cred: kauth_cred_get(), PRIV_NET_PRIVILEGED_NECP_POLICIES, flags: 0) != 0) {
12674 NECPLOG(LOG_ERR, "%s (process %s:%u) not permitted", __func__, proc_best_name(p), pid);
12675 return EPERM;
12676 }
12677 if (req->newptr != USER_ADDR_NULL && req->newlen != sizeof(struct necp_drop_dest_policy)) {
12678 NECPLOG(LOG_ERR, "%s (process %s:%u) bad newlen %lu", __func__, proc_best_name(p), pid, req->newlen);
12679 return EINVAL;
12680 }
12681
12682 memcpy(dst: &tmp_drop_dest_policy, src: &necp_drop_dest_policy, n: sizeof(struct necp_drop_dest_policy));
12683 error = sysctl_io_opaque(req, pValue: &tmp_drop_dest_policy, valueSize: sizeof(struct necp_drop_dest_policy), changed: &changed);
12684 if (error != 0) {
12685 NECPLOG(LOG_ERR, "%s (process %s:%u) sysctl_io_opaque() error %d", __func__, proc_best_name(p), pid, error);
12686 return error;
12687 }
12688 if (changed == 0 || req->newptr == USER_ADDR_NULL) {
12689 return error;
12690 }
12691
12692 //
12693 // Validate the passed parameters
12694 //
12695 if (tmp_drop_dest_policy.entry_count >= MAX_NECP_DROP_DEST_LEVEL_ADDRS) {
12696 NECPLOG(LOG_ERR, "%s (process %s:%u) bad entry_count %u", __func__, proc_best_name(p), pid, tmp_drop_dest_policy.entry_count);
12697 return EINVAL;
12698 }
12699 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
12700 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
12701 struct necp_policy_condition_addr *npca = &tmp_drop_dest_entry->cond_addr;
12702
12703 switch (tmp_drop_dest_entry->level) {
12704 case NECP_SESSION_PRIORITY_UNKNOWN:
12705 if (tmp_drop_dest_policy.entry_count != 0) {
12706 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);
12707 return EINVAL;
12708 }
12709 break;
12710 case NECP_SESSION_PRIORITY_CONTROL:
12711 case NECP_SESSION_PRIORITY_CONTROL_1:
12712 case NECP_SESSION_PRIORITY_PRIVILEGED_TUNNEL:
12713 case NECP_SESSION_PRIORITY_HIGH:
12714 case NECP_SESSION_PRIORITY_HIGH_1:
12715 case NECP_SESSION_PRIORITY_HIGH_2:
12716 case NECP_SESSION_PRIORITY_HIGH_3:
12717 case NECP_SESSION_PRIORITY_HIGH_4:
12718 case NECP_SESSION_PRIORITY_HIGH_RESTRICTED:
12719 case NECP_SESSION_PRIORITY_DEFAULT:
12720 case NECP_SESSION_PRIORITY_LOW:
12721 if (tmp_drop_dest_policy.entry_count == 0) {
12722 NECPLOG(LOG_ERR, "%s (process %s:%u) priority %u entry_count 0", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
12723 return EINVAL;
12724 }
12725 break;
12726 default: {
12727 NECPLOG(LOG_ERR, "%s (process %s:%u) bad level %u", __func__, proc_best_name(p), pid, tmp_drop_dest_entry->level);
12728 return EINVAL;
12729 }
12730 }
12731
12732 switch (npca->address.sa.sa_family) {
12733 case AF_INET: {
12734 if (npca->prefix > 32) {
12735 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
12736 return EINVAL;
12737 }
12738 if (npca->address.sin.sin_len != sizeof(struct sockaddr_in)) {
12739 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET bad sin_len %u", __func__, proc_best_name(p), pid, npca->address.sin.sin_len);
12740 return EINVAL;
12741 }
12742 if (npca->address.sin.sin_port != 0) {
12743 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);
12744 return EINVAL;
12745 }
12746 break;
12747 }
12748 case AF_INET6: {
12749 if (npca->prefix > 128) {
12750 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad prefix %u", __func__, proc_best_name(p), pid, npca->prefix);
12751 return EINVAL;
12752 }
12753 if (npca->address.sin6.sin6_len != sizeof(struct sockaddr_in6)) {
12754 NECPLOG(LOG_ERR, "%s (process %s:%u) AF_INET6 bad sin6_len %u", __func__, proc_best_name(p), pid, npca->address.sin6.sin6_len);
12755 return EINVAL;
12756 }
12757 if (npca->address.sin6.sin6_port != 0) {
12758 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);
12759 return EINVAL;
12760 }
12761 if (npca->address.sin6.sin6_flowinfo != 0) {
12762 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);
12763 return EINVAL;
12764 }
12765 if (npca->address.sin6.sin6_scope_id != 0) {
12766 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);
12767 return EINVAL;
12768 }
12769 break;
12770 }
12771 default: {
12772 return EINVAL;
12773 }
12774 }
12775 }
12776
12777 //
12778 // Commit the changed policy
12779 //
12780 lck_rw_lock_exclusive(lck: &necp_kernel_policy_lock);
12781 memset(s: &necp_drop_dest_policy, c: 0, n: sizeof(struct necp_drop_dest_policy));
12782
12783 necp_drop_dest_policy.entry_count = tmp_drop_dest_policy.entry_count;
12784 for (u_int32_t i = 0; i < tmp_drop_dest_policy.entry_count; i++) {
12785 struct necp_drop_dest_entry *tmp_drop_dest_entry = &tmp_drop_dest_policy.entries[i];
12786 struct necp_drop_dest_entry *necp_drop_dest_entry = &necp_drop_dest_policy.entries[i];
12787
12788 memcpy(dst: necp_drop_dest_entry, src: tmp_drop_dest_entry, n: sizeof(struct necp_drop_dest_entry));
12789
12790 necp_drop_dest_entry->order = necp_get_first_order_for_priority(priority: necp_drop_dest_entry->level);
12791 }
12792 lck_rw_done(lck: &necp_kernel_policy_lock);
12793
12794 return 0;
12795}
12796
12797const char*
12798necp_get_address_string(union necp_sockaddr_union *address, char addr_str[MAX_IPv6_STR_LEN])
12799{
12800 uint16_t fam = address->sa.sa_family;
12801 memset(s: addr_str, c: 0, MAX_IPv6_STR_LEN);
12802 if (fam == AF_INET) {
12803 (void) inet_ntop(AF_INET, &address->sin.sin_addr, addr_str, MAX_IPv6_STR_LEN);
12804 } else if (fam == AF_INET6) {
12805 (void) inet_ntop(AF_INET6, &address->sin6.sin6_addr, addr_str, MAX_IPv6_STR_LEN);
12806 }
12807 return addr_str;
12808}
12809